[PATCH v4 0/3] MR5988: winegstreamer: Output compressed samples from the media source.
-- v4: winegstreamer: Output compressed samples from the media source. winegstreamer: Stop on unparsed H.264 in autoplug-continue. winegstreamer: Explicitly append an H.264 parser for H.264. https://gitlab.winehq.org/wine/wine/-/merge_requests/5988
From: Elizabeth Figura <zfigura(a)codeweavers.com> --- dlls/winegstreamer/wg_parser.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e806298fb57..639d5356b4a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -957,6 +957,23 @@ static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) return false; } + else if (!strcmp(name, "video/x-h264")) + { + GstCaps *parsed_caps; + + /* Windows needs stream-format=byte-stream. + * decodebin will autoplug a h264parse if we stop on parsed=true, + * but it's not enough, because that h264parse will already have its + * caps set (to stream-format=avc), and we can't link it to our pad. */ + parsed_caps = gst_caps_copy(caps); + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, NULL); + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, caps, parsed_caps)) + || !append_element(parser->container, element, &first, &last)) + return false; + + if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) + return false; + } else { return link_src_to_sink(pad, stream->my_sink); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5988
From: Elizabeth Figura <zfigura(a)codeweavers.com> --- dlls/winegstreamer/wg_parser.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 639d5356b4a..f0cdfd47e65 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -133,10 +133,16 @@ static struct wg_parser_stream *get_stream(wg_parser_stream_t stream) static bool caps_is_compressed(GstCaps *caps) { + const GstStructure *structure = gst_caps_get_structure(caps, 0); struct wg_format format; - if (!caps) - return false; + /* H.264 not in byte-stream format cannot be used by Windows. + * wg_format_from_caps() rejects this accordingly, but we still want to + * stop here, and force h264parse to convert to byte-stream for us. + * Therefore explicitly accept it here. */ + if (!strcmp(gst_structure_get_name(structure), "video/x-h264")) + return true; + wg_format_from_caps(&format, caps); return format.major_type != WG_MAJOR_TYPE_UNKNOWN @@ -526,7 +532,7 @@ static bool parser_no_more_pads(struct wg_parser *parser) static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCaps * caps, gpointer user) { - return !caps_is_compressed(caps); + return caps && !caps_is_compressed(caps); } static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5988
From: Elizabeth Figura <zfigura(a)codeweavers.com> Several games depend directly or indirectly on this behaviour, including Onimusha: Warlords and Call of Cthulhu. --- dlls/mfplat/tests/mfplat.c | 48 +++++++++++++++---------------- dlls/mfreadwrite/tests/mfplat.c | 6 ++-- dlls/winegstreamer/media_source.c | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 1cdbb6f48ff..a66467d6dfd 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1090,13 +1090,13 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) L"video/mp4", { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264, .todo_value = TRUE), - ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_MPEG2Video, .todo = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264), + ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_MPEG2Video), ATTR_RATIO(MF_MT_FRAME_SIZE, 320, 240), ATTR_RATIO(MF_MT_FRAME_RATE, 30, 1), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High, .todo = TRUE), - ATTR_UINT32(MF_MT_MPEG2_LEVEL, eAVEncH264VLevel2, .todo = TRUE), + ATTR_UINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High), + ATTR_UINT32(MF_MT_MPEG2_LEVEL, eAVEncH264VLevel2), }, }, { @@ -1104,19 +1104,19 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) L"video/mp4", { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .todo_value = TRUE), - ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx, .todo = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC), + ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx), ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .todo_value = TRUE), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 9180, .todo_value = TRUE), - ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 9180, .todo = TRUE), + ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1), ATTR_UINT32(MF_MT_AVG_BITRATE, 73440, .todo = TRUE), - ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0, .todo = TRUE), + ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0), ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0, .todo = TRUE), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), - ATTR_BLOB(MF_MT_USER_DATA, aac_data, sizeof(aac_data), .todo = TRUE), + ATTR_BLOB(MF_MT_USER_DATA, aac_data, sizeof(aac_data)), }, }, { @@ -1124,7 +1124,7 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) L"video/x-ms-wmv", { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1), ATTR_RATIO(MF_MT_FRAME_SIZE, 320, 240), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), }, @@ -1134,13 +1134,13 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) L"video/x-ms-wmv", { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8), ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000, .todo_value = TRUE), - ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 743, .todo_value = TRUE), - ATTR_BLOB(MF_MT_USER_DATA, wma2_data, sizeof(wma2_data), .todo = TRUE), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), + ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 743), + ATTR_BLOB(MF_MT_USER_DATA, wma2_data, sizeof(wma2_data)), }, }, { @@ -1148,12 +1148,12 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) L"video/mp4", { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3, .todo_value = TRUE), - ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx, .todo = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3), + ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx), ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .todo = TRUE), + ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), }, }, @@ -1229,7 +1229,7 @@ static void test_compressed_media_types(IMFSourceResolver *resolver) hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(count == 1, "Got type count %lu.\n", count); + todo_wine_if (i == 5) ok(count == 1, "Got type count %lu.\n", count); IMFMediaTypeHandler_Release(handler); IMFStreamDescriptor_Release(sd); diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 2946425e494..6409d4c9a93 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -942,7 +942,7 @@ static void test_source_reader(const char *filename, bool video) hr = IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&subtype, &MFVideoFormat_H264), "Got subtype %s.\n", debugstr_guid(&subtype)); + ok(IsEqualGUID(&subtype, &MFVideoFormat_H264), "Got subtype %s.\n", debugstr_guid(&subtype)); hr = IMFMediaType_GetUINT64(mediatype, &MF_MT_FRAME_SIZE, &framesize); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -950,7 +950,7 @@ static void test_source_reader(const char *filename, bool video) (unsigned int)(framesize >> 32), (unsigned int)framesize); hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_DEFAULT_STRIDE, &stride); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(mediatype); @@ -1002,7 +1002,7 @@ static void test_source_reader(const char *filename, bool video) hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_DEFAULT_STRIDE, &stride); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(stride == 160 * 4, "Got stride %u.\n", stride); + ok(stride == 160 * 4, "Got stride %u.\n", stride); IMFMediaType_Release(mediatype); } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ab842b3e438..155d4ba0479 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1743,7 +1743,7 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(FALSE))) + if (!(parser = wg_parser_create(true))) { hr = E_OUTOFMEMORY; goto fail; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5988
Is there any reason not to commit this? This fixes several applications, unblocks other changes including !9327 and !10654, and the only objection that has been brought up is that it somehow makes it "harder to upstream" patches that, as far as I can tell, have already been upstreamed, and did not touch the same code as this patch series at all. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5988#note_149319
On Thu Aug 20 05:36:43 2026 +0000, Elizabeth Figura wrote:
Is there any reason not to commit this? This fixes several applications, unblocks other changes including !9327 and !10654, and the only objection that has been brought up is that it somehow makes it "harder to upstream" patches that, as far as I can tell, have already been upstreamed, and did not touch the same code as this patch series at all. I think the idea was that as soon as decoders are involved it's likely that D3D buffers and shared resources will also be expected and required, although this is only just a hunch than anything else now. There's probably many games that simply require shared resources regardless of what the source does anyway.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/5988#note_149331
participants (4)
-
Elizabeth Figura -
Elizabeth Figura (@zfigura) -
Elizabeth Figura (@zfigura) -
Rémi Bernon (@rbernon)