This is required to fix video playback in Crashlands 2 on Proton 10.
-- v2: mfreadwrite: Fix media type output when video processor is used. mfreadwrite/tests: Check DEFAULT_STRIDE is not always present.
From: Brendan McGrath bmcgrath@codeweavers.com
MF_MT_DEFAULT_STRIDE should not be present when MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING is TRUE. --- dlls/mfreadwrite/tests/mfplat.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 7ed757073ff..0fdd8459bcc 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -89,6 +89,7 @@ struct attribute_desc BOOL required; BOOL todo; BOOL todo_value; + BOOL not_present; };
#define ATTR_GUID(k, g, ...) {.key = &k, .name = #k, {.vt = VT_CLSID, .puuid = (GUID *)&g}, __VA_ARGS__ } @@ -111,7 +112,10 @@ void check_attributes_(const char *file, int line, IMFAttributes *attributes, { hr = IMFAttributes_GetItem(attributes, desc[i].key, &value); todo_wine_if(desc[i].todo) - ok_(file, line)(hr == S_OK, "%s missing, hr %#lx\n", debugstr_a(desc[i].name), hr); + if (desc[i].not_present) + ok_(file, line)(hr == MF_E_ATTRIBUTENOTFOUND, "%s present, hr %#lx\n", debugstr_a(desc[i].name), hr); + else + ok_(file, line)(hr == S_OK, "%s missing, hr %#lx\n", debugstr_a(desc[i].name), hr); if (hr != S_OK) continue;
switch (value.vt) @@ -2052,6 +2056,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE), {0}, }; static const struct attribute_desc yuy2_stream_type_desc[] = @@ -2086,6 +2091,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE), {0}, }; static const struct attribute_desc rgb32_stream_type_desc[] = @@ -2114,6 +2120,8 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE), + {0}, }; static const struct attribute_desc rgb32_expect_advanced_desc_todo2[] = { @@ -2123,6 +2131,8 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE, .todo = TRUE), + {0}, }; IMFStreamDescriptor *video_stream; IMFSourceReaderEx *reader_ex;
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/mfreadwrite/reader.c | 53 ++++++++++++++++++++++++++++++--- dlls/mfreadwrite/tests/mfplat.c | 2 +- 2 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 139b8991da2..70649bd19a9 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -716,14 +716,13 @@ static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const
/* update a media type with additional attributes reported by upstream element */ /* also present in mf/topology_loader.c pipeline */ -static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type, BOOL advanced) { HRESULT hr = S_OK;
/* propagate common video attributes */ media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); @@ -738,6 +737,9 @@ static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMedi media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
+ if (!advanced) + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr); + /* propagate common audio attributes */ media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); @@ -2030,6 +2032,44 @@ static BOOL source_reader_allow_video_processor(struct source_reader *reader, BO return *advanced; }
+static HRESULT set_default_video_attributes(struct source_reader *reader, IMFMediaType *output_type) +{ + UINT64 frame_size; + DWORD sample_size; + BOOL compressed; + GUID subtype; + LONG stride; + HRESULT hr; + + hr = IMFMediaType_IsCompressedFormat(output_type, &compressed); + + if (SUCCEEDED(hr) && !compressed) + { + if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_COMPRESSED, compressed))) + return hr; + + if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (FAILED(hr = IMFMediaType_GetUINT64(output_type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, &stride))) + return hr; + + if (FAILED(hr = MFGetPlaneSize(subtype.Data1, frame_size >> 32, frame_size & 0xffffffff, &sample_size))) + return hr; + + if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, abs(stride)))) + return hr; + + if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_SAMPLE_SIZE, sample_size))) + return hr; + } + + return hr; +} + static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor, IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out) { @@ -2121,7 +2161,11 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { - if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + BOOL enable_advanced; + + source_reader_allow_video_processor(reader, &enable_advanced); + + if ((SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type, enable_advanced))) && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && FAILED(hr = set_matching_transform_output_type(transform, output_type)) && allow_processor && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) @@ -2129,7 +2173,8 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL struct transform_entry *converter;
if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) - && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type, enable_advanced)) + && (enable_advanced || SUCCEEDED(hr = set_default_video_attributes(reader, output_type))) && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter))) list_add_tail(&entry->entry, &converter->entry);
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 0fdd8459bcc..2946425e494 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2131,7 +2131,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE, .todo = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE), {0}, }; IMFStreamDescriptor *video_stream;
On Fri May 30 07:00:47 2025 +0000, Brendan McGrath wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/8172/diffs?diff_id=181644&start_sha=4b2aae90b10b0ea10c9cd0e7ac84d70c10ccc30e#d2fe6f6c01e7302437c883178ff17ea96268b3ed_2287_2317)
Looks like the decoder MFT will provide these values, but not the Video Processor. It seems to just echo the media type that was passed in with `IMFTransform::SetOutputType`.
So I've changed the fix to calculate and add `MF_MT_DEFAULT_STRIDE` in the call to `IMFTransform::SetOutputType` of the Video Processor. But I also found that when using `MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING`, `MF_MT_DEFAULT_STRIDE` is not present. So I've added some tests for that and reflected that in the fix.
This doesn't seem to fix any of the existing tests, as it mainly seems to help only when `DisableGstByteStreamHandler` is set to `1` (such as with Proton).