Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/wm_asyncreader.c | 11 +-- dlls/winegstreamer/wm_reader.c | 32 ++++++++- dlls/wmvcore/tests/wmvcore.c | 108 +++++++++++++++++++++++++--- 4 files changed, 136 insertions(+), 17 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e31405a09ca..e0f8bdae4a6 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -125,6 +125,7 @@ struct wm_stream WORD index; bool eos; bool allocate_output; + bool allocate_stream; /* Note that we only pretend to read compressed samples, and instead output * uncompressed samples regardless of whether we are configured to read * compressed samples. Rather, the behaviour of the reader objects differs @@ -183,6 +184,7 @@ HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename); HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream); void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration); HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate); +HRESULT wm_reader_set_allocate_for_stream(struct wm_reader *reader, WORD stream_number, BOOL allocate); HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps *props); HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 9cf8a73eb53..b3dd7d41873 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -528,11 +528,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetAllocateForOutput(IWMReaderAdvanced6 * return E_NOTIMPL; }
-static HRESULT WINAPI WMReaderAdvanced_SetAllocateForStream(IWMReaderAdvanced6 *iface, WORD output_num, BOOL allocate) +static HRESULT WINAPI WMReaderAdvanced_SetAllocateForStream(IWMReaderAdvanced6 *iface, + WORD stream_number, BOOL allocate) { - struct async_reader *This = impl_from_IWMReaderAdvanced6(iface); - FIXME("(%p)->(%d %x)\n", This, output_num, allocate); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface); + + TRACE("reader %p, stream_number %u, allocate %d.\n", reader, stream_number, allocate); + + return wm_reader_set_allocate_for_stream(&reader->reader, stream_number, allocate); }
static HRESULT WINAPI WMReaderAdvanced_GetAllocateForStream(IWMReaderAdvanced6 *iface, WORD output_num, BOOL *allocate) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index c53fb8ea8ee..a6e73c2857e 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1792,12 +1792,22 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, HRESULT hr; BYTE *data;
- if (callback_advanced && !stream->read_compressed && stream->allocate_output) + if (callback_advanced && stream->read_compressed && stream->allocate_stream) + { + if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForStream(callback_advanced, + stream->index + 1, event.u.buffer.size, &sample, NULL))) + { + ERR("Failed to allocate stream sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); + wg_parser_stream_release_buffer(wg_stream); + return hr; + } + } + else if (callback_advanced && !stream->read_compressed && stream->allocate_output) { if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced, stream->index, event.u.buffer.size, &sample, NULL))) { - ERR("Failed to allocate sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); + ERR("Failed to allocate output sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); wg_parser_stream_release_buffer(wg_stream); return hr; } @@ -1970,6 +1980,24 @@ HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output return S_OK; }
+HRESULT wm_reader_set_allocate_for_stream(struct wm_reader *reader, WORD stream_number, BOOL allocate) +{ + struct wm_stream *stream; + + EnterCriticalSection(&reader->cs); + + if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number))) + { + LeaveCriticalSection(&reader->cs); + return E_INVALIDARG; + } + + stream->allocate_stream = !!allocate; + + LeaveCriticalSection(&reader->cs); + return S_OK; +} + HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_number, BOOL compressed) { struct wm_stream *stream; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index eb6e45b30ce..8e10d9f5e89 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -356,8 +356,13 @@ static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct buffer *buffer = impl_from_INSSBuffer(iface); + + if (winetest_debug > 1) + trace("%04x: INSSBuffer::GetBuffer()\n", GetCurrentThreadId()); + + *data = buffer->data; + return S_OK; }
static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size) @@ -1618,8 +1623,32 @@ static HRESULT WINAPI callback_advanced_OnOutputPropsChanged(IWMReaderCallbackAd static HRESULT WINAPI callback_advanced_AllocateForStream(IWMReaderCallbackAdvanced *iface, WORD stream_number, DWORD size, INSSBuffer **sample, void *context) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + struct buffer *object; + + if (winetest_debug > 1) + trace("%u: %04x: IWMReaderCallbackAdvanced::AllocateForStream(output %u, size %u)\n", + GetTickCount(), GetCurrentThreadId(), stream_number, size); + + ok(callback->read_compressed, "AllocateForStream() should only be called when reading compressed samples.\n"); + ok(callback->allocated_samples, "AllocateForStream() should only be called when using a custom allocator.\n"); + + if (!(object = malloc(offsetof(struct buffer, data[size])))) + return E_OUTOFMEMORY; + + size = max(size, 65536); + + object->INSSBuffer_iface.lpVtbl = &buffer_vtbl; + object->refcount = 1; + object->capacity = size; + /* Native seems to break if we set the size to zero. */ + object->size = size; + *sample = &object->INSSBuffer_iface; + + InterlockedIncrement(&outstanding_buffers); + + ok(!context, "Got unexpected context %p.\n", context); + return S_OK; }
static HRESULT WINAPI callback_advanced_AllocateForOutput(IWMReaderCallbackAdvanced *iface, @@ -1632,7 +1661,15 @@ static HRESULT WINAPI callback_advanced_AllocateForOutput(IWMReaderCallbackAdvan trace("%u: %04x: IWMReaderCallbackAdvanced::AllocateForOutput(output %u, size %u)\n", GetTickCount(), GetCurrentThreadId(), output, size);
- ok(callback->allocated_samples, "AllocateForOutput() should only be called when using a custom allocator.\n"); + if (!callback->read_compressed) + { + /* Actually AllocateForOutput() isn't called when reading compressed + * samples either, but native seems to have some sort of race that + * causes one call to this function to happen in + * test_async_reader_allocate_compressed(). */ + ok(callback->allocated_samples, + "AllocateForOutput() should only be called when using a custom allocator.\n"); + }
if (!(object = malloc(offsetof(struct buffer, data[size])))) return E_OUTOFMEMORY; @@ -1829,13 +1866,13 @@ static void test_async_reader_allocate(IWMReader *reader, ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 0, TRUE); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, TRUE); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, TRUE); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 3, TRUE); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate); todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -1858,9 +1895,9 @@ static void test_async_reader_allocate(IWMReader *reader, run_async_reader(reader, advanced, callback);
hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, FALSE); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, FALSE); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); }
static void test_async_reader_selection(IWMReader *reader, @@ -1963,6 +2000,54 @@ static void test_async_reader_compressed(IWMReader *reader, ok(hr == S_OK, "Got hr %#x.\n", hr); }
+static void test_async_reader_allocate_compressed(IWMReader *reader, + IWMReaderAdvanced2 *advanced, struct callback *callback) +{ + HRESULT hr; + + callback->read_compressed = true; + + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + callback->allocated_samples = true; + + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + run_async_reader(reader, advanced, callback); + + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 0, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 1, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + callback->allocated_samples = false; + + run_async_reader(reader, advanced, callback); + + hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 0, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 1, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + callback->read_compressed = false; +} + static void test_async_reader_streaming(void) { const WCHAR *filename = load_resource(L"test.wmv"); @@ -2056,6 +2141,7 @@ static void test_async_reader_streaming(void) test_async_reader_selection(reader, advanced, &callback); test_async_reader_allocate(reader, advanced, &callback); test_async_reader_compressed(reader, advanced, &callback); + test_async_reader_allocate_compressed(reader, advanced, &callback);
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#x.\n", hr);