-- v2: amstream: Release the allocator used by the direct draw stream. amstream: Implement dynamic formats in ddraw stream. amstream/tests: Test for dynamic formats in ddraw stream. amstream: Implement custom allocator for ddraw stream. amstream/tests: Test for custom allocator in ddraw stream. amstream: Implement IMemAllocator stub for ddraw stream.
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/ddrawstream.c | 82 ++++++++++++++++++++++++++++++++++ dlls/amstream/tests/amstream.c | 1 + 2 files changed, 83 insertions(+)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index dc77cb87813..47b856781e9 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -41,6 +41,7 @@ struct ddraw_stream IAMMediaStream IAMMediaStream_iface; IDirectDrawMediaStream IDirectDrawMediaStream_iface; IMemInputPin IMemInputPin_iface; + IMemAllocator IMemAllocator_iface; IPin IPin_iface; LONG ref; LONG sample_refs; @@ -201,6 +202,12 @@ static HRESULT WINAPI ddraw_IAMMediaStream_QueryInterface(IAMMediaStream *iface, *ret_iface = &This->IMemInputPin_iface; return S_OK; } + else if (IsEqualGUID(riid, &IID_IMemAllocator)) + { + IAMMediaStream_AddRef(iface); + *ret_iface = &This->IMemAllocator_iface; + return S_OK; + }
ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface); return E_NOINTERFACE; @@ -1274,6 +1281,80 @@ static const IPinVtbl ddraw_sink_vtbl = ddraw_sink_NewSegment, };
+static inline struct ddraw_stream *impl_from_IMemAllocator(IMemAllocator *iface) +{ + return CONTAINING_RECORD(iface, struct ddraw_stream, IMemAllocator_iface); +} + +static HRESULT WINAPI ddraw_mem_allocator_QueryInterface(IMemAllocator *iface, REFIID iid, void **out) +{ + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out); +} + +static ULONG WINAPI ddraw_mem_allocator_AddRef(IMemAllocator *iface) +{ + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface); +} + +static ULONG WINAPI ddraw_mem_allocator_Release(IMemAllocator *iface) +{ + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + return IAMMediaStream_Release(&stream->IAMMediaStream_iface); +} + +static HRESULT WINAPI ddraw_mem_allocator_SetProperties(IMemAllocator *iface, ALLOCATOR_PROPERTIES *request, ALLOCATOR_PROPERTIES *actual) +{ + FIXME("iface %p request %p actual %p stub!\n", iface, request, actual); + return E_NOTIMPL; +} + +static HRESULT WINAPI ddraw_mem_allocator_GetProperties(IMemAllocator *iface,ALLOCATOR_PROPERTIES *props) +{ + FIXME("iface %p props %p stub!\n", iface, props); + return E_NOTIMPL; +} + +static HRESULT WINAPI ddraw_mem_allocator_Commit(IMemAllocator *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI ddraw_mem_allocator_Decommit(IMemAllocator *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI ddraw_mem_allocator_GetBuffer(IMemAllocator *iface, IMediaSample **buf, + REFERENCE_TIME *start_time, REFERENCE_TIME *end_time, + DWORD flags) +{ + FIXME("iface %p buf %p start_time %p end_time %p flags %#lx stub!\n", iface, buf, start_time, end_time, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI ddraw_mem_allocator_ReleaseBuffer(IMemAllocator *iface,IMediaSample *buf) +{ + FIXME("iface %p buf %p stub!\n", iface, buf); + return E_NOTIMPL; +} + +static const IMemAllocatorVtbl ddraw_mem_allocator_vtbl = +{ + ddraw_mem_allocator_QueryInterface, + ddraw_mem_allocator_AddRef, + ddraw_mem_allocator_Release, + ddraw_mem_allocator_SetProperties, + ddraw_mem_allocator_GetProperties, + ddraw_mem_allocator_Commit, + ddraw_mem_allocator_Decommit, + ddraw_mem_allocator_GetBuffer, + ddraw_mem_allocator_ReleaseBuffer +}; + static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface) { return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface); @@ -1484,6 +1565,7 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl; object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl; object->IPin_iface.lpVtbl = &ddraw_sink_vtbl; + object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl; object->ref = 1;
object->format.width = 100; diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index b796dbd64f8..759c4b75fda 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -397,6 +397,7 @@ static void test_interfaces(void) check_interface(stream, &IID_IDirectDrawMediaStream, TRUE); check_interface(stream, &IID_IMediaStream, TRUE); check_interface(stream, &IID_IMemInputPin, TRUE); + check_interface(stream, &IID_IMemAllocator, TRUE); check_interface(stream, &IID_IPin, TRUE); check_interface(stream, &IID_IUnknown, TRUE);
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/tests/amstream.c | 161 +++++++++++++++++++++++++++++++-- 1 file changed, 154 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 759c4b75fda..a05ffb44406 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -1027,6 +1027,7 @@ struct testfilter HANDLE wait_state_event; IBaseFilter *qc_notify_sender; Quality qc_notify_quality; + BOOL use_input_pin_allocator; HRESULT get_duration_hr; HRESULT get_stop_position_hr; HRESULT set_positions_hr; @@ -1142,16 +1143,21 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid
static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface, IMemInputPin *pin, IMemAllocator **alloc) { + struct testfilter *filter = impl_from_base_pin(&iface->pin); ALLOCATOR_PROPERTIES props = {0}; HRESULT hr;
- /* AMDirectDrawStream tries to use it's custom allocator and - * when it is able to do so it's behavior changes slightly - * (e.g. it uses dynamic format change instead of reconnecting in SetFormat). - * We don't yet implement the custom allocator so force the standard one for now. */ - hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, - &IID_IMemAllocator, (void **)alloc); - ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (filter->use_input_pin_allocator) + { + hr = IMemInputPin_GetAllocator(pin, alloc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + else + { + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)alloc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + }
IMemInputPin_GetAllocatorRequirements(pin, &props); hr = iface->pFuncsTable->pfnDecideBufferSize(iface, *alloc, &props); @@ -1192,6 +1198,7 @@ static void testfilter_init(struct testfilter *filter) memset(filter, 0, sizeof(*filter)); strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops); + filter->use_input_pin_allocator = FALSE; filter->stop_position = 0x8000000000000000ULL; filter->wait_state_event = CreateEventW(NULL, TRUE, TRUE, NULL); } @@ -8485,6 +8492,145 @@ static void test_ddrawstream_qc(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_ddrawstream_mem_allocator(void) { + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IMemAllocator *ddraw_allocator, *mem_allocator, *new_allocator; + IDirectDrawMediaStream *ddraw_stream; + IMediaSample *media_sample1, *media_sample2; + IDirectDrawStreamSample *ddraw_sample1, *ddraw_sample2; + ALLOCATOR_PROPERTIES props, props2; + AM_MEDIA_TYPE *sample_mt; + struct testfilter source; + IMemInputPin *mem_input; + IMediaStream *stream; + IGraphBuilder *graph; + IPin *pin; + HRESULT hr; + ULONG ref; + + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryVideo, 0, &stream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaStream_QueryInterface(stream, &IID_IMemInputPin, (void**)&mem_input); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaStream_QueryInterface(stream, &IID_IDirectDrawMediaStream, (void**)&ddraw_stream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ddraw_allocator = NULL; + hr = IMediaStream_QueryInterface(stream, &IID_IMemAllocator, (void**)&ddraw_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + mem_allocator = NULL; + hr = IMemInputPin_GetAllocator(mem_input, &mem_allocator); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n"); + + if (mem_allocator) + { + check_interface(mem_allocator, &IID_IDirectDrawMediaStream, TRUE); + IMemAllocator_Release(mem_allocator); + } + + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&new_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + props.cbAlign = 1; + props.cbBuffer = 10000; + props.cBuffers = 0; + props.cbPrefix = 0; + hr = IMemAllocator_SetProperties(new_allocator, &props, &props2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemInputPin_NotifyAllocator(mem_input, new_allocator, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + mem_allocator = NULL; + hr = IMemInputPin_GetAllocator(mem_input, &mem_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n"); + todo_wine check_interface(mem_allocator, &IID_IDirectDrawMediaStream, TRUE); + + IMemInputPin_Release(mem_input); + + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(!!graph, "Expected non-NULL graph.\n"); + + testfilter_init(&source); + source.use_input_pin_allocator = TRUE; + source.preferred_mt = &rgb24_mt; + + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void**)&pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &rgb555_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb555_format, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &ddraw_sample1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectDrawStreamSample_Update(ddraw_sample1, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#lx.\n", hr); + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &ddraw_sample2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDirectDrawStreamSample_Update(ddraw_sample2, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_GetBuffer(mem_allocator, &media_sample1, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaSample_GetMediaType(media_sample1, &sample_mt); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (sample_mt) + { + ok(IsEqualGUID(&sample_mt->subtype, &MEDIASUBTYPE_RGB555), "Got subtype %s.\n", wine_dbgstr_guid(&sample_mt->subtype)); + DeleteMediaType(sample_mt); + } + hr = IMemAllocator_GetBuffer(mem_allocator, &media_sample2, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaSample_GetMediaType(media_sample2, &sample_mt); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (sample_mt) + { + ok(IsEqualGUID(&sample_mt->subtype, &MEDIASUBTYPE_RGB555), "Got subtype %s.\n", wine_dbgstr_guid(&sample_mt->subtype)); + DeleteMediaType(sample_mt); + } + IMediaSample_Release(media_sample1); + IMediaSample_Release(media_sample2); + IDirectDrawStreamSample_Release(ddraw_sample1); + IDirectDrawStreamSample_Release(ddraw_sample2); + IMemAllocator_Release(mem_allocator); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMemAllocator_Release(new_allocator); + IDirectDrawMediaStream_Release(ddraw_stream); + IMemAllocator_Release(ddraw_allocator); + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + IPin_Release(pin); + IGraphBuilder_Release(graph); + + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + + static void test_ddrawstreamsample_get_media_stream(void) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -9812,6 +9958,7 @@ START_TEST(amstream) test_ddrawstream_new_segment(); test_ddrawstream_get_time_per_frame(); test_ddrawstream_qc(); + test_ddrawstream_mem_allocator();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/ddrawstream.c | 58 +++++++++++++++++++++------------- dlls/amstream/tests/amstream.c | 8 ++--- 2 files changed, 40 insertions(+), 26 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 47b856781e9..a5a127bcc25 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -56,6 +56,7 @@ struct ddraw_stream
IPin *peer; IMemAllocator *allocator; + IMemAllocator *private_allocator; AM_MEDIA_TYPE mt; struct format format; FILTER_STATE state; @@ -235,6 +236,7 @@ static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface) DeleteCriticalSection(&stream->cs); if (stream->ddraw) IDirectDraw_Release(stream->ddraw); + IMemAllocator_Release(stream->private_allocator); free(stream); }
@@ -1306,40 +1308,46 @@ static ULONG WINAPI ddraw_mem_allocator_Release(IMemAllocator *iface)
static HRESULT WINAPI ddraw_mem_allocator_SetProperties(IMemAllocator *iface, ALLOCATOR_PROPERTIES *request, ALLOCATOR_PROPERTIES *actual) { - FIXME("iface %p request %p actual %p stub!\n", iface, request, actual); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_SetProperties(stream->private_allocator, request, actual); }
static HRESULT WINAPI ddraw_mem_allocator_GetProperties(IMemAllocator *iface,ALLOCATOR_PROPERTIES *props) { - FIXME("iface %p props %p stub!\n", iface, props); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_GetProperties(stream->private_allocator, props); }
static HRESULT WINAPI ddraw_mem_allocator_Commit(IMemAllocator *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_Commit(stream->private_allocator); }
static HRESULT WINAPI ddraw_mem_allocator_Decommit(IMemAllocator *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_Decommit(stream->private_allocator); }
static HRESULT WINAPI ddraw_mem_allocator_GetBuffer(IMemAllocator *iface, IMediaSample **buf, REFERENCE_TIME *start_time, REFERENCE_TIME *end_time, DWORD flags) { - FIXME("iface %p buf %p start_time %p end_time %p flags %#lx stub!\n", iface, buf, start_time, end_time, flags); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_GetBuffer(stream->private_allocator, buf, start_time, end_time, flags); }
static HRESULT WINAPI ddraw_mem_allocator_ReleaseBuffer(IMemAllocator *iface,IMediaSample *buf) { - FIXME("iface %p buf %p stub!\n", iface, buf); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + + return IMemAllocator_ReleaseBuffer(stream->private_allocator, buf); }
static const IMemAllocatorVtbl ddraw_mem_allocator_vtbl = @@ -1384,14 +1392,8 @@ static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAlloc
TRACE("stream %p, allocator %p.\n", stream, allocator);
- if (stream->allocator) - { - IMemAllocator_AddRef(*allocator = stream->allocator); - return S_OK; - } - - *allocator = NULL; - return VFW_E_NO_ALLOCATOR; + IMemAllocator_AddRef(*allocator = &stream->IMemAllocator_iface); + return S_OK; }
static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly) @@ -1403,10 +1405,12 @@ static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAl if (!allocator) return E_POINTER;
- if (allocator) + if (allocator != &stream->IMemAllocator_iface) IMemAllocator_AddRef(allocator); - if (stream->allocator) + + if (stream->allocator && stream->allocator != &stream->IMemAllocator_iface) IMemAllocator_Release(stream->allocator); + stream->allocator = allocator;
return S_OK; @@ -1554,6 +1558,7 @@ static const IMemInputPinVtbl ddraw_meminput_vtbl = HRESULT ddraw_stream_create(IUnknown *outer, void **out) { struct ddraw_stream *object; + HRESULT hr;
if (outer) return CLASS_E_NOAGGREGATION; @@ -1564,6 +1569,7 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl; object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl; object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl; + object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl; object->IPin_iface.lpVtbl = &ddraw_sink_vtbl; object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl; object->ref = 1; @@ -1571,6 +1577,14 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) object->format.width = 100; object->format.height = 100;
+ hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&object->private_allocator); + if (!SUCCEEDED(hr)) + { + free(object); + return hr; + }; + InitializeCriticalSection(&object->cs); InitializeConditionVariable(&object->update_queued_cv); list_init(&object->update_queue); diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index a05ffb44406..4d3e3f783b7 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -8526,8 +8526,8 @@ static void test_ddrawstream_mem_allocator(void) {
mem_allocator = NULL; hr = IMemInputPin_GetAllocator(mem_input, &mem_allocator); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n");
if (mem_allocator) { @@ -8552,8 +8552,8 @@ static void test_ddrawstream_mem_allocator(void) { mem_allocator = NULL; hr = IMemInputPin_GetAllocator(mem_input, &mem_allocator); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n"); - todo_wine check_interface(mem_allocator, &IID_IDirectDrawMediaStream, TRUE); + ok(mem_allocator == ddraw_allocator, "Expected GetAllocator to return ddraw allocator.\n"); + check_interface(mem_allocator, &IID_IDirectDrawMediaStream, TRUE);
IMemInputPin_Release(mem_input);
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/tests/amstream.c | 141 +++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+)
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 4d3e3f783b7..d0cb6948d13 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -1036,6 +1036,7 @@ struct testfilter HRESULT wait_state_hr; HRESULT is_format_supported_hr; HRESULT qc_notify_hr; + HRESULT query_accept_hr; };
static inline struct testfilter *impl_from_BaseFilter(struct strmbase_filter *iface) @@ -1141,6 +1142,13 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid return S_OK; }
+static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + struct testfilter *filter = impl_from_base_pin(iface); + + return filter->query_accept_hr; +} + static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface, IMemInputPin *pin, IMemAllocator **alloc) { struct testfilter *filter = impl_from_base_pin(&iface->pin); @@ -1187,6 +1195,7 @@ static const struct strmbase_source_ops testsource_ops = { .base.pin_get_media_type = testsource_get_media_type, .base.pin_query_interface = testsource_query_interface, + .base.pin_query_accept = testsource_query_accept, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideBufferSize = testsource_DecideBufferSize, .pfnDecideAllocator = testsource_DecideAllocator, @@ -1198,6 +1207,7 @@ static void testfilter_init(struct testfilter *filter) memset(filter, 0, sizeof(*filter)); strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops); + filter->query_accept_hr = S_OK; filter->use_input_pin_allocator = FALSE; filter->stop_position = 0x8000000000000000ULL; filter->wait_state_event = CreateEventW(NULL, TRUE, TRUE, NULL); @@ -8630,6 +8640,136 @@ static void test_ddrawstream_mem_allocator(void) { ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_ddrawstream_set_format_dynamic(void) +{ + IDirectDrawMediaStream *ddraw_stream; + IAMMultiMediaStream *mmstream; + DDSURFACEDESC current_format; + DDSURFACEDESC desired_format; + struct testfilter source; + IGraphBuilder *graph; + DDSURFACEDESC format; + IMediaStream *stream; + VIDEOINFO video_info; + AM_MEDIA_TYPE mt; + HRESULT hr; + ULONG ref; + IPin *pin; + + mmstream = create_ammultimediastream(); + + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryVideo, 0, &stream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IDirectDrawMediaStream, (void **)&ddraw_stream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(!!graph, "Expected non-NULL graph.\n"); + + testfilter_init(&source); + source.use_input_pin_allocator = TRUE; + + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &rgb8_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + source.preferred_mt = NULL; + source.query_accept_hr = S_OK; + + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb555_format, NULL); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), + "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); + hr = IDirectDrawMediaStream_GetFormat(ddraw_stream, ¤t_format, NULL, &desired_format, NULL); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", current_format.ddpfPixelFormat.u1.dwRGBBitCount); + todo_wine ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", desired_format.ddpfPixelFormat.u1.dwRGBBitCount); + + format = rgb555_format; + format.dwFlags = 0; + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &format, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), + "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); + + source.preferred_mt = &rgb555_mt; + + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb8_format, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb555_format, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), + "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); + hr = IDirectDrawMediaStream_GetFormat(ddraw_stream, ¤t_format, NULL, &desired_format, NULL); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", current_format.ddpfPixelFormat.u1.dwRGBBitCount); + todo_wine ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", desired_format.ddpfPixelFormat.u1.dwRGBBitCount); + + video_info = rgb555_video_info; + video_info.bmiHeader.biWidth = 222; + video_info.bmiHeader.biHeight = -555; + mt = rgb555_mt; + mt.pbFormat = (BYTE *)&video_info; + source.preferred_mt = &mt; + + format = rgb555_format; + format.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT; + format.dwWidth = 222; + format.dwHeight = 555; + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &format, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), + "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); + ok(((VIDEOINFO *)source.source.pin.mt.pbFormat)->bmiHeader.biWidth == 333, + "Got width %ld.\n", ((VIDEOINFO *)source.source.pin.mt.pbFormat)->bmiHeader.biWidth); + ok(((VIDEOINFO *)source.source.pin.mt.pbFormat)->bmiHeader.biHeight == -444, + "Got height %ld.\n", ((VIDEOINFO *)source.source.pin.mt.pbFormat)->bmiHeader.biHeight); + + source.query_accept_hr = S_FALSE; + + hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb8_format, NULL); + todo_wine ok(hr == DDERR_INVALIDSURFACETYPE, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), + "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); + memset(¤t_format, 0, sizeof(current_format)); + memset(&desired_format, 0, sizeof(desired_format)); + hr = IDirectDrawMediaStream_GetFormat(ddraw_stream, ¤t_format, NULL, &desired_format, NULL); + /* FIXME: The peer is not able to reconnect while the stream is running, so it stays disconnected. */ + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", current_format.ddpfPixelFormat.u1.dwRGBBitCount); + todo_wine ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + "Got rgb bit count %lu.\n", desired_format.ddpfPixelFormat.u1.dwRGBBitCount); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IGraphBuilder_Disconnect(graph, pin); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + IPin_Release(pin); + IDirectDrawMediaStream_Release(ddraw_stream); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +}
static void test_ddrawstreamsample_get_media_stream(void) { @@ -9959,6 +10099,7 @@ START_TEST(amstream) test_ddrawstream_get_time_per_frame(); test_ddrawstream_qc(); test_ddrawstream_mem_allocator(); + test_ddrawstream_set_format_dynamic();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/ddrawstream.c | 66 ++++++++++++++++++++++++++-------- dlls/amstream/tests/amstream.c | 20 +++++------ 2 files changed, 62 insertions(+), 24 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index a5a127bcc25..1922c43dc32 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -57,6 +57,7 @@ struct ddraw_stream IPin *peer; IMemAllocator *allocator; IMemAllocator *private_allocator; + IMediaSample *next_sample; AM_MEDIA_TYPE mt; struct format format; FILTER_STATE state; @@ -541,6 +542,28 @@ static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetFormat(IDirectDrawMediaStr return S_OK; }
+static void set_mt_from_desc(AM_MEDIA_TYPE *mt, const DDSURFACEDESC *format) +{ + VIDEOINFOHEADER *videoinfo; + + videoinfo = (VIDEOINFOHEADER*)mt->pbFormat; + videoinfo->bmiHeader.biWidth = format->dwWidth; + videoinfo->bmiHeader.biHeight = format->dwHeight; + + if (format->ddpfPixelFormat.dwRGBBitCount == 16 && format->ddpfPixelFormat.dwRBitMask == 0x7c00) + mt->subtype = MEDIASUBTYPE_RGB555; + else if (format->ddpfPixelFormat.dwRGBBitCount == 16 && format->ddpfPixelFormat.dwRBitMask == 0x7c00) + mt->subtype = MEDIASUBTYPE_RGB565; + else if (format->ddpfPixelFormat.dwRGBBitCount == 24) + mt->subtype = MEDIASUBTYPE_RGB24; + else if (format->ddpfPixelFormat.dwRGBBitCount == 32) + mt->subtype = MEDIASUBTYPE_RGB32; +} + +static inline BOOL using_private_allocator(struct ddraw_stream *stream) { + return !(stream->allocator) || stream->allocator == &stream->IMemAllocator_iface; +} + static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStream *iface, const DDSURFACEDESC *format, IDirectDrawPalette *palette) { @@ -637,23 +660,30 @@ static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStr LeaveCriticalSection(&stream->cs); return hr; } - old_peer = stream->peer; - IPin_AddRef(old_peer);
- IFilterGraph_Disconnect(stream->graph, stream->peer); - IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface); - hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL); - if (FAILED(hr)) + set_mt_from_desc(&stream->mt, format); + + if (!using_private_allocator(stream) || + (IPin_QueryAccept(stream->peer, &stream->mt) != S_OK)) { - stream->format = old_format; - IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_media_type); + /* Try re-connection */ + old_peer = stream->peer; + IPin_AddRef(old_peer); + + IFilterGraph_Disconnect(stream->graph, stream->peer); + IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface); + hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL); + if (FAILED(hr)) + { + stream->format = old_format; + IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_media_type); + IPin_Release(old_peer); + FreeMediaType(&old_media_type); + LeaveCriticalSection(&stream->cs); + return DDERR_INVALIDSURFACETYPE; + } IPin_Release(old_peer); - FreeMediaType(&old_media_type); - LeaveCriticalSection(&stream->cs); - return DDERR_INVALIDSURFACETYPE; } - - IPin_Release(old_peer); FreeMediaType(&old_media_type); }
@@ -1339,8 +1369,16 @@ static HRESULT WINAPI ddraw_mem_allocator_GetBuffer(IMemAllocator *iface, IMedia DWORD flags) { struct ddraw_stream *stream = impl_from_IMemAllocator(iface); + HRESULT hr;
- return IMemAllocator_GetBuffer(stream->private_allocator, buf, start_time, end_time, flags); + EnterCriticalSection(&stream->cs); + + hr = IMemAllocator_GetBuffer(stream->private_allocator, buf, start_time, end_time, flags); + IMediaSample_SetMediaType(*buf, &stream->mt); + + LeaveCriticalSection(&stream->cs); + + return hr; }
static HRESULT WINAPI ddraw_mem_allocator_ReleaseBuffer(IMemAllocator *iface,IMediaSample *buf) diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index d0cb6948d13..4744a786545 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -8602,7 +8602,7 @@ static void test_ddrawstream_mem_allocator(void) { hr = IMemAllocator_GetBuffer(mem_allocator, &media_sample1, NULL, NULL, 0); ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMediaSample_GetMediaType(media_sample1, &sample_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); if (sample_mt) { ok(IsEqualGUID(&sample_mt->subtype, &MEDIASUBTYPE_RGB555), "Got subtype %s.\n", wine_dbgstr_guid(&sample_mt->subtype)); @@ -8611,7 +8611,7 @@ static void test_ddrawstream_mem_allocator(void) { hr = IMemAllocator_GetBuffer(mem_allocator, &media_sample2, NULL, NULL, 0); ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMediaSample_GetMediaType(media_sample2, &sample_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); if (sample_mt) { ok(IsEqualGUID(&sample_mt->subtype, &MEDIASUBTYPE_RGB555), "Got subtype %s.\n", wine_dbgstr_guid(&sample_mt->subtype)); @@ -8685,14 +8685,14 @@ static void test_ddrawstream_set_format_dynamic(void) source.query_accept_hr = S_OK;
hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb555_format, NULL); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); hr = IDirectDrawMediaStream_GetFormat(ddraw_stream, ¤t_format, NULL, &desired_format, NULL); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, "Got rgb bit count %lu.\n", current_format.ddpfPixelFormat.u1.dwRGBBitCount); - todo_wine ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, "Got rgb bit count %lu.\n", desired_format.ddpfPixelFormat.u1.dwRGBBitCount);
format = rgb555_format; @@ -8712,10 +8712,10 @@ static void test_ddrawstream_set_format_dynamic(void) ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); hr = IDirectDrawMediaStream_GetFormat(ddraw_stream, ¤t_format, NULL, &desired_format, NULL); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(current_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, "Got rgb bit count %lu.\n", current_format.ddpfPixelFormat.u1.dwRGBBitCount); - todo_wine ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, + ok(desired_format.ddpfPixelFormat.u1.dwRGBBitCount == 16, "Got rgb bit count %lu.\n", desired_format.ddpfPixelFormat.u1.dwRGBBitCount);
video_info = rgb555_video_info; @@ -8741,7 +8741,7 @@ static void test_ddrawstream_set_format_dynamic(void) source.query_accept_hr = S_FALSE;
hr = IDirectDrawMediaStream_SetFormat(ddraw_stream, &rgb8_format, NULL); - todo_wine ok(hr == DDERR_INVALIDSURFACETYPE, "Got hr %#lx.\n", hr); + ok(hr == DDERR_INVALIDSURFACETYPE, "Got hr %#lx.\n", hr); ok(IsEqualGUID(&source.source.pin.mt.subtype, &MEDIASUBTYPE_RGB8), "Got subtype %s.\n", wine_dbgstr_guid(&source.source.pin.mt.subtype)); memset(¤t_format, 0, sizeof(current_format));
From: Santino Mazza smazza@codeweavers.com
--- dlls/amstream/ddrawstream.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 1922c43dc32..87bc7f520fa 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -237,6 +237,8 @@ static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface) DeleteCriticalSection(&stream->cs); if (stream->ddraw) IDirectDraw_Release(stream->ddraw); + if (stream->allocator && stream->allocator != &stream->IMemAllocator_iface) + IMemAllocator_Release(stream->allocator); IMemAllocator_Release(stream->private_allocator); free(stream); }
There is still something that I don't like about my changes. I'm not sure how to handle the case where NotifyAllocator receives the direct draw own allocator. Right now to prevent the ddraw stream object to reference to it self I just didn't add a reference in NotifyAllocator.
I also found that when the ddraw stream is released we don't release the assigned allocator.
On Mon Apr 7 16:45:00 2025 +0000, Santino Mazza wrote:
There is still something that I don't like about my changes. I'm not sure how to handle the case where NotifyAllocator receives the direct draw own allocator. Right now to prevent the ddraw stream object to reference to it self I just didn't add a reference in NotifyAllocator. I also found that when the ddraw stream is released we don't release the assigned allocator.
Releasing the allocator in `Disconnect()` should fix these issues. Here is how it's done in `strmbase`: [strmbase.c:880](libs/strmbase/pin.c?ref_type=heads#L880)
Anton Baskanov (@baskanov) commented about dlls/amstream/ddrawstream.c:
IPin *peer; IMemAllocator *allocator; IMemAllocator *private_allocator;
- IMediaSample *next_sample;
This is now unused.