[PATCH 0/3] MR9717: winegstreamer: Handle dynamic format change.
From: Elizabeth Figura <zfigura(a)codeweavers.com> --- dlls/quartz/tests/avidec.c | 52 +++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 4a0f731fc66..7460c04e788 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -1214,34 +1214,37 @@ static HRESULT WINAPI allocator_Decommit(IMemAllocator *iface) return IMemAllocator_Decommit(filter->wrapped_allocator); } +static const VIDEOINFOHEADER dynamic_format = +{ + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biCompression = mmioFOURCC('I','4','2','0'), + .bmiHeader.biWidth = 10, + .bmiHeader.biHeight = 20, + .bmiHeader.biBitCount = 32, + .bmiHeader.biPlanes = 1, + .bmiHeader.biSizeImage = 222, +}; + +static void init_dynamic_mt(AM_MEDIA_TYPE *mt) +{ + memset(mt, 0, sizeof(*mt)); + mt->majortype = MEDIATYPE_Video; + mt->subtype = MEDIASUBTYPE_I420; + 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; - VIDEOINFOHEADER format = - { - .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), - .bmiHeader.biCompression = mmioFOURCC('I','4','2','0'), - .bmiHeader.biWidth = 10, - .bmiHeader.biHeight = 20, - .bmiHeader.biBitCount = 32, - .bmiHeader.biPlanes = 1, - .bmiHeader.biSizeImage = 222, - }; - AM_MEDIA_TYPE mt = - { - .majortype = MEDIATYPE_Video, - .subtype = MEDIASUBTYPE_I420, - .formattype = FORMAT_VideoInfo, - .cbFormat = sizeof(format), - .pbFormat = (BYTE *)&format, - }; - if (winetest_debug > 1) trace("GetBuffer()\n"); - source_bitmap_info = format.bmiHeader; + source_bitmap_info = dynamic_format.bmiHeader; ok(!start_time, "Got start time.\n"); ok(!end_time, "Got end time.\n"); @@ -1251,6 +1254,7 @@ static HRESULT WINAPI allocator_GetBuffer(IMemAllocator *iface, IMediaSample **s 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; @@ -1342,6 +1346,7 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, { ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0}; IMemAllocator *allocator, *sink_allocator; + AM_MEDIA_TYPE mt, dynamic_mt; IMediaSample *sample; IMemInputPin *input; HRESULT hr; @@ -1527,6 +1532,13 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); testsink->got_sample = 0; + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + init_dynamic_mt(&dynamic_mt); + todo_wine ok(compare_media_types(&mt, &dynamic_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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9717
From: Elizabeth Figura <zfigura(a)codeweavers.com> --- dlls/quartz/avidec.c | 4 +++- dlls/quartz/tests/avidec.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 9f1a7db1586..cc845d32f8a 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -199,7 +199,9 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return E_OUTOFMEMORY; } - DeleteMediaType(mt); + FreeMediaType(&This->source.pin.mt); + This->source.pin.mt = *mt; + CoTaskMemFree(mt); if ((res = ICDecompressBegin(This->hvid, This->input_format, This->output_format))) { diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 7460c04e788..f89cf4ea42c 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -1535,7 +1535,7 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, hr = IPin_ConnectionMediaType(source, &mt); ok(hr == S_OK, "Got hr %#lx.\n", hr); init_dynamic_mt(&dynamic_mt); - todo_wine ok(compare_media_types(&mt, &dynamic_mt), "Media types didn't match.\n"); + ok(compare_media_types(&mt, &dynamic_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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9717
From: Elizabeth Figura <zfigura(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58261 --- dlls/winegstreamer/quartz_parser.c | 85 ++++++++++++++++++++++++--- dlls/winegstreamer/quartz_transform.c | 11 ++++ 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 6ba0b2128f2..d079f764203 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -53,7 +53,8 @@ struct parser struct parser_source **sources; unsigned int source_count; - BOOL enum_sink_first; + bool enum_sink_first; + bool output_compressed; wg_parser_t wg_parser; @@ -88,6 +89,8 @@ struct parser_source wg_parser_stream_t wg_stream; + struct wg_format current_format; + SourceSeeking seek; CRITICAL_SECTION flushing_cs; @@ -1311,10 +1314,11 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, /* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if * necessary). */ -static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer *buffer) +static void send_buffer(struct parser_source *pin, struct parser *filter, const struct wg_parser_buffer *buffer) { HRESULT hr; IMediaSample *sample; + AM_MEDIA_TYPE *mt; if (pin->need_segment) { @@ -1341,6 +1345,16 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer break; } + if ((hr = IMediaSample_GetMediaType(sample, &mt)) == S_OK) + { + FIXME("Dynamic format change.\n"); + DeleteMediaType(mt); + } + else if (hr != S_FALSE) + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } + advance = min(IMediaSample_GetSize(sample), buffer->size - offset); hr = send_sample(pin, sample, buffer, offset, advance, format->nAvgBytesPerSec); @@ -1361,7 +1375,61 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer } else { - hr = send_sample(pin, sample, buffer, 0, buffer->size, 0); + /* Dynamic format change. */ + if ((hr = IMediaSample_GetMediaType(sample, &mt)) == S_OK) + { + struct wg_format format; + + if (filter->output_compressed) + { + ERR("Ignoring dynamic format change attempt for compressed output.\n"); + send_sample(pin, sample, buffer, 0, buffer->size, 0); + } + else if (amt_to_wg_format(mt, &format)) + { + if (!memcmp(&format, &pin->current_format, sizeof(format))) + { + send_sample(pin, sample, buffer, 0, buffer->size, 0); + } + else + { + TRACE("Executing dynamic format change. Current format:\n"); + strmbase_dump_media_type(&pin->pin.pin.mt); + TRACE("New format:\n"); + strmbase_dump_media_type(mt); + + FreeMediaType(&pin->pin.pin.mt); + CopyMediaType(&pin->pin.pin.mt, mt); + pin->current_format = format; + wg_parser_stream_enable(pin->wg_stream, &format); + + /* We can't send the wg_parser_buffer we were about to + * send; it's in the old format. + * + * Also, we need to seek to re-decode any further + * queued buffers. This is not reliably seamless. + * See reader_SetOutputProps() in wm_reader.c. */ + wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, pin->seek.llCurrent, 0, + AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + } + } + else + { + /* This isn't supposed to happen; the downstream filter + * should call QueryAccept() first. */ + ERR("Attempt to dynamically set an unsupported format.\n"); + } + + DeleteMediaType(mt); + } + else if (hr == S_FALSE) + { + send_sample(pin, sample, buffer, 0, buffer->size, 0); + } + else + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } IMediaSample_Release(sample); } @@ -1405,7 +1473,7 @@ static DWORD CALLBACK stream_thread(void *arg) if (wg_parser_stream_get_buffer(filter->wg_parser, pin->wg_stream, &buffer)) { - send_buffer(pin, &buffer); + send_buffer(pin, filter, &buffer); } else { @@ -1542,14 +1610,13 @@ static HRESULT parser_init_stream(struct strmbase_filter *iface) for (i = 0; i < filter->source_count; ++i) { struct parser_source *source = filter->sources[i]; - struct wg_format format; bool ret; if (source->pin.pin.peer) { - ret = amt_to_wg_format(&source->pin.pin.mt, &format); + ret = amt_to_wg_format(&source->pin.pin.mt, &source->current_format); assert(ret); - wg_parser_stream_enable(source->wg_stream, &format); + wg_parser_stream_enable(source->wg_stream, &source->current_format); } else { @@ -1782,6 +1849,8 @@ static HRESULT parser_create(BOOL output_compressed, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; + object->output_compressed = output_compressed; + if (!(object->wg_parser = wg_parser_create(output_compressed))) { free(object); @@ -2657,7 +2726,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) object->init_gst = mpeg_splitter_filter_init_gst; object->source_query_accept = mpeg_splitter_source_query_accept; object->source_get_media_type = mpeg_splitter_source_get_media_type; - object->enum_sink_first = TRUE; + object->enum_sink_first = true; TRACE("Created MPEG-1 splitter %p.\n", object); *out = &object->filter.IUnknown_inner; diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index ff57ea02ed0..343df3ecc32 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -324,11 +324,22 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa for (;;) { IMediaSample *output_sample; + AM_MEDIA_TYPE *mt; hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &output_sample, NULL, NULL, 0); if (FAILED(hr)) return hr; + if ((hr = IMediaSample_GetMediaType(sample, &mt)) == S_OK) + { + FIXME("Dynamic format change.\n"); + DeleteMediaType(mt); + } + else if (hr != S_FALSE) + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } + hr = wg_sample_create_quartz(output_sample, &wg_sample); if (FAILED(hr)) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9717
participants (2)
-
Elizabeth Figura -
Elizabeth Figura (@zfigura)