Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 8 ++- dlls/winegstreamer/wm_asyncreader.c | 17 ++++-- dlls/winegstreamer/wm_reader.c | 84 ++++++++++++++++++++++++----- 3 files changed, 91 insertions(+), 18 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e1dec7b755c..f1862515ebc 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -120,10 +120,11 @@ struct wm_stream { struct wm_reader *reader; struct wg_parser_stream *wg_stream; - WORD index; - bool eos; struct wg_format format; WMT_STREAM_SELECTION selection; + WORD index; + bool eos; + bool allocate_output; };
struct wm_reader @@ -148,6 +149,8 @@ struct wm_reader struct wm_stream *streams; WORD stream_count;
+ IWMReaderCallbackAdvanced *callback_advanced; + const struct wm_reader_ops *ops; };
@@ -174,6 +177,7 @@ void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops); 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_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps *props); HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 35ed8221aa0..e0547dfda60 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -57,10 +57,16 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader) static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) { static const DWORD zero; + HRESULT hr;
IWMReaderCallback_AddRef(reader->callback = callback); reader->context = context; IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); + + if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, + &IID_IWMReaderCallbackAdvanced, (void **)&reader->reader.callback_advanced))) + reader->reader.callback_advanced = NULL; + TRACE("Querying for IWMReaderCallbackAdvanced returned %#x.\n", hr); }
static DWORD WINAPI stream_thread(void *arg) @@ -497,11 +503,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetReceiveStreamSamples(IWMReaderAdvanced return E_NOTIMPL; }
-static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL allocate) +static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface, + DWORD output, 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, output %u, allocate %d.\n", reader, output, allocate); + + return wm_reader_set_allocate_for_output(&reader->reader, output, allocate); }
static HRESULT WINAPI WMReaderAdvanced_GetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL *allocate) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 3ca43fb127e..09059c3a32b 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1554,6 +1554,10 @@ HRESULT wm_reader_close(struct wm_reader *reader) CloseHandle(reader->read_thread); reader->read_thread = NULL;
+ if (reader->callback_advanced) + IWMReaderCallbackAdvanced_Release(reader->callback_advanced); + reader->callback_advanced = NULL; + wg_parser_destroy(reader->wg_parser); reader->wg_parser = NULL;
@@ -1758,9 +1762,9 @@ static const char *get_major_type_string(enum wg_major_type type) HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags) { + IWMReaderCallbackAdvanced *callback_advanced = stream->reader->callback_advanced; struct wg_parser_stream *wg_stream = stream->wg_stream; struct wg_parser_event event; - struct buffer *object;
if (stream->selection == WMT_OFF) return NS_E_INVALID_REQUEST; @@ -1768,6 +1772,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, if (stream->eos) return NS_E_NO_MORE_SAMPLES;
+ if (!stream->allocate_output) + callback_advanced = NULL; + for (;;) { if (!wg_parser_stream_get_event(wg_stream, &event)) @@ -1782,24 +1789,59 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, switch (event.type) { case WG_PARSER_EVENT_BUFFER: - /* FIXME: Should these be pooled? */ - if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size])))) + { + DWORD size, capacity; + INSSBuffer *sample; + HRESULT hr; + BYTE *data; + + if (callback_advanced) { - wg_parser_stream_release_buffer(wg_stream); - return E_OUTOFMEMORY; + 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); + wg_parser_stream_release_buffer(wg_stream); + return hr; + } + } + else + { + struct buffer *object; + + /* FIXME: Should these be pooled? */ + if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size])))) + { + wg_parser_stream_release_buffer(wg_stream); + return E_OUTOFMEMORY; + } + + object->INSSBuffer_iface.lpVtbl = &buffer_vtbl; + object->refcount = 1; + object->capacity = event.u.buffer.size; + + TRACE("Created buffer %p.\n", object); + sample = &object->INSSBuffer_iface; }
- object->INSSBuffer_iface.lpVtbl = &buffer_vtbl; - object->refcount = 1; - object->capacity = object->size = event.u.buffer.size; + if (FAILED(hr = INSSBuffer_GetBufferAndLength(sample, &data, &size))) + ERR("Failed to get data pointer, hr %#x.\n", hr); + if (FAILED(hr = INSSBuffer_GetMaxLength(sample, &capacity))) + ERR("Failed to get capacity, hr %#x.\n", hr); + if (event.u.buffer.size > capacity) + ERR("Returned capacity %u is less than requested capacity %u.\n", + capacity, event.u.buffer.size);
- if (!wg_parser_stream_copy_buffer(wg_stream, object->data, 0, object->size)) + if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, event.u.buffer.size)) { /* The GStreamer pin has been flushed. */ - free(object); + INSSBuffer_Release(sample); break; }
+ if (FAILED(hr = INSSBuffer_SetLength(sample, event.u.buffer.size))) + ERR("Failed to set size %u, hr %#x.\n", event.u.buffer.size, hr); + wg_parser_stream_release_buffer(wg_stream);
if (!event.u.buffer.has_pts) @@ -1815,9 +1857,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, if (!event.u.buffer.delta) *flags |= WM_SF_CLEANPOINT;
- TRACE("Created buffer %p.\n", object); - *ret_sample = &object->INSSBuffer_iface; + *ret_sample = sample; return S_OK; + }
case WG_PARSER_EVENT_EOS: stream->eos = true; @@ -1913,6 +1955,24 @@ HRESULT wm_reader_get_stream_selection(struct wm_reader *reader, return S_OK; }
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate) +{ + struct wm_stream *stream; + + EnterCriticalSection(&reader->cs); + + if (!(stream = get_stream_by_output_number(reader, output))) + { + LeaveCriticalSection(&reader->cs); + return E_INVALIDARG; + } + + stream->allocate_output = !!allocate; + + LeaveCriticalSection(&reader->cs); + return S_OK; +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wmvcore/tests/wmvcore.c | 434 +++++++++++++++++++++++++++++++++-- 1 file changed, 415 insertions(+), 19 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 76586822c84..07a465c7518 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -273,6 +273,117 @@ static void test_iscontentprotected(void) ok(drm == FALSE, "got %0dx\n", drm); }
+static LONG outstanding_buffers; + +struct buffer +{ + INSSBuffer INSSBuffer_iface; + LONG refcount; + + DWORD capacity, size; + BYTE data[1]; +}; + +static inline struct buffer *impl_from_INSSBuffer(INSSBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface); +} + +static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out) +{ + if (winetest_debug > 1) + trace("%04x: INSSBuffer::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid)); + + if (!IsEqualGUID(iid, &IID_INSSBuffer3) && !IsEqualGUID(iid, &IID_IMediaBuffer)) + ok(0, "Unexpected IID %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI buffer_AddRef(INSSBuffer *iface) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + return InterlockedIncrement(&buffer->refcount); +} + +static ULONG WINAPI buffer_Release(INSSBuffer *iface) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + ULONG refcount = InterlockedDecrement(&buffer->refcount); + + if (!refcount) + { + InterlockedDecrement(&outstanding_buffers); + free(buffer); + } + return refcount; +} + +static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + if (winetest_debug > 1) + trace("%04x: INSSBuffer::GetLength()\n", GetCurrentThreadId()); + + *size = buffer->size; + return S_OK; +} + +static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + if (winetest_debug > 1) + trace("%04x: INSSBuffer::SetLength(%u)\n", GetCurrentThreadId(), size); + + ok(size <= buffer->capacity, "Got size %u, buffer capacity %u.\n", size, buffer->capacity); + + buffer->size = size; + return S_OK; +} + +static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + if (winetest_debug > 1) + trace("%04x: INSSBuffer::GetMaxLength()\n", GetCurrentThreadId()); + + *size = buffer->capacity; + return S_OK; +} + +static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + if (winetest_debug > 1) + trace("%04x: INSSBuffer::GetBufferAndLength()\n", GetCurrentThreadId()); + + *size = buffer->size; + *data = buffer->data; + return S_OK; +} + +static const INSSBufferVtbl buffer_vtbl = +{ + buffer_QueryInterface, + buffer_AddRef, + buffer_Release, + buffer_GetLength, + buffer_SetLength, + buffer_GetMaxLength, + buffer_GetBuffer, + buffer_GetBufferAndLength, +}; + struct teststream { IStream IStream_iface; @@ -1230,10 +1341,13 @@ static void test_sync_reader_file(void) struct callback { IWMReaderCallback IWMReaderCallback_iface; + IWMReaderCallbackAdvanced IWMReaderCallbackAdvanced_iface; + IWMReaderAllocatorEx IWMReaderAllocatorEx_iface; LONG refcount; HANDLE got_opened, got_stopped, eof_event; unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof; bool all_streams_off; + bool allocated_samples; };
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface) @@ -1243,13 +1357,25 @@ static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
static HRESULT WINAPI callback_QueryInterface(IWMReaderCallback *iface, REFIID iid, void **out) { + struct callback *callback = impl_from_IWMReaderCallback(iface); + if (winetest_debug > 1) trace("%04x: IWMReaderCallback::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid));
- if (!IsEqualGUID(iid, &IID_IWMReaderCallbackAdvanced) && !IsEqualGUID(iid, &IID_IWMCredentialCallback)) - ok(0, "Unexpected IID %s.\n", debugstr_guid(iid)); + if (IsEqualGUID(iid, &IID_IWMReaderAllocatorEx)) + *out = &callback->IWMReaderAllocatorEx_iface; + else if (IsEqualGUID(iid, &IID_IWMReaderCallbackAdvanced)) + *out = &callback->IWMReaderCallbackAdvanced_iface; + else + { + if (!IsEqualGUID(iid, &IID_IWMCredentialCallback)) + ok(0, "Unexpected IID %s.\n", debugstr_guid(iid));
- return E_NOINTERFACE; + return E_NOINTERFACE; + } + + IWMReaderCallback_AddRef(iface); + return S_OK; }
static ULONG WINAPI callback_AddRef(IWMReaderCallback *iface) @@ -1362,27 +1488,39 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
- hr = INSSBuffer_GetBufferAndLength(sample, &data, &size); - ok(hr == S_OK, "Got hr %#x.\n", hr); + if (callback->allocated_samples) + { + struct buffer *buffer = impl_from_INSSBuffer(sample);
- hr = INSSBuffer_GetBuffer(sample, &data2); - ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(data2 == data, "Data pointers didn't match.\n"); + ok(sample->lpVtbl == &buffer_vtbl, "Buffer vtbl didn't match.\n"); + ok(buffer->size > 0 && buffer->size <= buffer->capacity, "Got size %d.\n", buffer->size); + } + else + { + ok(sample->lpVtbl != &buffer_vtbl, "Buffer vtbl shouldn't match.\n");
- hr = INSSBuffer_GetMaxLength(sample, &capacity); - ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(size <= capacity, "Size %u exceeds capacity %u.\n", size, capacity); + hr = INSSBuffer_GetBufferAndLength(sample, &data, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = INSSBuffer_SetLength(sample, capacity + 1); - ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + hr = INSSBuffer_GetBuffer(sample, &data2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(data2 == data, "Data pointers didn't match.\n");
- hr = INSSBuffer_SetLength(sample, capacity - 1); - ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = INSSBuffer_GetMaxLength(sample, &capacity); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(size <= capacity, "Size %u exceeds capacity %u.\n", size, capacity);
- hr = INSSBuffer_GetBufferAndLength(sample, &data2, &size); - ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(data2 == data, "Data pointers didn't match.\n"); - ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size); + hr = INSSBuffer_SetLength(sample, capacity + 1); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = INSSBuffer_SetLength(sample, capacity - 1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = INSSBuffer_GetBufferAndLength(sample, &data2, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(data2 == data, "Data pointers didn't match.\n"); + ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size); + }
ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started); ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof); @@ -1400,10 +1538,164 @@ static const IWMReaderCallbackVtbl callback_vtbl = callback_OnSample, };
+static struct callback *impl_from_IWMReaderCallbackAdvanced(IWMReaderCallbackAdvanced *iface) +{ + return CONTAINING_RECORD(iface, struct callback, IWMReaderCallbackAdvanced_iface); +} + +static HRESULT WINAPI callback_advanced_QueryInterface(IWMReaderCallbackAdvanced *iface, REFIID iid, void **out) +{ + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + return IWMReaderCallback_QueryInterface(&callback->IWMReaderCallback_iface, iid, out); +} + +static ULONG WINAPI callback_advanced_AddRef(IWMReaderCallbackAdvanced *iface) +{ + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + return IWMReaderCallback_AddRef(&callback->IWMReaderCallback_iface); +} + +static ULONG WINAPI callback_advanced_Release(IWMReaderCallbackAdvanced *iface) +{ + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + return IWMReaderCallback_Release(&callback->IWMReaderCallback_iface); +} + +static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced *iface, + WORD stream_number, QWORD pts, QWORD duration, DWORD flags, INSSBuffer *sample, void *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI callback_advanced_OnTime(IWMReaderCallbackAdvanced *iface, QWORD time, void *context) +{ + if (winetest_debug > 1) + trace("%u: %04x: IWMReaderCallbackAdvanced::OnTime(time %I64u)\n", + GetTickCount(), GetCurrentThreadId(), time); + + ok(time == 3000 * 10000, "Got time %I64u.\n", time); + ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); + return S_OK; +} + +static HRESULT WINAPI callback_advanced_OnStreamSelection(IWMReaderCallbackAdvanced *iface, + WORD count, WORD *stream_numbers, WMT_STREAM_SELECTION *selections, void *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI callback_advanced_OnOutputPropsChanged(IWMReaderCallbackAdvanced *iface, + DWORD output, WM_MEDIA_TYPE *mt, void *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +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; +} + +static HRESULT WINAPI callback_advanced_AllocateForOutput(IWMReaderCallbackAdvanced *iface, + DWORD output, DWORD size, INSSBuffer **sample, void *context) +{ + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + struct buffer *object; + + if (winetest_debug > 1) + 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 (!(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; + object->size = 0; + *sample = &object->INSSBuffer_iface; + + InterlockedIncrement(&outstanding_buffers); + + ok(!context, "Got unexpected context %p.\n", context); + return S_OK; +} + +static const IWMReaderCallbackAdvancedVtbl callback_advanced_vtbl = +{ + callback_advanced_QueryInterface, + callback_advanced_AddRef, + callback_advanced_Release, + callback_advanced_OnStreamSample, + callback_advanced_OnTime, + callback_advanced_OnStreamSelection, + callback_advanced_OnOutputPropsChanged, + callback_advanced_AllocateForStream, + callback_advanced_AllocateForOutput, +}; + +static struct callback *impl_from_IWMReaderAllocatorEx(IWMReaderAllocatorEx *iface) +{ + return CONTAINING_RECORD(iface, struct callback, IWMReaderAllocatorEx_iface); +} + +static HRESULT WINAPI callback_allocator_QueryInterface(IWMReaderAllocatorEx *iface, REFIID iid, void **out) +{ + struct callback *callback = impl_from_IWMReaderAllocatorEx(iface); + return IWMReaderCallback_QueryInterface(&callback->IWMReaderCallback_iface, iid, out); +} + +static ULONG WINAPI callback_allocator_AddRef(IWMReaderAllocatorEx *iface) +{ + struct callback *callback = impl_from_IWMReaderAllocatorEx(iface); + return IWMReaderCallback_AddRef(&callback->IWMReaderCallback_iface); +} + +static ULONG WINAPI callback_allocator_Release(IWMReaderAllocatorEx *iface) +{ + struct callback *callback = impl_from_IWMReaderAllocatorEx(iface); + return IWMReaderCallback_Release(&callback->IWMReaderCallback_iface); +} + +static HRESULT WINAPI callback_allocator_AllocateForStreamEx(IWMReaderAllocatorEx *iface, + WORD stream_number, DWORD size, INSSBuffer **sample, DWORD flags, + QWORD pts, QWORD duration, void *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI callback_allocator_AllocateForOutputEx(IWMReaderAllocatorEx *iface, + DWORD output, DWORD size, INSSBuffer **sample, DWORD flags, + QWORD pts, QWORD duration, void *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IWMReaderAllocatorExVtbl callback_allocator_vtbl = +{ + callback_allocator_QueryInterface, + callback_allocator_AddRef, + callback_allocator_Release, + callback_allocator_AllocateForStreamEx, + callback_allocator_AllocateForOutputEx, +}; + static void callback_init(struct callback *callback) { memset(callback, 0, sizeof(*callback)); callback->IWMReaderCallback_iface.lpVtbl = &callback_vtbl; + callback->IWMReaderCallbackAdvanced_iface.lpVtbl = &callback_advanced_vtbl; + callback->IWMReaderAllocatorEx_iface.lpVtbl = &callback_allocator_vtbl; callback->refcount = 1; callback->got_opened = CreateEventW(NULL, FALSE, FALSE, NULL); callback->got_stopped = CreateEventW(NULL, FALSE, FALSE, NULL); @@ -1444,6 +1736,109 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(hr == S_OK, "Got hr %#x.\n", hr); ret = WaitForSingleObject(callback->got_stopped, 1000); ok(!ret, "Wait timed out.\n"); + + ok(!outstanding_buffers, "Got %d outstanding buffers.\n", outstanding_buffers); +} + +static void test_async_reader_allocate(IWMReader *reader, + IWMReaderAdvanced2 *advanced, struct callback *callback) +{ + BOOL allocate; + HRESULT hr; + + callback->allocated_samples = true; + + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 2, &allocate); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 0, &allocate); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 3, &allocate); + todo_wine ok(hr == E_INVALIDARG, "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); + hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 2, TRUE); + 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); + if (hr == S_OK) + ok(allocate == TRUE, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(allocate == TRUE, "Got allocate %d.\n", allocate); + + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + + run_async_reader(reader, advanced, callback); + + callback->allocated_samples = false; + + 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_SetAllocateForStream(advanced, 0, TRUE); + todo_wine 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); + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, TRUE); + todo_wine 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); + + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(!allocate, "Got allocate %d.\n", allocate); + + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(allocate == TRUE, "Got allocate %d.\n", allocate); + hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + ok(allocate == TRUE, "Got allocate %d.\n", allocate); + + run_async_reader(reader, advanced, callback); + + hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, FALSE); + todo_wine 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); }
static void test_async_reader_selection(IWMReader *reader, @@ -1611,6 +2006,7 @@ static void test_async_reader_streaming(void)
test_reader_attributes(profile); test_async_reader_selection(reader, advanced, &callback); + test_async_reader_allocate(reader, advanced, &callback);
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#x.\n", hr);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 7 +++ dlls/winegstreamer/wm_asyncreader.c | 20 +++++--- dlls/winegstreamer/wm_reader.c | 23 ++++++++-- dlls/wmvcore/tests/wmvcore.c | 71 ++++++++++++++++++++++++----- 4 files changed, 100 insertions(+), 21 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index f1862515ebc..e31405a09ca 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -125,6 +125,11 @@ struct wm_stream WORD index; bool eos; bool allocate_output; + /* 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 + * in nontrivial ways depending on this field. */ + bool read_compressed; };
struct wm_reader @@ -180,6 +185,8 @@ 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_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps *props); +HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, + WORD stream_number, BOOL compressed); HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections);
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index e0547dfda60..9cf8a73eb53 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -129,7 +129,13 @@ static DWORD WINAPI stream_thread(void *arg) } }
- IWMReaderCallback_OnSample(callback, i, pts, duration, flags, sample, reader->context); + if (stream->read_compressed) + hr = IWMReaderCallbackAdvanced_OnStreamSample(reader->reader.callback_advanced, + i + 1, pts, duration, flags, sample, reader->context); + else + hr = IWMReaderCallback_OnSample(callback, i, pts, duration, + flags, sample, reader->context); + TRACE("Callback returned %#x.\n", hr); INSSBuffer_Release(sample); all_eos = false; } @@ -487,12 +493,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetReceiveSelectionCallbacks(IWMReaderAdv return E_NOTIMPL; }
-static HRESULT WINAPI WMReaderAdvanced_SetReceiveStreamSamples(IWMReaderAdvanced6 *iface, WORD stream_num, - BOOL receive_stream_samples) +static HRESULT WINAPI WMReaderAdvanced_SetReceiveStreamSamples(IWMReaderAdvanced6 *iface, + WORD stream_number, BOOL compressed) { - struct async_reader *This = impl_from_IWMReaderAdvanced6(iface); - FIXME("(%p)->(%d %x)\n", This, stream_num, receive_stream_samples); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface); + + TRACE("reader %p, stream_number %u, compressed %d.\n", reader, stream_number, compressed); + + return wm_reader_set_read_compressed(&reader->reader, stream_number, compressed); }
static HRESULT WINAPI WMReaderAdvanced_GetReceiveStreamSamples(IWMReaderAdvanced6 *iface, WORD stream_num, diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 09059c3a32b..c53fb8ea8ee 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1772,9 +1772,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, if (stream->eos) return NS_E_NO_MORE_SAMPLES;
- if (!stream->allocate_output) - callback_advanced = NULL; - for (;;) { if (!wg_parser_stream_get_event(wg_stream, &event)) @@ -1795,7 +1792,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, HRESULT hr; BYTE *data;
- if (callback_advanced) + if (callback_advanced && !stream->read_compressed && stream->allocate_output) { if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced, stream->index, event.u.buffer.size, &sample, NULL))) @@ -1973,6 +1970,24 @@ HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output return S_OK; }
+HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_number, BOOL compressed) +{ + 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->read_compressed = compressed; + + LeaveCriticalSection(&reader->cs); + return S_OK; +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 07a465c7518..eb6e45b30ce 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1348,6 +1348,7 @@ struct callback unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof; bool all_streams_off; bool allocated_samples; + bool read_compressed; };
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface) @@ -1474,20 +1475,12 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta return S_OK; }
-static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, - QWORD time, QWORD duration, DWORD flags, INSSBuffer *sample, void *context) +static void check_async_sample(struct callback *callback, INSSBuffer *sample) { - struct callback *callback = impl_from_IWMReaderCallback(iface); DWORD size, capacity; BYTE *data, *data2; HRESULT hr;
- if (winetest_debug > 1) - trace("%u: %04x: IWMReaderCallback::OnSample(output %u, time %I64u, duration %I64u, flags %#x)\n", - GetTickCount(), GetCurrentThreadId(), output, time, duration, flags); - - ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); - if (callback->allocated_samples) { struct buffer *buffer = impl_from_INSSBuffer(sample); @@ -1521,7 +1514,22 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, ok(data2 == data, "Data pointers didn't match.\n"); ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size); } +}
+static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, + QWORD time, QWORD duration, DWORD flags, INSSBuffer *sample, void *context) +{ + struct callback *callback = impl_from_IWMReaderCallback(iface); + + if (winetest_debug > 1) + trace("%u: %04x: IWMReaderCallback::OnSample(output %u, time %I64u, duration %I64u, flags %#x)\n", + GetTickCount(), GetCurrentThreadId(), output, time, duration, flags); + + ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); + + check_async_sample(callback, sample); + + ok(!callback->read_compressed, "OnSample() should not be called when reading compressed samples.\n"); ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started); ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof); ++callback->got_sample; @@ -1564,8 +1572,22 @@ static ULONG WINAPI callback_advanced_Release(IWMReaderCallbackAdvanced *iface) static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced *iface, WORD stream_number, QWORD pts, QWORD duration, DWORD flags, INSSBuffer *sample, void *context) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); + + if (winetest_debug > 1) + trace("%u: %04x: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#x)\n", + GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags); + + ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); + + check_async_sample(callback, sample); + + ok(callback->read_compressed, "OnStreamSample() should not be called unless reading compressed samples.\n"); + ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started); + ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof); + ++callback->got_sample; + + return S_OK; }
static HRESULT WINAPI callback_advanced_OnTime(IWMReaderCallbackAdvanced *iface, QWORD time, void *context) @@ -1915,6 +1937,32 @@ static void test_async_reader_selection(IWMReader *reader, ok(hr == S_OK, "Got hr %#x.\n", hr); }
+static void test_async_reader_compressed(IWMReader *reader, + IWMReaderAdvanced2 *advanced, struct callback *callback) +{ + HRESULT hr; + + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 0, TRUE); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 3, TRUE); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + 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->read_compressed = true; + run_async_reader(reader, advanced, callback); + callback->read_compressed = false; + + 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); +} + static void test_async_reader_streaming(void) { const WCHAR *filename = load_resource(L"test.wmv"); @@ -2007,6 +2055,7 @@ static void test_async_reader_streaming(void) test_reader_attributes(profile); test_async_reader_selection(reader, advanced, &callback); test_async_reader_allocate(reader, advanced, &callback); + test_async_reader_compressed(reader, advanced, &callback);
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#x.\n", hr);
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);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_syncreader.c | 10 ++++--- dlls/wmvcore/tests/wmvcore.c | 43 +++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 73bbf18898f..96754d107de 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -296,11 +296,13 @@ static HRESULT WINAPI WMSyncReader_SetRangeByFrame(IWMSyncReader2 *iface, WORD s return E_NOTIMPL; }
-static HRESULT WINAPI WMSyncReader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_num, BOOL compressed) +static HRESULT WINAPI WMSyncReader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL compressed) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%u %x): stub!\n", This, stream_num, compressed); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, stream_index %u, compressed %d.\n", reader, stream_number, compressed); + + return wm_reader_set_read_compressed(&reader->reader, stream_number, compressed); }
static HRESULT WINAPI WMSyncReader_SetStreamsSelected(IWMSyncReader2 *iface, diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 8e10d9f5e89..9ddd53ab9e7 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -821,6 +821,45 @@ static void test_sync_reader_selection(IWMSyncReader *reader) ok(hr == S_OK, "Got hr %#x.\n", hr); }
+static void test_sync_reader_compressed(IWMSyncReader *reader) +{ + QWORD pts, duration; + INSSBuffer *sample; + WORD stream_number; + DWORD flags; + HRESULT hr; + + hr = IWMSyncReader_SetReadStreamSamples(reader, 0, TRUE); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + hr = IWMSyncReader_SetReadStreamSamples(reader, 1, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMSyncReader_SetReadStreamSamples(reader, 2, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMSyncReader_SetReadStreamSamples(reader, 3, TRUE); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_SetRange(reader, 0, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, &stream_number); + ok(hr == S_OK, "Got hr %#x.\n", hr); + INSSBuffer_Release(sample); + + for (;;) + { + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, &stream_number); + if (hr == NS_E_NO_MORE_SAMPLES) + break; + ok(hr == S_OK, "Got hr %#x.\n", hr); + INSSBuffer_Release(sample); + } + + hr = IWMSyncReader_SetReadStreamSamples(reader, 1, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMSyncReader_SetReadStreamSamples(reader, 2, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); +} + static void test_sync_reader_streaming(void) { DWORD size, capacity, flags, output_number, expect_output_number; @@ -883,9 +922,6 @@ static void test_sync_reader_streaming(void)
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %d.\n", ref); - - hr = IWMSyncReader_SetReadStreamSamples(reader, stream_numbers[i], FALSE); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); }
hr = IWMProfile_GetStream(profile, 2, &config); @@ -1028,6 +1064,7 @@ static void test_sync_reader_streaming(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
test_sync_reader_selection(reader); + test_sync_reader_compressed(reader);
test_reader_attributes(profile);