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