[PATCH 0/1] MR9743: winegstreamer: Support dynamic reconnection in the DirectShow transform.
From: Elizabeth Figura <zfigura@codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58171 --- dlls/quartz/tests/mpegvideo.c | 389 ++++++++++++++++++++++++-- dlls/winegstreamer/quartz_transform.c | 73 +++-- dlls/winegstreamer/wg_sample.c | 2 +- 3 files changed, 427 insertions(+), 37 deletions(-) diff --git a/dlls/quartz/tests/mpegvideo.c b/dlls/quartz/tests/mpegvideo.c index 9977862de81..0895019aadd 100644 --- a/dlls/quartz/tests/mpegvideo.c +++ b/dlls/quartz/tests/mpegvideo.c @@ -834,6 +834,11 @@ struct testfilter unsigned int got_sample, got_new_segment, got_eos, got_begin_flush, got_end_flush; REFERENCE_TIME expected_start_time; REFERENCE_TIME expected_stop_time; + + IMemAllocator IMemAllocator_iface; + IMemAllocator *wrapped_allocator; + IMediaSample IMediaSample_iface; + IMediaSample *wrapped_sample; }; static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -916,15 +921,22 @@ static HRESULT testsink_connect(struct strmbase_sink *iface, IPin *peer, const A static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + bool dynamic_format_change = (filter->sink.pAllocator == &filter->IMemAllocator_iface); REFERENCE_TIME start, stop; AM_MEDIA_TYPE *mt = (AM_MEDIA_TYPE *)0xdeadbeef; HRESULT hr; LONG size; size = IMediaSample_GetSize(sample); - ok(size == filter->sink.pin.mt.lSampleSize, "Got size %lu, expected %lu.\n", size, filter->sink.pin.mt.lSampleSize); + if (dynamic_format_change) + ok(size == 32 * 24 * 32 / 8, "Got size %ld.\n", size); + else + ok(size == filter->sink.pin.mt.lSampleSize, "Got size %ld, expected %ld.\n", size, filter->sink.pin.mt.lSampleSize); size = IMediaSample_GetActualDataLength(sample); - ok(size == filter->sink.pin.mt.lSampleSize, "Got actual size %lu, expected %lu.\n", size, filter->sink.pin.mt.lSampleSize); + if (dynamic_format_change) + ok(size == 32 * 24 * 32 / 8, "Got size %ld.\n", size); + else + ok(size == filter->sink.pin.mt.lSampleSize, "Got size %ld, expected %ld.\n", size, filter->sink.pin.mt.lSampleSize); ok(IMediaSample_GetActualDataLength(sample) <= IMediaSample_GetSize(sample), "Buffer overflow"); start = 0xdeadbeef; @@ -932,10 +944,12 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample hr = IMediaSample_GetTime(sample, &start, &stop); ok(hr == S_OK, "Got hr %#lx.\n", hr); - hr = IMediaSample_GetMediaType(sample, &mt); - ok(hr == S_FALSE, "Got hr %#lx.\n", hr); - if (mt) - DeleteMediaType(mt); + if (!dynamic_format_change) + { + hr = IMediaSample_GetMediaType(sample, &mt); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(!mt, "Got unexpected media type.\n"); + } if (filter->got_sample == 0 && filter->expected_start_time != (REFERENCE_TIME)-1) { @@ -995,6 +1009,279 @@ static const struct strmbase_sink_ops testsink_ops = .sink_end_flush = testsink_end_flush, }; +static struct testfilter *impl_from_IMediaSample(IMediaSample *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IMediaSample_iface); +} + +static HRESULT WINAPI sample_QueryInterface(IMediaSample *iface, REFIID iid, void **out) +{ + ok(IsEqualGUID(iid, &IID_IDirectDraw), "Got unexpected IID %s.\n", debugstr_guid(iid)); + return E_NOTIMPL; +} + +static ULONG WINAPI sample_AddRef(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_AddRef(filter->wrapped_sample); +} + +static ULONG WINAPI sample_Release(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + ULONG refcount = IMediaSample_Release(filter->wrapped_sample); + + if (!refcount) + filter->wrapped_sample = NULL; + return refcount; +} + +static HRESULT WINAPI sample_GetPointer(IMediaSample *iface, BYTE **data) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetPointer(filter->wrapped_sample, data); +} + +static LONG WINAPI sample_GetSize(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetSize(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_GetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetTime(filter->wrapped_sample, start, end); +} + +static HRESULT WINAPI sample_SetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetTime(filter->wrapped_sample, start, end); +} + +static HRESULT WINAPI sample_IsSyncPoint(IMediaSample *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_SetSyncPoint(IMediaSample *iface, BOOL sync_point) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetSyncPoint(filter->wrapped_sample, sync_point); +} + +static HRESULT WINAPI sample_IsPreroll(IMediaSample *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_SetPreroll(IMediaSample *iface, BOOL preroll) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static LONG WINAPI sample_GetActualDataLength(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetActualDataLength(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_SetActualDataLength(IMediaSample *iface, LONG size) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + if (winetest_debug > 1) trace("SetActualDataLength(%ld)\n", size); + + ok(size == 32 * 24 * 32 / 8, "Got size %ld.\n", size); + + IMediaSample_SetActualDataLength(filter->wrapped_sample, size); + return E_FAIL; +} + +static HRESULT WINAPI sample_GetMediaType(IMediaSample *iface, AM_MEDIA_TYPE **mt) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetMediaType(filter->wrapped_sample, mt); +} + +static HRESULT WINAPI sample_SetMediaType(IMediaSample *iface, AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_IsDiscontinuity(IMediaSample *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_SetDiscontinuity(IMediaSample *iface, BOOL discontinuity) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetDiscontinuity(filter->wrapped_sample, discontinuity); +} + +static HRESULT WINAPI sample_GetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_SetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMediaSampleVtbl sample_vtbl = +{ + sample_QueryInterface, + sample_AddRef, + sample_Release, + sample_GetPointer, + sample_GetSize, + sample_GetTime, + sample_SetTime, + sample_IsSyncPoint, + sample_SetSyncPoint, + sample_IsPreroll, + sample_SetPreroll, + sample_GetActualDataLength, + sample_SetActualDataLength, + sample_GetMediaType, + sample_SetMediaType, + sample_IsDiscontinuity, + sample_SetDiscontinuity, + sample_GetMediaTime, + sample_SetMediaTime, +}; + +static struct testfilter *impl_from_IMemAllocator(IMemAllocator *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IMemAllocator_iface); +} + +static HRESULT WINAPI allocator_QueryInterface(IMemAllocator *iface, REFIID iid, void **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI allocator_AddRef(IMemAllocator *iface) +{ + return 2; +} + +static ULONG WINAPI allocator_Release(IMemAllocator *iface) +{ + return 1; +} + +static HRESULT WINAPI allocator_SetProperties(IMemAllocator *iface, + ALLOCATOR_PROPERTIES *req_props, ALLOCATOR_PROPERTIES *ret_props) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_SetProperties(filter->wrapped_allocator, req_props, ret_props); +} + +static HRESULT WINAPI allocator_GetProperties(IMemAllocator *iface, ALLOCATOR_PROPERTIES *props) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_GetProperties(filter->wrapped_allocator, props); +} + +static HRESULT WINAPI allocator_Commit(IMemAllocator *iface) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_Commit(filter->wrapped_allocator); +} + +static HRESULT WINAPI allocator_Decommit(IMemAllocator *iface) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_Decommit(filter->wrapped_allocator); +} + +static const VIDEOINFOHEADER dynamic_format = +{ + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biCompression = BI_RGB, + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = -24, + .bmiHeader.biBitCount = 32, + .bmiHeader.biPlanes = 1, + .bmiHeader.biSizeImage = 32 * 24 * 32 / 8, +}; + +static void init_dynamic_mt(AM_MEDIA_TYPE *mt) +{ + memset(mt, 0, sizeof(*mt)); + mt->majortype = MEDIATYPE_Video; + mt->subtype = MEDIASUBTYPE_RGB32; + mt->formattype = FORMAT_VideoInfo; + mt->cbFormat = sizeof(dynamic_format); + mt->pbFormat = (BYTE *)&dynamic_format; +}; + +static HRESULT WINAPI allocator_GetBuffer(IMemAllocator *iface, IMediaSample **sample, + REFERENCE_TIME *start_time, REFERENCE_TIME *end_time, DWORD flags) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + AM_MEDIA_TYPE mt; + HRESULT hr; + + if (winetest_debug > 1) trace("GetBuffer(%#I64x, %#I64x, %#lx)\n", *start_time, *end_time, flags); + + ok(!flags || flags == AM_GBF_PREVFRAMESKIPPED, "Got flags %#lx.\n", flags); + + ok(!filter->wrapped_sample, "Should not have called GetBuffer() twice here.\n"); + + hr = IMemAllocator_GetBuffer(filter->wrapped_allocator, &filter->wrapped_sample, start_time, end_time, flags); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + init_dynamic_mt(&mt); + hr = IMediaSample_SetMediaType(filter->wrapped_sample, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + *sample = &filter->IMediaSample_iface; + return S_OK; +} + +static HRESULT WINAPI allocator_ReleaseBuffer(IMemAllocator *iface, IMediaSample *sample) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMemAllocatorVtbl allocator_vtbl = +{ + allocator_QueryInterface, + allocator_AddRef, + allocator_Release, + allocator_SetProperties, + allocator_GetProperties, + allocator_Commit, + allocator_Decommit, + allocator_GetBuffer, + allocator_ReleaseBuffer, +}; + static void testfilter_init(struct testfilter *filter) { static const GUID clsid = {0xabacab}; @@ -1002,6 +1289,8 @@ static void testfilter_init(struct testfilter *filter) strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops); strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL); + filter->IMemAllocator_iface.lpVtbl = &allocator_vtbl; + filter->IMediaSample_iface.lpVtbl = &sample_vtbl; } static void test_sink_allocator(IMemInputPin *input) @@ -1054,22 +1343,25 @@ static void test_sink_allocator(IMemInputPin *input) IMemAllocator_Release(ret_allocator); } +static void test_send_video(IMemInputPin *input, IMediaSample *sample); + static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, IPin *sink, IPin *source, struct testfilter *testsource, struct testfilter *testsink, unsigned type_idx, BOOL should_work) { ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0}; - IMemAllocator *allocator; + IMemAllocator *allocator, *sink_allocator; + AM_MEDIA_TYPE mt, source_mt; IMediaSample *sample; VIDEOINFOHEADER format; - AM_MEDIA_TYPE mt; + IMemInputPin *input; HRESULT hr; hr = IFilterGraph2_ConnectDirect(graph, &testsource->source.pin.IPin_iface, sink, &mpeg_mt); ok(hr == S_OK, "(%u) Got hr %#lx.\n", type_idx, hr); - init_video_mt(&mt, &format, type_idx); - hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt); + init_video_mt(&source_mt, &format, type_idx); + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); if (!should_work) { ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "(%u) Got hr %#lx.\n", type_idx, hr); @@ -1083,7 +1375,7 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); - ok(props.cbBuffer == mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); + ok(props.cbBuffer == source_mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); @@ -1107,15 +1399,15 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, IFilterGraph2_Disconnect(graph, source); IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); - init_video_mt(&mt, &format, type_idx); - hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt); + init_video_mt(&source_mt, &format, type_idx); + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(!!testsink->sink.pAllocator, "Expected an allocator.\n"); hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); - ok(props.cbBuffer == mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); + ok(props.cbBuffer == source_mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); @@ -1124,23 +1416,82 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&allocator); - testsink->sink.pAllocator = allocator; + testsink->wrapped_allocator = allocator; + testsink->sink.pAllocator = &testsink->IMemAllocator_iface; hr = IMemAllocator_SetProperties(allocator, &req_props, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); - init_video_mt(&mt, &format, type_idx); - hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt); + init_video_mt(&source_mt, &format, type_idx); + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ok(testsink->sink.pAllocator == allocator, "Expected an allocator.\n"); + ok(testsink->sink.pAllocator == &testsink->IMemAllocator_iface, "Expected our allocator to be used.\n"); + hr = IMemAllocator_GetProperties(allocator, &props); hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); - ok(props.cbBuffer == mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); + ok(props.cbBuffer == source_mt.lSampleSize, "Got size %ld.\n", props.cbBuffer); ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + /* Test dynamic format change. */ + + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input); + + CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&sink_allocator); + + /* We can use a bogus too-small size here. Native will happily respect it, + * and apparently just truncate the frame to fit. */ + req_props.cBuffers = 1; + req_props.cbBuffer = 32 * 24 * 32 / 8; + req_props.cbAlign = 1; + req_props.cbPrefix = 0; + hr = IMemAllocator_SetProperties(sink_allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemInputPin_NotifyAllocator(input, sink_allocator, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_Commit(sink_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + req_props.cbBuffer = 32 * 24 * 32 / 8; + hr = IMemAllocator_SetProperties(allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_GetProperties(allocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); + ok(props.cbBuffer == 32 * 24 * 32 / 8, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + hr = IMemAllocator_GetBuffer(sink_allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + testsink->expected_start_time = -1; /* native returns start and stop 0xff80000000000001 */ + test_send_video(input, sample); + ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); + ok(!testsink->wrapped_sample, "Sample was not fully released.\n"); + testsink->got_sample = 0; + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(compare_media_types(&mt, &source_mt), "Media types didn't match.\n"); + ok(compare_media_types(&testsink->sink.pin.mt, &source_mt), "Media types didn't match.\n"); + FreeMediaType(&mt); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMemInputPin_Release(input); + IMemAllocator_Release(sink_allocator); + IFilterGraph2_Disconnect(graph, source); IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 343df3ecc32..8b828993e66 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -36,6 +36,11 @@ struct transform struct strmbase_source source; struct strmbase_passthrough passthrough; + /* Dynamic reconnection changes the source media type, but the mpeg video + * decoder does not reflect it in ConnectionMediaType(). + * [Note that this differs from other filters, viz. avidec, which does.] */ + AM_MEDIA_TYPE source_mt; + IQualityControl sink_IQualityControl_iface; IQualityControl source_IQualityControl_iface; IQualityControl *qc_sink; @@ -106,6 +111,7 @@ static HRESULT transform_init_stream(struct strmbase_filter *iface) if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr; + CopyMediaType(&filter->source_mt, &filter->source.pin.mt); if (FAILED(hr = wg_transform_create_quartz(&filter->sink.pin.mt, &filter->source.pin.mt, &attrs, &filter->transform))) { @@ -133,6 +139,7 @@ static HRESULT transform_cleanup_stream(struct strmbase_filter *iface) wg_transform_destroy(filter->transform); wg_sample_queue_destroy(filter->sample_queue); LeaveCriticalSection(&filter->filter.stream_cs); + FreeMediaType(&filter->source_mt); } return S_OK; @@ -291,10 +298,21 @@ static HRESULT transform_sink_query_interface(struct strmbase_pin *pin, REFIID i return S_OK; } +static bool compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b) +{ + return IsEqualGUID(&a->majortype, &b->majortype) + && IsEqualGUID(&a->subtype, &b->subtype) + && IsEqualGUID(&a->formattype, &b->formattype) + && a->cbFormat == b->cbFormat + && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); +} + static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSample *sample) { struct transform *filter = impl_from_strmbase_filter(pin->pin.filter); struct wg_sample *wg_sample; + IMediaSample *output_sample; + AM_MEDIA_TYPE *mt; HRESULT hr; /* We do not expect pin connection state to change while the filter is @@ -313,33 +331,51 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa if (filter->sink.flushing) return S_FALSE; - hr = wg_sample_create_quartz(sample, &wg_sample); - if (FAILED(hr)) + if (FAILED(hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &output_sample, NULL, NULL, 0))) return hr; - hr = wg_transform_push_quartz(filter->transform, wg_sample, filter->sample_queue); - if (FAILED(hr)) - return hr; - - for (;;) + if ((hr = IMediaSample_GetMediaType(output_sample, &mt)) == S_OK) { - IMediaSample *output_sample; - AM_MEDIA_TYPE *mt; + struct wg_transform_attrs attrs = {0}; - hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &output_sample, NULL, NULL, 0); - if (FAILED(hr)) - return hr; - - if ((hr = IMediaSample_GetMediaType(sample, &mt)) == S_OK) + if (compare_media_types(mt, &filter->source_mt)) { - FIXME("Dynamic format change.\n"); DeleteMediaType(mt); } - else if (hr != S_FALSE) + else { - ERR("Failed to get media type, hr %#lx.\n", hr); + TRACE("Executing dynamic format change. Current format:\n"); + strmbase_dump_media_type(&filter->source_mt); + TRACE("New format:\n"); + strmbase_dump_media_type(mt); + + FreeMediaType(&filter->source_mt); + filter->source_mt = *mt; + CoTaskMemFree(mt); + + wg_transform_destroy(filter->transform); + if (FAILED(hr = wg_transform_create_quartz(&filter->sink.pin.mt, + &filter->source_mt, &attrs, &filter->transform))) + ERR("Failed to recreate transform, hr %#lx.\n", hr); } + DeleteMediaType(mt); + } + else if (hr != S_FALSE) + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } + + hr = wg_sample_create_quartz(sample, &wg_sample); + if (FAILED(hr)) + return hr; + + hr = wg_transform_push_quartz(filter->transform, wg_sample, filter->sample_queue); + if (FAILED(hr)) + return hr; + + for (;;) + { hr = wg_sample_create_quartz(output_sample, &wg_sample); if (FAILED(hr)) { @@ -371,6 +407,9 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa } IMediaSample_Release(output_sample); + + if (FAILED(hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &output_sample, NULL, NULL, 0))) + return hr; } return S_OK; diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index 2fc2679337f..3882d18ee54 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -430,7 +430,7 @@ HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *wg_ } if (FAILED(hr = IMediaSample_SetActualDataLength(sample->u.quartz.sample, wg_sample->size))) - return hr; + ERR("SetActualDataLength() returned %#lx.\n", hr); if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_PTS) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9743
This is another regression fix, from 277c8924c1ecd8626b26e19206908f648cc86e2c. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9743#note_125309
participants (2)
-
Elizabeth Figura -
Elizabeth Figura (@zfigura)