From c531bb7f3d57828bff7c30701cdbc02883a39e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 Jul 2024 08:31:29 +0200 Subject: [PATCH 001/301] Revert "winegstreamer: Prepend a h264parse element before decoder." This reverts commit 5ffe4f3fd691d19ce46cbbca3d28ccb7961abd0e. --- dlls/winegstreamer/wg_transform.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e4f166982b1..754140e96a2 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -404,16 +404,12 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { - case WG_MAJOR_TYPE_VIDEO_H264: - if (!(element = create_element("h264parse", "bad")) - || !append_element(transform->container, element, &first, &last)) - goto out; - /* FALLTHROUGH */ case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_ENCODED: + case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: From 51d5d13caa3b93a938ba8924ca98aaca83466458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Jul 2024 13:51:15 +0200 Subject: [PATCH 002/301] Revert "winegstreamer: Use MFCalculateImageSize to compute output info size." This reverts commit 3e1c699fdcca554f01d3b7d4db7c25f41c18691d. CW-Bug-Id: 20833 --- dlls/winegstreamer/video_decoder.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 32f68809d3a..8da8a7f0902 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -539,23 +539,6 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR return create_output_media_type(decoder, decoder->output_types[index], NULL, type); } -static HRESULT update_output_info_size(struct video_decoder *decoder, UINT32 width, UINT32 height) -{ - HRESULT hr = E_FAIL; - UINT32 i, size; - - decoder->output_info.cbSize = 0; - - for (i = 0; i < decoder->output_type_count; ++i) - { - if (FAILED(hr = MFCalculateImageSize(decoder->output_types[i], width, height, &size))) - return hr; - decoder->output_info.cbSize = max(size, decoder->output_info.cbSize); - } - - return hr; -} - static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct video_decoder *decoder = impl_from_IMFTransform(iface); @@ -595,8 +578,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) WARN("Failed to update stream type frame size, hr %#lx\n", hr); - if (FAILED(hr = update_output_info_size(decoder, frame_size >> 32, frame_size))) - return hr; + MFCalculateImageSize(decoder->output_types[0], frame_size >> 32, frame_size, (UINT32 *)&decoder->output_info.cbSize); } if (decoder->wg_transform) @@ -828,8 +810,7 @@ static HRESULT handle_stream_type_change(struct video_decoder *decoder, const st return hr; if (FAILED(hr = IMFMediaType_GetGUID(decoder->stream_type, &MF_MT_SUBTYPE, &subtype))) return hr; - if (FAILED(hr = update_output_info_size(decoder, frame_size >> 32, frame_size))) - return hr; + MFCalculateImageSize(&subtype, frame_size >> 32, frame_size, (UINT32 *)&decoder->output_info.cbSize); uninit_allocator(decoder); return MF_E_TRANSFORM_STREAM_CHANGE; From 866e0fa8c1c026867009a07252507cff944f1a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:15 +0200 Subject: [PATCH 003/301] Revert "winegstreamer/video_decoder: HACK: Try use I420 input if failed to create transform." This reverts commit 161cfd83144b0f1975df6c35057883833b194d97. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 8da8a7f0902..fb8b555ce08 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1188,27 +1188,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde } if (FAILED(hr = wg_transform_create_quartz(&decoder->dmo_input_type, type, &decoder->wg_transform_attrs, &decoder->wg_transform))) - { - /* HACK: Try I420 if failed to create gstreamer transform. The reason for - * the failure may be gstreamer decoder plugins are missing in proton. - * In that case, the video is likely to be transcoded already. Transcoded - * video streams are in theora format, and gstreamer theora decoder will - * finally output I420, so we try use I420 input here. */ - DMO_MEDIA_TYPE input_type; - - input_type = decoder->dmo_input_type; - input_type.subtype = MEDIASUBTYPE_I420; - input_type.formattype = FORMAT_VideoInfo; - input_type.cbFormat = sizeof(VIDEOINFOHEADER); - input_type.pbFormat = CoTaskMemAlloc(input_type.cbFormat); - memcpy(input_type.pbFormat, decoder->dmo_input_type.pbFormat, sizeof(VIDEOINFOHEADER)); - - hr = wg_transform_create_quartz(&input_type, type, - &decoder->wg_transform_attrs, &decoder->wg_transform); - FreeMediaType(&input_type); - return hr; - } return S_OK; } From 063d6beb5d91f0627f02ef25a2ffb0e191347741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:16 +0200 Subject: [PATCH 004/301] Revert "winegstreamer/video_decoder: HACK: Create wmv decoder even if plugins are not installed." This reverts commit 90de0f723dfb86e2598158a324a64b74abf2b72d. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index fb8b555ce08..a2e70663c40 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1709,9 +1709,11 @@ HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) TRACE("outer %p, out %p.\n", outer, out); if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - FIXME_(winediag)("HACK: Create wmv decoder even if plugins are not installed.\n"); - else - wg_transform_destroy(transform); + { + ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); + return E_FAIL; + } + wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(wmv_decoder_input_types, ARRAY_SIZE(wmv_decoder_input_types), wmv_decoder_output_types, ARRAY_SIZE(wmv_decoder_output_types), outer, &decoder))) From 6e7efd38dc56665185174b99e2824f0065220783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:16 +0200 Subject: [PATCH 005/301] Revert "mfplat/mediatype: Implement MFCreateMediaTypeFromRepresentation." This reverts commit d4321fe3e3814ad4b893925170043f14655d09e1. CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 26 ------------------- dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 51 -------------------------------------- include/mfapi.h | 2 -- 4 files changed, 1 insertion(+), 80 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index ea863eac5f3..a159ae4b56f 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4049,29 +4049,3 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM return E_NOTIMPL; } - -/*********************************************************************** - * MFCreateMediaTypeFromRepresentation (mfplat.@) - */ -HRESULT WINAPI MFCreateMediaTypeFromRepresentation(GUID guid_representation, void *representation, - IMFMediaType **media_type) -{ - HRESULT hr; - - TRACE("%s, %p, %p\n", debugstr_guid(&guid_representation), representation, media_type); - - if (!IsEqualGUID(&guid_representation, &AM_MEDIA_TYPE_REPRESENTATION)) - return MF_E_UNSUPPORTED_REPRESENTATION; - if (!representation || !media_type) - return E_INVALIDARG; - - if (FAILED(hr = MFCreateMediaType(media_type))) - return hr; - if (FAILED(hr = MFInitMediaTypeFromAMMediaType(*media_type, representation))) - { - IMFMediaType_Release(*media_type); - *media_type = NULL; - } - - return hr; -} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 8a9750a7eb8..d7f75351960 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -59,7 +59,7 @@ @ stub MFCreateMediaBufferWrapper @ stdcall MFCreateMediaEvent(long ptr long ptr ptr) @ stdcall MFCreateMediaType(ptr) -@ stdcall MFCreateMediaTypeFromRepresentation(int128 ptr ptr) +@ stub MFCreateMediaTypeFromRepresentation @ stdcall MFCreateMemoryBuffer(long ptr) @ stub MFCreateMemoryStream @ stdcall MFCreatePathFromURL(wstr ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 01290763003..f785df89b32 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7741,56 +7741,6 @@ static void test_IMFMediaType_GetRepresentation(void) IMFMediaType_Release(media_type); } -static void test_MFCreateMediaTypeFromRepresentation(void) -{ - IMFMediaType *media_type; - AM_MEDIA_TYPE amt = {0}; - WAVEFORMATEX wfx = {0}; - HRESULT hr; - GUID guid; - - hr = MFCreateMediaTypeFromRepresentation(GUID_NULL, &amt, &media_type); - ok(hr == MF_E_UNSUPPORTED_REPRESENTATION, "Unexpected hr %#lx.\n", hr); - hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, NULL, &media_type); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, NULL); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - - hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, &media_type); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - memset(&guid, 0xcd, sizeof(guid)); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(IsEqualGUID(&guid, &GUID_NULL), "got %s.\n", debugstr_guid(&guid)); - memset(&guid, 0xcd, sizeof(guid)); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(IsEqualGUID(&guid, &GUID_NULL), "got %s.\n", debugstr_guid(&guid)); - IMFMediaType_Release(media_type); - } - - amt.formattype = FORMAT_WaveFormatEx; - amt.majortype = MFMediaType_Audio; - amt.subtype = MFAudioFormat_PCM; - amt.pbFormat = (BYTE *)&wfx; - amt.cbFormat = sizeof(wfx); - hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, &media_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - memset(&guid, 0xcd, sizeof(guid)); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(IsEqualGUID(&guid, &MFMediaType_Audio), "got %s.\n", debugstr_guid(&guid)); - memset(&guid, 0xcd, sizeof(guid)); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine - ok(IsEqualGUID(&guid, &MFAudioFormat_PCM), "got %s.\n", debugstr_guid(&guid)); - IMFMediaType_Release(media_type); -} - static void test_MFCreateDXSurfaceBuffer(void) { IDirect3DSurface9 *backbuffer = NULL, *surface; @@ -10564,7 +10514,6 @@ START_TEST(mfplat) test_MFInitAMMediaTypeFromMFMediaType(); test_MFCreateAMMediaTypeFromMFMediaType(); test_IMFMediaType_GetRepresentation(); - test_MFCreateMediaTypeFromRepresentation(); test_MFCreateDXSurfaceBuffer(); test_MFCreateTrackedSample(); test_MFFrameRateToAverageTimePerFrame(); diff --git a/include/mfapi.h b/include/mfapi.h index 53fb5052e6e..ef5bec16369 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -547,8 +547,6 @@ HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HR HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); HRESULT WINAPI MFCreateAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID format_type, AM_MEDIA_TYPE **am_type); HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size); -HRESULT WINAPI MFCreateMediaTypeFromRepresentation(GUID guid_representation, void *representation, - IMFMediaType **media_type); HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateTempFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, IMFByteStream **bytestream); From 053770869f8ab58b547b169283ce078cdd08c087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:16 +0200 Subject: [PATCH 006/301] Revert "winegstreamer/wg_parser: HACK: Return untranscoded codec format for transcoded stream." This reverts commit fbe7fa1dfe0612111b3bcf7167b031eef8d21de7. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 1cd44a90e6e..6ed3e4d9a4c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -248,20 +248,6 @@ static NTSTATUS wg_parser_stream_get_codec_format(void *args) struct wg_parser_stream_get_codec_format_params *params = args; struct wg_parser_stream *stream = get_stream(params->stream); - { - /* HACK: Return untranscoded codec format for transcoded stream. */ - struct wg_format untranscoded_format; - - untranscoded_format = stream->preferred_format; - if (get_untranscoded_stream_format(stream->parser->container, stream->number, &untranscoded_format)) - { - *params->format = untranscoded_format; - return S_OK; - } - - GST_WARNING("Failed to get untranscoded codec format for stream %u.\n", stream->number); - } - *params->format = format_is_compressed(&stream->codec_format) ? stream->codec_format : stream->preferred_format; From b04920bf67ccfd4b3503229bb387d5446badbf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:16 +0200 Subject: [PATCH 007/301] Revert "winegstreamer/video_decoder: Make output_plane_align specific to h264." This reverts commit 44f882104176884afe4b6802cb9123425e1d8a22. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index a2e70663c40..599b826b79b 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1516,6 +1516,7 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) goto failed; + decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.input_queue_length = 15; *out = decoder; @@ -1605,7 +1606,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; - decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.allow_size_change = TRUE; TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); From 6030eba25c521fee6deb7956455c0054585ff8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:16 +0200 Subject: [PATCH 008/301] Revert "winegstreamer/video_decoder: Use video_decoder to implement wmv decoder." This reverts commit 896de5f43d43e5859452bf4111a4d2c344f3d075. CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 69 +-- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/video_decoder.c | 761 +----------------------- dlls/winegstreamer/wmv_decoder.c | 893 +++++++++++++++++++++++++++++ 4 files changed, 925 insertions(+), 799 deletions(-) create mode 100644 dlls/winegstreamer/wmv_decoder.c diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 84cf32b8f2d..912ad29eb59 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -680,7 +680,6 @@ static void check_mft_set_input_type_required_(int line, IMFTransform *transform hr = IMFMediaType_DeleteItem(media_type, attr->key); ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr); hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); - todo_wine_if(attr->todo) ok_(__FILE__, line)(FAILED(hr) == attr->required, "SetInputType returned %#lx.\n", hr); hr = IMFMediaType_SetItem(media_type, attr->key, &attr->value); ok_(__FILE__, line)(hr == S_OK, "SetItem returned %#lx\n", hr); @@ -1285,7 +1284,7 @@ static DWORD check_mf_sample_(const char *file, int line, IMFSample *sample, con timestamp = 0xdeadbeef; hr = IMFSample_GetSampleDuration(sample, ×tamp); ok_(file, line)(hr == S_OK, "GetSampleDuration returned %#lx\n", hr); - todo_wine_if(expect->todo_duration) + todo_wine_if(expect->todo_duration && expect->todo_duration == timestamp) ok_(file, line)(llabs(timestamp - expect->sample_duration) <= 1, "got sample duration %I64d\n", timestamp); @@ -5602,7 +5601,7 @@ static void test_wmv_decoder(void) ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2), {0}, }; const media_type_desc expect_available_outputs[] = @@ -5714,7 +5713,7 @@ static void test_wmv_decoder(void) { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE), - ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE, .todo = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), {0}, }; const struct attribute_desc output_type_desc[] = @@ -5760,7 +5759,7 @@ static void test_wmv_decoder(void) ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), {0}, }; const struct attribute_desc expect_output_type_desc[] = @@ -5828,7 +5827,6 @@ static void test_wmv_decoder(void) .cbSize = 0x9000, .cbAlignment = 1, }; - const MFT_INPUT_STREAM_INFO empty_input_info = {0}; const struct attribute_desc output_sample_attributes[] = { @@ -5850,21 +5848,12 @@ static void test_wmv_decoder(void) .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_nv12, - .todo_duration = TRUE, - }; - const struct sample_desc output_sample_desc_nv12_todo_time = - { - .attributes = output_sample_attributes, - .sample_time = 0, .sample_duration = 333333, - .buffer_count = 1, .buffers = &output_buffer_desc_nv12, - .todo_time = TRUE, .todo_duration = TRUE, }; const struct sample_desc output_sample_desc_rgb = { .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_rgb, - .todo_time = TRUE, .todo_duration = TRUE, }; const struct transform_desc @@ -5896,7 +5885,7 @@ static void test_wmv_decoder(void) .expect_output_type_desc = expect_output_type_desc, .expect_input_info = &expect_input_info, .expect_output_info = &expect_output_info, - .output_sample_desc = &output_sample_desc_nv12_todo_time, + .output_sample_desc = &output_sample_desc_nv12, .result_bitmap = L"nv12frame.bmp", .delta = 0, }, @@ -5939,8 +5928,6 @@ static void test_wmv_decoder(void) MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_WMV1}; IMFSample *input_sample, *output_sample; - MFT_OUTPUT_STREAM_INFO output_info; - MFT_INPUT_STREAM_INFO input_info; IMFCollection *output_samples; IMFMediaType *media_type; IMFTransform *transform; @@ -5977,27 +5964,13 @@ static void test_wmv_decoder(void) check_mft_optional_methods(transform, 1); check_mft_get_attributes(transform, expect_attributes, TRUE); - - memset(&input_info, 0xcd, sizeof(input_info)); - hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); - todo_wine - ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetInputStreamInfo returned %#lx\n", hr); - check_member(input_info, empty_input_info, "%I64d", hnsMaxLatency); - check_member(input_info, empty_input_info, "%#lx", dwFlags); - check_member(input_info, empty_input_info, "%#lx", cbSize); - check_member(input_info, empty_input_info, "%#lx", cbMaxLookahead); - check_member(input_info, empty_input_info, "%#lx", cbAlignment); - - memset(&output_info, 0xcd, sizeof(output_info)); - hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); todo_wine - ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputStreamInfo returned %#lx\n", hr); + check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); todo_wine - check_member(output_info, empty_output_info, "%#lx", dwFlags); - check_member(output_info, empty_output_info, "%#lx", cbSize); - check_member(output_info, empty_output_info, "%#lx", cbAlignment); + check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_output_info); hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type); + todo_wine ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr); i = -1; @@ -6011,7 +5984,9 @@ static void test_wmv_decoder(void) ok(!ret, "Release returned %lu\n", ret); winetest_pop_context(); } + todo_wine ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); + todo_wine ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i); if (hr == E_NOTIMPL) @@ -6045,28 +6020,10 @@ static void test_wmv_decoder(void) check_mft_set_output_type_required(transform, transform_tests[j].output_type_desc); check_mft_set_output_type(transform, transform_tests[j].output_type_desc, S_OK); - check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, TRUE); + check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, FALSE); - memset(&input_info, 0xcd, sizeof(input_info)); - hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); - ok(hr == S_OK, "GetInputStreamInfo returned %#lx\n", hr); - check_member(input_info, *transform_tests[j].expect_input_info, "%I64d", hnsMaxLatency); - check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", dwFlags); - todo_wine - check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbSize); - check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbMaxLookahead); - todo_wine - check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbAlignment); - - memset(&output_info, 0xcd, sizeof(output_info)); - hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); - ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); - todo_wine - check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", dwFlags); - todo_wine_if(transform_tests[j].expect_output_info == &expect_output_info) - check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbSize); - todo_wine - check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbAlignment); + check_mft_get_input_stream_info(transform, S_OK, transform_tests[j].expect_input_info); + check_mft_get_output_stream_info(transform, S_OK, transform_tests[j].expect_output_info); load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index a26ac0bff93..f76a7fb35f2 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -32,6 +32,7 @@ SOURCES = \ winegstreamer_classes.idl \ wm_reader.c \ wma_decoder.c \ + wmv_decoder.c \ media-converter/audioconv.c \ media-converter/audioconvbin.c \ media-converter/fossilize.c \ diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 599b826b79b..7c708413b65 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -24,8 +24,6 @@ #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" -#include "mediaerr.h" -#include "wmcodecdsp.h" #include "wine/debug.h" @@ -37,36 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); extern GUID MFVideoFormat_GStreamer; - -struct subtype_info -{ - const GUID *subtype; - WORD bpp; - DWORD compression; -}; - -static const struct subtype_info subtype_info_list[] = -{ - { &MFVideoFormat_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, - { &MFVideoFormat_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, - { &MFVideoFormat_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, - { &MFVideoFormat_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, - { &MFVideoFormat_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, - { &MFVideoFormat_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, - { &MFVideoFormat_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, - { &MFVideoFormat_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, - { &MFVideoFormat_RGB8, 8, BI_RGB }, - { &MFVideoFormat_RGB555, 16, BI_RGB }, - { &MFVideoFormat_RGB565, 16, BI_BITFIELDS }, - { &MFVideoFormat_RGB24, 24, BI_RGB }, - { &MFVideoFormat_RGB32, 32, BI_RGB }, - { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, - { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, - { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, - { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, - { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, -}; - static const GUID *const video_decoder_input_types[] = { &MFVideoFormat_GStreamer, @@ -84,9 +52,6 @@ struct video_decoder { IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; - IMediaObject IMediaObject_iface; - IPropertyBag IPropertyBag_iface; - IPropertyStore IPropertyStore_iface; IUnknown *outer; LONG refcount; @@ -113,9 +78,6 @@ struct video_decoder BOOL allocator_initialized; IMFTransform *copier; IMFMediaBuffer *temp_buffer; - - DMO_MEDIA_TYPE dmo_input_type; - DMO_MEDIA_TYPE dmo_output_type; }; static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) @@ -133,12 +95,6 @@ static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void * *out = &decoder->IUnknown_inner; else if (IsEqualGUID(iid, &IID_IMFTransform)) *out = &decoder->IMFTransform_iface; - else if (IsEqualGUID(iid, &IID_IMediaObject) && decoder->IMediaObject_iface.lpVtbl) - *out = &decoder->IMediaObject_iface; - else if (IsEqualGUID(iid, &IID_IPropertyBag) && decoder->IPropertyBag_iface.lpVtbl) - *out = &decoder->IPropertyBag_iface; - else if (IsEqualGUID(iid, &IID_IPropertyStore) && decoder->IPropertyStore_iface.lpVtbl) - *out = &decoder->IPropertyStore_iface; else { *out = NULL; @@ -197,48 +153,6 @@ static const IUnknownVtbl unknown_vtbl = unknown_Release, }; -static WORD get_subtype_bpp(const GUID *subtype) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) - { - if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) - return subtype_info_list[i].bpp; - } - - return 0; -} - -static DWORD get_subtype_compression(const GUID *subtype) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) - { - if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) - return subtype_info_list[i].compression; - } - - return 0; -} - -static const GUID *get_dmo_subtype(const GUID *subtype) -{ - if (IsEqualGUID(subtype, &MFVideoFormat_RGB8)) - return &MEDIASUBTYPE_RGB8; - else if (IsEqualGUID(subtype, &MFVideoFormat_RGB555)) - return &MEDIASUBTYPE_RGB555; - else if (IsEqualGUID(subtype, &MFVideoFormat_RGB565)) - return &MEDIASUBTYPE_RGB565; - else if (IsEqualGUID(subtype, &MFVideoFormat_RGB24)) - return &MEDIASUBTYPE_RGB24; - else if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) - return &MEDIASUBTYPE_RGB32; - else - return subtype; -} - static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -291,7 +205,6 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; MFVideoArea default_aperture = {{0}}, aperture; IMFVideoMediaType *video_type; - LONG default_stride, stride; UINT32 value, width, height; UINT64 ratio; HRESULT hr; @@ -324,20 +237,9 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) goto done; - /* WMV decoder uses positive stride by default, and enforces it for YUV formats, - * accepts negative stride for RGB if specified */ - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, &default_stride))) - goto done; - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) - stride = abs(default_stride); - else if (default_stride > 0) - stride = abs(stride); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, stride))) - goto done; - - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_VIDEO_NOMINAL_RANGE, (UINT32 *)&value))) - value = MFNominalRange_Wide; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_NOMINAL_RANGE, value))) + if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) + hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); + if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) goto done; if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) @@ -932,547 +834,8 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, }; -static inline struct video_decoder *impl_from_IMediaObject(IMediaObject *iface) -{ - return CONTAINING_RECORD(iface, struct video_decoder, IMediaObject_iface); -} - -static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) -{ - return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); -} - -static ULONG WINAPI media_object_AddRef(IMediaObject *iface) -{ - return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); -} - -static ULONG WINAPI media_object_Release(IMediaObject *iface) -{ - return IUnknown_Release(impl_from_IMediaObject(iface)->outer); -} - -static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) -{ - TRACE("iface %p, input %p, output %p.\n", iface, input, output); - - if (!input || !output) - return E_POINTER; - - *input = *output = 1; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= decoder->input_type_count) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *get_dmo_subtype(decoder->input_types[type_index]); - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - UINT64 frame_size, frame_rate; - IMFMediaType *media_type; - VIDEOINFOHEADER *info; - const GUID *subtype; - LONG width, height; - UINT32 image_size; - HRESULT hr; - - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= decoder->output_type_count) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - &decoder->dmo_input_type, &media_type))) - return hr; - - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) - frame_size = 0; - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) - frame_rate = (UINT64)1 << 32 | 1; - - width = frame_size >> 32; - height = (UINT32)frame_size; - subtype = get_dmo_subtype(decoder->output_types[type_index]); - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) - { - FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); - IMFMediaType_Release(media_type); - return hr; - } - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *subtype; - type->bFixedSizeSamples = TRUE; - type->bTemporalCompression = FALSE; - type->lSampleSize = image_size; - type->formattype = FORMAT_VideoInfo; - type->cbFormat = sizeof(VIDEOINFOHEADER); - type->pbFormat = CoTaskMemAlloc(type->cbFormat); - memset(type->pbFormat, 0, type->cbFormat); - - info = (VIDEOINFOHEADER *)type->pbFormat; - info->rcSource.right = width; - info->rcSource.bottom = height; - info->rcTarget.right = width; - info->rcTarget.bottom = height; - if (frame_rate) - MFFrameRateToAverageTimePerFrame(frame_rate >> 32, frame_rate, (UINT64 *)&info->AvgTimePerFrame); - info->bmiHeader.biSize = sizeof(info->bmiHeader); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = get_subtype_bpp(subtype); - info->bmiHeader.biCompression = get_subtype_compression(subtype); - info->bmiHeader.biSizeImage = image_size; - - IMFMediaType_Release(media_type); - return S_OK; -} - -static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - unsigned int i; - - TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->dmo_input_type); - memset(&decoder->dmo_input_type, 0, sizeof(decoder->dmo_input_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return DMO_E_TYPE_NOT_ACCEPTED; - } - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < decoder->input_type_count; ++i) - if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->input_types[i]))) - break; - if (i == decoder->input_type_count) - FIXME("HACK: Using a type which is not an available input type of this decoder.\n"); - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->dmo_input_type); - CopyMediaType(&decoder->dmo_input_type, type); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - - return S_OK; -} - -static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - unsigned int i; - HRESULT hr; - - TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->dmo_output_type); - memset(&decoder->dmo_output_type, 0, sizeof(decoder->dmo_output_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return E_POINTER; - } - - if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < decoder->output_type_count; ++i) - if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->output_types[i]))) - break; - if (i == decoder->output_type_count) - return DMO_E_TYPE_NOT_ACCEPTED; - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->dmo_output_type); - CopyMediaType(&decoder->dmo_output_type, type); - - /* Set up wg_transform. */ - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - if (FAILED(hr = wg_transform_create_quartz(&decoder->dmo_input_type, type, - &decoder->wg_transform_attrs, &decoder->wg_transform))) - return hr; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, - DWORD *lookahead, DWORD *alignment) -{ - FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, - lookahead, alignment); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - HRESULT hr; - - TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (IsEqualGUID(&decoder->dmo_output_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(&media_type))) - return hr; - if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->dmo_output_type)) - && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) - *alignment = 1; - IMFMediaType_Release(media_type); - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) -{ - FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) -{ - FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_Flush(IMediaObject *iface) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p.\n", iface); - - if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) - return hr; - - wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); - - return S_OK; -} - -static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) -{ - TRACE("iface %p, index %lu.\n", iface, index); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - return S_OK; -} - -static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) -{ - TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (!flags) - return E_POINTER; - - *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; - - return S_OK; -} - -static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, - IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - - TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); -} - -static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, - DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) -{ - struct video_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) - hr = wg_transform_read_dmo(decoder->wg_transform, buffers); - - if (SUCCEEDED(hr)) - wg_sample_queue_flush(decoder->wg_sample_queue, false); - - return hr; -} - -static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) -{ - FIXME("iface %p, lock %ld stub!\n", iface, lock); - return E_NOTIMPL; -} - -static const IMediaObjectVtbl media_object_vtbl = -{ - media_object_QueryInterface, - media_object_AddRef, - media_object_Release, - media_object_GetStreamCount, - media_object_GetInputStreamInfo, - media_object_GetOutputStreamInfo, - media_object_GetInputType, - media_object_GetOutputType, - media_object_SetInputType, - media_object_SetOutputType, - media_object_GetInputCurrentType, - media_object_GetOutputCurrentType, - media_object_GetInputSizeInfo, - media_object_GetOutputSizeInfo, - media_object_GetInputMaxLatency, - media_object_SetInputMaxLatency, - media_object_Flush, - media_object_Discontinuity, - media_object_AllocateStreamingResources, - media_object_FreeStreamingResources, - media_object_GetInputStatus, - media_object_ProcessInput, - media_object_ProcessOutput, - media_object_Lock, -}; - -static inline struct video_decoder *impl_from_IPropertyBag(IPropertyBag *iface) -{ - return CONTAINING_RECORD(iface, struct video_decoder, IPropertyBag_iface); -} - -static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); -} - -static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); -} - -static ULONG WINAPI property_bag_Release(IPropertyBag *iface) -{ - return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); -} - -static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, - IErrorLog *error_log) -{ - FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) -{ - FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); - return S_OK; -} - -static const IPropertyBagVtbl property_bag_vtbl = -{ - property_bag_QueryInterface, - property_bag_AddRef, - property_bag_Release, - property_bag_Read, - property_bag_Write, -}; - -static inline struct video_decoder *impl_from_IPropertyStore(IPropertyStore *iface) -{ - return CONTAINING_RECORD(iface, struct video_decoder, IPropertyStore_iface); -} - -static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); -} - -static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); -} - -static ULONG WINAPI property_store_Release(IPropertyStore *iface) -{ - return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); -} - -static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) -{ - FIXME("iface %p, count %p stub!\n", iface, count); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) -{ - FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static const IPropertyStoreVtbl property_store_vtbl = -{ - property_store_QueryInterface, - property_store_AddRef, - property_store_Release, - property_store_GetCount, - property_store_GetAt, - property_store_GetValue, - property_store_SetValue, - property_store_Commit, -}; - static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IUnknown *outer, struct video_decoder **out) + const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) { struct video_decoder *decoder; HRESULT hr; @@ -1519,8 +882,8 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.input_queue_length = 15; - *out = decoder; - TRACE("Created decoder %p\n", decoder); + *ret = &decoder->IMFTransform_iface; + TRACE("Created decoder %p\n", *ret); return S_OK; failed: @@ -1540,19 +903,17 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U HRESULT video_decoder_create(REFIID riid, void **out) { - struct video_decoder *decoder; + IMFTransform *iface; HRESULT hr; TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); if (FAILED(hr = video_decoder_create_with_types(video_decoder_input_types, ARRAY_SIZE(video_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) return hr; - TRACE("Create generic video decoder transform %p.\n", &decoder->IMFTransform_iface); - - hr = IMFTransform_QueryInterface(&decoder->IMFTransform_iface, riid, out); - IMFTransform_Release(&decoder->IMFTransform_iface); + hr = IMFTransform_QueryInterface(iface, riid, out); + IMFTransform_Release(iface); return hr; } @@ -1578,6 +939,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) struct wg_transform_attrs attrs = {0}; struct video_decoder *decoder; wg_transform_t transform; + IMFTransform *iface; HRESULT hr; TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); @@ -1590,12 +952,13 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) return hr; + decoder = impl_from_IMFTransform(iface); if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) { - IMFTransform_Release(&decoder->IMFTransform_iface); + IMFTransform_Release(iface); return hr; } @@ -1608,10 +971,8 @@ HRESULT h264_decoder_create(REFIID riid, void **out) decoder->wg_transform_attrs.allow_size_change = TRUE; - TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); - - hr = IMFTransform_QueryInterface(&decoder->IMFTransform_iface, riid, out); - IMFTransform_Release(&decoder->IMFTransform_iface); + hr = IMFTransform_QueryInterface(iface, riid, out); + IMFTransform_Release(iface); return hr; } @@ -1635,97 +996,11 @@ static const GUID *const iv50_decoder_output_types[] = HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) { - struct video_decoder *decoder; - HRESULT hr; - TRACE("out %p.\n", out); if (!init_gstreamer()) return E_FAIL; - if (FAILED(hr = video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, &decoder))) - return hr; - - TRACE("Created iv50 transform %p.\n", &decoder->IMFTransform_iface); - - *out = &decoder->IMFTransform_iface; - return S_OK; -} - -extern const GUID MEDIASUBTYPE_VC1S; -extern const GUID MEDIASUBTYPE_WMV_Unknown; -static const GUID *const wmv_decoder_input_types[] = -{ - &MEDIASUBTYPE_WMV1, - &MEDIASUBTYPE_WMV2, - &MEDIASUBTYPE_WMVA, - &MEDIASUBTYPE_WMVP, - &MEDIASUBTYPE_WVP2, - &MEDIASUBTYPE_WMV_Unknown, - &MEDIASUBTYPE_WVC1, - &MEDIASUBTYPE_WMV3, - &MEDIASUBTYPE_VC1S, -}; -static const GUID *const wmv_decoder_output_types[] = -{ - &MFVideoFormat_NV12, - &MFVideoFormat_YV12, - &MFVideoFormat_IYUV, - &MFVideoFormat_I420, - &MFVideoFormat_YUY2, - &MFVideoFormat_UYVY, - &MFVideoFormat_YVYU, - &MFVideoFormat_NV11, - &MFVideoFormat_RGB32, - &MFVideoFormat_RGB24, - &MFVideoFormat_RGB565, - &MFVideoFormat_RGB555, - &MFVideoFormat_RGB8, -}; - -HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) -{ - static const struct wg_format input_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO_WMV, - .u.video.format = WG_VIDEO_FORMAT_WMV3, - }; - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, - }; - struct wg_transform_attrs attrs = {0}; - struct video_decoder *decoder; - wg_transform_t transform; - HRESULT hr; - - TRACE("outer %p, out %p.\n", outer, out); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - - if (FAILED(hr = video_decoder_create_with_types(wmv_decoder_input_types, ARRAY_SIZE(wmv_decoder_input_types), - wmv_decoder_output_types, ARRAY_SIZE(wmv_decoder_output_types), outer, &decoder))) - return hr; - - decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; - decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; - decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; - - TRACE("Created wmv transform %p, media object %p.\n", - &decoder->IMFTransform_iface, &decoder->IMediaObject_iface); - - *out = &decoder->IUnknown_inner; - return S_OK; + return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); } diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c new file mode 100644 index 00000000000..f61edbd0164 --- /dev/null +++ b/dlls/winegstreamer/wmv_decoder.c @@ -0,0 +1,893 @@ +/* Copyright 2022 RĂ©mi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mediaerr.h" +#include "mfobjects.h" +#include "mftransform.h" +#include "wmcodecdsp.h" +#include "initguid.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +extern const GUID MEDIASUBTYPE_VC1S; +extern const GUID MEDIASUBTYPE_WMV_Unknown; + +struct decoder_type +{ + const GUID *subtype; + WORD bpp; + DWORD compression; +}; + +static const GUID *const wmv_decoder_input_types[] = +{ + &MEDIASUBTYPE_WMV1, + &MEDIASUBTYPE_WMV2, + &MEDIASUBTYPE_WMVA, + &MEDIASUBTYPE_WMVP, + &MEDIASUBTYPE_WVP2, + &MEDIASUBTYPE_WMV_Unknown, + &MEDIASUBTYPE_WVC1, + &MEDIASUBTYPE_WMV3, + &MEDIASUBTYPE_VC1S, +}; + +static const struct decoder_type wmv_decoder_output_types[] = +{ + { &MEDIASUBTYPE_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, + { &MEDIASUBTYPE_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, + { &MEDIASUBTYPE_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, + { &MEDIASUBTYPE_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, + { &MEDIASUBTYPE_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, + { &MEDIASUBTYPE_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, + { &MEDIASUBTYPE_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, + { &MEDIASUBTYPE_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, + { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, + { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, + { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, + { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, + { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, +}; + +struct wmv_decoder +{ + IUnknown IUnknown_inner; + IMFTransform IMFTransform_iface; + IMediaObject IMediaObject_iface; + IPropertyBag IPropertyBag_iface; + IPropertyStore IPropertyStore_iface; + IUnknown *outer; + LONG refcount; + + struct wg_format input_format; + struct wg_format output_format; + GUID output_subtype; + + wg_transform_t wg_transform; + struct wg_sample_queue *wg_sample_queue; +}; + +static bool wg_format_is_set(struct wg_format *format) +{ + return format->major_type != WG_MAJOR_TYPE_UNKNOWN; +} + +static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct wmv_decoder, IUnknown_inner); +} + +static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + struct wmv_decoder *impl = impl_from_IUnknown(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = &impl->IUnknown_inner; + else if (IsEqualGUID(iid, &IID_IMFTransform)) + *out = &impl->IMFTransform_iface; + else if (IsEqualGUID(iid, &IID_IMediaObject)) + *out = &impl->IMediaObject_iface; + else if (IsEqualIID(iid, &IID_IPropertyBag)) + *out = &impl->IPropertyBag_iface; + else if (IsEqualIID(iid, &IID_IPropertyStore)) + *out = &impl->IPropertyStore_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI unknown_AddRef(IUnknown *iface) +{ + struct wmv_decoder *impl = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&impl->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI unknown_Release(IUnknown *iface) +{ + struct wmv_decoder *impl = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&impl->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) + { + if (impl->wg_transform) + wg_transform_destroy(impl->wg_transform); + wg_sample_queue_destroy(impl->wg_sample_queue); + free(impl); + } + + return refcount; +} + +static const IUnknownVtbl unknown_vtbl = +{ + unknown_QueryInterface, + unknown_AddRef, + unknown_Release, +}; + +static struct wmv_decoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct wmv_decoder, IMFTransform_iface); +} + +static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + return IUnknown_Release(impl_from_IMFTransform(iface)->outer); +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; + return S_OK; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + *inputs = *outputs = 1; + return S_OK; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, + input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + FIXME("iface %p, attributes %p stub!\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + TRACE("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); + return E_NOTIMPL; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +static inline struct wmv_decoder *impl_from_IMediaObject(IMediaObject *iface) +{ + return CONTAINING_RECORD(iface, struct wmv_decoder, IMediaObject_iface); +} + +static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) +{ + return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); +} + +static ULONG WINAPI media_object_AddRef(IMediaObject *iface) +{ + return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); +} + +static ULONG WINAPI media_object_Release(IMediaObject *iface) +{ + return IUnknown_Release(impl_from_IMediaObject(iface)->outer); +} + +static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) +{ + TRACE("iface %p, input %p, output %p.\n", iface, input, output); + + if (!input || !output) + return E_POINTER; + + *input = *output = 1; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= ARRAY_SIZE(wmv_decoder_input_types)) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *wmv_decoder_input_types[type_index]; + type->bFixedSizeSamples = FALSE; + type->bTemporalCompression = TRUE; + type->lSampleSize = 0; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + VIDEOINFOHEADER *info; + const GUID *subtype; + LONG width, height; + UINT32 image_size; + HRESULT hr; + + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= ARRAY_SIZE(wmv_decoder_output_types)) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + if (!wg_format_is_set(&decoder->input_format)) + return DMO_E_TYPE_NOT_SET; + + width = decoder->input_format.u.video.width; + height = abs(decoder->input_format.u.video.height); + subtype = wmv_decoder_output_types[type_index].subtype; + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) + { + FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); + return hr; + } + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *subtype; + type->bFixedSizeSamples = TRUE; + type->bTemporalCompression = FALSE; + type->lSampleSize = image_size; + type->formattype = FORMAT_VideoInfo; + type->cbFormat = sizeof(VIDEOINFOHEADER); + type->pbFormat = CoTaskMemAlloc(type->cbFormat); + memset(type->pbFormat, 0, type->cbFormat); + + info = (VIDEOINFOHEADER *)type->pbFormat; + info->rcSource.right = width; + info->rcSource.bottom = height; + info->rcTarget.right = width; + info->rcTarget.bottom = height; + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = wmv_decoder_output_types[type_index].bpp; + info->bmiHeader.biCompression = wmv_decoder_output_types[type_index].compression; + info->bmiHeader.biSizeImage = image_size; + + return S_OK; +} + +static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + struct wg_format wg_format; + + TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return DMO_E_TYPE_NOT_ACCEPTED; + } + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + decoder->input_format = wg_format; + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; +} + +static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + struct wg_transform_attrs attrs = {0}; + struct wg_format wg_format; + unsigned int i; + + TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return E_POINTER; + } + + if (!wg_format_is_set(&decoder->input_format)) + return DMO_E_TYPE_NOT_SET; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < ARRAY_SIZE(wmv_decoder_output_types); ++i) + if (IsEqualGUID(&type->subtype, wmv_decoder_output_types[i].subtype)) + break; + if (i == ARRAY_SIZE(wmv_decoder_output_types)) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + return DMO_E_TYPE_NOT_ACCEPTED; + assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO); + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + decoder->output_subtype = type->subtype; + decoder->output_format = wg_format; + + /* Set up wg_transform. */ + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) + return E_FAIL; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, + DWORD *lookahead, DWORD *alignment) +{ + FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, + lookahead, alignment); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!wg_format_is_set(&decoder->output_format)) + return DMO_E_TYPE_NOT_SET; + + if (FAILED(hr = MFCalculateImageSize(&decoder->output_subtype, + decoder->output_format.u.video.width, abs(decoder->output_format.u.video.height), (UINT32 *)size))) + { + FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(&decoder->output_subtype)); + return hr; + } + *alignment = 1; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) +{ + FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) +{ + FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_Flush(IMediaObject *iface) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p.\n", iface); + + if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) + return hr; + + wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); + + return S_OK; +} + +static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) +{ + TRACE("iface %p, index %lu.\n", iface, index); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + return S_OK; +} + +static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) +{ + TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!flags) + return E_POINTER; + + *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; + + return S_OK; +} + +static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, + IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, + index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); +} + +static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, + DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) + hr = wg_transform_read_dmo(decoder->wg_transform, buffers); + + if (SUCCEEDED(hr)) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + return hr; +} + +static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) +{ + FIXME("iface %p, lock %ld stub!\n", iface, lock); + return E_NOTIMPL; +} + +static const IMediaObjectVtbl media_object_vtbl = +{ + media_object_QueryInterface, + media_object_AddRef, + media_object_Release, + media_object_GetStreamCount, + media_object_GetInputStreamInfo, + media_object_GetOutputStreamInfo, + media_object_GetInputType, + media_object_GetOutputType, + media_object_SetInputType, + media_object_SetOutputType, + media_object_GetInputCurrentType, + media_object_GetOutputCurrentType, + media_object_GetInputSizeInfo, + media_object_GetOutputSizeInfo, + media_object_GetInputMaxLatency, + media_object_SetInputMaxLatency, + media_object_Flush, + media_object_Discontinuity, + media_object_AllocateStreamingResources, + media_object_FreeStreamingResources, + media_object_GetInputStatus, + media_object_ProcessInput, + media_object_ProcessOutput, + media_object_Lock, +}; + +static inline struct wmv_decoder *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyBag_iface); +} + +static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); +} + +static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); +} + +static ULONG WINAPI property_bag_Release(IPropertyBag *iface) +{ + return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); +} + +static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, + IErrorLog *error_log) +{ + FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) +{ + FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); + return S_OK; +} + +static const IPropertyBagVtbl property_bag_vtbl = +{ + property_bag_QueryInterface, + property_bag_AddRef, + property_bag_Release, + property_bag_Read, + property_bag_Write, +}; + +static inline struct wmv_decoder *impl_from_IPropertyStore(IPropertyStore *iface) +{ + return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyStore_iface); +} + +static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); +} + +static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); +} + +static ULONG WINAPI property_store_Release(IPropertyStore *iface) +{ + return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); +} + +static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) +{ + FIXME("iface %p, count %p stub!\n", iface, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) +{ + FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const IPropertyStoreVtbl property_store_vtbl = +{ + property_store_QueryInterface, + property_store_AddRef, + property_store_Release, + property_store_GetCount, + property_store_GetAt, + property_store_GetValue, + property_store_SetValue, + property_store_Commit, +}; + +HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) +{ + struct wmv_decoder *decoder; + HRESULT hr; + + TRACE("outer %p, out %p.\n", outer, out); + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + { + free(decoder); + return hr; + } + + decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; + decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; + decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; + decoder->refcount = 1; + decoder->outer = outer ? outer : &decoder->IUnknown_inner; + + *out = &decoder->IUnknown_inner; + TRACE("Created %p\n", *out); + return S_OK; +} From 4dd15b84259e79b5be9c8d8704307905445f99e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:17 +0200 Subject: [PATCH 009/301] Revert "winegstreamer/video_decoder: Support aggregation." This reverts commit 9c7791ddf19a0629b34886d93f6cbb80fec0f148. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 136 +++++++++++------------------ 1 file changed, 52 insertions(+), 84 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 7c708413b65..5afdca931a8 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -50,9 +50,7 @@ static const GUID *const video_decoder_output_types[] = struct video_decoder { - IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; - IUnknown *outer; LONG refcount; IMFAttributes *attributes; @@ -80,79 +78,6 @@ struct video_decoder IMFMediaBuffer *temp_buffer; }; -static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct video_decoder, IUnknown_inner); -} - -static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) -{ - struct video_decoder *decoder = impl_from_IUnknown(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown)) - *out = &decoder->IUnknown_inner; - else if (IsEqualGUID(iid, &IID_IMFTransform)) - *out = &decoder->IMFTransform_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI unknown_AddRef(IUnknown *iface) -{ - struct video_decoder *decoder = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&decoder->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); - - return refcount; -} - -static ULONG WINAPI unknown_Release(IUnknown *iface) -{ - struct video_decoder *decoder = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&decoder->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) - { - IMFTransform_Release(decoder->copier); - IMFVideoSampleAllocatorEx_Release(decoder->allocator); - if (decoder->temp_buffer) - IMFMediaBuffer_Release(decoder->temp_buffer); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - if (decoder->output_attributes) - IMFAttributes_Release(decoder->output_attributes); - if (decoder->attributes) - IMFAttributes_Release(decoder->attributes); - wg_sample_queue_destroy(decoder->wg_sample_queue); - free(decoder); - } - - return refcount; -} - -static const IUnknownVtbl unknown_vtbl = -{ - unknown_QueryInterface, - unknown_AddRef, - unknown_Release, -}; - static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -310,17 +235,62 @@ static void uninit_allocator(struct video_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); + struct video_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; } static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; } static ULONG WINAPI transform_Release(IMFTransform *iface) { - return IUnknown_Release(impl_from_IMFTransform(iface)->outer); + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + IMFTransform_Release(decoder->copier); + IMFVideoSampleAllocatorEx_Release(decoder->allocator); + if (decoder->temp_buffer) + IMFMediaBuffer_Release(decoder->temp_buffer); + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + if (decoder->output_attributes) + IMFAttributes_Release(decoder->output_attributes); + if (decoder->attributes) + IMFAttributes_Release(decoder->attributes); + wg_sample_queue_destroy(decoder->wg_sample_queue); + free(decoder); + } + + return refcount; } static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, @@ -835,7 +805,7 @@ static const IMFTransformVtbl transform_vtbl = }; static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) + const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) { struct video_decoder *decoder; HRESULT hr; @@ -843,10 +813,8 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; - decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; - decoder->outer = outer ? outer : &decoder->IUnknown_inner; decoder->input_type_count = input_type_count; decoder->input_types = input_types; @@ -909,7 +877,7 @@ HRESULT video_decoder_create(REFIID riid, void **out) TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); if (FAILED(hr = video_decoder_create_with_types(video_decoder_input_types, ARRAY_SIZE(video_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) return hr; hr = IMFTransform_QueryInterface(iface, riid, out); @@ -952,7 +920,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) return hr; decoder = impl_from_IMFTransform(iface); @@ -1002,5 +970,5 @@ HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) return E_FAIL; return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), out); } From 7236087172ca5674b6af70f80f9d3e0a77940cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:17 +0200 Subject: [PATCH 010/301] Revert "winegstreamer/video_decoder: Add wg_transform_attrs member." This reverts commit 42ee7e01ab054278e4344dd65e1a7c733a915cc8. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 5afdca931a8..69f3fa4c1a6 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -69,7 +69,6 @@ struct video_decoder IMFMediaType *stream_type; wg_transform_t wg_transform; - struct wg_transform_attrs wg_transform_attrs; struct wg_sample_queue *wg_sample_queue; IMFVideoSampleAllocatorEx *allocator; @@ -90,6 +89,12 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) * transform to be able to queue its input buffers. We need to use a buffer list * to match its expectations. */ + struct wg_transform_attrs attrs = + { + .output_plane_align = 15, + .input_queue_length = 15, + .allow_size_change = TRUE, + }; struct wg_format input_format; struct wg_format output_format; UINT32 low_latency; @@ -107,15 +112,15 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) return MF_E_INVALIDMEDIATYPE; if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) - decoder->wg_transform_attrs.low_latency = !!low_latency; + attrs.low_latency = !!low_latency; { const char *sgi; if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100") || !strcmp(sgi, "2555360") || !strcmp(sgi, "1630110"))) - decoder->wg_transform_attrs.low_latency = FALSE; + attrs.low_latency = FALSE; } - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &decoder->wg_transform_attrs))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; @@ -847,9 +852,6 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) goto failed; - decoder->wg_transform_attrs.output_plane_align = 15; - decoder->wg_transform_attrs.input_queue_length = 15; - *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; @@ -937,8 +939,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; - decoder->wg_transform_attrs.allow_size_change = TRUE; - hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface); return hr; From c40194c7f7d7311c37e7109172613041d393b913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:17 +0200 Subject: [PATCH 011/301] Revert "winegstreamer/video_decoder: Change decoder attributes." This reverts commit 00e288da5e8bedc256d2e9c42ca841dc2a840d3e. CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 4 ++-- dlls/winegstreamer/video_decoder.c | 16 +++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 912ad29eb59..a930e156c12 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3931,9 +3931,9 @@ static void test_h264_decoder(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MF_LOW_LATENCY, 0), - ATTR_UINT32(MF_SA_D3D_AWARE, 1), + ATTR_UINT32(MF_SA_D3D_AWARE, 1, .todo = TRUE), ATTR_UINT32(MF_SA_D3D11_AWARE, 1), - ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0), + ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE), /* more H264 decoder specific attributes from CODECAPI */ ATTR_UINT32(AVDecVideoAcceleration_H264, 1), {0}, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 69f3fa4c1a6..cd49667f9b4 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -830,11 +830,11 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, FALSE)) - || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, TRUE)) - || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)) - || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, - &MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, FALSE))) + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) + goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) + goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) goto failed; { @@ -926,12 +926,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) return hr; decoder = impl_from_IMFTransform(iface); - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) - { - IMFTransform_Release(iface); - return hr; - } - decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->input_info.cbSize = 0x1000; From 112e36685b91c99bcd603a5f8d9188530225acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:17 +0200 Subject: [PATCH 012/301] Revert "winegstreamer/video_decoder: Set input/output infos in h264_decoder_create." This reverts commit e1457a434b2edb2ae21f6a5ab98f2b4c60935765. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index cd49667f9b4..a62caf4b6c4 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -826,6 +826,13 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->output_type_count = output_type_count; decoder->output_types = output_types; + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->input_info.cbSize = 0x1000; + decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->output_info.cbSize = 1920 * 1088 * 2; + if (FAILED(hr = MFCreateMediaType(&decoder->stream_type))) goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) @@ -907,7 +914,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; struct wg_transform_attrs attrs = {0}; - struct video_decoder *decoder; wg_transform_t transform; IMFTransform *iface; HRESULT hr; @@ -924,14 +930,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) return hr; - decoder = impl_from_IMFTransform(iface); - - decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->input_info.cbSize = 0x1000; - decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->output_info.cbSize = 1920 * 1088 * 2; hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface); From d60b527340d56f5a5612e05dce7f92dfe6939274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:17 +0200 Subject: [PATCH 013/301] Revert "winegstreamer: Implement mf_media_type_to_wg_format_video_wmv." This reverts commit dfb00a10a6c43afdb95e9678615d136dbafb0168. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 60 +++++++++++--------------------- dlls/winegstreamer/wmv_decoder.c | 3 +- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 27218569188..0529f0e9021 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -47,7 +47,8 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFAudioFormat_GStreamer,MAKEFOURCC('G','S','T','a')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_GStreamer,MAKEFOURCC('G','S','T','v')); -DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); + +extern GUID MEDIASUBTYPE_VC1S; struct class_factory { @@ -1086,61 +1087,42 @@ static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t format->u.video.version = version; } -static void mf_media_type_to_wg_format_video_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT64 frame_rate, frame_size; - UINT32 codec_data_len; - BYTE *codec_data; - memset(format, 0, sizeof(*format)); format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; + format->u.video.width = 0; + format->u.video.height = 0; + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video.width = frame_size >> 32; + format->u.video.width = (UINT32)(frame_size >> 32); format->u.video.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video.fps_n = frame_rate >> 32; + format->u.video.fps_n = (UINT32)(frame_rate >> 32); format->u.video.fps_d = (UINT32)frame_rate; } - else - { - format->u.video.fps_n = 1; - format->u.video.fps_d = 1; - } - if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV1)) + if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) format->u.video.format = WG_VIDEO_FORMAT_WMV1; - else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV2)) + else if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) format->u.video.format = WG_VIDEO_FORMAT_WMV2; - else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV3)) + else if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) format->u.video.format = WG_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) format->u.video.format = WG_VIDEO_FORMAT_WMVA; - else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WVC1)) + else if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) format->u.video.format = WG_VIDEO_FORMAT_WVC1; else format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; - - if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &codec_data, &codec_data_len))) - { - if (codec_data_len <= sizeof(format->u.video.codec_data)) - { - format->u.video.codec_data_len = codec_data_len; - memcpy(format->u.video.codec_data, codec_data, codec_data_len); - } - else - { - WARN("Codec data buffer too small, codec data size %u.\n", codec_data_len); - } - CoTaskMemFree(codec_data); - } } - static void mf_media_type_to_wg_format_video_encoded(IMFMediaType *type, struct wg_format *format) { UINT64 frame_rate, frame_size; @@ -1214,16 +1196,16 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) mf_media_type_to_wg_format_video_h264(type, format); else if (IsEqualGUID(&subtype, &MFVideoFormat_IV50)) mf_media_type_to_wg_format_video_indeo(type, 5, format); - else if (IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV1) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV2) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) + else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV1) + || IsEqualGUID(&subtype, &MFVideoFormat_WMV2) + || IsEqualGUID(&subtype, &MFVideoFormat_WMV3) || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVP) || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVP2) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV_Unknown) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVC1) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV3) - || IsEqualGUID(&subtype, &MFVideoFormat_VC1S)) - mf_media_type_to_wg_format_video_wmv(type, &subtype, format); + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVR) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) + || IsEqualGUID(&subtype, &MFVideoFormat_WVC1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_VC1S)) + mf_media_type_to_wg_format_wmv(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFVideoFormat_GStreamer)) mf_media_type_to_wg_format_video_encoded(type, format); else diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index f61edbd0164..537956dc924 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -30,7 +30,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); extern const GUID MEDIASUBTYPE_VC1S; -extern const GUID MEDIASUBTYPE_WMV_Unknown; + +DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); struct decoder_type { From 33200eead4923a33e8004383725890150f957ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:18 +0200 Subject: [PATCH 014/301] Revert "winegstreamer: Introduce a new wg_transform_create_quartz helper." This reverts commit 9b1d9e556732cbd6f3e855c890bafb85bc0205dd. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 -- dlls/winegstreamer/main.c | 15 --------------- dlls/winegstreamer/quartz_transform.c | 13 ++++++++++--- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 88804c08a4c..bce9b5d2fe4 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -121,8 +121,6 @@ void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select); wg_transform_t wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format, const struct wg_transform_attrs *attrs); -HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, - const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index f7733fcbcfb..fbd3c9f47ca 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -551,21 +551,6 @@ wg_transform_t wg_transform_create(const struct wg_format *input_format, return params.transform; } -HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_type, const AM_MEDIA_TYPE *output_type, - const struct wg_transform_attrs *attrs, wg_transform_t *transform) -{ - struct wg_format input_format, output_format; - - if (!amt_to_wg_format(input_type, &input_format)) - return E_FAIL; - if (!amt_to_wg_format(output_type, &output_format)) - return E_FAIL; - - if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) - return E_FAIL; - return S_OK; -} - void wg_transform_destroy(wg_transform_t transform) { TRACE("transform %#I64x.\n", transform); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index b85b24f4278..ad0c3077733 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -98,19 +98,26 @@ static HRESULT transform_query_interface(struct strmbase_filter *iface, REFIID i static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); + struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; HRESULT hr; if (filter->source.pin.peer) { + if (!amt_to_wg_format(&filter->sink.pin.mt, &input_format)) + return E_FAIL; + + if (!amt_to_wg_format(&filter->source.pin.mt, &output_format)) + return E_FAIL; + if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr; - if (FAILED(hr = wg_transform_create_quartz(&filter->sink.pin.mt, &filter->source.pin.mt, - &attrs, &filter->transform))) + filter->transform = wg_transform_create(&input_format, &output_format, &attrs); + if (!filter->transform) { wg_sample_queue_destroy(filter->sample_queue); - return hr; + return E_FAIL; } hr = IMemAllocator_Commit(filter->source.pAllocator); From 2af7b5d31dfaa6f9283392ee0adcc8c6a620beee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:18 +0200 Subject: [PATCH 015/301] Revert "winegstreamer: Always set aperture attributes on video decoder output types." This reverts commit 0820c0b51428f80331671100c27bd9e3de3528d5. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 38 +++++++++++++++++------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index a62caf4b6c4..d3f5032cb7c 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -133,9 +133,9 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI IMFMediaType *output_type, IMFMediaType **media_type) { IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; - MFVideoArea default_aperture = {{0}}, aperture; IMFVideoMediaType *video_type; UINT32 value, width, height; + MFVideoArea aperture; UINT64 ratio; HRESULT hr; @@ -149,9 +149,6 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI width = ratio >> 32; height = ratio; - default_aperture.Area.cx = width; - default_aperture.Area.cy = height; - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) @@ -192,20 +189,29 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) goto done; - if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) - aperture = default_aperture; - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) - goto done; + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) + { + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + (BYTE *)&aperture, sizeof(aperture)))) + goto done; + } - if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) - aperture = default_aperture; - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) - goto done; + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) + { + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&aperture, sizeof(aperture)))) + goto done; + } - if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) - aperture = default_aperture; - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) - goto done; + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) + { + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, + (BYTE *)&aperture, sizeof(aperture)))) + goto done; + } IMFMediaType_AddRef((*media_type = (IMFMediaType *)video_type)); done: From 7d94e67399bd3995c897544766ee8f5f8217c701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:18 +0200 Subject: [PATCH 016/301] Revert "winegstreamer: Set other aperture attributes on video media types." This reverts commit 5d9b965dc799e92aa1e4eefc0da026b6a4cc8e4a. CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 10 ---------- dlls/winegstreamer/mfplat.c | 4 ---- dlls/winegstreamer/video_decoder.c | 16 ---------------- 3 files changed, 30 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index a930e156c12..f11f4368cfb 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4089,8 +4089,6 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4105,8 +4103,6 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4121,8 +4117,6 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4137,8 +4131,6 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4153,8 +4145,6 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, }; const MFT_OUTPUT_STREAM_INFO initial_output_info = diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0529f0e9021..8e572d87f9a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -659,10 +659,6 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * IMFMediaType_SetBlob(type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); - IMFMediaType_SetBlob(type, &MF_MT_GEOMETRIC_APERTURE, - (BYTE *)&aperture, sizeof(aperture)); - IMFMediaType_SetBlob(type, &MF_MT_PAN_SCAN_APERTURE, - (BYTE *)&aperture, sizeof(aperture)); } return type; diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index d3f5032cb7c..9374c4d27a1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -197,22 +197,6 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI goto done; } - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } - - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } - IMFMediaType_AddRef((*media_type = (IMFMediaType *)video_type)); done: IMFVideoMediaType_Release(video_type); From b59ef0c49b31294803cd9ac65ef93f93e4dfc9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:18 +0200 Subject: [PATCH 017/301] Revert "winegstreamer: Complete H264 current output type reported attributes." This reverts commit 95035b0ae5be4e35e7afb981216335e4ad428f51. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 882 ----------------------------- dlls/winegstreamer/video_decoder.c | 31 +- 2 files changed, 15 insertions(+), 898 deletions(-) delete mode 100644 dlls/winegstreamer/h264_decoder.c diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c deleted file mode 100644 index fae4ede3b54..00000000000 --- a/dlls/winegstreamer/h264_decoder.c +++ /dev/null @@ -1,882 +0,0 @@ -/* H264 Decoder Transform - * - * Copyright 2022 RĂ©mi Bernon for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "gst_private.h" - -#include "mfapi.h" -#include "mferror.h" -#include "mfobjects.h" -#include "mftransform.h" - -#include "wine/debug.h" - -#include "initguid.h" - -#include "codecapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -WINE_DECLARE_DEBUG_CHANNEL(winediag); - -static const GUID *const video_decoder_output_types[] = -{ - &MFVideoFormat_NV12, - &MFVideoFormat_YV12, - &MFVideoFormat_IYUV, - &MFVideoFormat_I420, - &MFVideoFormat_YUY2, -}; - -struct h264_decoder -{ - IMFTransform IMFTransform_iface; - LONG refcount; - - IMFAttributes *attributes; - IMFAttributes *output_attributes; - - UINT input_type_count; - const GUID *const *input_types; - UINT output_type_count; - const GUID *const *output_types; - - UINT64 sample_time; - IMFMediaType *input_type; - MFT_INPUT_STREAM_INFO input_info; - IMFMediaType *output_type; - MFT_OUTPUT_STREAM_INFO output_info; - IMFMediaType *stream_type; - - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; - - IMFVideoSampleAllocatorEx *allocator; - BOOL allocator_initialized; - IMFTransform *copier; - IMFMediaBuffer *temp_buffer; -}; - -static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -{ - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); -} - -static HRESULT try_create_wg_transform(struct h264_decoder *decoder) -{ - /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput - * return values, it calls them in a specific order and expects the decoder - * transform to be able to queue its input buffers. We need to use a buffer list - * to match its expectations. - */ - struct wg_transform_attrs attrs = - { - .output_plane_align = 15, - .input_queue_length = 15, - .allow_size_change = TRUE, - }; - struct wg_format input_format; - struct wg_format output_format; - UINT32 low_latency; - - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(decoder->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) - attrs.low_latency = !!low_latency; - - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - return E_FAIL; - - return S_OK; -} - -static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, - IMFMediaType *output_type, IMFMediaType **media_type) -{ - IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; - IMFVideoMediaType *video_type; - UINT32 value, width, height; - MFVideoArea aperture; - UINT64 ratio; - HRESULT hr; - - if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) - return hr; - - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_SIZE, &ratio))) - ratio = (UINT64)1920 << 32 | 1080; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) - goto done; - width = ratio >> 32; - height = ratio; - - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_RATE, &ratio))) - ratio = (UINT64)30000 << 32 | 1001; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) - goto done; - - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) - ratio = (UINT64)1 << 32 | 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) - goto done; - - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_SAMPLE_SIZE, &value))) - hr = MFCalculateImageSize(subtype, width, height, &value); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) - goto done; - - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) - hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) - value = MFVideoInterlace_MixedInterlaceOrProgressive; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) - value = 0; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) - goto done; - - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } - -done: - if (SUCCEEDED(hr)) - *media_type = (IMFMediaType *)video_type; - else - { - IMFVideoMediaType_Release(video_type); - *media_type = NULL; - } - - return hr; -} - -static HRESULT init_allocator(struct h264_decoder *decoder) -{ - HRESULT hr; - - if (decoder->allocator_initialized) - return S_OK; - - if (FAILED(hr = IMFTransform_SetInputType(decoder->copier, 0, decoder->output_type, 0))) - return hr; - if (FAILED(hr = IMFTransform_SetOutputType(decoder->copier, 0, decoder->output_type, 0))) - return hr; - - if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10, - decoder->attributes, decoder->output_type))) - return hr; - decoder->allocator_initialized = TRUE; - return S_OK; -} - -static void uninit_allocator(struct h264_decoder *decoder) -{ - IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator); - decoder->allocator_initialized = FALSE; -} - -static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IMFTransform)) - *out = &decoder->IMFTransform_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI transform_AddRef(IMFTransform *iface) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&decoder->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); - - return refcount; -} - -static ULONG WINAPI transform_Release(IMFTransform *iface) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&decoder->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) - { - IMFTransform_Release(decoder->copier); - IMFVideoSampleAllocatorEx_Release(decoder->allocator); - if (decoder->temp_buffer) - IMFMediaBuffer_Release(decoder->temp_buffer); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - if (decoder->output_attributes) - IMFAttributes_Release(decoder->output_attributes); - if (decoder->attributes) - IMFAttributes_Release(decoder->attributes); - wg_sample_queue_destroy(decoder->wg_sample_queue); - free(decoder); - } - - return refcount; -} - -static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, - DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) -{ - TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", - iface, input_minimum, input_maximum, output_minimum, output_maximum); - *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -{ - TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); - *inputs = *outputs = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, - DWORD output_size, DWORD *outputs) -{ - TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, - input_size, inputs, output_size, outputs); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - - *info = decoder->input_info; - return S_OK; -} - -static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - - *info = decoder->output_info; - return S_OK; -} - -static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); - - if (!attributes) - return E_POINTER; - - IMFAttributes_AddRef((*attributes = decoder->attributes)); - return S_OK; -} - -static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes); - - if (!attributes) - return E_POINTER; - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - IMFAttributes_AddRef((*attributes = decoder->output_attributes)); - return S_OK; -} - -static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) -{ - TRACE("iface %p, id %#lx.\n", iface, id); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -{ - TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - - *type = NULL; - if (index >= decoder->input_type_count) - return MF_E_NO_MORE_TYPES; - return MFCreateVideoMediaTypeFromSubtype(decoder->input_types[index], (IMFVideoMediaType **)type); -} - -static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, - DWORD index, IMFMediaType **type) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - - *type = NULL; - if (!decoder->input_type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - if (index >= decoder->output_type_count) - return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, decoder->output_types[index], NULL, type); -} - -static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - GUID major, subtype; - UINT64 frame_size; - HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return E_INVALIDARG; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return MF_E_INVALIDMEDIATYPE; - - for (i = 0; i < decoder->input_type_count; ++i) - if (IsEqualGUID(&subtype, decoder->input_types[i])) - break; - if (i == decoder->input_type_count) - return MF_E_INVALIDMEDIATYPE; - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - - if (decoder->output_type) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - } - - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - IMFMediaType_AddRef((decoder->input_type = type)); - - if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - { - if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) - WARN("Failed to update stream type frame size, hr %#lx\n", hr); - decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; - } - - return S_OK; -} - -static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - UINT64 frame_size, stream_frame_size; - GUID major, subtype; - HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (!decoder->input_type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return hr; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return MF_E_INVALIDMEDIATYPE; - - for (i = 0; i < decoder->output_type_count; ++i) - if (IsEqualGUID(&subtype, decoder->output_types[i])) - break; - if (i == decoder->output_type_count) - return MF_E_INVALIDMEDIATYPE; - - if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - return MF_E_INVALIDMEDIATYPE; - if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &stream_frame_size)) - && frame_size != stream_frame_size) - return MF_E_INVALIDMEDIATYPE; - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - IMFMediaType_AddRef((decoder->output_type = type)); - - if (decoder->wg_transform) - { - struct wg_format output_format; - mf_media_type_to_wg_format(decoder->output_type, &output_format); - - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - return MF_E_INVALIDMEDIATYPE; - } - } - else if (FAILED(hr = try_create_wg_transform(decoder))) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - } - - return hr; -} - -static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - HRESULT hr; - - TRACE("iface %p, id %#lx, type %p\n", iface, id, type); - - if (!decoder->input_type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) - return hr; - - return IMFMediaType_CopyAllItems(decoder->input_type, (IMFAttributes *)*type); -} - -static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - GUID subtype; - HRESULT hr; - - TRACE("iface %p, id %#lx, type %p\n", iface, id, type); - - if (!decoder->output_type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) - return hr; - return create_output_media_type(decoder, &subtype, decoder->output_type, type); -} - -static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *flags = MFT_INPUT_STATUS_ACCEPT_DATA; - return S_OK; -} - -static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) -{ - FIXME("iface %p, flags %p stub!\n", iface, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -{ - TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -{ - FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - HRESULT hr; - - TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); - - switch (message) - { - case MFT_MESSAGE_SET_D3D_MANAGER: - if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param))) - return hr; - - uninit_allocator(decoder); - if (param) - decoder->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; - else - decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; - return S_OK; - - case MFT_MESSAGE_COMMAND_DRAIN: - return wg_transform_drain(decoder->wg_transform); - - case MFT_MESSAGE_COMMAND_FLUSH: - return wg_transform_flush(decoder->wg_transform); - - default: - FIXME("Ignoring message %#x.\n", message); - return S_OK; - } -} - -static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); -} - -static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample) -{ - MFT_OUTPUT_DATA_BUFFER output[1]; - IMFSample *sample; - DWORD status; - HRESULT hr; - - if (FAILED(hr = init_allocator(decoder))) - { - ERR("Failed to initialize allocator, hr %#lx.\n", hr); - return hr; - } - if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample))) - return hr; - - if (FAILED(hr = IMFTransform_ProcessInput(decoder->copier, 0, src_sample, 0))) - { - IMFSample_Release(sample); - return hr; - } - output[0].pSample = sample; - if (FAILED(hr = IMFTransform_ProcessOutput(decoder->copier, 0, 1, output, &status))) - { - IMFSample_Release(sample); - return hr; - } - *out = sample; - return S_OK; -} - -static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format) -{ - UINT64 frame_size, frame_rate; - HRESULT hr; - - if (decoder->stream_type) - IMFMediaType_Release(decoder->stream_type); - if (!(decoder->stream_type = mf_media_type_from_wg_format(format))) - return E_OUTOFMEMORY; - - if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)) - && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate))) - WARN("Failed to update stream type frame size, hr %#lx\n", hr); - - if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size))) - return hr; - decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; - uninit_allocator(decoder); - - return MF_E_TRANSFORM_STREAM_CHANGE; -} - -static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -{ - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - struct wg_format wg_format; - UINT32 sample_size; - LONGLONG duration; - IMFSample *sample; - UINT64 frame_size, frame_rate; - GUID subtype; - DWORD size; - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); - - if (count != 1) - return E_INVALIDARG; - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *status = samples->dwStatus = 0; - if (!(sample = samples->pSample) && !(decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)) - return E_INVALIDARG; - - if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) - return hr; - if (FAILED(hr = IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) - return hr; - if (FAILED(hr = MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, &sample_size))) - return hr; - - if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) - { - if (decoder->temp_buffer) - { - if (FAILED(IMFMediaBuffer_GetMaxLength(decoder->temp_buffer, &size)) || size < sample_size) - { - IMFMediaBuffer_Release(decoder->temp_buffer); - decoder->temp_buffer = NULL; - } - } - if (!decoder->temp_buffer && FAILED(hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer))) - return hr; - if (FAILED(hr = MFCreateSample(&sample))) - return hr; - if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer))) - { - IMFSample_Release(sample); - return hr; - } - } - - if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample, - sample_size, &wg_format, &samples->dwStatus))) - { - wg_sample_queue_flush(decoder->wg_sample_queue, false); - - if (FAILED(IMFMediaType_GetUINT64(decoder->input_type, &MF_MT_FRAME_RATE, &frame_rate))) - frame_rate = (UINT64)30000 << 32 | 1001; - - duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); - if (FAILED(IMFSample_SetSampleTime(sample, decoder->sample_time))) - WARN("Failed to set sample time\n"); - if (FAILED(IMFSample_SetSampleDuration(sample, duration))) - WARN("Failed to set sample duration\n"); - decoder->sample_time += duration; - } - - if (hr == MF_E_TRANSFORM_STREAM_CHANGE) - { - samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - hr = handle_stream_type_change(decoder, &wg_format); - } - - if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) - { - if (hr == S_OK && FAILED(hr = output_sample(decoder, &samples->pSample, sample))) - ERR("Failed to output sample, hr %#lx.\n", hr); - IMFSample_Release(sample); - } - - return hr; -} - -static const IMFTransformVtbl transform_vtbl = -{ - transform_QueryInterface, - transform_AddRef, - transform_Release, - transform_GetStreamLimits, - transform_GetStreamCount, - transform_GetStreamIDs, - transform_GetInputStreamInfo, - transform_GetOutputStreamInfo, - transform_GetAttributes, - transform_GetInputStreamAttributes, - transform_GetOutputStreamAttributes, - transform_DeleteInputStream, - transform_AddInputStreams, - transform_GetInputAvailableType, - transform_GetOutputAvailableType, - transform_SetInputType, - transform_SetOutputType, - transform_GetInputCurrentType, - transform_GetOutputCurrentType, - transform_GetInputStatus, - transform_GetOutputStatus, - transform_SetOutputBounds, - transform_ProcessEvent, - transform_ProcessMessage, - transform_ProcessInput, - transform_ProcessOutput, -}; - -static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) -{ - struct h264_decoder *decoder; - HRESULT hr; - - if (!(decoder = calloc(1, sizeof(*decoder)))) - return E_OUTOFMEMORY; - - decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; - decoder->refcount = 1; - - decoder->input_type_count = input_type_count; - decoder->input_types = input_types; - decoder->output_type_count = output_type_count; - decoder->output_types = output_types; - - decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->input_info.cbSize = 0x1000; - decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->output_info.cbSize = 1920 * 1088 * 2; - - if (FAILED(hr = MFCreateMediaType(&decoder->stream_type))) - goto failed; - if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) - goto failed; - - if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0))) - goto failed; - if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) - goto failed; - if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator))) - goto failed; - if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) - goto failed; - - *ret = &decoder->IMFTransform_iface; - TRACE("Created decoder %p\n", *ret); - return S_OK; - -failed: - if (decoder->allocator) - IMFVideoSampleAllocatorEx_Release(decoder->allocator); - if (decoder->wg_sample_queue) - wg_sample_queue_destroy(decoder->wg_sample_queue); - if (decoder->output_attributes) - IMFAttributes_Release(decoder->output_attributes); - if (decoder->attributes) - IMFAttributes_Release(decoder->attributes); - if (decoder->stream_type) - IMFMediaType_Release(decoder->stream_type); - free(decoder); - return hr; -} - -static const GUID *const h264_decoder_input_types[] = -{ - &MFVideoFormat_H264, - &MFVideoFormat_H264_ES, -}; - -HRESULT h264_decoder_create(REFIID riid, void **out) -{ - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, - }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; - IMFTransform *iface; - HRESULT hr; - - TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - - if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) - return hr; - - hr = IMFTransform_QueryInterface(iface, riid, out); - IMFTransform_Release(iface); - return hr; -} diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 9374c4d27a1..ad48e91df35 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -130,9 +130,9 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) } static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, - IMFMediaType *output_type, IMFMediaType **media_type) + IMFMediaType **media_type) { - IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; + IMFMediaType *default_type = decoder->output_type; IMFVideoMediaType *video_type; UINT32 value, width, height; MFVideoArea aperture; @@ -142,31 +142,31 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) return hr; - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_SIZE, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) ratio = (UINT64)1920 << 32 | 1080; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) goto done; width = ratio >> 32; height = ratio; - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_RATE, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) goto done; - if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) ratio = (UINT64)1 << 32 | 1; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) goto done; - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_SAMPLE_SIZE, &value))) - hr = MFCalculateImageSize(subtype, width, height, &value); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) goto done; - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) - hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) goto done; if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) @@ -189,7 +189,7 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) goto done; - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, @@ -403,7 +403,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR return MF_E_TRANSFORM_TYPE_NOT_SET; if (index >= decoder->output_type_count) return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, decoder->output_types[index], NULL, type); + return create_output_media_type(decoder, decoder->output_types[index], type); } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) @@ -519,7 +519,6 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct video_decoder *decoder = impl_from_IMFTransform(iface); - GUID subtype; HRESULT hr; TRACE("iface %p, id %#lx, type %p\n", iface, id, type); @@ -527,10 +526,10 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + if (FAILED(hr = MFCreateMediaType(type))) return hr; - return create_output_media_type(decoder, &subtype, decoder->output_type, type); + return IMFMediaType_CopyAllItems(decoder->input_type, (IMFAttributes *)*type); } static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) From f78775dd85b03805337fc977e3b9ff5073e133b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:19 +0200 Subject: [PATCH 018/301] Revert "winegstreamer: Merge video_encoded into video field." This reverts commit 65245e99f3a5ed3fe0bf4521899e0b219d193a8b. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 18 +++++++++--------- dlls/winegstreamer/unixlib.h | 7 ++++++- dlls/winegstreamer/wg_format.c | 16 ++++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 8e572d87f9a..b350ac9e6d0 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -718,14 +718,14 @@ static IMFMediaType *mf_media_type_from_wg_format_video_encoded(const struct wg_ if (FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_COMPRESSED, TRUE))) goto done; - frame_size = (UINT64)format->u.video.width << 32 | format->u.video.height; + frame_size = (UINT64)format->u.video_encoded.width << 32 | format->u.video_encoded.height; if (FAILED(hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, frame_size))) goto done; - frame_rate = (UINT64)format->u.video.fps_n << 32 | format->u.video.fps_d; + frame_rate = (UINT64)format->u.video_encoded.fps_n << 32 | format->u.video_encoded.fps_d; if (FAILED(hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_RATE, frame_rate))) goto done; - if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.video.caps, - strlen(format->u.video.caps) + 1))) + if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.video_encoded.caps, + strlen(format->u.video_encoded.caps) + 1))) goto done; done: @@ -1133,23 +1133,23 @@ static void mf_media_type_to_wg_format_video_encoded(IMFMediaType *type, struct WARN("Failed to get MF_MT_FRAME_SIZE for type %p, hr %#lx.\n", type, hr); else { - format->u.video.width = frame_size >> 32; - format->u.video.height = (UINT32)frame_size; + format->u.video_encoded.width = frame_size >> 32; + format->u.video_encoded.height = (UINT32)frame_size; } if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) WARN("Failed to get MF_MT_FRAME_RATE for type %p, hr %#lx.\n", type, hr); else { - format->u.video.fps_n = frame_rate >> 32; - format->u.video.fps_d = (UINT32)frame_rate; + format->u.video_encoded.fps_n = frame_rate >> 32; + format->u.video_encoded.fps_d = (UINT32)frame_rate; } if (FAILED(hr = IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &caps, &caps_len))) WARN("Failed to get MF_MT_USER_DATA for type %p, hr %#lx.\n", type, hr); else { - strcpy(format->u.video.caps, (char *)caps); + strcpy(format->u.video_encoded.caps, (char *)caps); CoTaskMemFree(caps); } } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 7fe6bc284d4..9b53d68d875 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -142,8 +142,13 @@ struct wg_format uint32_t version; uint32_t codec_data_len; unsigned char codec_data[64]; - char caps[512]; } video; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + char caps[512]; + } video_encoded; } u; }; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 5e560c50170..d93dc241d13 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -418,17 +418,17 @@ static void wg_format_from_caps_video_encoded(struct wg_format *format, const Gs gint len; format->major_type = WG_MAJOR_TYPE_VIDEO_ENCODED; - format->u.video.width = info->width; - format->u.video.height = info->height; - format->u.video.fps_n = info->fps_n; - format->u.video.fps_d = info->fps_d; + format->u.video_encoded.width = info->width; + format->u.video_encoded.height = info->height; + format->u.video_encoded.fps_n = info->fps_n; + format->u.video_encoded.fps_d = info->fps_d; str = gst_caps_to_string(caps); len = strlen(str) + 1; - if (len >= ARRAY_SIZE(format->u.video.caps)) - GST_FIXME("wg_format.video.caps buffer is too small, need %u bytes", len); + if (len >= ARRAY_SIZE(format->u.video_encoded.caps)) + GST_FIXME("wg_format.video_encoded.caps buffer is too small, need %u bytes", len); else - memcpy(format->u.video.caps, str, len); + memcpy(format->u.video_encoded.caps, str, len); g_free(str); } @@ -935,7 +935,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_MPEG1: return wg_format_to_caps_video_mpeg1(format); case WG_MAJOR_TYPE_VIDEO_ENCODED: - return gst_caps_from_string(format->u.video.caps); + return gst_caps_from_string(format->u.video_encoded.caps); } assert(0); return NULL; From ba144f6b4c65fb121f161d8386ed13cde2ea4ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:19 +0200 Subject: [PATCH 019/301] Revert "winegstreamer: Merge video_mpeg1 into video field." This reverts commit a980d564d30e2ef56f68a158e435c7c945d91e50. CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 19 +++++++++++-------- dlls/winegstreamer/quartz_transform.c | 2 +- dlls/winegstreamer/unixlib.h | 8 ++++++-- dlls/winegstreamer/wg_format.c | 20 ++++++++++---------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index e7f7e767136..a0fc667299b 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -404,10 +404,13 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) return format->u.video.width * format->u.video.height * 3; case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_WMV: /* Estimated max size of a compressed video frame. * There's no way to no way to know the real upper bound, * so let's just use the decompressed size and hope it works. */ + return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, + format->u.video_mpeg1.width, format->u.video_mpeg1.height); + + case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, format->u.video.width, format->u.video.height); @@ -713,11 +716,11 @@ static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video_mpeg1.fps_d, format->u.video_mpeg1.fps_n)) != -1) video_format->hdr.AvgTimePerFrame = frame_time; video_format->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - video_format->hdr.bmiHeader.biWidth = format->u.video.width; - video_format->hdr.bmiHeader.biHeight = format->u.video.height; + video_format->hdr.bmiHeader.biWidth = format->u.video_mpeg1.width; + video_format->hdr.bmiHeader.biHeight = format->u.video_mpeg1.height; video_format->hdr.bmiHeader.biPlanes = 1; video_format->hdr.bmiHeader.biBitCount = 12; video_format->hdr.bmiHeader.biCompression = mt->subtype.Data1; @@ -1051,10 +1054,10 @@ static bool amt_to_wg_format_video_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form } format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; - format->u.video.width = video_format->hdr.bmiHeader.biWidth; - format->u.video.height = video_format->hdr.bmiHeader.biHeight; - format->u.video.fps_n = 10000000; - format->u.video.fps_d = video_format->hdr.AvgTimePerFrame; + format->u.video_mpeg1.width = video_format->hdr.bmiHeader.biWidth; + format->u.video_mpeg1.height = video_format->hdr.bmiHeader.biHeight; + format->u.video_mpeg1.fps_n = 10000000; + format->u.video_mpeg1.fps_d = video_format->hdr.AvgTimePerFrame; return true; } diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index ad0c3077733..784bf6f9411 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -907,7 +907,7 @@ HRESULT mpeg_video_codec_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_VIDEO_MPEG1, - .u.video = {}, + .u.video_mpeg1 = {}, }; struct wg_transform_attrs attrs = {0}; wg_transform_t transform; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9b53d68d875..a6778fd48e9 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -126,8 +126,7 @@ struct wg_format * CINEPAK: width, height, fps_n, fps_d. * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. - * INDEO: width, height, fps_n, fps_d, version. - * MPEG1: width, height, fps_n, fps_d. */ + * INDEO: width, height, fps_n, fps_d, version. */ struct { wg_video_format format; @@ -144,6 +143,11 @@ struct wg_format unsigned char codec_data[64]; } video; struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + } video_mpeg1; + struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index d93dc241d13..2ebb72973d2 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -405,10 +405,10 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC } format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; - format->u.video.width = width; - format->u.video.height = height; - format->u.video.fps_n = fps_n; - format->u.video.fps_d = fps_d; + format->u.video_mpeg1.width = width; + format->u.video_mpeg1.height = height; + format->u.video_mpeg1.fps_n = fps_n; + format->u.video_mpeg1.fps_d = fps_d; } static void wg_format_from_caps_video_encoded(struct wg_format *format, const GstCaps *caps, @@ -897,12 +897,12 @@ static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format) gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); gst_caps_set_simple(caps, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - if (format->u.video.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); - if (format->u.video.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); - if (format->u.video.fps_d || format->u.video.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + if (format->u.video_mpeg1.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_mpeg1.width, NULL); + if (format->u.video_mpeg1.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_mpeg1.height, NULL); + if (format->u.video_mpeg1.fps_d || format->u.video.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_mpeg1.fps_n, format->u.video_mpeg1.fps_d, NULL); return caps; } From 14aba682c0afbfa3a3187c3d66005d59ad99a461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:19 +0200 Subject: [PATCH 020/301] Revert "winegstreamer: Merge video_indeo into video field." This reverts commit d45d7162caa696a92e2660248f15c5dcd5940387. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 14 +++++++------- dlls/winegstreamer/unixlib.h | 10 +++++++--- dlls/winegstreamer/wg_format.c | 16 ++++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index b350ac9e6d0..0fa0974e40e 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -1065,22 +1065,22 @@ static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video.width = frame_size >> 32; - format->u.video.height = (UINT32)frame_size; + format->u.video_indeo.width = frame_size >> 32; + format->u.video_indeo.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video.fps_n = frame_rate >> 32; - format->u.video.fps_d = (UINT32)frame_rate; + format->u.video_indeo.fps_n = frame_rate >> 32; + format->u.video_indeo.fps_d = (UINT32)frame_rate; } else { - format->u.video.fps_n = 1; - format->u.video.fps_d = 1; + format->u.video_indeo.fps_n = 1; + format->u.video_indeo.fps_d = 1; } - format->u.video.version = version; + format->u.video_indeo.version = version; } static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index a6778fd48e9..dda8cad5751 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -125,8 +125,7 @@ struct wg_format * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. * CINEPAK: width, height, fps_n, fps_d. * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. - * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. - * INDEO: width, height, fps_n, fps_d, version. */ + * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. */ struct { wg_video_format format; @@ -138,11 +137,16 @@ struct wg_format RECT padding; uint32_t profile; uint32_t level; - uint32_t version; uint32_t codec_data_len; unsigned char codec_data[64]; } video; struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + uint32_t version; + } video_indeo; + struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 2ebb72973d2..31274882d61 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -875,14 +875,14 @@ static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-indeo"))) return NULL; - if (format->u.video.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); - if (format->u.video.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); - if (format->u.video.fps_d || format->u.video.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); - if (format->u.video.version) - gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video.version, NULL); + if (format->u.video_indeo.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_indeo.width, NULL); + if (format->u.video_indeo.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_indeo.height, NULL); + if (format->u.video_indeo.fps_d || format->u.video_indeo.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_indeo.fps_n, format->u.video_indeo.fps_d, NULL); + if (format->u.video_indeo.version) + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video_indeo.version, NULL); return caps; } From 7082c1d14d74f1ddb92586b4053ea04d1d2f2102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:19 +0200 Subject: [PATCH 021/301] Revert "winegstreamer: Merge video_wmv into video field." This reverts commit e596a446c76e0f20e57d70c7897733bfe6ab060d. CW-Bug-Id: #20833 --- dlls/winegstreamer/main.c | 9 +++- dlls/winegstreamer/mfplat.c | 28 +++++----- dlls/winegstreamer/quartz_parser.c | 83 ++++++++++++++---------------- dlls/winegstreamer/unixlib.h | 26 +++++++--- dlls/winegstreamer/wg_format.c | 70 ++++++++++++------------- dlls/winegstreamer/wmv_decoder.c | 4 +- 6 files changed, 117 insertions(+), 103 deletions(-) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index fbd3c9f47ca..992f6b3ae98 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -847,7 +847,14 @@ bool wg_video_format_is_rgb(enum wg_video_format format) case WG_VIDEO_FORMAT_RGB16: return true; - default: + case WG_VIDEO_FORMAT_AYUV: + case WG_VIDEO_FORMAT_I420: + case WG_VIDEO_FORMAT_NV12: + case WG_VIDEO_FORMAT_UYVY: + case WG_VIDEO_FORMAT_YUY2: + case WG_VIDEO_FORMAT_YV12: + case WG_VIDEO_FORMAT_YVYU: + case WG_VIDEO_FORMAT_UNKNOWN: break; } diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0fa0974e40e..4619020af71 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -1088,35 +1088,35 @@ static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subty UINT64 frame_rate, frame_size; format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video.width = 0; - format->u.video.height = 0; - format->u.video.fps_n = 1; - format->u.video.fps_d = 1; + format->u.video_wmv.width = 0; + format->u.video_wmv.height = 0; + format->u.video_wmv.fps_n = 1; + format->u.video_wmv.fps_d = 1; if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video.width = (UINT32)(frame_size >> 32); - format->u.video.height = (UINT32)frame_size; + format->u.video_wmv.width = (UINT32)(frame_size >> 32); + format->u.video_wmv.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video.fps_n = (UINT32)(frame_rate >> 32); - format->u.video.fps_d = (UINT32)frame_rate; + format->u.video_wmv.fps_n = (UINT32)(frame_rate >> 32); + format->u.video_wmv.fps_d = (UINT32)frame_rate; } if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) - format->u.video.format = WG_VIDEO_FORMAT_WMV1; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; else if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) - format->u.video.format = WG_VIDEO_FORMAT_WMV2; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV2; else if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) - format->u.video.format = WG_VIDEO_FORMAT_WMV3; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) - format->u.video.format = WG_VIDEO_FORMAT_WMVA; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMVA; else if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) - format->u.video.format = WG_VIDEO_FORMAT_WVC1; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WVC1; else - format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN; } static void mf_media_type_to_wg_format_video_encoded(IMFMediaType *type, struct wg_format *format) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a0fc667299b..00090533661 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -380,8 +380,8 @@ static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */ - default: - FIXME("Cannot guess maximum sample size for video format %d.\n", format); + case WG_VIDEO_FORMAT_UNKNOWN: + FIXME("Cannot guess maximum sample size for unknown video format.\n"); return 0; } @@ -412,7 +412,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, - format->u.video.width, format->u.video.height); + format->u.video_wmv.width, format->u.video_wmv.height); case WG_MAJOR_TYPE_AUDIO: { @@ -501,11 +501,6 @@ static const GUID *wg_video_format_get_mediasubtype(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return &MEDIASUBTYPE_YUY2; case WG_VIDEO_FORMAT_YV12: return &MEDIASUBTYPE_YV12; case WG_VIDEO_FORMAT_YVYU: return &MEDIASUBTYPE_YVYU; - case WG_VIDEO_FORMAT_WMV1: return &MEDIASUBTYPE_WMV1; - case WG_VIDEO_FORMAT_WMV2: return &MEDIASUBTYPE_WMV2; - case WG_VIDEO_FORMAT_WMV3: return &MEDIASUBTYPE_WMV3; - case WG_VIDEO_FORMAT_WMVA: return &MEDIASUBTYPE_WMVA; - case WG_VIDEO_FORMAT_WVC1: return &MEDIASUBTYPE_WVC1; } assert(0); @@ -530,10 +525,10 @@ static DWORD wg_video_format_get_compression(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return mmioFOURCC('Y','U','Y','2'); case WG_VIDEO_FORMAT_YV12: return mmioFOURCC('Y','V','1','2'); case WG_VIDEO_FORMAT_YVYU: return mmioFOURCC('Y','V','Y','U'); - default: - ERR("Cannot get compression for video format %d.", format); - return 0; } + + assert(0); + return 0; } static WORD wg_video_format_get_depth(enum wg_video_format format) @@ -554,10 +549,10 @@ static WORD wg_video_format_get_depth(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return 16; case WG_VIDEO_FORMAT_YV12: return 12; case WG_VIDEO_FORMAT_YVYU: return 16; - default: - ERR("Cannot get depth for video format %d.", format); - return 0; } + + assert(0); + return 0; } static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) @@ -648,29 +643,29 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form uint32_t frame_time; const GUID *subtype; - switch (format->u.video.format) + switch (format->u.video_wmv.format) { - case WG_VIDEO_FORMAT_WMV1: + case WG_WMV_VIDEO_FORMAT_WMV1: subtype = &MEDIASUBTYPE_WMV1; break; - case WG_VIDEO_FORMAT_WMV2: + case WG_WMV_VIDEO_FORMAT_WMV2: subtype = &MEDIASUBTYPE_WMV2; break; - case WG_VIDEO_FORMAT_WMV3: + case WG_WMV_VIDEO_FORMAT_WMV3: subtype = &MEDIASUBTYPE_WMV3; break; - case WG_VIDEO_FORMAT_WMVA: + case WG_WMV_VIDEO_FORMAT_WMVA: subtype = &MEDIASUBTYPE_WMVA; break; - case WG_VIDEO_FORMAT_WVC1: + case WG_WMV_VIDEO_FORMAT_WVC1: subtype = &MEDIASUBTYPE_WVC1; break; default: - WARN("Invalid WMV format %u.\n", format->u.video.format); + WARN("Invalid WMV format %u.\n", format->u.video_wmv.format); return false; } - if (!(video_format = CoTaskMemAlloc(sizeof(*video_format) + format->u.video.codec_data_len))) + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format) + format->u.video_wmv.codec_data_len))) return false; mt->majortype = MEDIATYPE_Video; @@ -679,22 +674,22 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form mt->bTemporalCompression = TRUE; mt->lSampleSize = 0; mt->formattype = FORMAT_VideoInfo; - mt->cbFormat = sizeof(*video_format) + format->u.video.codec_data_len; + mt->cbFormat = sizeof(*video_format) + format->u.video_wmv.codec_data_len; mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height); + SetRect(&video_format->rcSource, 0, 0, format->u.video_wmv.width, format->u.video_wmv.height); video_format->rcTarget = video_format->rcSource; - if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video_wmv.fps_d, format->u.video_wmv.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; - video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + format->u.video.codec_data_len; - video_format->bmiHeader.biWidth = format->u.video.width; - video_format->bmiHeader.biHeight = format->u.video.height; + video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + format->u.video_wmv.codec_data_len; + video_format->bmiHeader.biWidth = format->u.video_wmv.width; + video_format->bmiHeader.biHeight = format->u.video_wmv.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biCompression = mt->subtype.Data1; video_format->bmiHeader.biBitCount = 24; video_format->dwBitRate = 0; - memcpy(video_format+1, format->u.video.codec_data, format->u.video.codec_data_len); + memcpy(video_format+1, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len); return true; } @@ -1010,31 +1005,31 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format } format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video.width = video_format->bmiHeader.biWidth; - format->u.video.height = video_format->bmiHeader.biHeight; - format->u.video.fps_n = 10000000; - format->u.video.fps_d = video_format->AvgTimePerFrame; + format->u.video_wmv.width = video_format->bmiHeader.biWidth; + format->u.video_wmv.height = video_format->bmiHeader.biHeight; + format->u.video_wmv.fps_n = 10000000; + format->u.video_wmv.fps_d = video_format->AvgTimePerFrame; if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)) - format->u.video.format = WG_VIDEO_FORMAT_WMV1; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2)) - format->u.video.format = WG_VIDEO_FORMAT_WMV2; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV2; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV3)) - format->u.video.format = WG_VIDEO_FORMAT_WMV3; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA)) - format->u.video.format = WG_VIDEO_FORMAT_WMVA; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMVA; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WVC1)) - format->u.video.format = WG_VIDEO_FORMAT_WVC1; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WVC1; else - format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN; - format->u.video.codec_data_len = mt->cbFormat - sizeof(VIDEOINFOHEADER); - if (format->u.video.codec_data_len > sizeof(format->u.video.codec_data)) + format->u.video_wmv.codec_data_len = mt->cbFormat - sizeof(VIDEOINFOHEADER); + if (format->u.video_wmv.codec_data_len > sizeof(format->u.video_wmv.codec_data)) { - ERR("Too big codec_data value (%u).\n", format->u.video.codec_data_len); - format->u.video.codec_data_len = 0; + ERR("Too big codec_data value (%u).\n", format->u.video_wmv.codec_data_len); + format->u.video_wmv.codec_data_len = 0; } - memcpy(format->u.video.codec_data, video_format+1, format->u.video.codec_data_len); + memcpy(format->u.video_wmv.codec_data, video_format+1, format->u.video_wmv.codec_data_len); return true; } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index dda8cad5751..ec786cb2794 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -79,12 +79,17 @@ enum wg_video_format WG_VIDEO_FORMAT_YUY2, WG_VIDEO_FORMAT_YV12, WG_VIDEO_FORMAT_YVYU, +}; - WG_VIDEO_FORMAT_WMV1, - WG_VIDEO_FORMAT_WMV2, - WG_VIDEO_FORMAT_WMV3, - WG_VIDEO_FORMAT_WMVA, - WG_VIDEO_FORMAT_WVC1, +typedef UINT32 wg_wmv_video_format; +enum wg_wmv_video_format +{ + WG_WMV_VIDEO_FORMAT_UNKNOWN, + WG_WMV_VIDEO_FORMAT_WMV1, + WG_WMV_VIDEO_FORMAT_WMV2, + WG_WMV_VIDEO_FORMAT_WMV3, + WG_WMV_VIDEO_FORMAT_WMVA, + WG_WMV_VIDEO_FORMAT_WVC1, }; struct wg_format @@ -124,8 +129,7 @@ struct wg_format * * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. * CINEPAK: width, height, fps_n, fps_d. - * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. - * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. */ + * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. */ struct { wg_video_format format; @@ -141,6 +145,14 @@ struct wg_format unsigned char codec_data[64]; } video; struct + { + wg_wmv_video_format format; + int32_t width, height; + uint32_t fps_n, fps_d; + uint32_t codec_data_len; + unsigned char codec_data[64]; + } video_wmv; + struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 31274882d61..4bc7f931f06 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -319,8 +319,8 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap const GstStructure *structure = gst_caps_get_structure(caps, 0); gint width, height, fps_n, fps_d, wmv_version = 0; gchar format_buffer[5] = {'W','M','V','0',0}; + enum wg_wmv_video_format wmv_format; const gchar *wmv_format_str = NULL; - enum wg_video_format video_format; const GValue *codec_data_value; GstBuffer *codec_data; GstMapInfo map; @@ -344,17 +344,17 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap wmv_format_str = format_buffer; } if (!strcmp(wmv_format_str, "WMV1")) - video_format = WG_VIDEO_FORMAT_WMV1; + wmv_format = WG_WMV_VIDEO_FORMAT_WMV1; else if (!strcmp(wmv_format_str, "WMV2")) - video_format = WG_VIDEO_FORMAT_WMV2; + wmv_format = WG_WMV_VIDEO_FORMAT_WMV2; else if (!strcmp(wmv_format_str, "WMV3")) - video_format = WG_VIDEO_FORMAT_WMV3; + wmv_format = WG_WMV_VIDEO_FORMAT_WMV3; else if (!strcmp(wmv_format_str, "WMVA")) - video_format = WG_VIDEO_FORMAT_WMVA; + wmv_format = WG_WMV_VIDEO_FORMAT_WMVA; else if (!strcmp(wmv_format_str, "WVC1")) - video_format = WG_VIDEO_FORMAT_WVC1; + wmv_format = WG_WMV_VIDEO_FORMAT_WVC1; else - video_format = WG_VIDEO_FORMAT_UNKNOWN; + wmv_format = WG_WMV_VIDEO_FORMAT_UNKNOWN; if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) { @@ -363,19 +363,19 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap } format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video.width = width; - format->u.video.height = height; - format->u.video.format = video_format; - format->u.video.fps_n = fps_n; - format->u.video.fps_d = fps_d; + format->u.video_wmv.width = width; + format->u.video_wmv.height = height; + format->u.video_wmv.format = wmv_format; + format->u.video_wmv.fps_n = fps_n; + format->u.video_wmv.fps_d = fps_d; if ((codec_data_value = gst_structure_get_value(structure, "codec_data")) && (codec_data = gst_value_get_buffer(codec_data_value))) { gst_buffer_map(codec_data, &map, GST_MAP_READ); - if (map.size <= sizeof(format->u.video.codec_data)) + if (map.size <= sizeof(format->u.video_wmv.codec_data)) { - format->u.video.codec_data_len = map.size; - memcpy(format->u.video.codec_data, map.data, map.size); + format->u.video_wmv.codec_data_len = map.size; + memcpy(format->u.video_wmv.codec_data, map.data, map.size); } else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); @@ -810,32 +810,32 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-wmv"))) return NULL; - switch (format->u.video.format) + switch (format->u.video_wmv.format) { - case WG_VIDEO_FORMAT_WMV1: + case WG_WMV_VIDEO_FORMAT_WMV1: wmv_format = "WMV1"; wmv_version = 1; break; - case WG_VIDEO_FORMAT_WMV2: + case WG_WMV_VIDEO_FORMAT_WMV2: wmv_format = "WMV2"; wmv_version = 2; break; - case WG_VIDEO_FORMAT_WMV3: + case WG_WMV_VIDEO_FORMAT_WMV3: wmv_format = "WMV3"; wmv_version = 3; break; - case WG_VIDEO_FORMAT_WMVA: + case WG_WMV_VIDEO_FORMAT_WMVA: wmv_format = "WMVA"; wmv_version = 3; break; - case WG_VIDEO_FORMAT_WVC1: + case WG_WMV_VIDEO_FORMAT_WVC1: wmv_format = "WVC1"; wmv_version = 3; break; default: - GST_WARNING("Unknown WMV format %u.", format->u.video.format); + GST_WARNING("Unknown WMV format %u.", format->u.video_wmv.format); /* fallthrough */ - case WG_VIDEO_FORMAT_UNKNOWN: + case WG_WMV_VIDEO_FORMAT_UNKNOWN: wmv_format = NULL; wmv_version = 0; break; @@ -845,22 +845,22 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) gst_caps_set_simple(caps, "format", G_TYPE_STRING, wmv_format, NULL); if (wmv_version) gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, wmv_version, NULL); - if (format->u.video.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); - if (format->u.video.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); - if (format->u.video.fps_d || format->u.video.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + if (format->u.video_wmv.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_wmv.width, NULL); + if (format->u.video_wmv.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_wmv.height, NULL); + if (format->u.video_wmv.fps_d || format->u.video_wmv.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_wmv.fps_n, format->u.video_wmv.fps_d, NULL); - if (format->u.video.codec_data_len) + if (format->u.video_wmv.codec_data_len) { - if (!(buffer = gst_buffer_new_and_alloc(format->u.video.codec_data_len))) + if (!(buffer = gst_buffer_new_and_alloc(format->u.video_wmv.codec_data_len))) { gst_caps_unref(caps); return NULL; } - gst_buffer_fill(buffer, 0, format->u.video.codec_data, format->u.video.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } @@ -980,9 +980,9 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_VIDEO_WMV: /* Do not compare FPS. */ - return a->u.video.format == b->u.video.format - && a->u.video.width == b->u.video.width - && a->u.video.height == b->u.video.height; + return a->u.video_wmv.format == b->u.video_wmv.format + && a->u.video_wmv.width == b->u.video_wmv.width + && a->u.video_wmv.height == b->u.video_wmv.height; } assert(0); diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 537956dc924..edd6c744e94 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -444,8 +444,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde if (!wg_format_is_set(&decoder->input_format)) return DMO_E_TYPE_NOT_SET; - width = decoder->input_format.u.video.width; - height = abs(decoder->input_format.u.video.height); + width = decoder->input_format.u.video_wmv.width; + height = abs(decoder->input_format.u.video_wmv.height); subtype = wmv_decoder_output_types[type_index].subtype; if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) { From cd51014f1be426c5c383f0bfb9240877eeae4953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:20 +0200 Subject: [PATCH 022/301] Revert "winegstreamer: Merge video_h264 into video field." This reverts commit a94d5cec2d5daf96d9e66afa1ae3190f344a416c. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 22 +++++++++++----------- dlls/winegstreamer/unixlib.h | 10 +++++++--- dlls/winegstreamer/wg_format.c | 26 +++++++++++++------------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 4619020af71..68ea3541a83 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -1020,33 +1020,33 @@ static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video.width = frame_size >> 32; - format->u.video.height = (UINT32)frame_size; + format->u.video_h264.width = frame_size >> 32; + format->u.video_h264.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video.fps_n = frame_rate >> 32; - format->u.video.fps_d = (UINT32)frame_rate; + format->u.video_h264.fps_n = frame_rate >> 32; + format->u.video_h264.fps_d = (UINT32)frame_rate; } else { - format->u.video.fps_n = 1; - format->u.video.fps_d = 1; + format->u.video_h264.fps_n = 1; + format->u.video_h264.fps_d = 1; } if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) - format->u.video.profile = profile; + format->u.video_h264.profile = profile; if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) - format->u.video.level = level; + format->u.video_h264.level = level; if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_MPEG_SEQUENCE_HEADER, &codec_data, &codec_data_len))) { - if (codec_data_len <= sizeof(format->u.video.codec_data)) + if (codec_data_len <= sizeof(format->u.video_h264.codec_data)) { - format->u.video.codec_data_len = codec_data_len; - memcpy(format->u.video.codec_data, codec_data, codec_data_len); + format->u.video_h264.codec_data_len = codec_data_len; + memcpy(format->u.video_h264.codec_data, codec_data, codec_data_len); } else { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index ec786cb2794..627f97f8043 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -128,8 +128,7 @@ struct wg_format /* Valid members for different video formats: * * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. - * CINEPAK: width, height, fps_n, fps_d. - * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. */ + * CINEPAK: width, height, fps_n, fps_d. */ struct { wg_video_format format; @@ -139,11 +138,16 @@ struct wg_format int32_t width, height; uint32_t fps_n, fps_d; RECT padding; + } video; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; uint32_t profile; uint32_t level; uint32_t codec_data_len; unsigned char codec_data[64]; - } video; + } video_h264; struct { wg_wmv_video_format format; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 4bc7f931f06..22f07b00661 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -733,20 +733,20 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) return NULL; gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); - if (format->u.video.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); - if (format->u.video.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); - if (format->u.video.fps_n || format->u.video.fps_d) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + if (format->u.video_h264.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_h264.width, NULL); + if (format->u.video_h264.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_h264.height, NULL); + if (format->u.video_h264.fps_n || format->u.video_h264.fps_d) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_h264.fps_n, format->u.video_h264.fps_d, NULL); - switch (format->u.video.profile) + switch (format->u.video_h264.profile) { case eAVEncH264VProfile_Main: profile = "main"; break; case eAVEncH264VProfile_High: profile = "high"; break; case eAVEncH264VProfile_444: profile = "high-4:4:4"; break; default: - GST_FIXME("H264 profile attribute %u not implemented.", format->u.video.profile); + GST_FIXME("H264 profile attribute %u not implemented.", format->u.video_h264.profile); /* fallthrough */ case eAVEncH264VProfile_unknown: profile = "baseline"; @@ -754,7 +754,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) } gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); - switch (format->u.video.level) + switch (format->u.video_h264.level) { case eAVEncH264VLevel1: level = "1"; break; case eAVEncH264VLevel1_1: level = "1.1"; break; @@ -773,7 +773,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) case eAVEncH264VLevel5_1: level = "5.1"; break; case eAVEncH264VLevel5_2: level = "5.2"; break; default: - GST_FIXME("H264 level attribute %u not implemented.", format->u.video.level); + GST_FIXME("H264 level attribute %u not implemented.", format->u.video_h264.level); /* fallthrough */ case 0: level = NULL; @@ -782,9 +782,9 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) if (level) gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); - if (format->u.video.codec_data_len) + if (format->u.video_h264.codec_data_len) { - if (!(buffer = gst_buffer_new_and_alloc(format->u.video.codec_data_len))) + if (!(buffer = gst_buffer_new_and_alloc(format->u.video_h264.codec_data_len))) { gst_caps_unref(caps); return NULL; @@ -792,7 +792,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) GST_BUFFER_PTS(buffer) = 0; GST_BUFFER_DTS(buffer) = 0; - gst_buffer_fill(buffer, 0, format->u.video.codec_data, format->u.video.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.video_h264.codec_data, format->u.video_h264.codec_data_len); gst_caps_set_simple(caps, "streamheader", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } From c68b8ca6cc7429cddb0e6e53fc84eebbb1bfb3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:20 +0200 Subject: [PATCH 023/301] Revert "winegstreamer: Merge video_cinepak into video field." This reverts commit 49c18ece35055c7de6f9c975627b85782c7affda. CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 8 ++++---- dlls/winegstreamer/unixlib.h | 12 +++++++----- dlls/winegstreamer/wg_format.c | 26 +++++++++++++------------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 00090533661..59e47a403e3 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -401,7 +401,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) /* Both ffmpeg's encoder and a Cinepak file seen in the wild report * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, * but as long as every sample fits into our allocator, we're fine. */ - return format->u.video.width * format->u.video.height * 3; + return format->u.video_cinepak.width * format->u.video_cinepak.height * 3; case WG_MAJOR_TYPE_VIDEO_MPEG1: /* Estimated max size of a compressed video frame. @@ -624,11 +624,11 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_ mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video_cinepak.fps_d, format->u.video_cinepak.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - video_format->bmiHeader.biWidth = format->u.video.width; - video_format->bmiHeader.biHeight = format->u.video.height; + video_format->bmiHeader.biWidth = format->u.video_cinepak.width; + video_format->bmiHeader.biHeight = format->u.video_cinepak.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biBitCount = 24; video_format->bmiHeader.biCompression = mt->subtype.Data1; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 627f97f8043..c1fb829da0e 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -125,14 +125,9 @@ struct wg_format char caps[512]; } audio; - /* Valid members for different video formats: - * - * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. - * CINEPAK: width, height, fps_n, fps_d. */ struct { wg_video_format format; - /* Positive height indicates top-down video; negative height * indicates bottom-up video. */ int32_t width, height; @@ -140,6 +135,13 @@ struct wg_format RECT padding; } video; struct + { + uint32_t width; + uint32_t height; + uint32_t fps_n; + uint32_t fps_d; + } video_cinepak; + struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 22f07b00661..0b128fccb69 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -308,10 +308,10 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs } format->major_type = WG_MAJOR_TYPE_VIDEO_CINEPAK; - format->u.video.width = width; - format->u.video.height = height; - format->u.video.fps_n = fps_n; - format->u.video.fps_d = fps_d; + format->u.video_cinepak.width = width; + format->u.video_cinepak.height = height; + format->u.video_cinepak.fps_n = fps_n; + format->u.video_cinepak.fps_d = fps_d; } static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCaps *caps) @@ -666,12 +666,12 @@ static GstCaps *wg_format_to_caps_video_cinepak(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-cinepak"))) return NULL; - if (format->u.video.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); - if (format->u.video.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); - if (format->u.video.fps_d || format->u.video.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + if (format->u.video_cinepak.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_cinepak.width, NULL); + if (format->u.video_cinepak.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_cinepak.height, NULL); + if (format->u.video_cinepak.fps_d || format->u.video_cinepak.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_cinepak.fps_n, format->u.video_cinepak.fps_d, NULL); return caps; } @@ -901,7 +901,7 @@ static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_mpeg1.width, NULL); if (format->u.video_mpeg1.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_mpeg1.height, NULL); - if (format->u.video_mpeg1.fps_d || format->u.video.fps_n) + if (format->u.video_mpeg1.fps_d || format->u.video_cinepak.fps_n) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_mpeg1.fps_n, format->u.video_mpeg1.fps_d, NULL); return caps; } @@ -975,8 +975,8 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_VIDEO_CINEPAK: /* Do not compare FPS. */ - return a->u.video.width == b->u.video.width - && a->u.video.height == b->u.video.height; + return a->u.video_cinepak.width == b->u.video_cinepak.width + && a->u.video_cinepak.height == b->u.video_cinepak.height; case WG_MAJOR_TYPE_VIDEO_WMV: /* Do not compare FPS. */ From 85402121e3047afa26bc1fa85cd90b89b6495187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:20 +0200 Subject: [PATCH 024/301] Revert "winegstreamer: Merge audio_encoded into audio field." This reverts commit 259f2db244a43561665b3871c4ddbcf0c1123686. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 14 +++++++------- dlls/winegstreamer/unixlib.h | 10 +++++++--- dlls/winegstreamer/wg_format.c | 12 ++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 68ea3541a83..45c8dcdbb15 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -682,14 +682,14 @@ static IMFMediaType *mf_media_type_from_wg_format_audio_encoded(const struct wg_ if (FAILED(hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFAudioFormat_GStreamer))) goto done; - value = format->u.audio.rate; + value = format->u.audio_encoded.rate; if (value && FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, value))) goto done; - value = format->u.audio.channels; + value = format->u.audio_encoded.channels; if (value && FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, value))) goto done; - if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.audio.caps, - strlen(format->u.audio.caps) + 1))) + if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.audio_encoded.caps, + strlen(format->u.audio_encoded.caps) + 1))) goto done; done: @@ -867,16 +867,16 @@ static void mf_media_type_to_wg_format_audio_encoded(IMFMediaType *type, struct memset(format, 0, sizeof(*format)); format->major_type = WG_MAJOR_TYPE_AUDIO_ENCODED; - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &format->u.audio.rate))) + if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &format->u.audio_encoded.rate))) WARN("Failed to get MF_MT_AUDIO_SAMPLES_PER_SECOND for type %p, hr %#lx.\n", type, hr); - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &format->u.audio.channels))) + if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &format->u.audio_encoded.channels))) WARN("Failed to get MF_MT_AUDIO_NUM_CHANNELS for type %p, hr %#lx.\n", type, hr); if (FAILED(hr = IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &caps, &caps_len))) WARN("Failed to get MF_MT_USER_DATA for type %p, hr %#lx.\n", type, hr); else { - strcpy(format->u.audio.caps, (char *)caps); + strcpy(format->u.audio_encoded.caps, (char *)caps); CoTaskMemFree(caps); } } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c1fb829da0e..6a945da26ff 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -104,8 +104,7 @@ struct wg_format * MPEG1: channels, rate, layer. * MPEG4: payload_type, codec_data_len, codec_data. * WMA: channels, rate, bitrate, depth, block_align, version, layer, - * payload_type, codec_data_len, codec_data, is_xma. - * ENCODED: channels, rate, caps. */ + * payload_type, codec_data_len, codec_data, is_xma */ struct { wg_audio_format format; @@ -122,8 +121,13 @@ struct wg_format uint32_t codec_data_len; unsigned char codec_data[64]; UINT8 is_xma; - char caps[512]; } audio; + struct + { + uint32_t channels; + uint32_t rate; + char caps[512]; + } audio_encoded; struct { diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 0b128fccb69..46de3ad2e5c 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -274,15 +274,15 @@ static void wg_format_from_caps_audio_encoded(struct wg_format *format, const Gs gint len; format->major_type = WG_MAJOR_TYPE_AUDIO_ENCODED; - format->u.audio.rate = info->rate; - format->u.audio.channels = info->channels; + format->u.audio_encoded.rate = info->rate; + format->u.audio_encoded.channels = info->channels; str = gst_caps_to_string(caps); len = strlen(str) + 1; - if (len >= ARRAY_SIZE(format->u.audio.caps)) - GST_FIXME("wg_format.audio.caps buffer is too small, need %u bytes", len); + if (len >= ARRAY_SIZE(format->u.audio_encoded.caps)) + GST_FIXME("wg_format.audio_encoded.caps buffer is too small, need %u bytes", len); else - memcpy(format->u.audio.caps, str, len); + memcpy(format->u.audio_encoded.caps, str, len); g_free(str); } @@ -921,7 +921,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO_WMA: return wg_format_to_caps_audio_wma(format); case WG_MAJOR_TYPE_AUDIO_ENCODED: - return gst_caps_from_string(format->u.audio.caps); + return gst_caps_from_string(format->u.audio_encoded.caps); case WG_MAJOR_TYPE_VIDEO: return wg_format_to_caps_video(format); case WG_MAJOR_TYPE_VIDEO_CINEPAK: From d23f4064eb419aeea115921fa3f2c361b5879232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:21 +0200 Subject: [PATCH 025/301] Revert "winegstreamer: Merge audio_wma into audio field." This reverts commit f6be597adcd79274027c106f448fa7fe945ea240. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 18 ++++---- dlls/winegstreamer/quartz_parser.c | 68 +++++++++++++++--------------- dlls/winegstreamer/unixlib.h | 19 ++++++--- dlls/winegstreamer/wg_format.c | 54 ++++++++++++------------ dlls/winegstreamer/wma_decoder.c | 18 ++++---- 5 files changed, 91 insertions(+), 86 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 45c8dcdbb15..6ab65f7cc99 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -998,15 +998,15 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID } format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio.version = version; - format->u.audio.bitrate = bytes_per_second * 8; - format->u.audio.rate = rate; - format->u.audio.depth = depth; - format->u.audio.channels = channels; - format->u.audio.block_align = block_align; - format->u.audio.codec_data_len = codec_data_len; - memcpy(format->u.audio.codec_data, codec_data, codec_data_len); - format->u.audio.is_xma = is_xma; + format->u.audio_wma.version = version; + format->u.audio_wma.bitrate = bytes_per_second * 8; + format->u.audio_wma.rate = rate; + format->u.audio_wma.depth = depth; + format->u.audio_wma.channels = channels; + format->u.audio_wma.block_align = block_align; + format->u.audio_wma.codec_data_len = codec_data_len; + memcpy(format->u.audio_wma.codec_data, codec_data, codec_data_len); + format->u.audio_wma.is_xma = is_xma; } static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_format *format) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 59e47a403e3..d53ee7be485 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -292,7 +292,7 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form mt->majortype = MEDIATYPE_Audio; mt->formattype = FORMAT_WaveFormatEx; - switch (format->u.audio.version) + switch (format->u.audio_wma.version) { case 1: subtype = &MEDIASUBTYPE_MSAUDIO1; @@ -303,7 +303,7 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form subtype = &MEDIASUBTYPE_WMAUDIO2; codec_data_len = WMAUDIO2_WFX_EXTRA_BYTES; fmt_tag = WAVE_FORMAT_WMAUDIO2; - if (format->u.audio.is_xma) + if (format->u.audio_wma.is_xma) { subtype = &MEDIASUBTYPE_XMAUDIO2; fmt_tag = 0x0166; @@ -331,21 +331,21 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form mt->subtype = *subtype; mt->bFixedSizeSamples = TRUE; - mt->lSampleSize = format->u.audio.block_align; + mt->lSampleSize = format->u.audio_wma.block_align; mt->cbFormat = size; mt->pbFormat = (BYTE *)wave_format; wave_format->wFormatTag = fmt_tag; - wave_format->nChannels = format->u.audio.channels; - wave_format->nSamplesPerSec = format->u.audio.rate; - wave_format->nAvgBytesPerSec = format->u.audio.bitrate / 8; - wave_format->nBlockAlign = format->u.audio.block_align; - wave_format->wBitsPerSample = format->u.audio.depth; + wave_format->nChannels = format->u.audio_wma.channels; + wave_format->nSamplesPerSec = format->u.audio_wma.rate; + wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8; + wave_format->nBlockAlign = format->u.audio_wma.block_align; + wave_format->wBitsPerSample = format->u.audio_wma.depth; wave_format->cbSize = codec_data_len; - if (format->u.audio.codec_data_len == codec_data_len) - memcpy(wave_format+1, format->u.audio.codec_data, format->u.audio.codec_data_len); + if (format->u.audio_wma.codec_data_len == codec_data_len) + memcpy(wave_format+1, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); else - FIXME("Unexpected codec_data length; got %u, expected %lu\n", format->u.audio.codec_data_len, codec_data_len); + FIXME("Unexpected codec_data length; got %u, expected %lu\n", format->u.audio_wma.codec_data_len, codec_data_len); return true; } @@ -464,7 +464,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) /* Estimated max size of a compressed audio frame. * There's no way to no way to know the real upper bound, * so let's just use one second of decompressed size and hope it works. */ - return format->u.audio.rate * format->u.audio.channels * format->u.audio.depth / 8; + return format->u.audio_wma.rate * format->u.audio_wma.channels * format->u.audio_wma.depth / 8; case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_ENCODED: @@ -896,34 +896,34 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format } if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) - format->u.audio.version = 1; + format->u.audio_wma.version = 1; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) - format->u.audio.version = 2; + format->u.audio_wma.version = 2; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) - format->u.audio.version = 3; + format->u.audio_wma.version = 3; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) - format->u.audio.version = 4; + format->u.audio_wma.version = 4; else assert(false); format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio.is_xma = is_xma; - format->u.audio.bitrate = audio_format->nAvgBytesPerSec * 8; - format->u.audio.rate = audio_format->nSamplesPerSec; - format->u.audio.depth = audio_format->wBitsPerSample; - format->u.audio.channels = audio_format->nChannels; - format->u.audio.block_align = audio_format->nBlockAlign; - - format->u.audio.codec_data_len = 0; - if (format->u.audio.version == 1) - format->u.audio.codec_data_len = 4; - if (format->u.audio.version == 2) - format->u.audio.codec_data_len = 10; - if (format->u.audio.version == 3) - format->u.audio.codec_data_len = 18; - if (format->u.audio.version == 4) - format->u.audio.codec_data_len = 18; - if (mt->cbFormat >= sizeof(WAVEFORMATEX) + format->u.audio.codec_data_len) - memcpy(format->u.audio.codec_data, audio_format+1, format->u.audio.codec_data_len); + format->u.audio_wma.is_xma = is_xma; + format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; + format->u.audio_wma.rate = audio_format->nSamplesPerSec; + format->u.audio_wma.depth = audio_format->wBitsPerSample; + format->u.audio_wma.channels = audio_format->nChannels; + format->u.audio_wma.block_align = audio_format->nBlockAlign; + + format->u.audio_wma.codec_data_len = 0; + if (format->u.audio_wma.version == 1) + format->u.audio_wma.codec_data_len = 4; + if (format->u.audio_wma.version == 2) + format->u.audio_wma.codec_data_len = 10; + if (format->u.audio_wma.version == 3) + format->u.audio_wma.codec_data_len = 18; + if (format->u.audio_wma.version == 4) + format->u.audio_wma.codec_data_len = 18; + if (mt->cbFormat >= sizeof(WAVEFORMATEX) + format->u.audio_wma.codec_data_len) + memcpy(format->u.audio_wma.codec_data, audio_format+1, format->u.audio_wma.codec_data_len); else FIXME("Too small format block, can't copy codec data\n"); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 6a945da26ff..d97f795a670 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -102,9 +102,7 @@ struct wg_format * * Uncompressed(PCM): channels, channel_mask, rate. * MPEG1: channels, rate, layer. - * MPEG4: payload_type, codec_data_len, codec_data. - * WMA: channels, rate, bitrate, depth, block_align, version, layer, - * payload_type, codec_data_len, codec_data, is_xma */ + * MPEG4: payload_type, codec_data_len, codec_data. */ struct { wg_audio_format format; @@ -112,16 +110,23 @@ struct wg_format uint32_t channels; uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; + uint32_t layer; + uint32_t payload_type; + uint32_t codec_data_len; + unsigned char codec_data[64]; + } audio; + struct + { + uint32_t version; uint32_t bitrate; + uint32_t rate; uint32_t depth; + uint32_t channels; uint32_t block_align; - uint32_t version; - uint32_t layer; - uint32_t payload_type; uint32_t codec_data_len; unsigned char codec_data[64]; UINT8 is_xma; - } audio; + } audio_wma; struct { uint32_t channels; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 46de3ad2e5c..4deb30cb39e 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -249,18 +249,18 @@ static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCap } format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio.version = version; - format->u.audio.bitrate = bitrate; - format->u.audio.rate = rate; - format->u.audio.depth = depth; - format->u.audio.channels = channels; - format->u.audio.block_align = block_align; + format->u.audio_wma.version = version; + format->u.audio_wma.bitrate = bitrate; + format->u.audio_wma.rate = rate; + format->u.audio_wma.depth = depth; + format->u.audio_wma.channels = channels; + format->u.audio_wma.block_align = block_align; gst_buffer_map(codec_data, &map, GST_MAP_READ); - if (map.size <= sizeof(format->u.audio.codec_data)) + if (map.size <= sizeof(format->u.audio_wma.codec_data)) { - format->u.audio.codec_data_len = map.size; - memcpy(format->u.audio.codec_data, map.data, map.size); + format->u.audio_wma.codec_data_len = map.size; + memcpy(format->u.audio_wma.codec_data, map.data, map.size); } else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); @@ -681,41 +681,41 @@ static GstCaps *wg_format_to_caps_audio_wma(const struct wg_format *format) GstBuffer *buffer; GstCaps *caps; - if (format->u.audio.is_xma) + if (format->u.audio_wma.is_xma) { if (!(caps = gst_caps_new_empty_simple("audio/x-xma"))) return NULL; - if (format->u.audio.version) - gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.audio.version, NULL); + if (format->u.audio_wma.version) + gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); } else { if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) return NULL; - if (format->u.audio.version) - gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); + if (format->u.audio_wma.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); } - if (format->u.audio.bitrate) - gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio.bitrate, NULL); - if (format->u.audio.rate) - gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio.rate, NULL); - if (format->u.audio.depth) - gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.audio.depth, NULL); - if (format->u.audio.channels) - gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio.channels, NULL); - if (format->u.audio.block_align) - gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.audio.block_align, NULL); + if (format->u.audio_wma.bitrate) + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio_wma.bitrate, NULL); + if (format->u.audio_wma.rate) + gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio_wma.rate, NULL); + if (format->u.audio_wma.depth) + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.audio_wma.depth, NULL); + if (format->u.audio_wma.channels) + gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio_wma.channels, NULL); + if (format->u.audio_wma.block_align) + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.audio_wma.block_align, NULL); - if (format->u.audio.codec_data_len) + if (format->u.audio_wma.codec_data_len) { - if (!(buffer = gst_buffer_new_and_alloc(format->u.audio.codec_data_len))) + if (!(buffer = gst_buffer_new_and_alloc(format->u.audio_wma.codec_data_len))) { gst_caps_unref(caps); return NULL; } - gst_buffer_fill(buffer, 0, format->u.audio.codec_data, format->u.audio.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 34b2bba9ebe..a4380d3a3b5 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -319,19 +319,19 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, - decoder->input_format.u.audio.channels))) + decoder->input_format.u.audio_wma.channels))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, - decoder->input_format.u.audio.rate))) + decoder->input_format.u.audio_wma.rate))) goto done; - block_alignment = sample_size * decoder->input_format.u.audio.channels / 8; + block_alignment = sample_size * decoder->input_format.u.audio_wma.channels / 8; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, - decoder->input_format.u.audio.rate * block_alignment))) + decoder->input_format.u.audio_wma.rate * block_alignment))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) @@ -448,7 +448,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - decoder->input_format.u.audio.depth = sample_size; + decoder->input_format.u.audio_wma.depth = sample_size; mf_media_type_to_wg_format(type, &decoder->output_format); decoder->output_buf_size = 1024 * block_alignment * channel_count; @@ -695,13 +695,13 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde memset(type->pbFormat, 0, type->cbFormat); wfx = (WAVEFORMATEX *)type->pbFormat; - if (decoder->input_format.u.audio.depth == 32) + if (decoder->input_format.u.audio_wma.depth == 32) wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; else wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = decoder->input_format.u.audio.channels; - wfx->nSamplesPerSec = decoder->input_format.u.audio.rate; - wfx->wBitsPerSample = decoder->input_format.u.audio.depth; + wfx->nChannels = decoder->input_format.u.audio_wma.channels; + wfx->nSamplesPerSec = decoder->input_format.u.audio_wma.rate; + wfx->wBitsPerSample = decoder->input_format.u.audio_wma.depth; wfx->nAvgBytesPerSec = wfx->nChannels * wfx->nSamplesPerSec * wfx->wBitsPerSample / 8; wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; From 760d7888cdb81e2ceeed8471fb182d73522fb7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:21 +0200 Subject: [PATCH 026/301] Revert "winegstreamer: Merge audio_mpeg4 into audio field." This reverts commit 55cf44d312cb3c2584fed22c6b2be16a851cb6eb. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 12 ++++++------ dlls/winegstreamer/unixlib.h | 8 +++++--- dlls/winegstreamer/wg_format.c | 8 ++++---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 6ab65f7cc99..0c2e37abe8a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -840,22 +840,22 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUI raw_aac = IsEqualGUID(subtype, &MFAudioFormat_RAW_AAC); if (!raw_aac) codec_data_size -= min(codec_data_size, sizeof(HEAACWAVEINFO) - sizeof(WAVEFORMATEX)); - if (codec_data_size > sizeof(format->u.audio.codec_data)) + if (codec_data_size > sizeof(format->u.audio_mpeg4.codec_data)) { FIXME("Codec data needs %u bytes.\n", codec_data_size); return; } if (raw_aac) - memcpy(format->u.audio.codec_data, (BYTE *)(&wfx->wfInfo.wfx + 1), codec_data_size); + memcpy(format->u.audio_mpeg4.codec_data, (BYTE *)(&wfx->wfInfo.wfx + 1), codec_data_size); else - memcpy(format->u.audio.codec_data, wfx->pbAudioSpecificConfig, codec_data_size); + memcpy(format->u.audio_mpeg4.codec_data, wfx->pbAudioSpecificConfig, codec_data_size); format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG4; - if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio.payload_type))) - format->u.audio.payload_type = 0; + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio_mpeg4.payload_type))) + format->u.audio_mpeg4.payload_type = 0; - format->u.audio.codec_data_len = codec_data_size; + format->u.audio_mpeg4.codec_data_len = codec_data_size; } static void mf_media_type_to_wg_format_audio_encoded(IMFMediaType *type, struct wg_format *format) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index d97f795a670..98612cfc355 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -101,8 +101,7 @@ struct wg_format /* Valid members for different audio formats: * * Uncompressed(PCM): channels, channel_mask, rate. - * MPEG1: channels, rate, layer. - * MPEG4: payload_type, codec_data_len, codec_data. */ + * MPEG1: channels, rate, layer. */ struct { wg_audio_format format; @@ -111,10 +110,13 @@ struct wg_format uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; uint32_t layer; + } audio; + struct + { uint32_t payload_type; uint32_t codec_data_len; unsigned char codec_data[64]; - } audio; + } audio_mpeg4; struct { uint32_t version; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 4deb30cb39e..1c1437de7ff 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -566,7 +566,7 @@ static GstCaps *wg_format_to_caps_audio_mpeg4(const struct wg_format *format) gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); - switch (format->u.audio.payload_type) + switch (format->u.audio_mpeg4.payload_type) { case 0: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); break; case 1: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); break; @@ -576,10 +576,10 @@ static GstCaps *wg_format_to_caps_audio_mpeg4(const struct wg_format *format) /* FIXME: Use gst_codec_utils_aac_caps_set_level_and_profile from GStreamer pbutils library */ - if (format->u.audio.codec_data_len) + if (format->u.audio_mpeg4.codec_data_len) { - buffer = gst_buffer_new_and_alloc(format->u.audio.codec_data_len); - gst_buffer_fill(buffer, 0, format->u.audio.codec_data, format->u.audio.codec_data_len); + buffer = gst_buffer_new_and_alloc(format->u.audio_mpeg4.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.audio_mpeg4.codec_data, format->u.audio_mpeg4.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } From 9054fb090ee5e64d200067361b56206c87f31103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:55:21 +0200 Subject: [PATCH 027/301] Revert "winegstreamer: Merge audio_mpeg1 into audio field." This reverts commit 1c35b6cd95b3768888b95ee2c2ebd5cacb8daeaa. CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 26 +++++++++++++------------- dlls/winegstreamer/quartz_transform.c | 4 ++-- dlls/winegstreamer/unixlib.h | 11 ++++++----- dlls/winegstreamer/wg_format.c | 12 ++++++------ 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index d53ee7be485..c386c671520 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -231,7 +231,7 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->majortype = MEDIATYPE_Audio; mt->formattype = FORMAT_WaveFormatEx; - switch (format->u.audio.layer) + switch (format->u.audio_mpeg1.layer) { case 1: case 2: @@ -246,10 +246,10 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->cbFormat = sizeof(*wave_format); mt->pbFormat = (BYTE *)wave_format; wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEG; - wave_format->wfx.nChannels = format->u.audio.channels; - wave_format->wfx.nSamplesPerSec = format->u.audio.rate; + wave_format->wfx.nChannels = format->u.audio_mpeg1.channels; + wave_format->wfx.nSamplesPerSec = format->u.audio_mpeg1.rate; wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX); - wave_format->fwHeadLayer = format->u.audio.layer; + wave_format->fwHeadLayer = format->u.audio_mpeg1.layer; return true; } @@ -265,8 +265,8 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->cbFormat = sizeof(*wave_format); mt->pbFormat = (BYTE *)wave_format; wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; - wave_format->wfx.nChannels = format->u.audio.channels; - wave_format->wfx.nSamplesPerSec = format->u.audio.rate; + wave_format->wfx.nChannels = format->u.audio_mpeg1.channels; + wave_format->wfx.nSamplesPerSec = format->u.audio_mpeg1.rate; wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX); /* FIXME: We can't get most of the MPEG data from the caps. We may have * to manually parse the header. */ @@ -447,7 +447,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) } case WG_MAJOR_TYPE_AUDIO_MPEG1: - switch (format->u.audio.layer) + switch (format->u.audio_mpeg1.layer) { case 1: return 56000; @@ -851,9 +851,9 @@ static bool amt_to_wg_format_audio_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio.channels = audio_format->wfx.nChannels; - format->u.audio.rate = audio_format->wfx.nSamplesPerSec; - format->u.audio.layer = audio_format->fwHeadLayer; + format->u.audio_mpeg1.channels = audio_format->wfx.nChannels; + format->u.audio_mpeg1.rate = audio_format->wfx.nSamplesPerSec; + format->u.audio_mpeg1.layer = audio_format->fwHeadLayer; return true; } @@ -873,9 +873,9 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio.channels = audio_format->wfx.nChannels; - format->u.audio.rate = audio_format->wfx.nSamplesPerSec; - format->u.audio.layer = 3; + format->u.audio_mpeg1.channels = audio_format->wfx.nChannels; + format->u.audio_mpeg1.rate = audio_format->wfx.nSamplesPerSec; + format->u.audio_mpeg1.layer = 3; return true; } diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 784bf6f9411..5189c0b22d3 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -758,7 +758,7 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio = + .u.audio_mpeg1 = { .layer = 2, .channels = 1, @@ -1036,7 +1036,7 @@ HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio = + .u.audio_mpeg1 = { .layer = 3, .channels = 1, diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 98612cfc355..fe21a24f6f5 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -98,10 +98,6 @@ struct wg_format union { - /* Valid members for different audio formats: - * - * Uncompressed(PCM): channels, channel_mask, rate. - * MPEG1: channels, rate, layer. */ struct { wg_audio_format format; @@ -109,9 +105,14 @@ struct wg_format uint32_t channels; uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; - uint32_t layer; } audio; struct + { + uint32_t layer; + uint32_t rate; + uint32_t channels; + } audio_mpeg1; + struct { uint32_t payload_type; uint32_t codec_data_len; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 1c1437de7ff..7cf93830d11 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -198,9 +198,9 @@ static void wg_format_from_caps_audio_mpeg1(struct wg_format *format, const GstC } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio.layer = layer; - format->u.audio.channels = channels; - format->u.audio.rate = rate; + format->u.audio_mpeg1.layer = layer; + format->u.audio_mpeg1.channels = channels; + format->u.audio_mpeg1.rate = rate; } static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCaps *caps) @@ -548,9 +548,9 @@ static GstCaps *wg_format_to_caps_audio_mpeg1(const struct wg_format *format) return NULL; gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); - gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->u.audio.layer, NULL); - gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio.rate, NULL); - gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio.channels, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->u.audio_mpeg1.layer, NULL); + gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio_mpeg1.rate, NULL); + gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio_mpeg1.channels, NULL); gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); return caps; From 5f7260242d77382344d0059c5c025571f56e20e3 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 9 Dec 2023 12:02:06 +0100 Subject: [PATCH 028/301] mf: Avoid implicit enum to int pointer casts. (cherry picked from commit b4fa0147e3ba8f91052909c71605d8b5f235bc52) CW-Bug-Id: #20833 --- dlls/mf/topology_loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index a56fb3e3909..ad442a10cba 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -389,8 +389,8 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME { IMFMediaTypeHandler *down_handler; IMFMediaType *down_type = NULL; - MF_CONNECT_METHOD method; MF_TOPOLOGY_TYPE type; + UINT32 method; DWORD flags; HRESULT hr; @@ -468,7 +468,7 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types) { - MF_CONNECT_METHOD method; + UINT32 method; HRESULT hr; TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch)); From 641608044c6a56cf4bcacff5fa9bcfa479138705 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 9 Dec 2023 12:14:21 +0100 Subject: [PATCH 029/301] mfplat: Avoid implicit cast in IMFAttributes_GetUINT32 call. (cherry picked from commit e935c242c3c7ef0b274e54d376fa52de93d32396) CW-Bug-Id: #20833 --- dlls/mfplat/sample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 8e489d22acd..4b9151b56b2 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -1488,7 +1488,7 @@ static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, u unsigned int i, value; GUID major, subtype; UINT64 frame_size; - D3D11_USAGE usage; + UINT32 usage; HRESULT hr; if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major))) From b2f6c62fdded54a22c49c22ad89df1c6e666f56a Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 9 Dec 2023 12:21:34 +0100 Subject: [PATCH 030/301] mfplat/tests: Use MF_ATTRIBUTE_TYPE type in IMFMediaType_GetItemType call. (cherry picked from commit 2e89cb4040bf38d05c76b4770f5e8cf23e1f4118) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index f785df89b32..e9a537bfcb3 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -5075,7 +5075,8 @@ static void test_attributes_serialization(void) static void test_wrapped_media_type(void) { IMFMediaType *mediatype, *mediatype2; - UINT32 count, type; + MF_ATTRIBUTE_TYPE type; + UINT32 count; HRESULT hr; GUID guid; From 034985a4711c3f503af7ea04fac65da46409e182 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 9 Dec 2023 12:19:42 +0100 Subject: [PATCH 031/301] mfplat: Introduce media_type_get_uint32 helper. (cherry picked from commit b8326ad4de6016a77ad0f65c7d59e8c145d22f50) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 45 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index a159ae4b56f..86474eacdb3 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3223,12 +3223,18 @@ HRESULT WINAPI MFCreateAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID return hr; } +static UINT32 media_type_get_uint32(IMFMediaType *media_type, REFGUID guid) +{ + UINT32 value; + return SUCCEEDED(IMFMediaType_GetUINT32(media_type, guid, &value)) ? value : 0; +} + /*********************************************************************** * MFCreateMFVideoFormatFromMFMediaType (mfplat.@) */ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size) { - UINT32 flags, palette_size = 0, value; + UINT32 palette_size = 0; MFVIDEOFORMAT *format; INT32 stride; GUID guid; @@ -3260,40 +3266,35 @@ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MF media_type_get_ratio(media_type, &MF_MT_FRAME_RATE, &format->videoInfo.FramesPerSecond.Numerator, &format->videoInfo.FramesPerSecond.Denominator); - IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &format->videoInfo.SourceChromaSubsampling); - IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &format->videoInfo.InterlaceMode); - IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &format->videoInfo.TransferFunction); - IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &format->videoInfo.ColorPrimaries); - IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &format->videoInfo.TransferMatrix); - IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &format->videoInfo.SourceLighting); - IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &format->videoInfo.NominalRange); + format->videoInfo.SourceChromaSubsampling = media_type_get_uint32(media_type, &MF_MT_VIDEO_CHROMA_SITING); + format->videoInfo.InterlaceMode = media_type_get_uint32(media_type, &MF_MT_INTERLACE_MODE); + format->videoInfo.TransferFunction = media_type_get_uint32(media_type, &MF_MT_TRANSFER_FUNCTION); + format->videoInfo.ColorPrimaries = media_type_get_uint32(media_type, &MF_MT_VIDEO_PRIMARIES); + format->videoInfo.TransferMatrix = media_type_get_uint32(media_type, &MF_MT_YUV_MATRIX); + format->videoInfo.SourceLighting = media_type_get_uint32(media_type, &MF_MT_VIDEO_LIGHTING); + format->videoInfo.NominalRange = media_type_get_uint32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE); IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&format->videoInfo.GeometricAperture, sizeof(format->videoInfo.GeometricAperture), NULL); IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 *)&format->videoInfo.MinimumDisplayAperture, sizeof(format->videoInfo.MinimumDisplayAperture), NULL); /* Video flags. */ - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_PAD_CONTROL_FLAGS, &flags))) - format->videoInfo.VideoFlags |= flags; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SOURCE_CONTENT_HINT, &flags))) - format->videoInfo.VideoFlags |= flags; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_DRM_FLAGS, &flags))) - format->videoInfo.VideoFlags |= flags; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &flags)) && !!flags) + format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_PAD_CONTROL_FLAGS); + format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_SOURCE_CONTENT_HINT); + format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_DRM_FLAGS); + if (media_type_get_uint32(media_type, &MF_MT_PAN_SCAN_ENABLED)) { format->videoInfo.VideoFlags |= MFVideoFlag_PanScanEnabled; IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (UINT8 *)&format->videoInfo.PanScanAperture, sizeof(format->videoInfo.PanScanAperture), NULL); } - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride)) && stride < 0) + stride = media_type_get_uint32(media_type, &MF_MT_DEFAULT_STRIDE); + if (stride < 0) format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value))) - format->compressedInfo.AvgBitrate = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value))) - format->compressedInfo.AvgBitErrorRate = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value))) - format->compressedInfo.MaxKeyFrameSpacing = value; + format->compressedInfo.AvgBitrate = media_type_get_uint32(media_type, &MF_MT_AVG_BITRATE); + format->compressedInfo.AvgBitErrorRate = media_type_get_uint32(media_type, &MF_MT_AVG_BIT_ERROR_RATE); + format->compressedInfo.MaxKeyFrameSpacing = media_type_get_uint32(media_type, &MF_MT_MAX_KEYFRAME_SPACING); /* Palette. */ if (palette_size) From 44f2f43f0ede84daea4df5483bcd7b7623702271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 12:27:14 +0100 Subject: [PATCH 032/301] mfplat/tests: Test each VIDEOINFOHEADER field conversion separately. (cherry picked from commit 2692cd8b049928458030929123929578722fb49b) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 200 ++++++++++++++++++++++++++++--------- 1 file changed, 154 insertions(+), 46 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index e9a537bfcb3..c985d5b8a0f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -9853,15 +9853,8 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - vih.bmiHeader.biSize = sizeof(vih.bmiHeader); - vih.bmiHeader.biPlanes = 1; - vih.bmiHeader.biWidth = 16; - vih.bmiHeader.biHeight = 32; - vih.bmiHeader.biBitCount = 32; - hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected guid %s.\n", debugstr_guid(&guid)); @@ -9869,22 +9862,20 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&guid, &GUID_NULL), "Unexpected guid %s.\n", debugstr_guid(&guid)); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); - hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value64 == ((UINT64)1 << 32 | 1), "Unexpected value %#I64x.\n", value64); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value32 == MFVideoInterlace_Progressive, "Unexpected value %#x.\n", value32); - - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + + vih.bmiHeader.biWidth = 16; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); vih.bmiHeader.biHeight = -32; @@ -9893,20 +9884,12 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); vih.bmiHeader.biHeight = 32; - hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) goto failed; - - hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected guid %s.\n", debugstr_guid(&guid)); - hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine - ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "Unexpected guid %s.\n", debugstr_guid(&guid)); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); @@ -9916,31 +9899,156 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value32 == MFVideoInterlace_Progressive, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.bmiHeader.biSizeImage = 12345; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value32 == 2048, "Unexpected value %u.\n", value32); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value32 == -64, "Unexpected value %d.\n", value32); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + todo_wine + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwBitRate = 678910; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!value32, "Unexpected value %#x.\n", value32); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!value32, "Unexpected value %#x.\n", value32); + todo_wine + ok(value32 == 678910, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - /* Negative height. */ - vih.bmiHeader.biHeight = -32; - hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); + value32 = 0xdeadbeef; + vih.dwBitErrorRate = 11121314; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value32 == 64, "Unexpected value %d.\n", value32); - hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(value32 == 11121314, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value64 = 0xdeadbeef; + vih.AvgTimePerFrame = 1151617; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == ((UINT64)10000000 << 32 | 1151617), "Unexpected value %#I64x.\n", value64); + + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &MFVideoFormat_NV12); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + + + /* biBitCount is used for implicit RGB format if GUID is NULL */ + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); + todo_wine + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + for (vih.bmiHeader.biBitCount = 1; vih.bmiHeader.biBitCount <= 32; vih.bmiHeader.biBitCount++) + { + winetest_push_context("%u", vih.bmiHeader.biBitCount); + + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); + if (vih.bmiHeader.biBitCount != 1 && vih.bmiHeader.biBitCount != 4 && vih.bmiHeader.biBitCount != 8 + && vih.bmiHeader.biBitCount != 16 && vih.bmiHeader.biBitCount != 24 && vih.bmiHeader.biBitCount != 32) + todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + else + { + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount == 32) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 24) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB24), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 16) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB555), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 8) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB8), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 4) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB4), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 1) + todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB1), "Unexpected guid %s.\n", debugstr_guid(&guid)); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount > 1) + todo_wine + ok(value32 == 16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); + else + todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); + + hr = IMFMediaType_GetItem(media_type, &MF_MT_PALETTE, NULL); + if (vih.bmiHeader.biBitCount > 1) + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + else + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "Unexpected value %#x.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "Unexpected value %#x.\n", value32); + + value32 = 0xdeadbeef; + vih.bmiHeader.biHeight = 32; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount > 1) + todo_wine + ok(value32 == -16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); + else + todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); + + vih.bmiHeader.biHeight = -32; + } + + winetest_pop_context(); + } -failed: IMFMediaType_Release(media_type); } From 89a25ad0438ec1ae7e53bf5cec0bcc09988fdc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 14:07:00 +0100 Subject: [PATCH 033/301] mfplat/mediatype: Implement implicit MFInitMediaTypeFromVideoInfoHeader subtype. (cherry picked from commit e497f0e88d32fc2a5f566cca4abd83004437c108) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 37 +++++++++++++++++++++++++++++-------- dlls/mfplat/tests/mfplat.c | 28 +++++++--------------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 86474eacdb3..6602b41bfd8 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2698,13 +2698,14 @@ struct uncompressed_video_format static int __cdecl uncompressed_video_format_compare(const void *a, const void *b) { - const GUID *guid = a; - const struct uncompressed_video_format *format = b; - return memcmp(guid, format->subtype, sizeof(*guid)); + const struct uncompressed_video_format *a_format = a, *b_format = b; + return memcmp(a_format->subtype, b_format->subtype, sizeof(GUID)); } -static const struct uncompressed_video_format video_formats[] = +static struct uncompressed_video_format video_formats[] = { + { &MFVideoFormat_RGB1, 1, 0, 1, 0, BI_RGB }, + { &MFVideoFormat_RGB4, 4, 0, 1, 0, BI_RGB }, { &MFVideoFormat_RGB24, 24, 3, 1, 0, BI_RGB }, { &MFVideoFormat_ARGB32, 32, 3, 1, 0, BI_RGB }, { &MFVideoFormat_RGB32, 32, 3, 1, 0, BI_RGB }, @@ -2738,14 +2739,26 @@ static const struct uncompressed_video_format video_formats[] = { &MEDIASUBTYPE_RGB32, 32, 3, 1, 0, BI_RGB }, }; +static BOOL WINAPI mf_video_formats_init(INIT_ONCE *once, void *param, void **context) +{ + qsort(video_formats, ARRAY_SIZE(video_formats), sizeof(*video_formats), uncompressed_video_format_compare); + return TRUE; +} + static struct uncompressed_video_format *mf_get_video_format(const GUID *subtype) { - return bsearch(subtype, video_formats, ARRAY_SIZE(video_formats), sizeof(*video_formats), + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + struct uncompressed_video_format key = {.subtype = subtype}; + + InitOnceExecuteOnce(&init_once, mf_video_formats_init, NULL, NULL); + + return bsearch(&key, video_formats, ARRAY_SIZE(video_formats), sizeof(*video_formats), uncompressed_video_format_compare); } static unsigned int mf_get_stride_for_format(const struct uncompressed_video_format *format, unsigned int width) { + if (format->bpp < 8) return (width * format->bpp) / 8; return (width * (format->bpp / 8) + format->alignment) & ~format->alignment; } @@ -3747,14 +3760,22 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons DWORD height; LONG stride; - FIXME("%p, %p, %u, %s.\n", media_type, vih, size, debugstr_guid(subtype)); + TRACE("%p, %p, %u, %s.\n", media_type, vih, size, debugstr_guid(subtype)); IMFMediaType_DeleteAllItems(media_type); if (!subtype) { - FIXME("Implicit subtype is not supported.\n"); - return E_NOTIMPL; + switch (vih->bmiHeader.biBitCount) + { + case 1: subtype = &MFVideoFormat_RGB1; break; + case 4: subtype = &MFVideoFormat_RGB4; break; + case 8: subtype = &MFVideoFormat_RGB8; break; + case 16: subtype = &MFVideoFormat_RGB555; break; + case 24: subtype = &MFVideoFormat_RGB24; break; + case 32: subtype = &MFVideoFormat_RGB32; break; + default: return E_INVALIDARG; + } } height = abs(vih->bmiHeader.biHeight); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index c985d5b8a0f..135efcc82fb 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -9847,10 +9847,8 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) memset(&vih, 0, sizeof(vih)); hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, 0, NULL); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); @@ -9967,7 +9965,6 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) /* biBitCount is used for implicit RGB format if GUID is NULL */ hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); for (vih.bmiHeader.biBitCount = 1; vih.bmiHeader.biBitCount <= 32; vih.bmiHeader.biBitCount++) @@ -9977,35 +9974,31 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); if (vih.bmiHeader.biBitCount != 1 && vih.bmiHeader.biBitCount != 4 && vih.bmiHeader.biBitCount != 8 && vih.bmiHeader.biBitCount != 16 && vih.bmiHeader.biBitCount != 24 && vih.bmiHeader.biBitCount != 32) - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); else { - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); memset(&guid, 0xcd, sizeof(guid)); hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (vih.bmiHeader.biBitCount == 32) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "Unexpected guid %s.\n", debugstr_guid(&guid)); else if (vih.bmiHeader.biBitCount == 24) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB24), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB24), "Unexpected guid %s.\n", debugstr_guid(&guid)); else if (vih.bmiHeader.biBitCount == 16) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB555), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB555), "Unexpected guid %s.\n", debugstr_guid(&guid)); else if (vih.bmiHeader.biBitCount == 8) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB8), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB8), "Unexpected guid %s.\n", debugstr_guid(&guid)); else if (vih.bmiHeader.biBitCount == 4) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB4), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB4), "Unexpected guid %s.\n", debugstr_guid(&guid)); else if (vih.bmiHeader.biBitCount == 1) - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB1), "Unexpected guid %s.\n", debugstr_guid(&guid)); + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB1), "Unexpected guid %s.\n", debugstr_guid(&guid)); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (vih.bmiHeader.biBitCount > 1) - todo_wine ok(value32 == 16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); else todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); @@ -10018,27 +10011,20 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "Unexpected value %#x.\n", value32); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "Unexpected value %#x.\n", value32); value32 = 0xdeadbeef; vih.bmiHeader.biHeight = 32; hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), NULL); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (vih.bmiHeader.biBitCount > 1) - todo_wine ok(value32 == -16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); else todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); From cf06f2a300e55ba7b271d78b34e18c8aa182b64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 12:30:53 +0100 Subject: [PATCH 034/301] mfplat/mediatype: Implement MFInitMediaTypeFromVideoInfoHeader2. (cherry picked from commit 4319ada73674ca0403b06e1655f4a2757139f87a) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 26 ++++++++++++++++++++++++-- dlls/mfplat/mfplat.spec | 2 +- include/mfapi.h | 4 ++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 6602b41bfd8..3d5438b44f2 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -25,6 +25,7 @@ #include "uuids.h" #include "strmif.h" #include "initguid.h" +#include "dvdmedia.h" #include "ks.h" #include "ksmedia.h" #include "amvideo.h" @@ -3751,9 +3752,9 @@ HRESULT WINAPI MFCreateVideoMediaTypeFromVideoInfoHeader(const KS_VIDEOINFOHEADE } /*********************************************************************** - * MFInitMediaTypeFromVideoInfoHeader (mfplat.@) + * MFInitMediaTypeFromVideoInfoHeader2 (mfplat.@) */ -HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, const VIDEOINFOHEADER *vih, UINT32 size, +HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, const VIDEOINFOHEADER2 *vih, UINT32 size, const GUID *subtype) { HRESULT hr = S_OK; @@ -3797,6 +3798,27 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons return hr; } +/*********************************************************************** + * MFInitMediaTypeFromVideoInfoHeader (mfplat.@) + */ +HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, const VIDEOINFOHEADER *vih, UINT32 size, + const GUID *subtype) +{ + VIDEOINFOHEADER2 vih2 = + { + .rcSource = vih->rcSource, + .rcTarget = vih->rcTarget, + .dwBitRate = vih->dwBitRate, + .dwBitErrorRate = vih->dwBitErrorRate, + .AvgTimePerFrame = vih->AvgTimePerFrame, + .bmiHeader = vih->bmiHeader, + }; + + TRACE("%p, %p, %u, %s.\n", media_type, vih, size, debugstr_guid(subtype)); + + return MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih2, sizeof(vih2), subtype); +} + static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) { UINT32 num_channels, value; diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index d7f75351960..44d1b89fff5 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -123,7 +123,7 @@ @ stub MFInitMediaTypeFromMFVideoFormat @ stub MFInitMediaTypeFromMPEG1VideoInfo @ stub MFInitMediaTypeFromMPEG2VideoInfo -@ stub MFInitMediaTypeFromVideoInfoHeader2 +@ stdcall MFInitMediaTypeFromVideoInfoHeader2(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromVideoInfoHeader(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromWaveFormatEx(ptr ptr long) @ stub MFInitVideoFormat diff --git a/include/mfapi.h b/include/mfapi.h index ef5bec16369..27b0f4fd841 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -507,6 +507,8 @@ typedef enum struct tagVIDEOINFOHEADER; typedef struct tagVIDEOINFOHEADER VIDEOINFOHEADER; +struct tagVIDEOINFOHEADER2; +typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; typedef struct _AMMediaType AM_MEDIA_TYPE; HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); @@ -593,6 +595,8 @@ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID f HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *mediatype, const AM_MEDIA_TYPE *am_type); HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, const VIDEOINFOHEADER *vih, UINT32 size, const GUID *subtype); +HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, const VIDEOINFOHEADER2 *vih, + UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInitVideoFormat_RGB(MFVIDEOFORMAT *format, DWORD width, DWORD height, DWORD d3dformat); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); From 26f014361aa4a3d47561e2b4bab09a5783834235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 13:16:57 +0100 Subject: [PATCH 035/301] mfplat/tests: Add tests for MFInitMediaTypeFromVideoInfoHeader2. (cherry picked from commit d307cfede9ad66d64b3b39ac85e6814122f078d9) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 259 +++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 135efcc82fb..8dffde34d27 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10038,6 +10038,264 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) IMFMediaType_Release(media_type); } +static void test_MFInitMediaTypeFromVideoInfoHeader2(void) +{ + IMFMediaType *media_type; + VIDEOINFOHEADER2 vih; + UINT32 value32; + UINT64 value64; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&vih, 0, sizeof(vih)); + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, 0, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &GUID_NULL), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.bmiHeader.biWidth = 16; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.bmiHeader.biHeight = -32; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.bmiHeader.biHeight = 32; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == MFVideoInterlace_Progressive, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.bmiHeader.biSizeImage = 12345; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwBitRate = 678910; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 678910, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwBitErrorRate = 11121314; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 11121314, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value64 = 0xdeadbeef; + vih.AvgTimePerFrame = 1151617; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == ((UINT64)10000000 << 32 | 1151617), "Unexpected value %#I64x.\n", value64); + + value32 = 0xdeadbeef; + vih.dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOrWeave; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive, "Unexpected value %#x.\n", value32); + + vih.dwPictAspectRatioX = 123; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value64 = 0xdeadbeef; + vih.dwPictAspectRatioY = 456; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == ((UINT64)41 << 32 | 76), "Unexpected value %#I64x.\n", value64); + + vih.dwControlFlags = AMCONTROL_COLORINFO_PRESENT; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwControlFlags = AMCONTROL_COLORINFO_PRESENT | (MFVideoTransferMatrix_SMPTE240M << 15); + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoTransferMatrix_SMPTE240M, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwControlFlags = AMCONTROL_COLORINFO_PRESENT | (MFVideoTransferMatrix_SMPTE240M << 15) | (MFNominalRange_Wide << 12); + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFNominalRange_Wide, "Unexpected value %#x.\n", value32); + + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &MFVideoFormat_NV12); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + + + /* biBitCount is used for implicit RGB format if GUID is NULL */ + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + for (vih.bmiHeader.biBitCount = 1; vih.bmiHeader.biBitCount <= 32; vih.bmiHeader.biBitCount++) + { + winetest_push_context("%u", vih.bmiHeader.biBitCount); + + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), NULL); + if (vih.bmiHeader.biBitCount != 1 && vih.bmiHeader.biBitCount != 4 && vih.bmiHeader.biBitCount != 8 + && vih.bmiHeader.biBitCount != 16 && vih.bmiHeader.biBitCount != 24 && vih.bmiHeader.biBitCount != 32) + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + else + { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount == 32) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 24) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB24), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 16) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB555), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 8) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB8), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 4) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB4), "Unexpected guid %s.\n", debugstr_guid(&guid)); + else if (vih.bmiHeader.biBitCount == 1) + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB1), "Unexpected guid %s.\n", debugstr_guid(&guid)); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount > 1) + ok(value32 == 16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); + else + todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); + + hr = IMFMediaType_GetItem(media_type, &MF_MT_PALETTE, NULL); + if (vih.bmiHeader.biBitCount > 1) + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + else + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + + value32 = 0xdeadbeef; + vih.bmiHeader.biHeight = 32; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (vih.bmiHeader.biBitCount > 1) + ok(value32 == -16 * vih.bmiHeader.biBitCount / 8, "Unexpected value %#x.\n", value32); + else + todo_wine ok(value32 == -4, "Unexpected value %#x.\n", value32); + + vih.bmiHeader.biHeight = -32; + } + + winetest_pop_context(); + } + + IMFMediaType_Release(media_type); +} + static void test_MFInitMediaTypeFromAMMediaType(void) { IMFMediaType *media_type; @@ -10626,6 +10884,7 @@ START_TEST(mfplat) test_MFInitVideoFormat_RGB(); test_MFCreateVideoMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromVideoInfoHeader(); + test_MFInitMediaTypeFromVideoInfoHeader2(); test_MFInitMediaTypeFromAMMediaType(); test_MFCreatePathFromURL(); test_2dbuffer_copy(); From 26bc85a7396a06e4800c8000669b6c4208382f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 16:48:58 +0100 Subject: [PATCH 036/301] mfplat/mediatype: Implement MFInitAMMediaTypeFromMFMediaType for FORMAT_VideoInfo2. (cherry picked from commit 8dd24ad2a450c15ba4853d8af4e7e7b5d9afeab5) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 106 +++++++++++++++++++++++-------------- dlls/mfplat/tests/mfplat.c | 8 +-- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 3d5438b44f2..1c74ba8d45c 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3907,11 +3907,51 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us return S_OK; } -static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) +static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, IMFMediaType *media_type) { + struct uncompressed_video_format *video_format = mf_get_video_format(subtype); UINT32 image_size, bitrate, sample_size; UINT64 frame_size, frame_rate; INT32 width, height; + + vih->bmiHeader.biSize = sizeof(vih->bmiHeader); + vih->bmiHeader.biPlanes = 1; + vih->bmiHeader.biBitCount = video_format ? video_format->bpp : 0; + + if (video_format && video_format->compression != -1) + vih->bmiHeader.biCompression = video_format->compression; + else + vih->bmiHeader.biCompression = subtype->Data1; + + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &bitrate))) + vih->dwBitRate = bitrate; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &bitrate))) + vih->dwBitErrorRate = bitrate; + if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate)) && (frame_rate >> 32)) + vih->AvgTimePerFrame = round(10000000. * (UINT32)frame_rate / (frame_rate >> 32)); + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) + vih->bmiHeader.biSizeImage = sample_size; + + if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + { + BOOL bottom_up = vih->bmiHeader.biCompression == BI_RGB || vih->bmiHeader.biCompression == BI_BITFIELDS; + + if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&width))) + width = (frame_size >> 32) * (bottom_up ? -1 : 1); + else if (video_format) + width /= video_format->bpp / 8; + height = (UINT32)frame_size; + + vih->bmiHeader.biWidth = abs(width); + vih->bmiHeader.biHeight = height * (bottom_up && width >= 0 ? -1 : 1); + + if (SUCCEEDED(MFCalculateImageSize(subtype, abs(width), height, &image_size))) + vih->bmiHeader.biSizeImage = image_size; + } +} + +static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) +{ HRESULT hr; if (IsEqualGUID(&am_type->formattype, &FORMAT_WaveFormatEx)) @@ -3924,7 +3964,7 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) || IsEqualGUID(&am_type->formattype, &GUID_NULL)) { - struct uncompressed_video_format *video_format = mf_get_video_format(&am_type->subtype); + VIDEOINFOHEADER2 vih = {{0}}; VIDEOINFOHEADER *format; am_type->cbFormat = sizeof(*format) + user_size; @@ -3933,53 +3973,41 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us format = (VIDEOINFOHEADER *)am_type->pbFormat; memset(format, 0, sizeof(*format)); - format->bmiHeader.biSize = sizeof(format->bmiHeader) + user_size; - format->bmiHeader.biPlanes = 1; - format->bmiHeader.biBitCount = video_format ? video_format->bpp : 0; - - if (video_format && video_format->compression != -1) - format->bmiHeader.biCompression = video_format->compression; - else - format->bmiHeader.biCompression = am_type->subtype.Data1; - - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &bitrate))) - format->dwBitRate = bitrate; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &bitrate))) - format->dwBitErrorRate = bitrate; - if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate)) && (frame_rate >> 32)) - format->AvgTimePerFrame = round(10000000. * (UINT32)frame_rate / (frame_rate >> 32)); - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) - format->bmiHeader.biSizeImage = sample_size; - - if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) - { - BOOL bottom_up = format->bmiHeader.biCompression == BI_RGB || format->bmiHeader.biCompression == BI_BITFIELDS; - - if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&width))) - width = (frame_size >> 32) * (bottom_up ? -1 : 1); - else if (video_format) - width /= video_format->bpp / 8; - height = (UINT32)frame_size; - - format->bmiHeader.biWidth = abs(width); - format->bmiHeader.biHeight = height * (bottom_up && width >= 0 ? -1 : 1); - - if (SUCCEEDED(MFCalculateImageSize(&am_type->subtype, abs(width), height, &image_size))) - format->bmiHeader.biSizeImage = image_size; - } + init_video_info_header2(&vih, &am_type->subtype, media_type); + format->rcSource = vih.rcSource; + format->rcTarget = vih.rcTarget; + format->dwBitRate = vih.dwBitRate; + format->dwBitErrorRate = vih.dwBitErrorRate; + format->AvgTimePerFrame = vih.AvgTimePerFrame; + format->bmiHeader = vih.bmiHeader; if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)(format + 1), user_size, NULL))) return hr; + format->bmiHeader.biSize += user_size; am_type->formattype = FORMAT_VideoInfo; am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); } else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2)) { - FIXME("Not implemented!\n"); - am_type->formattype = GUID_NULL; - return E_NOTIMPL; + VIDEOINFOHEADER2 *format; + + am_type->cbFormat = sizeof(*format) + user_size; + if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) + return E_OUTOFMEMORY; + format = (VIDEOINFOHEADER2 *)am_type->pbFormat; + memset(format, 0, sizeof(*format)); + + init_video_info_header2(format, &am_type->subtype, media_type); + + if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, + (BYTE *)(format + 1), user_size, NULL))) + return hr; + format->bmiHeader.biSize += user_size; + + am_type->formattype = FORMAT_VideoInfo2; + am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); } else { diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 8dffde34d27..fcd271d72b3 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7214,11 +7214,11 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(am_type.cbFormat == sizeof(VIDEOINFOHEADER), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_VideoInfo2, &am_type); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); - todo_wine ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); - todo_wine ok(IsEqualGUID(&am_type.formattype, &FORMAT_VideoInfo2), "got %s.\n", debugstr_guid(&am_type.formattype)); - todo_wine ok(am_type.cbFormat == sizeof(VIDEOINFOHEADER2), "got %lu\n", am_type.cbFormat); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_VideoInfo2), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(VIDEOINFOHEADER2), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MFVideoFormat, &am_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From c2cf21aa23e6e28e0699a89600e40d7660e17d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 09:07:41 +0100 Subject: [PATCH 037/301] mfplat/tests: Test aperture to VIDEOINFOHEADER fields mapping. (cherry picked from commit 6413303e600bff412eb162b418ba5ea7b9f3d89d) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 262 ++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 7 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index fcd271d72b3..538bdfa8319 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7565,10 +7565,11 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->bmiHeader.biWidth == 123, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == 456, "got %lu\n", video_info->bmiHeader.biHeight); - ok(video_info->bmiHeader.biSizeImage == 224352, "got %lu\n", video_info->bmiHeader.biSizeImage); + ok(video_info->bmiHeader.biSizeImage == 123 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); CoTaskMemFree(am_type.pbFormat); IMFMediaType_DeleteAllItems(media_type); + /* MF_MT_MINIMUM_DISPLAY_APERTURE has no effect */ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); @@ -7577,7 +7578,7 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 123456); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 12345678); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7592,7 +7593,102 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(video_info->rcTarget.bottom == 0, "got %lu\n", video_info->rcTarget.bottom); ok(video_info->bmiHeader.biWidth == 123, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == 456, "got %lu\n", video_info->bmiHeader.biHeight); - ok(video_info->bmiHeader.biSizeImage == 224352, "got %lu\n", video_info->bmiHeader.biSizeImage); + ok(video_info->bmiHeader.biSizeImage == 123 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); + CoTaskMemFree(am_type.pbFormat); + IMFMediaType_DeleteAllItems(media_type); + + /* MF_MT_DEFAULT_STRIDE / MF_MT_FRAME_SIZE mismatch is translated into rcSource / rcTarget */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)123 << 32 | 456); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -246 * 4); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 12345678); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + video_info = (VIDEOINFOHEADER *)am_type.pbFormat; + ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); + todo_wine + ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); + ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); + todo_wine + ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); + ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); + todo_wine + ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); + ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); + todo_wine + ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); + ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); + ok(video_info->bmiHeader.biHeight == 456, "got %ld\n", video_info->bmiHeader.biHeight); + ok(video_info->bmiHeader.biSizeImage == 246 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); + CoTaskMemFree(am_type.pbFormat); + + /* positive stride only changes biHeight */ + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, 246 * 4); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + video_info = (VIDEOINFOHEADER *)am_type.pbFormat; + ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); + todo_wine + ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); + ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); + todo_wine + ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); + ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); + todo_wine + ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); + ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); + todo_wine + ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); + ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); + ok(video_info->bmiHeader.biHeight == -456, "got %ld\n", video_info->bmiHeader.biHeight); + ok(video_info->bmiHeader.biSizeImage == 246 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); + CoTaskMemFree(am_type.pbFormat); + IMFMediaType_DeleteAllItems(media_type); + + /* same thing happens with other formats */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_NV12); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)123 << 32 | 456); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, 246); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 12345678); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + video_info = (VIDEOINFOHEADER *)am_type.pbFormat; + ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); + todo_wine + ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); + ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); + todo_wine + ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); + ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); + todo_wine + ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); + ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); + todo_wine + ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); + ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); + ok(video_info->bmiHeader.biHeight == 456, "got %ld\n", video_info->bmiHeader.biHeight); + ok(video_info->bmiHeader.biSizeImage == 246 * 456 * 3 / 2, "got %lu\n", video_info->bmiHeader.biSizeImage); CoTaskMemFree(am_type.pbFormat); IMFMediaType_DeleteAllItems(media_type); @@ -7602,14 +7698,14 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)123 << 32 | 456); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -984); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -246 * 4); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == 456, "got %ld\n", video_info->bmiHeader.biHeight); - ok(video_info->bmiHeader.biSizeImage == 448704, "got %lu\n", video_info->bmiHeader.biSizeImage); + ok(video_info->bmiHeader.biSizeImage == 246 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); CoTaskMemFree(am_type.pbFormat); IMFMediaType_DeleteAllItems(media_type); @@ -7619,14 +7715,14 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)123 << 32 | 456); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, 984); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, 246 * 4); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == -456, "got %ld\n", video_info->bmiHeader.biHeight); - ok(video_info->bmiHeader.biSizeImage == 448704, "got %lu\n", video_info->bmiHeader.biSizeImage); + ok(video_info->bmiHeader.biSizeImage == 246 * 456 * 4, "got %lu\n", video_info->bmiHeader.biSizeImage); CoTaskMemFree(am_type.pbFormat); IMFMediaType_DeleteAllItems(media_type); @@ -9835,7 +9931,10 @@ static void test_MFCreateVideoMediaTypeFromVideoInfoHeader(void) static void test_MFInitMediaTypeFromVideoInfoHeader(void) { + static const MFVideoArea expect_aperture = {.OffsetX = {.value = 1}, .OffsetY = {.value = 2}, .Area = {.cx = 3, .cy = 5}}; + static const RECT source = {1, 2, 4, 7}, target = {3, 2, 12, 9}; IMFMediaType *media_type; + MFVideoArea aperture; VIDEOINFOHEADER vih; UINT32 value32; UINT64 value64; @@ -9953,6 +10052,63 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + /* only rcSource is considered, translated into both MF_MT_MINIMUM_DISPLAY_APERTURE and MF_MT_PAN_SCAN_APERTURE */ + value32 = 0xdeadbeef; + vih.rcSource = source; + vih.rcTarget = target; + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %d.\n", value32); + todo_wine + ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %d.\n", (UINT32)value32); + + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %d.\n", value32); + todo_wine + ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); + + hr = IMFMediaType_GetItem(media_type, &MF_MT_GEOMETRIC_APERTURE, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &MFVideoFormat_NV12); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); @@ -10040,8 +10196,11 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) static void test_MFInitMediaTypeFromVideoInfoHeader2(void) { + static const MFVideoArea expect_aperture = {.OffsetX = {.value = 1}, .OffsetY = {.value = 2}, .Area = {.cx = 3, .cy = 5}}; + static const RECT source = {1, 2, 4, 7}, target = {3, 2, 12, 9}; IMFMediaType *media_type; VIDEOINFOHEADER2 vih; + MFVideoArea aperture; UINT32 value32; UINT64 value64; HRESULT hr; @@ -10220,6 +10379,62 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value32 == 1, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + /* only rcSource is considered, translated into both MF_MT_MINIMUM_DISPLAY_APERTURE and MF_MT_PAN_SCAN_APERTURE */ + value32 = 0xdeadbeef; + vih.rcSource = source; + vih.rcTarget = target; + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %d.\n", value32); + todo_wine + ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); + + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %d.\n", (UINT32)value32); + + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %d.\n", value32); + todo_wine + ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); + + hr = IMFMediaType_GetItem(media_type, &MF_MT_GEOMETRIC_APERTURE, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + /* biBitCount is used for implicit RGB format if GUID is NULL */ hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), NULL); @@ -10298,6 +10513,8 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) static void test_MFInitMediaTypeFromAMMediaType(void) { + static const MFVideoArea expect_aperture = {.OffsetX = {.value = 13}, .OffsetY = {.value = 46}, .Area = {.cx = 110, .cy = 410}}; + static const RECT source = {13, 46, 123, 456}, target = {25, 34, 107, 409}; IMFMediaType *media_type; AM_MEDIA_TYPE mt; UINT32 value32; @@ -10348,6 +10565,7 @@ static void test_MFInitMediaTypeFromAMMediaType(void) { &MEDIASUBTYPE_h264, &MEDIASUBTYPE_h264 }, { &MEDIASUBTYPE_H264, &MFVideoFormat_H264 }, }; + MFVideoArea aperture; unsigned int i; hr = MFCreateMediaType(&media_type); @@ -10467,6 +10685,36 @@ static void test_MFInitMediaTypeFromAMMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value32 == 128, "Unexpected value %d.\n", value32); + /* only rcSource is considered, lSampleSize is ignored if biSizeImage was present */ + memcpy(&mt.subtype, &MEDIASUBTYPE_RGB32, sizeof(GUID)); + vih.rcSource = source; + vih.rcTarget = target; + vih.bmiHeader.biWidth = 432; + vih.bmiHeader.biHeight = -654; + vih.bmiHeader.biSizeImage = 12345678; + mt.lSampleSize = 87654321; + hr = MFInitMediaTypeFromAMMediaType(media_type, &mt); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok((UINT32)(value64 >> 32) == 432, "got %d.\n", (UINT32)(value64 >> 32)); + ok((UINT32)value64 == 654, "got %d.\n", (UINT32)value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 432 * 4, "got %d.\n", (UINT32)value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 12345678, "got %d.\n", (UINT32)value32); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %d.\n", value32); + todo_wine + ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); + vih.bmiHeader.biHeight = 24; for (i = 0; i < ARRAY_SIZE(guid_types); ++i) { From 996fd778d1bbc85873f8b6ab45725e5aca888970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 09:14:21 +0100 Subject: [PATCH 038/301] mfplat/mediatype: Support FORMAT_VideoInfo2 in MFInitMediaTypeFromAMMediaType. (cherry picked from commit 08cafe23d54915982ca403c9f46952eb584e79c8) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 50 ++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 1c74ba8d45c..2af1d1ade2b 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4078,46 +4078,30 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM if (IsEqualGUID(&am_type->majortype, &MEDIATYPE_Video)) { - if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo)) - { - const VIDEOINFOHEADER *vih = (const VIDEOINFOHEADER *)am_type->pbFormat; - const GUID *subtype; - DWORD height; - LONG stride; - - subtype = get_mf_subtype_for_am_subtype(&am_type->subtype); - height = abs(vih->bmiHeader.biHeight); - - mediatype_set_guid(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video, &hr); - mediatype_set_guid(media_type, &MF_MT_SUBTYPE, subtype, &hr); - mediatype_set_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, 1, 1, &hr); - mediatype_set_uint32(media_type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive, &hr); - mediatype_set_uint64(media_type, &MF_MT_FRAME_SIZE, vih->bmiHeader.biWidth, height, &hr); - mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); + const GUID *subtype = get_mf_subtype_for_am_subtype(&am_type->subtype); - if (SUCCEEDED(mf_get_stride_for_bitmap_info_header(subtype->Data1, &vih->bmiHeader, &stride))) - { - mediatype_set_uint32(media_type, &MF_MT_DEFAULT_STRIDE, stride, &hr); - mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, abs(stride) * height, &hr); - mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); - } - else - { - if (am_type->bFixedSizeSamples) - mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); - if (am_type->lSampleSize) - mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, am_type->lSampleSize, &hr); - } - - return hr; - } + if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo)) + hr = MFInitMediaTypeFromVideoInfoHeader(media_type, (VIDEOINFOHEADER *)am_type->pbFormat, am_type->cbFormat, subtype); + else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2)) + hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, (VIDEOINFOHEADER2 *)am_type->pbFormat, am_type->cbFormat, subtype); else { FIXME("Unsupported format type %s.\n", debugstr_guid(&am_type->formattype)); + return E_NOTIMPL; } + + if (!am_type->bTemporalCompression && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) + mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); + if (am_type->bFixedSizeSamples && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) + mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); + if (am_type->lSampleSize && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) + mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, am_type->lSampleSize, &hr); } else + { FIXME("Unsupported major type %s.\n", debugstr_guid(&am_type->majortype)); + return E_NOTIMPL; + } - return E_NOTIMPL; + return hr; } From 002372fb4e6e0064a66a728be2f1fbb7c3f45b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 10:26:42 +0100 Subject: [PATCH 039/301] mfplat/mediatype: Set MF_MT_SAMPLE_SIZE from bmiHeader.biSizeImage. (cherry picked from commit 66ea15f13a1510e75e3ffb7f556a6fc578f23a28) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 3 +++ dlls/mfplat/tests/mfplat.c | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 2af1d1ade2b..337fe077796 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3795,6 +3795,9 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); } + if (vih->bmiHeader.biSizeImage) + mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, vih->bmiHeader.biSizeImage, &hr); + return hr; } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 538bdfa8319..66ab4e9a880 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10006,9 +10006,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 12345, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -10071,9 +10069,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 12345, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -10271,9 +10267,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 12345, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -10398,9 +10392,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 12345, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -10705,7 +10697,6 @@ static void test_MFInitMediaTypeFromAMMediaType(void) ok(value32 == 432 * 4, "got %d.\n", (UINT32)value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 12345678, "got %d.\n", (UINT32)value32); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); todo_wine From fb4763f6c137a4d72394b4751cfc8ff2726b5fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 14:04:58 +0100 Subject: [PATCH 040/301] mfplat/mediatype: Map rcSource to MF_MT_(PAN_SCAN|MINIMUM_DISPLAY)_APERTURE. (cherry picked from commit d0c996b2b4f3279286034be75936239f9dcf0bd1) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 14 ++++++++++++++ dlls/mfplat/tests/mfplat.c | 19 ------------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 337fe077796..f57954a5dca 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3798,6 +3798,20 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con if (vih->bmiHeader.biSizeImage) mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, vih->bmiHeader.biSizeImage, &hr); + if (vih->rcSource.left || vih->rcSource.top || vih->rcSource.right || vih->rcSource.bottom) + { + MFVideoArea aperture = {{0}}; + + aperture.OffsetX.value = vih->rcSource.left; + aperture.OffsetY.value = vih->rcSource.top; + aperture.Area.cx = vih->rcSource.right - vih->rcSource.left; + aperture.Area.cy = vih->rcSource.bottom - vih->rcSource.top; + + mediatype_set_uint32(media_type, &MF_MT_PAN_SCAN_ENABLED, 1, &hr); + mediatype_set_blob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &hr); + mediatype_set_blob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &hr); + } + return hr; } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 66ab4e9a880..45797abb15e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10077,28 +10077,20 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %d.\n", value32); - todo_wine ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %d.\n", (UINT32)value32); value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %d.\n", value32); - todo_wine ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); hr = IMFMediaType_GetItem(media_type, &MF_MT_GEOMETRIC_APERTURE, NULL); @@ -10400,28 +10392,20 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %d.\n", value32); - todo_wine ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %d.\n", (UINT32)value32); value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %d.\n", value32); - todo_wine ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); hr = IMFMediaType_GetItem(media_type, &MF_MT_GEOMETRIC_APERTURE, NULL); @@ -10699,11 +10683,8 @@ static void test_MFInitMediaTypeFromAMMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value32 == 12345678, "got %d.\n", (UINT32)value32); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %d.\n", value32); - todo_wine ok(!memcmp(&aperture, &expect_aperture, sizeof(aperture)), "unexpected aperture\n"); vih.bmiHeader.biHeight = 24; From 61a273d7fa8d9e5d87576e61bf365caea1b00d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 16:56:57 +0100 Subject: [PATCH 041/301] mfplat/mediatype: Set rcSource and rcTarget if stride differs from width. (cherry picked from commit c94c464920dbda6d5471d30d33a448aba4d71d80) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 23 +++++++++++++++-------- dlls/mfplat/tests/mfplat.c | 12 ------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index f57954a5dca..d7bb620aede 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3927,9 +3927,8 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, IMFMediaType *media_type) { struct uncompressed_video_format *video_format = mf_get_video_format(subtype); - UINT32 image_size, bitrate, sample_size; + UINT32 image_size, bitrate, sample_size, width, height; UINT64 frame_size, frame_rate; - INT32 width, height; vih->bmiHeader.biSize = sizeof(vih->bmiHeader); vih->bmiHeader.biPlanes = 1; @@ -3952,18 +3951,26 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) { BOOL bottom_up = vih->bmiHeader.biCompression == BI_RGB || vih->bmiHeader.biCompression == BI_BITFIELDS; + INT32 stride; - if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&width))) - width = (frame_size >> 32) * (bottom_up ? -1 : 1); + width = frame_size >> 32; + if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) + stride = width * (bottom_up ? -1 : 1); else if (video_format) - width /= video_format->bpp / 8; + stride /= video_format->bpp / 8; height = (UINT32)frame_size; - vih->bmiHeader.biWidth = abs(width); - vih->bmiHeader.biHeight = height * (bottom_up && width >= 0 ? -1 : 1); + vih->bmiHeader.biWidth = abs(stride); + vih->bmiHeader.biHeight = height * (bottom_up && stride >= 0 ? -1 : 1); - if (SUCCEEDED(MFCalculateImageSize(subtype, abs(width), height, &image_size))) + if (SUCCEEDED(MFCalculateImageSize(subtype, abs(stride), height, &image_size))) vih->bmiHeader.biSizeImage = image_size; + + if (vih->bmiHeader.biWidth > width) + { + vih->rcSource.right = vih->rcTarget.right = width; + vih->rcSource.bottom = vih->rcTarget.bottom = height; + } } } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 45797abb15e..7b96376b1b9 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7620,16 +7620,12 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); - todo_wine ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); - todo_wine ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); - todo_wine ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); - todo_wine ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == 456, "got %ld\n", video_info->bmiHeader.biHeight); @@ -7643,16 +7639,12 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); - todo_wine ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); - todo_wine ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); - todo_wine ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); - todo_wine ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == -456, "got %ld\n", video_info->bmiHeader.biHeight); @@ -7675,16 +7667,12 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); video_info = (VIDEOINFOHEADER *)am_type.pbFormat; ok(video_info->rcSource.left == 0, "got %lu\n", video_info->rcSource.left); - todo_wine ok(video_info->rcSource.right == 123, "got %lu\n", video_info->rcSource.right); ok(video_info->rcSource.top == 0, "got %lu\n", video_info->rcSource.top); - todo_wine ok(video_info->rcSource.bottom == 456, "got %lu\n", video_info->rcSource.bottom); ok(video_info->rcTarget.left == 0, "got %lu\n", video_info->rcTarget.left); - todo_wine ok(video_info->rcTarget.right == 123, "got %lu\n", video_info->rcTarget.right); ok(video_info->rcTarget.top == 0, "got %lu\n", video_info->rcTarget.top); - todo_wine ok(video_info->rcTarget.bottom == 456, "got %lu\n", video_info->rcTarget.bottom); ok(video_info->bmiHeader.biWidth == 246, "got %lu\n", video_info->bmiHeader.biWidth); ok(video_info->bmiHeader.biHeight == 456, "got %ld\n", video_info->bmiHeader.biHeight); From 39121d30cc99da8505796ac1359877bc667e15bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Mar 2024 13:35:22 +0100 Subject: [PATCH 042/301] mfplat/tests: Add more MFAverageTimePerFrameToFrameRate tests. (cherry picked from commit 578d104cf6f3dc131423fd861373e2e33eaaf231) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 7b96376b1b9..86809cbe89f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8203,16 +8203,40 @@ static void test_MFAverageTimePerFrameToFrameRate(void) unsigned int numerator; unsigned int denominator; UINT64 avgtime; + BOOL todo; } frame_rate_tests[] = { + { 60000, 1001, 166863, TRUE }, { 60000, 1001, 166833 }, + { 60000, 1001, 166803, TRUE }, + + { 30000, 1001, 333697, TRUE }, { 30000, 1001, 333667 }, + { 30000, 1001, 333637, TRUE }, + + { 24000, 1001, 417218, TRUE }, { 24000, 1001, 417188 }, + { 24000, 1001, 417158, TRUE }, + + { 60, 1, 166697, TRUE }, { 60, 1, 166667 }, + { 60, 1, 166637, TRUE }, + + { 30, 1, 333363, TRUE }, { 30, 1, 333333 }, + { 30, 1, 333303, TRUE }, + + { 50, 1, 200030, TRUE }, { 50, 1, 200000 }, + { 50, 1, 199970, TRUE }, + + { 25, 1, 400030, TRUE }, { 25, 1, 400000 }, + { 25, 1, 399970, TRUE }, + + { 24, 1, 416697, TRUE }, { 24, 1, 416667 }, + { 24, 1, 416637, TRUE }, { 1000000, 25641, 256410 }, { 10000000, 83333, 83333 }, @@ -8237,6 +8261,7 @@ static void test_MFAverageTimePerFrameToFrameRate(void) numerator = denominator = 12345; hr = MFAverageTimePerFrameToFrameRate(frame_rate_tests[i].avgtime, &numerator, &denominator); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(frame_rate_tests[i].todo) ok(numerator == frame_rate_tests[i].numerator && denominator == frame_rate_tests[i].denominator, "%u: unexpected %u/%u, expected %u/%u.\n", i, numerator, denominator, frame_rate_tests[i].numerator, frame_rate_tests[i].denominator); From b23551a3f2b5502951c48f5c8c56b116300be777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Mar 2024 13:41:28 +0100 Subject: [PATCH 043/301] mfplat: Support flexible frame time in MFAverageTimePerFrameToFrameRate. (cherry picked from commit aa385765a1229c4dd6c15d45cb1883ce93bbc30b) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 82 +++++++++++++++++++------------------- dlls/mfplat/tests/mfplat.c | 34 ++++++++-------- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index d7bb620aede..dc0769db030 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3355,15 +3355,45 @@ HRESULT WINAPI MFConvertColorInfoToDXVA(DWORD *dxva_info, const MFVIDEOFORMAT *f struct frame_rate { - UINT64 key; - UINT64 value; + UINT64 time; + UINT64 rate; +}; + +static const struct frame_rate known_rates[] = +{ +#define KNOWN_RATE(ft,n,d) { ft, ((UINT64)n << 32) | d } + KNOWN_RATE(417188, 24000, 1001), + KNOWN_RATE(416667, 24, 1), + KNOWN_RATE(400000, 25, 1), + KNOWN_RATE(333667, 30000, 1001), + KNOWN_RATE(333333, 30, 1), + KNOWN_RATE(200000, 50, 1), + KNOWN_RATE(166833, 60000, 1001), + KNOWN_RATE(166667, 60, 1), +#undef KNOWN_RATE }; -static int __cdecl frame_rate_compare(const void *a, const void *b) +static const struct frame_rate *known_rate_from_rate(UINT64 rate) +{ + UINT i; + for (i = 0; i < ARRAY_SIZE(known_rates); i++) + { + if (rate == known_rates[i].rate) + return known_rates + i; + } + return NULL; +} + +static const struct frame_rate *known_rate_from_time(UINT64 time) { - const UINT64 *key = a; - const struct frame_rate *known_rate = b; - return *key == known_rate->key ? 0 : ( *key < known_rate->key ? 1 : -1 ); + UINT i; + for (i = 0; i < ARRAY_SIZE(known_rates); i++) + { + if (time >= known_rates[i].time - 30 + && time <= known_rates[i].time + 30) + return known_rates + i; + } + return NULL; } /*********************************************************************** @@ -3371,29 +3401,13 @@ static int __cdecl frame_rate_compare(const void *a, const void *b) */ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denominator, UINT64 *avgframetime) { - static const struct frame_rate known_rates[] = - { -#define KNOWN_RATE(n,d,ft) { ((UINT64)n << 32) | d, ft } - KNOWN_RATE(60000, 1001, 166833), - KNOWN_RATE(30000, 1001, 333667), - KNOWN_RATE(24000, 1001, 417188), - KNOWN_RATE(60, 1, 166667), - KNOWN_RATE(50, 1, 200000), - KNOWN_RATE(30, 1, 333333), - KNOWN_RATE(25, 1, 400000), - KNOWN_RATE(24, 1, 416667), -#undef KNOWN_RATE - }; UINT64 rate = ((UINT64)numerator << 32) | denominator; const struct frame_rate *entry; TRACE("%u, %u, %p.\n", numerator, denominator, avgframetime); - if ((entry = bsearch(&rate, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates), - frame_rate_compare))) - { - *avgframetime = entry->value; - } + if ((entry = known_rate_from_rate(rate))) + *avgframetime = entry->time; else *avgframetime = numerator ? denominator * (UINT64)10000000 / numerator : 0; @@ -3419,29 +3433,15 @@ static unsigned int get_gcd(unsigned int a, unsigned int b) */ HRESULT WINAPI MFAverageTimePerFrameToFrameRate(UINT64 avgtime, UINT32 *numerator, UINT32 *denominator) { - static const struct frame_rate known_rates[] = - { -#define KNOWN_RATE(ft,n,d) { ft, ((UINT64)n << 32) | d } - KNOWN_RATE(417188, 24000, 1001), - KNOWN_RATE(416667, 24, 1), - KNOWN_RATE(400000, 25, 1), - KNOWN_RATE(333667, 30000, 1001), - KNOWN_RATE(333333, 30, 1), - KNOWN_RATE(200000, 50, 1), - KNOWN_RATE(166833, 60000, 1001), - KNOWN_RATE(166667, 60, 1), -#undef KNOWN_RATE - }; const struct frame_rate *entry; unsigned int gcd; TRACE("%s, %p, %p.\n", wine_dbgstr_longlong(avgtime), numerator, denominator); - if ((entry = bsearch(&avgtime, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates), - frame_rate_compare))) + if ((entry = known_rate_from_time(avgtime))) { - *numerator = entry->value >> 32; - *denominator = entry->value; + *numerator = entry->rate >> 32; + *denominator = entry->rate; } else if (avgtime) { diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 86809cbe89f..bd925353c19 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8203,40 +8203,39 @@ static void test_MFAverageTimePerFrameToFrameRate(void) unsigned int numerator; unsigned int denominator; UINT64 avgtime; - BOOL todo; } frame_rate_tests[] = { - { 60000, 1001, 166863, TRUE }, + { 60000, 1001, 166863 }, { 60000, 1001, 166833 }, - { 60000, 1001, 166803, TRUE }, + { 60000, 1001, 166803 }, - { 30000, 1001, 333697, TRUE }, + { 30000, 1001, 333697 }, { 30000, 1001, 333667 }, - { 30000, 1001, 333637, TRUE }, + { 30000, 1001, 333637 }, - { 24000, 1001, 417218, TRUE }, + { 24000, 1001, 417218 }, { 24000, 1001, 417188 }, - { 24000, 1001, 417158, TRUE }, + { 24000, 1001, 417158 }, - { 60, 1, 166697, TRUE }, + { 60, 1, 166697 }, { 60, 1, 166667 }, - { 60, 1, 166637, TRUE }, + { 60, 1, 166637 }, - { 30, 1, 333363, TRUE }, + { 30, 1, 333363 }, { 30, 1, 333333 }, - { 30, 1, 333303, TRUE }, + { 30, 1, 333303 }, - { 50, 1, 200030, TRUE }, + { 50, 1, 200030 }, { 50, 1, 200000 }, - { 50, 1, 199970, TRUE }, + { 50, 1, 199970 }, - { 25, 1, 400030, TRUE }, + { 25, 1, 400030 }, { 25, 1, 400000 }, - { 25, 1, 399970, TRUE }, + { 25, 1, 399970 }, - { 24, 1, 416697, TRUE }, + { 24, 1, 416697 }, { 24, 1, 416667 }, - { 24, 1, 416637, TRUE }, + { 24, 1, 416637 }, { 1000000, 25641, 256410 }, { 10000000, 83333, 83333 }, @@ -8261,7 +8260,6 @@ static void test_MFAverageTimePerFrameToFrameRate(void) numerator = denominator = 12345; hr = MFAverageTimePerFrameToFrameRate(frame_rate_tests[i].avgtime, &numerator, &denominator); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine_if(frame_rate_tests[i].todo) ok(numerator == frame_rate_tests[i].numerator && denominator == frame_rate_tests[i].denominator, "%u: unexpected %u/%u, expected %u/%u.\n", i, numerator, denominator, frame_rate_tests[i].numerator, frame_rate_tests[i].denominator); From 4c7a6d8f44de0e873eac9b5c0a6ead4337884ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 15:32:11 +0100 Subject: [PATCH 044/301] mfplat/mediatype: Implement MF_MT_FRAME_RATE from VIDEOINFOHEADER2. Native seems to also treat some frame rate specially, matching a wide range of time per frame into the same predefined frame rates. (cherry picked from commit 5a3460160670f9bbfb4f6ffc6bb7baadc5182f03) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 7 +++++++ dlls/mfplat/tests/mfplat.c | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index dc0769db030..6c10f3efc7f 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3812,6 +3812,13 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con mediatype_set_blob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &hr); } + if (SUCCEEDED(hr) && vih->AvgTimePerFrame) + { + UINT32 num, den; + if (SUCCEEDED(hr = MFAverageTimePerFrameToFrameRate(vih->AvgTimePerFrame, &num, &den))) + mediatype_set_uint64(media_type, &MF_MT_FRAME_RATE, num, den, &hr); + } + return hr; } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index bd925353c19..1f49ef8c6f7 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10051,9 +10051,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader(void) hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value64 == ((UINT64)10000000 << 32 | 1151617), "Unexpected value %#I64x.\n", value64); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); @@ -10304,9 +10302,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value64 == ((UINT64)10000000 << 32 | 1151617), "Unexpected value %#I64x.\n", value64); value32 = 0xdeadbeef; From 750ff57276a878e798eee5aa5af80eee21709bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 15:45:36 +0100 Subject: [PATCH 045/301] mfplat/mediatype: Implement VIDEOINFOHEADER2 dwControlFlags conversion. (cherry picked from commit 76abdf3403f0f91543742c24b90f35c06a1bec55) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 39 +++++++++++++++++++++++++++++++++++++- dlls/mfplat/tests/mfplat.c | 4 ---- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 6c10f3efc7f..e2ad72204d4 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -21,6 +21,7 @@ #include "mfplat_private.h" #include +#include "dxva.h" #include "dxva2api.h" #include "uuids.h" #include "strmif.h" @@ -3819,6 +3820,24 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con mediatype_set_uint64(media_type, &MF_MT_FRAME_RATE, num, den, &hr); } + if (vih->dwControlFlags & AMCONTROL_COLORINFO_PRESENT) + { + DXVA_ExtendedFormat *format = (DXVA_ExtendedFormat *)&vih->dwControlFlags; + + if (format->VideoChromaSubsampling) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_CHROMA_SITING, format->VideoChromaSubsampling, &hr); + if (format->NominalRange) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, format->NominalRange, &hr); + if (format->VideoTransferMatrix) + mediatype_set_uint32(media_type, &MF_MT_YUV_MATRIX, format->VideoTransferMatrix, &hr); + if (format->VideoLighting) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_LIGHTING, format->VideoLighting, &hr); + if (format->VideoPrimaries) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_PRIMARIES, format->VideoPrimaries, &hr); + if (format->VideoTransferFunction) + mediatype_set_uint32(media_type, &MF_MT_TRANSFER_FUNCTION, format->VideoTransferFunction, &hr); + } + return hr; } @@ -3934,7 +3953,8 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, IMFMediaType *media_type) { struct uncompressed_video_format *video_format = mf_get_video_format(subtype); - UINT32 image_size, bitrate, sample_size, width, height; + DXVA_ExtendedFormat *format = (DXVA_ExtendedFormat *)&vih->dwControlFlags; + UINT32 image_size, bitrate, sample_size, width, height, value; UINT64 frame_size, frame_rate; vih->bmiHeader.biSize = sizeof(vih->bmiHeader); @@ -3979,6 +3999,23 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, vih->rcSource.bottom = vih->rcTarget.bottom = height; } } + + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value))) + format->VideoChromaSubsampling = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value))) + format->NominalRange = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value))) + format->VideoTransferMatrix = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value))) + format->VideoLighting = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value))) + format->VideoPrimaries = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value))) + format->VideoTransferFunction = value; + + if (format->VideoChromaSubsampling || format->NominalRange || format->VideoTransferMatrix + || format->VideoLighting || format->VideoPrimaries || format->VideoTransferFunction) + format->SampleFormat = AMCONTROL_COLORINFO_PRESENT; } static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 1f49ef8c6f7..80c6b3d753d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10341,9 +10341,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoTransferMatrix_SMPTE240M, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -10353,9 +10351,7 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFNominalRange_Wide, "Unexpected value %#x.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); From 430683adc7c702409e74b5974110c79ba104f4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 15:48:08 +0100 Subject: [PATCH 046/301] mfplat/mediatype: Implement some VIDEOINFOHEADER2 dwInterlaceFlags conversion. (cherry picked from commit fc97535ccbc6856e74d302eec02d7c5c862794d0) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 24 +++++++++++++++++++++++- dlls/mfplat/tests/mfplat.c | 1 - 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index e2ad72204d4..87d53f687ab 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3785,7 +3785,6 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con mediatype_set_guid(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video, &hr); mediatype_set_guid(media_type, &MF_MT_SUBTYPE, subtype, &hr); mediatype_set_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, 1, 1, &hr); - mediatype_set_uint32(media_type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive, &hr); mediatype_set_uint64(media_type, &MF_MT_FRAME_SIZE, vih->bmiHeader.biWidth, height, &hr); if (SUCCEEDED(mf_get_stride_for_bitmap_info_header(subtype->Data1, &vih->bmiHeader, &stride))) @@ -3838,6 +3837,13 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con mediatype_set_uint32(media_type, &MF_MT_TRANSFER_FUNCTION, format->VideoTransferFunction, &hr); } + if (!(vih->dwInterlaceFlags & AMINTERLACE_IsInterlaced)) + mediatype_set_uint32(media_type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive, &hr); + else if (vih->dwInterlaceFlags & AMINTERLACE_DisplayModeBobOrWeave) + mediatype_set_uint32(media_type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_MixedInterlaceOrProgressive, &hr); + else + FIXME("dwInterlaceFlags %#lx not implemented\n", vih->dwInterlaceFlags); + return hr; } @@ -4016,6 +4022,22 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, if (format->VideoChromaSubsampling || format->NominalRange || format->VideoTransferMatrix || format->VideoLighting || format->VideoPrimaries || format->VideoTransferFunction) format->SampleFormat = AMCONTROL_COLORINFO_PRESENT; + + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value))) + { + switch (value) + { + case MFVideoInterlace_Progressive: + break; + case MFVideoInterlace_MixedInterlaceOrProgressive: + vih->dwInterlaceFlags = AMINTERLACE_DisplayModeBobOrWeave | AMINTERLACE_IsInterlaced; + break; + default: + FIXME("MF_MT_INTERLACE_MODE %u not implemented!\n", value); + vih->dwInterlaceFlags = AMINTERLACE_IsInterlaced; + break; + } + } } static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 80c6b3d753d..1de4ff0e78b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10311,7 +10311,6 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive, "Unexpected value %#x.\n", value32); vih.dwPictAspectRatioX = 123; From 5f462e6993ae43b8a275ac83bd267f004cae1039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Mar 2024 23:13:04 +0100 Subject: [PATCH 047/301] mfplat/tests: Test that aperture is dropped with VIDEOINFOHEADER2. But preserved with MFVIDEOFORMAT. (cherry picked from commit 7598556b64834e432b7a144d33af4996b5dda9a8) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 47 +++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 1de4ff0e78b..756fb04305b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7144,8 +7144,10 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) WAVEFORMATEXTENSIBLE *wave_format_ext; VIDEOINFOHEADER *video_info; WAVEFORMATEX *wave_format; - IMFMediaType *media_type; + IMFMediaType *media_type, *other_type; AM_MEDIA_TYPE am_type; + MFVideoArea *area; + UINT32 value32; HRESULT hr; hr = MFCreateMediaType(&media_type); @@ -7714,6 +7716,49 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) CoTaskMemFree(am_type.pbFormat); IMFMediaType_DeleteAllItems(media_type); + /* aperture is lost with VIDEOINFOHEADER(2), preserved with MFVIDEOFORMAT */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_NV12); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)1920 << 32 | 1088); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&other_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_VideoInfo, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromAMMediaType(other_type, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetAllocatedBlob(other_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE **)&area, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(other_type); + CoTaskMemFree(am_type.pbFormat); + + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_VideoInfo2, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromAMMediaType(other_type, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetAllocatedBlob(other_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE **)&area, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(other_type); + CoTaskMemFree(am_type.pbFormat); + + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MFVideoFormat, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromAMMediaType(other_type, &am_type); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetAllocatedBlob(other_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE **)&area, &value32); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) CoTaskMemFree(area); + IMFMediaType_DeleteAllItems(other_type); + CoTaskMemFree(am_type.pbFormat); + + IMFMediaType_Release(other_type); + IMFMediaType_Release(media_type); } From fbbf678ff3db605a5664174d8204b4dd86fe5802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Mar 2024 22:46:07 +0100 Subject: [PATCH 048/301] mfplat/tests: Test that MFCreateMFVideoFormatFromMFMediaType appends user data. (cherry picked from commit 75a5263c60882e4ed6e523ad69bf2dc0fb019a42) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 756fb04305b..dd3e5485677 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7121,16 +7121,43 @@ static void test_MFCreateMFVideoFormatFromMFMediaType(void) { MFVIDEOFORMAT *video_format; IMFMediaType *media_type; - UINT32 size; + UINT32 size, expect_size; + PALETTEENTRY palette[64]; + BYTE codec_data[32]; HRESULT hr; + hr = MFCreateMediaType(&media_type); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + expect_size = sizeof(*video_format); + hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!video_format, "Unexpected format.\n"); + ok(size == expect_size, "Unexpected size %u.\n", size); + ok(video_format->dwSize == size, "Unexpected size %u.\n", size); + CoTaskMemFree(video_format); + + memset(palette, 0xa5, sizeof(palette)); + expect_size = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(palette) + 1]); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_PALETTE, (BYTE *)palette, sizeof(palette)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!video_format, "Unexpected format.\n"); + todo_wine ok(size == expect_size, "Unexpected size %u.\n", size); + ok(video_format->dwSize == size, "Unexpected size %u.\n", size); + CoTaskMemFree(video_format); + + memset(codec_data, 0xcd, sizeof(codec_data)); + expect_size += sizeof(codec_data); + hr = IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!video_format, "Unexpected format.\n"); - ok(video_format->dwSize == size && size == sizeof(*video_format), "Unexpected size %u.\n", size); + todo_wine ok(size == expect_size, "Unexpected size %u.\n", size); + ok(video_format->dwSize == size, "Unexpected size %u.\n", size); CoTaskMemFree(video_format); IMFMediaType_Release(media_type); From 2c54257bcb747a1f5cc7812cf563ff96d1d3dd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 19:40:24 +0100 Subject: [PATCH 049/301] mfplat/mediatype: Append user data in MFCreateMFVideoFormatFromMFMediaType. (cherry picked from commit b1d7c03514b7f7a5a490c9208a80fdc9c7a38d3d) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 16 ++++++++++++---- dlls/mfplat/tests/mfplat.c | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 87d53f687ab..9eee04836df 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3249,17 +3249,20 @@ static UINT32 media_type_get_uint32(IMFMediaType *media_type, REFGUID guid) */ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size) { - UINT32 palette_size = 0; + UINT32 palette_size = 0, user_data_size = 0; MFVIDEOFORMAT *format; INT32 stride; GUID guid; TRACE("%p, %p, %p.\n", media_type, video_format, size); - *size = sizeof(*format); - if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_PALETTE, &palette_size))) - *size += palette_size; + *size = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[palette_size / sizeof(MFPaletteEntry) + 1]); + else + *size = sizeof(*format); + + if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_data_size))) + *size += user_data_size; if (!(format = CoTaskMemAlloc(*size))) return E_OUTOFMEMORY; @@ -3318,6 +3321,11 @@ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MF IMFMediaType_GetBlob(media_type, &MF_MT_PALETTE, (UINT8 *)format->surfaceInfo.Palette, palette_size, NULL); } + if (user_data_size) + { + IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (UINT8 *)format + *size - user_data_size, user_data_size, NULL); + } + return S_OK; } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index dd3e5485677..29c5d5db424 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7145,7 +7145,7 @@ static void test_MFCreateMFVideoFormatFromMFMediaType(void) hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!video_format, "Unexpected format.\n"); - todo_wine ok(size == expect_size, "Unexpected size %u.\n", size); + ok(size == expect_size, "Unexpected size %u.\n", size); ok(video_format->dwSize == size, "Unexpected size %u.\n", size); CoTaskMemFree(video_format); @@ -7156,7 +7156,7 @@ static void test_MFCreateMFVideoFormatFromMFMediaType(void) hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!video_format, "Unexpected format.\n"); - todo_wine ok(size == expect_size, "Unexpected size %u.\n", size); + ok(size == expect_size, "Unexpected size %u.\n", size); ok(video_format->dwSize == size, "Unexpected size %u.\n", size); CoTaskMemFree(video_format); From d95db35873a0003df1a23952616c25b103e7e4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Mar 2024 10:18:09 +0100 Subject: [PATCH 050/301] mfplat/tests: Check the conditions for the MFVideoFlag_BottomUpLinearRep flags. (cherry picked from commit fe0c129e0bfcdf38360b2ebca33e2a3c0d2c43bf) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 29c5d5db424..6aa6019d2f6 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7138,6 +7138,37 @@ static void test_MFCreateMFVideoFormatFromMFMediaType(void) ok(video_format->dwSize == size, "Unexpected size %u.\n", size); CoTaskMemFree(video_format); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)123 << 32 | 456); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 123 * 456 * 4); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_format->videoInfo.dwWidth == 123, "got %lu.\n", video_format->videoInfo.dwWidth); + ok(video_format->videoInfo.dwHeight == 456, "got %lu.\n", video_format->videoInfo.dwHeight); + ok(video_format->videoInfo.VideoFlags == 0, "got %#I64x.\n", video_format->videoInfo.VideoFlags); + CoTaskMemFree(video_format); + + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, 123 * 4); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_format->videoInfo.VideoFlags == 0, "got %#I64x.\n", video_format->videoInfo.VideoFlags); + CoTaskMemFree(video_format); + + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -123 * 4); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &video_format, &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_format->videoInfo.VideoFlags == MFVideoFlag_BottomUpLinearRep, "got %#I64x.\n", video_format->videoInfo.VideoFlags); + CoTaskMemFree(video_format); + + memset(palette, 0xa5, sizeof(palette)); expect_size = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(palette) + 1]); hr = IMFMediaType_SetBlob(media_type, &MF_MT_PALETTE, (BYTE *)palette, sizeof(palette)); From 6aada8542aafc206cdf529bddf129374ff9b8270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 23:03:31 +0100 Subject: [PATCH 051/301] mfplat/mediatype: Stub MFInitMediaTypeFromMFVideoFormat. (cherry picked from commit a712d7ec871e5bd87ec0edfdf1e95991faadbd43) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 9 +++++++++ dlls/mfplat/mfplat.spec | 2 +- include/mfapi.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 9eee04836df..c6f2cb757e5 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3760,6 +3760,15 @@ HRESULT WINAPI MFCreateVideoMediaTypeFromVideoInfoHeader(const KS_VIDEOINFOHEADE return E_NOTIMPL; } +/*********************************************************************** + * MFInitMediaTypeFromMFVideoFormat (mfplat.@) + */ +HRESULT WINAPI MFInitMediaTypeFromMFVideoFormat(IMFMediaType *media_type, const MFVIDEOFORMAT *format, UINT32 size) +{ + FIXME("%p, %p, %u\n", media_type, format, size); + return E_NOTIMPL; +} + /*********************************************************************** * MFInitMediaTypeFromVideoInfoHeader2 (mfplat.@) */ diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 44d1b89fff5..d8a6eb5ce83 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -120,7 +120,7 @@ @ stdcall MFInitAMMediaTypeFromMFMediaType(ptr int128 ptr) @ stdcall MFInitAttributesFromBlob(ptr ptr long) @ stdcall MFInitMediaTypeFromAMMediaType(ptr ptr) -@ stub MFInitMediaTypeFromMFVideoFormat +@ stdcall MFInitMediaTypeFromMFVideoFormat(ptr ptr long) @ stub MFInitMediaTypeFromMPEG1VideoInfo @ stub MFInitMediaTypeFromMPEG2VideoInfo @ stdcall MFInitMediaTypeFromVideoInfoHeader2(ptr ptr long ptr) diff --git a/include/mfapi.h b/include/mfapi.h index 27b0f4fd841..f986edd0d5a 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -593,6 +593,7 @@ BOOL WINAPI MFIsFormatYUV(DWORD format); HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 *buffer, UINT size); HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID format, AM_MEDIA_TYPE *am_type); HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *mediatype, const AM_MEDIA_TYPE *am_type); +HRESULT WINAPI MFInitMediaTypeFromMFVideoFormat(IMFMediaType *media_type, const MFVIDEOFORMAT *format, UINT32 size); HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, const VIDEOINFOHEADER *vih, UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, const VIDEOINFOHEADER2 *vih, From f04fa2f785b4c0a9154eb17400cad6695f70d4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Mar 2024 08:01:50 +0100 Subject: [PATCH 052/301] mfplat/tests: Add tests for MFInitMediaTypeFromMFVideoFormat. (cherry picked from commit 899abeafe42cfe9b2ca717bfdfc96ae79391eec5) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 557 +++++++++++++++++++++++++++++++++++++ 1 file changed, 557 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 6aa6019d2f6..5f0d5c43b77 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7856,6 +7856,562 @@ static void test_MFCreateAMMediaTypeFromMFMediaType(void) IMFMediaType_Release(media_type); } +static void test_MFInitMediaTypeFromMFVideoFormat(void) +{ + static const MFPaletteEntry expect_palette[] = {{{1}},{{2}},{{3}},{{4}},{{5}},{{6}},{{7}},{{8}}}; + static const BYTE expect_user_data[] = {6,5,4,3,2,1}; + MFPaletteEntry palette[ARRAY_SIZE(expect_palette)]; + BYTE user_data[sizeof(expect_user_data)]; + char buffer[sizeof(MFVIDEOFORMAT) + sizeof(palette) + sizeof(user_data)]; + MFVIDEOFORMAT format, *format_buf = (MFVIDEOFORMAT *)buffer; + IMFMediaType *media_type; + MFVideoArea aperture; + UINT32 i, value32; + UINT64 value64; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromMFVideoFormat(media_type, NULL, 0); + todo_wine + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + memset(&format, 0, sizeof(format)); + format.dwSize = sizeof(format) - 1; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format) - 1); + todo_wine + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + format.dwSize = sizeof(format); + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format) - 1); + todo_wine + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(IsEqualGUID(&guid, &MFMediaType_Video), "got %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.guidFormat = MFVideoFormat_H264; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(IsEqualGUID(&guid, &MFVideoFormat_H264), "got %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.guidFormat = MFVideoFormat_RGB32; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "got %s.\n", debugstr_guid(&guid)); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %u.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %u.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.dwWidth = -123; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), "Unexpected hr %#lx.\n", hr); + format.videoInfo.dwWidth = 123; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + format.videoInfo.dwHeight = -456; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), "Unexpected hr %#lx.\n", hr); + format.videoInfo.dwHeight = 456; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value64 = 0xdeadbeef; + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == (((UINT64)123 << 32) | 456), "got %#I64x.\n", value64); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 123 * 4, "got %u.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 123 * 4 * 456, "got %u.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + /* MFVideoFlag_BottomUpLinearRep flag inverts the stride */ + format.videoInfo.VideoFlags = MFVideoFlag_BottomUpLinearRep; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == -123 * 4, "got %u.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 123 * 4 * 456, "got %u.\n", value32); + IMFMediaType_DeleteAllItems(media_type); + + /* MFVideoFlag_BottomUpLinearRep flag only works with RGB formats */ + format.guidFormat = MFVideoFormat_H264; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.guidFormat = MFVideoFormat_NV12; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 124, "got %u.\n", value32); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 124 * 456 * 3 / 2, "got %u.\n", value32); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.PixelAspectRatio.Numerator = 7; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + format.videoInfo.PixelAspectRatio.Denominator = 8; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value64 = 0xdeadbeef; + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == (((UINT64)7 << 32) | 8), "got %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.SourceChromaSubsampling = MFVideoChromaSubsampling_MPEG2; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoChromaSubsampling_MPEG2, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.InterlaceMode = MFVideoInterlace_MixedInterlaceOrProgressive; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.TransferFunction = MFVideoTransFunc_709; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoTransFunc_709, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.ColorPrimaries = MFVideoPrimaries_BT709; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoPrimaries_BT709, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.TransferMatrix = MFVideoTransferMatrix_BT709; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoTransferMatrix_BT709, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.SourceLighting = MFVideoLighting_bright; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFVideoLighting_bright, "got %u.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.FramesPerSecond.Numerator = 30000; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + format.videoInfo.FramesPerSecond.Denominator = 1001; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value64 = 0xdeadbeef; + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value64 == (((UINT64)30000 << 32) | 1001), "got %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.NominalRange = MFNominalRange_Wide; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == MFNominalRange_Wide, "got %u.\n", value32); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_GEOMETRIC_APERTURE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.GeometricAperture.OffsetX.value = 1; + format.videoInfo.GeometricAperture.OffsetX.fract = 2; + format.videoInfo.GeometricAperture.OffsetY.value = 3; + format.videoInfo.GeometricAperture.OffsetY.fract = 4; + format.videoInfo.GeometricAperture.Area.cx = -120; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + format.videoInfo.GeometricAperture.Area.cy = -450; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %u.\n", value32); + todo_wine + ok(!memcmp(&format.videoInfo.GeometricAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.MinimumDisplayAperture.OffsetX.value = 1; + format.videoInfo.MinimumDisplayAperture.OffsetX.fract = 2; + format.videoInfo.MinimumDisplayAperture.OffsetY.value = 3; + format.videoInfo.MinimumDisplayAperture.OffsetY.fract = 4; + format.videoInfo.MinimumDisplayAperture.Area.cx = 120; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + format.videoInfo.MinimumDisplayAperture.Area.cy = 450; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %u.\n", value32); + todo_wine + ok(!memcmp(&format.videoInfo.MinimumDisplayAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PAN_SCAN_APERTURE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.PanScanAperture.OffsetX.value = 1; + format.videoInfo.PanScanAperture.OffsetX.fract = 2; + format.videoInfo.PanScanAperture.OffsetY.value = 3; + format.videoInfo.PanScanAperture.OffsetY.fract = 4; + format.videoInfo.PanScanAperture.Area.cx = 120; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + format.videoInfo.PanScanAperture.Area.cy = 450; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&aperture, 0xcd, sizeof(aperture)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(aperture), "got %u.\n", value32); + todo_wine + ok(!memcmp(&format.videoInfo.PanScanAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.VideoFlags |= MFVideoFlag_PanScanEnabled; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAD_CONTROL_FLAGS, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.VideoFlags |= MFVideoFlag_PAD_TO_16x9; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAD_CONTROL_FLAGS, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 2, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SOURCE_CONTENT_HINT, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.VideoFlags |= MFVideoFlag_SrcContentHint16x9; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SOURCE_CONTENT_HINT, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 1, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DRM_FLAGS, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.videoInfo.VideoFlags |= MFVideoFlag_DigitallyProtected; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DRM_FLAGS, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 2, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.compressedInfo.AvgBitrate = 123456; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 123456, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.compressedInfo.AvgBitErrorRate = 654321; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == 654321, "got %u.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + format.compressedInfo.MaxKeyFrameSpacing = -123; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == -123, "got %u.\n", value32); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PALETTE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + /* any subtype works here */ + format.guidFormat = MFVideoFormat_H264; + format.surfaceInfo.Format = MFVideoFormat_H264.Data1; + hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PALETTE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + *format_buf = format; + for (i = 0; i < ARRAY_SIZE(expect_palette); i++) + format_buf->surfaceInfo.Palette[i] = expect_palette[i]; + format_buf->surfaceInfo.PaletteEntries = ARRAY_SIZE(expect_palette); + + /* format sizes needs to include an extra palette entry */ + format_buf->dwSize = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(expect_palette)]); + hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, sizeof(format)); + todo_wine + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + format_buf->dwSize = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(expect_palette) + 1]); + hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, format_buf->dwSize); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&palette, 0xcd, sizeof(palette)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_PALETTE, (BYTE *)&palette, sizeof(palette), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(expect_palette), "got %u.\n", value32); + todo_wine + ok(!memcmp(palette, expect_palette, value32), "Unexpected palette.\n"); + hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); + + memcpy(buffer + format_buf->dwSize, expect_user_data, sizeof(expect_user_data)); + format_buf->dwSize += sizeof(expect_user_data); + hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, format_buf->dwSize); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&user_data, 0xcd, sizeof(user_data)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(user_data), &value32); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value32 == sizeof(expect_user_data), "got %u.\n", value32); + todo_wine + ok(!memcmp(user_data, expect_user_data, value32), "Unexpected user data.\n"); + IMFMediaType_DeleteAllItems(media_type); + + IMFMediaType_Release(media_type); +} + static void test_IMFMediaType_GetRepresentation(void) { WAVEFORMATEX wfx = {.wFormatTag = WAVE_FORMAT_PCM}; @@ -11191,6 +11747,7 @@ START_TEST(mfplat) test_MFCreateMFVideoFormatFromMFMediaType(); test_MFInitAMMediaTypeFromMFMediaType(); test_MFCreateAMMediaTypeFromMFMediaType(); + test_MFInitMediaTypeFromMFVideoFormat(); test_IMFMediaType_GetRepresentation(); test_MFCreateDXSurfaceBuffer(); test_MFCreateTrackedSample(); From 712af78b7143610c88f1d07c59b1c1d917b8b07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Mar 2024 11:53:36 +0100 Subject: [PATCH 053/301] mfplat/mediatype: Implement MFInitMediaTypeFromMFVideoFormat. (cherry picked from commit eac5ad2a2618218028b7c563b5b3e0b6efafdf76) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 91 ++++++++++++++++++++++++++++++- dlls/mfplat/tests/mfplat.c | 109 ------------------------------------- 2 files changed, 89 insertions(+), 111 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index c6f2cb757e5..c06dd9f7687 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3765,8 +3765,95 @@ HRESULT WINAPI MFCreateVideoMediaTypeFromVideoInfoHeader(const KS_VIDEOINFOHEADE */ HRESULT WINAPI MFInitMediaTypeFromMFVideoFormat(IMFMediaType *media_type, const MFVIDEOFORMAT *format, UINT32 size) { - FIXME("%p, %p, %u\n", media_type, format, size); - return E_NOTIMPL; + UINT32 stride, sample_size, palette_size, user_data_size, value; + struct uncompressed_video_format *video_format; + const void *user_data; + HRESULT hr = S_OK; + + TRACE("%p, %p, %u\n", media_type, format, size); + + if (!format || size < sizeof(*format) || format->dwSize != size) + return E_INVALIDARG; + if (size < offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[format->surfaceInfo.PaletteEntries + 1])) + return E_INVALIDARG; + + mediatype_set_guid(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video, &hr); + if (!IsEqualGUID(&format->guidFormat, &GUID_NULL)) + mediatype_set_guid(media_type, &MF_MT_SUBTYPE, &format->guidFormat, &hr); + if ((video_format = mf_get_video_format(&format->guidFormat))) + { + mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); + mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); + } + + if (format->videoInfo.dwWidth && format->videoInfo.dwHeight) + { + mediatype_set_uint64(media_type, &MF_MT_FRAME_SIZE, format->videoInfo.dwWidth, format->videoInfo.dwHeight, &hr); + + if (video_format && (stride = mf_get_stride_for_format(video_format, format->videoInfo.dwWidth))) + { + if (!video_format->yuv && (format->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep)) + stride = -stride; + mediatype_set_uint32(media_type, &MF_MT_DEFAULT_STRIDE, stride, &hr); + } + + if (SUCCEEDED(MFCalculateImageSize(&format->guidFormat, format->videoInfo.dwWidth, format->videoInfo.dwHeight, &sample_size))) + mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, sample_size, &hr); + } + + if (format->videoInfo.PixelAspectRatio.Denominator) + mediatype_set_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, format->videoInfo.PixelAspectRatio.Numerator, + format->videoInfo.PixelAspectRatio.Denominator, &hr); + if (format->videoInfo.SourceChromaSubsampling) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_CHROMA_SITING, format->videoInfo.SourceChromaSubsampling, &hr); + if (format->videoInfo.InterlaceMode) + mediatype_set_uint32(media_type, &MF_MT_INTERLACE_MODE, format->videoInfo.InterlaceMode, &hr); + if (format->videoInfo.TransferFunction) + mediatype_set_uint32(media_type, &MF_MT_TRANSFER_FUNCTION, format->videoInfo.TransferFunction, &hr); + if (format->videoInfo.ColorPrimaries) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_PRIMARIES, format->videoInfo.ColorPrimaries, &hr); + if (format->videoInfo.TransferMatrix) + mediatype_set_uint32(media_type, &MF_MT_YUV_MATRIX, format->videoInfo.TransferMatrix, &hr); + if (format->videoInfo.SourceLighting) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_LIGHTING, format->videoInfo.SourceLighting, &hr); + if (format->videoInfo.FramesPerSecond.Denominator) + mediatype_set_uint64(media_type, &MF_MT_FRAME_RATE, format->videoInfo.FramesPerSecond.Numerator, + format->videoInfo.FramesPerSecond.Denominator, &hr); + if (format->videoInfo.NominalRange) + mediatype_set_uint32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, format->videoInfo.NominalRange, &hr); + if (format->videoInfo.GeometricAperture.Area.cx && format->videoInfo.GeometricAperture.Area.cy) + mediatype_set_blob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&format->videoInfo.GeometricAperture, + sizeof(format->videoInfo.GeometricAperture), &hr); + if (format->videoInfo.MinimumDisplayAperture.Area.cx && format->videoInfo.MinimumDisplayAperture.Area.cy) + mediatype_set_blob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&format->videoInfo.MinimumDisplayAperture, + sizeof(format->videoInfo.MinimumDisplayAperture), &hr); + if (format->videoInfo.PanScanAperture.Area.cx && format->videoInfo.PanScanAperture.Area.cy) + mediatype_set_blob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&format->videoInfo.PanScanAperture, + sizeof(format->videoInfo.PanScanAperture), &hr); + if ((value = !!(format->videoInfo.VideoFlags & MFVideoFlag_PanScanEnabled))) + mediatype_set_uint32(media_type, &MF_MT_PAN_SCAN_ENABLED, value, &hr); + if ((value = format->videoInfo.VideoFlags & MFVideoFlag_PAD_TO_Mask)) + mediatype_set_uint32(media_type, &MF_MT_PAD_CONTROL_FLAGS, value, &hr); + if ((value = format->videoInfo.VideoFlags & MFVideoFlag_SrcContentHintMask)) + mediatype_set_uint32(media_type, &MF_MT_SOURCE_CONTENT_HINT, value >> 2, &hr); + if ((value = format->videoInfo.VideoFlags & (MFVideoFlag_AnalogProtected | MFVideoFlag_DigitallyProtected))) + mediatype_set_uint32(media_type, &MF_MT_DRM_FLAGS, value >> 5, &hr); + + if (format->compressedInfo.AvgBitrate) + mediatype_set_uint32(media_type, &MF_MT_AVG_BITRATE, format->compressedInfo.AvgBitrate, &hr); + if (format->compressedInfo.AvgBitErrorRate) + mediatype_set_uint32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, format->compressedInfo.AvgBitErrorRate, &hr); + if (format->compressedInfo.MaxKeyFrameSpacing) + mediatype_set_uint32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, format->compressedInfo.MaxKeyFrameSpacing, &hr); + + if ((palette_size = format->surfaceInfo.PaletteEntries * sizeof(*format->surfaceInfo.Palette))) + mediatype_set_blob(media_type, &MF_MT_PALETTE, (BYTE *)format->surfaceInfo.Palette, palette_size, &hr); + + user_data = &format->surfaceInfo.Palette[format->surfaceInfo.PaletteEntries + 1]; + if ((user_data_size = (BYTE *)format + format->dwSize - (BYTE *)user_data)) + mediatype_set_blob(media_type, &MF_MT_USER_DATA, user_data, user_data_size, &hr); + + return hr; } /*********************************************************************** diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 5f0d5c43b77..4f7f702fb1f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7875,27 +7875,21 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFInitMediaTypeFromMFVideoFormat(media_type, NULL, 0); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); memset(&format, 0, sizeof(format)); format.dwSize = sizeof(format) - 1; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format) - 1); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); format.dwSize = sizeof(format); hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format) - 1); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); memset(&guid, 0xcd, sizeof(guid)); hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&guid, &MFMediaType_Video), "got %s.\n", debugstr_guid(&guid)); hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -7903,13 +7897,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.guidFormat = MFVideoFormat_H264; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); memset(&guid, 0xcd, sizeof(guid)); hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_H264), "got %s.\n", debugstr_guid(&guid)); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -7919,25 +7910,18 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.guidFormat = MFVideoFormat_RGB32; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); memset(&guid, 0xcd, sizeof(guid)); hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&guid, &MFVideoFormat_RGB32), "got %s.\n", debugstr_guid(&guid)); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %u.\n", value32); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %u.\n", value32); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -7953,7 +7937,6 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) ok(hr == HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), "Unexpected hr %#lx.\n", hr); format.videoInfo.dwWidth = 123; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -7964,25 +7947,18 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) ok(hr == HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), "Unexpected hr %#lx.\n", hr); format.videoInfo.dwHeight = 456; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value64 = 0xdeadbeef; hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value64 == (((UINT64)123 << 32) | 456), "got %#I64x.\n", value64); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 123 * 4, "got %u.\n", value32); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 123 * 4 * 456, "got %u.\n", value32); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -7991,26 +7967,20 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) /* MFVideoFlag_BottomUpLinearRep flag inverts the stride */ format.videoInfo.VideoFlags = MFVideoFlag_BottomUpLinearRep; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == -123 * 4, "got %u.\n", value32); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 123 * 4 * 456, "got %u.\n", value32); IMFMediaType_DeleteAllItems(media_type); /* MFVideoFlag_BottomUpLinearRep flag only works with RGB formats */ format.guidFormat = MFVideoFormat_H264; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8020,38 +7990,30 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.guidFormat = MFVideoFormat_NV12; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); todo_wine ok(value32 == 124, "got %u.\n", value32); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 124 * 456 * 3 / 2, "got %u.\n", value32); IMFMediaType_DeleteAllItems(media_type); format.videoInfo.PixelAspectRatio.Numerator = 7; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); IMFMediaType_DeleteAllItems(media_type); format.videoInfo.PixelAspectRatio.Denominator = 8; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value64 = 0xdeadbeef; hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value64 == (((UINT64)7 << 32) | 8), "got %#I64x.\n", value64); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8059,13 +8021,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.SourceChromaSubsampling = MFVideoChromaSubsampling_MPEG2; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoChromaSubsampling_MPEG2, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8073,13 +8032,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.InterlaceMode = MFVideoInterlace_MixedInterlaceOrProgressive; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8087,13 +8043,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.TransferFunction = MFVideoTransFunc_709; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoTransFunc_709, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8101,13 +8054,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.ColorPrimaries = MFVideoPrimaries_BT709; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoPrimaries_BT709, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8115,13 +8065,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.TransferMatrix = MFVideoTransferMatrix_BT709; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoTransferMatrix_BT709, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8129,13 +8076,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.SourceLighting = MFVideoLighting_bright; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFVideoLighting_bright, "got %u.\n", value32); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8143,20 +8087,16 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.FramesPerSecond.Numerator = 30000; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); IMFMediaType_DeleteAllItems(media_type); format.videoInfo.FramesPerSecond.Denominator = 1001; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value64 = 0xdeadbeef; hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &value64); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value64 == (((UINT64)30000 << 32) | 1001), "got %#I64x.\n", value64); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8164,13 +8104,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.NominalRange = MFNominalRange_Wide; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == MFNominalRange_Wide, "got %u.\n", value32); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_GEOMETRIC_APERTURE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8182,22 +8119,17 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.GeometricAperture.OffsetY.fract = 4; format.videoInfo.GeometricAperture.Area.cx = -120; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); format.videoInfo.GeometricAperture.Area.cy = -450; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %u.\n", value32); - todo_wine ok(!memcmp(&format.videoInfo.GeometricAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8209,22 +8141,17 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.MinimumDisplayAperture.OffsetY.fract = 4; format.videoInfo.MinimumDisplayAperture.Area.cx = 120; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); format.videoInfo.MinimumDisplayAperture.Area.cy = 450; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %u.\n", value32); - todo_wine ok(!memcmp(&format.videoInfo.MinimumDisplayAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PAN_SCAN_APERTURE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8236,22 +8163,17 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.PanScanAperture.OffsetY.fract = 4; format.videoInfo.PanScanAperture.Area.cx = 120; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); format.videoInfo.PanScanAperture.Area.cy = 450; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; memset(&aperture, 0xcd, sizeof(aperture)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(aperture), "got %u.\n", value32); - todo_wine ok(!memcmp(&format.videoInfo.PanScanAperture, &aperture, sizeof(aperture)), "Unexpected aperture.\n"); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8259,13 +8181,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.VideoFlags |= MFVideoFlag_PanScanEnabled; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAN_SCAN_ENABLED, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAD_CONTROL_FLAGS, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8273,13 +8192,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.VideoFlags |= MFVideoFlag_PAD_TO_16x9; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_PAD_CONTROL_FLAGS, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 2, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SOURCE_CONTENT_HINT, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8287,13 +8203,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.VideoFlags |= MFVideoFlag_SrcContentHint16x9; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SOURCE_CONTENT_HINT, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 1, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DRM_FLAGS, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8301,13 +8214,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.videoInfo.VideoFlags |= MFVideoFlag_DigitallyProtected; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DRM_FLAGS, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 2, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8315,13 +8225,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.compressedInfo.AvgBitrate = 123456; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 123456, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8329,13 +8236,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.compressedInfo.AvgBitErrorRate = 654321; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == 654321, "got %u.\n", value32); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8343,13 +8247,10 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.compressedInfo.MaxKeyFrameSpacing = -123; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == -123, "got %u.\n", value32); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PALETTE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8359,7 +8260,6 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) format.guidFormat = MFVideoFormat_H264; format.surfaceInfo.Format = MFVideoFormat_H264.Data1; hr = MFInitMediaTypeFromMFVideoFormat(media_type, &format, sizeof(format)); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_PALETTE, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8373,21 +8273,16 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) /* format sizes needs to include an extra palette entry */ format_buf->dwSize = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(expect_palette)]); hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, sizeof(format)); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); format_buf->dwSize = offsetof(MFVIDEOFORMAT, surfaceInfo.Palette[ARRAY_SIZE(expect_palette) + 1]); hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, format_buf->dwSize); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; memset(&palette, 0xcd, sizeof(palette)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_PALETTE, (BYTE *)&palette, sizeof(palette), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(expect_palette), "got %u.\n", value32); - todo_wine ok(!memcmp(palette, expect_palette, value32), "Unexpected palette.\n"); hr = IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &value32); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -8396,16 +8291,12 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) memcpy(buffer + format_buf->dwSize, expect_user_data, sizeof(expect_user_data)); format_buf->dwSize += sizeof(expect_user_data); hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, format_buf->dwSize); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value32 = 0xdeadbeef; memset(&user_data, 0xcd, sizeof(user_data)); hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(user_data), &value32); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value32 == sizeof(expect_user_data), "got %u.\n", value32); - todo_wine ok(!memcmp(user_data, expect_user_data, value32), "Unexpected user data.\n"); IMFMediaType_DeleteAllItems(media_type); From 94c7eee7be6be8b580b00220a648e42f77fd83a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Mar 2024 09:55:00 +0100 Subject: [PATCH 054/301] mfplat/tests: Add some broken results for Win7. (cherry picked from commit 2734b266de6562a6693d5b8b8219222911d9ffb5) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 4f7f702fb1f..58f6aace333 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -10861,7 +10861,9 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive, "Unexpected value %#x.\n", value32); + ok(value32 == MFVideoInterlace_MixedInterlaceOrProgressive + || broken(value32 == MFVideoInterlace_FieldInterleavedLowerFirst) /* Win7 */, + "Unexpected value %#x.\n", value32); vih.dwPictAspectRatioX = 123; hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih, sizeof(vih), &GUID_NULL); From 75d8696fc0496053f2890a42e60aad1aa1a52781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Mar 2024 21:22:08 +0100 Subject: [PATCH 055/301] mfplat/tests: Test initializing mediatype from AAC WAVEFORMATEXTENSIBLE. (cherry picked from commit 3593ce002fe68a44d729eee47ce139b2e933a971) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 71 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 58f6aace333..4d74631ecc6 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6999,6 +6999,7 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) HEAACWAVEFORMAT aacformat; IMFMediaType *mediatype; unsigned int i, size; + WAVEFORMATEX *wfx; UINT32 value; HRESULT hr; @@ -7088,6 +7089,15 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) ok(size == aacformat.wfInfo.wfx.cbSize, "Unexpected size %u.\n", size); ok(!memcmp(buff, (WAVEFORMATEX *)&aacformat + 1, size), "Unexpected user data.\n"); + /* check that we get an HEAACWAVEFORMAT by default */ + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(wfx->wFormatTag == WAVE_FORMAT_MPEG_HEAAC, "got wFormatTag %#x\n", wfx->wFormatTag); + ok(wfx->cbSize == sizeof(HEAACWAVEFORMAT) - sizeof(WAVEFORMATEX), "got cbSize %u\n", wfx->cbSize); + ok(!memcmp(wfx + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); + CoTaskMemFree(wfx); + + /* MFWaveFormatExConvertFlag_ForceExtensible can force a WAVEFORMATEXTENSIBLE */ hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&format, &size, MFWaveFormatExConvertFlag_ForceExtensible); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE, "got wFormatTag %#x\n", format->Format.wFormatTag); @@ -7099,6 +7109,62 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) ok(!memcmp(format + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); CoTaskMemFree(format); + /* adding more channels has no immediate effect */ + hr = IMFMediaType_SetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, 6); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, 63); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(wfx->wFormatTag == WAVE_FORMAT_MPEG_HEAAC, "got wFormatTag %#x\n", wfx->wFormatTag); + ok(wfx->cbSize == sizeof(HEAACWAVEFORMAT) - sizeof(WAVEFORMATEX), "got cbSize %u\n", wfx->cbSize); + ok(!memcmp(wfx + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); + CoTaskMemFree(wfx); + + /* but adding MF_MT_AUDIO_SAMPLES_PER_BLOCK as well forces the WAVEFORMATEXTENSIBLE format */ + hr = IMFMediaType_SetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, 4); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&format, &size, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE, "got wFormatTag %#x\n", format->Format.wFormatTag); + todo_wine + ok(format->Format.cbSize == aacformat.wfInfo.wfx.cbSize + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), + "got cbSize %u\n", format->Format.cbSize); + todo_wine + ok(IsEqualGUID(&format->SubFormat, &MFAudioFormat_AAC), "got SubFormat %s\n", debugstr_guid(&format->SubFormat)); + todo_wine + ok(format->dwChannelMask == 63, "got dwChannelMask %#lx\n", format->dwChannelMask); + todo_wine + ok(format->Samples.wSamplesPerBlock == 4, "got wSamplesPerBlock %u\n", format->Samples.wSamplesPerBlock); + todo_wine + ok(!memcmp(format + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); + + /* test initializing media type from an WAVE_FORMAT_EXTENSIBLE AAC format */ + IMFMediaType_DeleteAllItems(mediatype); + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, (WAVEFORMATEX *)format, sizeof(WAVEFORMATEX) + format->Format.cbSize); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CoTaskMemFree(format); + + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &value); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Failed to get attribute, hr %#lx.\n", hr); + todo_wine + ok(value == 0xdeadbeef, "Unexpected AAC_AUDIO_PROFILE_LEVEL_INDICATION %u.\n", value); + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_PAYLOAD_TYPE, &value); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Failed to get attribute, hr %#lx.\n", hr); + todo_wine + ok(value == 0xdeadbeef, "Unexpected AAC_PAYLOAD_TYPE %u.\n", value); + + hr = IMFMediaType_GetBlob(mediatype, &MF_MT_USER_DATA, buff, sizeof(buff), &size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(size == aacformat.wfInfo.wfx.cbSize, "Unexpected size %u.\n", size); + ok(!memcmp(buff, (WAVEFORMATEX *)&aacformat + 1, size), "Unexpected user data.\n"); + + /* test with invalid format size */ aacformat.wfInfo.wfx.cbSize = 1; hr = IMFMediaType_SetBlob(mediatype, &MF_MT_USER_DATA, buff, aacformat.wfInfo.wfx.cbSize); @@ -7109,8 +7175,9 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) ok(format->Format.cbSize == aacformat.wfInfo.wfx.cbSize + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), "got cbSize %u\n", format->Format.cbSize); ok(IsEqualGUID(&format->SubFormat, &MFAudioFormat_AAC), "got SubFormat %s\n", debugstr_guid(&format->SubFormat)); - ok(format->dwChannelMask == 3, "got dwChannelMask %#lx\n", format->dwChannelMask); - ok(format->Samples.wSamplesPerBlock == 0, "got wSamplesPerBlock %u\n", format->Samples.wSamplesPerBlock); + ok(format->dwChannelMask == 63, "got dwChannelMask %#lx\n", format->dwChannelMask); + todo_wine + ok(format->Samples.wSamplesPerBlock == 4, "got wSamplesPerBlock %u\n", format->Samples.wSamplesPerBlock); ok(!memcmp(format + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); CoTaskMemFree(format); From 235774bbcdbc363f07c33944b159d167164085a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Mar 2024 09:46:36 +0100 Subject: [PATCH 056/301] mfplat/tests: Check how AAC attributes are copied from user data. (cherry picked from commit 9ee0720d98f89bb840332f21e4b79119fe78a73a) CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 4d74631ecc6..3b6cc186c8e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -74,6 +74,7 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB1555, D3DFMT_A1R5G5B5); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB4444, D3DFMT_A4R4G4B4); /* SDK MFVideoFormat_A2R10G10B10 uses D3DFMT_A2B10G10R10, let's name it the other way */ DEFINE_MEDIATYPE_GUID(MFVideoFormat_A2B10G10R10, D3DFMT_A2R10G10B10); +DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_h264,MAKEFOURCC('h','2','6','4')); DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_MP3,WAVE_FORMAT_MPEGLAYER3); @@ -6992,6 +6993,15 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) { WAVE_FORMAT_WMASPDIF }, }; + static const BYTE aac_codec_data[] = + { + 0x12, 0x00, + 0x34, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x12, 0x08, + }; UINT8 buff[1024]; WAVEFORMATEXTENSIBLE waveformatext; MPEGLAYER3WAVEFORMAT mp3format; @@ -7181,6 +7191,84 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) ok(!memcmp(format + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); CoTaskMemFree(format); + IMFMediaType_DeleteAllItems(mediatype); + + + /* check that HEAACWAVEFORMAT extra fields are copied directly from MF_MT_USER_DATA */ + aacformat.wfInfo.wfx.cbSize = sizeof(aacformat) - sizeof(WAVEFORMATEX); + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, (WAVEFORMATEX *)&aacformat, sizeof(aacformat)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_USER_DATA); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(wfx->wFormatTag == WAVE_FORMAT_MPEG_HEAAC, "got wFormatTag %#x\n", wfx->wFormatTag); + ok(wfx->cbSize == 0, "got cbSize %u\n", wfx->cbSize); + CoTaskMemFree(wfx); + } + + hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_AAC_PAYLOAD_TYPE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(mediatype, &MF_MT_USER_DATA, aac_codec_data, sizeof(aac_codec_data)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(wfx->wFormatTag == WAVE_FORMAT_MPEG_HEAAC, "got wFormatTag %#x\n", wfx->wFormatTag); + ok(wfx->cbSize == sizeof(aac_codec_data), "got cbSize %u\n", wfx->cbSize); + memcpy(&aacformat, wfx, sizeof(aacformat)); + ok(aacformat.wfInfo.wPayloadType == 0x12, "got %u\n", aacformat.wfInfo.wPayloadType); + ok(aacformat.wfInfo.wAudioProfileLevelIndication == 0x34, "got %u\n", aacformat.wfInfo.wAudioProfileLevelIndication); + + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, wfx, sizeof(*wfx) + wfx->cbSize); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_PAYLOAD_TYPE, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + ok(value == 0x12, "Unexpected AAC_PAYLOAD_TYPE %u.\n", value); + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + ok(value == 0x34, "Unexpected AAC_AUDIO_PROFILE_LEVEL_INDICATION %u.\n", value); + + CoTaskMemFree(wfx); + + + /* check that RAW AAC doesn't have MF_MT_AAC_* attributes */ + aacformat.wfInfo.wfx.cbSize = sizeof(aacformat) - sizeof(WAVEFORMATEX); + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, (WAVEFORMATEX *)&aacformat, sizeof(aacformat)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFAudioFormat_RAW_AAC); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_AAC_PAYLOAD_TYPE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(mediatype, &MF_MT_USER_DATA, aac_codec_data, sizeof(aac_codec_data)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(wfx->wFormatTag == WAVE_FORMAT_RAW_AAC1, "got wFormatTag %#x\n", wfx->wFormatTag); + ok(wfx->cbSize == sizeof(aac_codec_data), "got cbSize %u\n", wfx->cbSize); + + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, wfx, sizeof(*wfx) + wfx->cbSize); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_PAYLOAD_TYPE, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Failed to get attribute, hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Failed to get attribute, hr %#lx.\n", hr); + + CoTaskMemFree(wfx); + + IMFMediaType_Release(mediatype); } From 5547d5fe5e0b3097e4ef7426d842a63caa8a0a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 19:58:36 +0100 Subject: [PATCH 057/301] mfplat/mediatype: Check format pointers and sizes in MFInitMediaTypeFromAMMediaType. (cherry picked from commit 45d4aa9f606e6c41ea78e10e205883bcc4e33a15) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index c06dd9f7687..7955de8ca7a 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4274,13 +4274,17 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM { const GUID *subtype = get_mf_subtype_for_am_subtype(&am_type->subtype); - if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo)) + if (am_type->cbFormat && !am_type->pbFormat) + hr = E_INVALIDARG; + else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) + && am_type->cbFormat >= sizeof(VIDEOINFOHEADER)) hr = MFInitMediaTypeFromVideoInfoHeader(media_type, (VIDEOINFOHEADER *)am_type->pbFormat, am_type->cbFormat, subtype); - else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2)) + else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2) + && am_type->cbFormat >= sizeof(VIDEOINFOHEADER2)) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, (VIDEOINFOHEADER2 *)am_type->pbFormat, am_type->cbFormat, subtype); else { - FIXME("Unsupported format type %s.\n", debugstr_guid(&am_type->formattype)); + FIXME("Unsupported format type %s / size %ld.\n", debugstr_guid(&am_type->formattype), am_type->cbFormat); return E_NOTIMPL; } From 94b468314e721f4ea10b5885b8f548f99a3dd415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Mar 2024 17:21:22 +0100 Subject: [PATCH 058/301] mfplat/mediatype: Support audio major type in MFInitMediaTypeFromAMMediaType. (cherry picked from commit 689868cd501a7855dc0535531dd57cf494e11c12) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 7955de8ca7a..7af0032dceb 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4287,13 +4287,19 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM FIXME("Unsupported format type %s / size %ld.\n", debugstr_guid(&am_type->formattype), am_type->cbFormat); return E_NOTIMPL; } - - if (!am_type->bTemporalCompression && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) - mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); - if (am_type->bFixedSizeSamples && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) - mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); - if (am_type->lSampleSize && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) - mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, am_type->lSampleSize, &hr); + } + else if (IsEqualGUID(&am_type->majortype, &MEDIATYPE_Audio)) + { + if (am_type->cbFormat && !am_type->pbFormat) + hr = E_INVALIDARG; + else if (IsEqualGUID(&am_type->formattype, &FORMAT_WaveFormatEx) + && am_type->cbFormat >= sizeof(WAVEFORMATEX)) + hr = MFInitMediaTypeFromWaveFormatEx(media_type, (WAVEFORMATEX *)am_type->pbFormat, am_type->cbFormat); + else + { + FIXME("Unsupported format type %s / size %ld.\n", debugstr_guid(&am_type->formattype), am_type->cbFormat); + return E_NOTIMPL; + } } else { @@ -4301,5 +4307,12 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM return E_NOTIMPL; } + if (!am_type->bTemporalCompression && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) + mediatype_set_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); + if (am_type->bFixedSizeSamples && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) + mediatype_set_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1, &hr); + if (am_type->lSampleSize && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) + mediatype_set_uint32(media_type, &MF_MT_SAMPLE_SIZE, am_type->lSampleSize, &hr); + return hr; } From ceabceb74e73544a150b8183733d920a467f4cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 19:44:22 +0100 Subject: [PATCH 059/301] mfplat/mediatype: Force WAVEFORMATEXTENSIBLE in MFCreateWaveFormatExFromMFMediaType in some cases. (cherry picked from commit a4fb357c89723328ba95c46fbc2c1271c329784e) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 28 +++++++++++++++++++++++++--- dlls/mfplat/tests/mfplat.c | 6 ------ dlls/winegstreamer/audio_decoder.c | 1 + 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 7af0032dceb..d5a1d7bfbf2 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2982,7 +2982,7 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE { UINT32 value, extra_size = 0, user_size; WAVEFORMATEX *format; - GUID major, subtype; + GUID major, subtype, basetype = MFAudioFormat_Base; void *user_data; HRESULT hr; @@ -3004,6 +3004,19 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE user_size = 0; } + if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, &value)) && value > 2 + && SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, NULL))) + { + if (SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, NULL))) + flags = MFWaveFormatExConvertFlag_ForceExtensible; + if (SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, NULL))) + flags = MFWaveFormatExConvertFlag_ForceExtensible; + } + + basetype.Data1 = subtype.Data1; + if (subtype.Data1 >> 16 || !IsEqualGUID(&subtype, &basetype)) + flags = MFWaveFormatExConvertFlag_ForceExtensible; + if (flags == MFWaveFormatExConvertFlag_ForceExtensible) extra_size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(*format); @@ -3036,6 +3049,8 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE user_data = format_ext + 1; if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &value))) + format_ext->Samples.wValidBitsPerSample = value; + if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &value))) format_ext->Samples.wSamplesPerBlock = value; if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, &value))) @@ -3082,6 +3097,8 @@ static void mediatype_set_blob(IMFMediaType *mediatype, const GUID *attr, const HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size) { const WAVEFORMATEXTENSIBLE *wfex = (const WAVEFORMATEXTENSIBLE *)format; + const void *user_data; + int user_data_size; GUID subtype; HRESULT hr; @@ -3106,6 +3123,9 @@ HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WA if (format->wBitsPerSample && wfex->Samples.wValidBitsPerSample) mediatype_set_uint32(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, wfex->Samples.wValidBitsPerSample, &hr); + + user_data_size = format->cbSize - sizeof(WAVEFORMATEXTENSIBLE) + sizeof(WAVEFORMATEX); + user_data = wfex + 1; } else { @@ -3113,6 +3133,8 @@ HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WA subtype.Data1 = format->wFormatTag; mediatype_set_uint32(mediatype, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, &hr); + user_data_size = format->cbSize; + user_data = format + 1; } mediatype_set_guid(mediatype, &MF_MT_SUBTYPE, &subtype, &hr); @@ -3146,8 +3168,8 @@ HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WA mediatype_set_uint32(mediatype, &MF_MT_AAC_PAYLOAD_TYPE, info->wPayloadType, &hr); } - if (format->cbSize && format->wFormatTag != WAVE_FORMAT_EXTENSIBLE) - mediatype_set_blob(mediatype, &MF_MT_USER_DATA, (const UINT8 *)(format + 1), format->cbSize, &hr); + if (user_data_size > 0) + mediatype_set_blob(mediatype, &MF_MT_USER_DATA, user_data, user_data_size, &hr); return hr; } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3b6cc186c8e..b9adb6c9a0a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7136,18 +7136,12 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&format, &size, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE, "got wFormatTag %#x\n", format->Format.wFormatTag); - todo_wine ok(format->Format.cbSize == aacformat.wfInfo.wfx.cbSize + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), "got cbSize %u\n", format->Format.cbSize); - todo_wine ok(IsEqualGUID(&format->SubFormat, &MFAudioFormat_AAC), "got SubFormat %s\n", debugstr_guid(&format->SubFormat)); - todo_wine ok(format->dwChannelMask == 63, "got dwChannelMask %#lx\n", format->dwChannelMask); - todo_wine ok(format->Samples.wSamplesPerBlock == 4, "got wSamplesPerBlock %u\n", format->Samples.wSamplesPerBlock); - todo_wine ok(!memcmp(format + 1, &aacformat.wfInfo.wfx + 1, aacformat.wfInfo.wfx.cbSize), "Unexpected user data.\n"); /* test initializing media type from an WAVE_FORMAT_EXTENSIBLE AAC format */ diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/audio_decoder.c index 771eae465fe..e65dcabaaba 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -292,6 +292,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR wfx.SubFormat = MFAudioFormat_Base; wfx.SubFormat.Data1 = wfx.Format.wFormatTag; wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); wfx.dwChannelMask = default_channel_mask[wfx.Format.nChannels]; } From e3e5088c070411a65e39c2855a173f54db82f2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 23:03:31 +0100 Subject: [PATCH 060/301] mfplat/mediatype: Implement MFCreateMediaTypeFromRepresentation. (cherry picked from commit 1e053810f3fec90bf20eb536d1e7dd063e3a581d) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 26 +++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 51 ++++++++++++++++++++++++++++++++++++++ include/mfapi.h | 2 ++ 4 files changed, 80 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index d5a1d7bfbf2..269445572bf 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4338,3 +4338,29 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM return hr; } + +/*********************************************************************** + * MFCreateMediaTypeFromRepresentation (mfplat.@) + */ +HRESULT WINAPI MFCreateMediaTypeFromRepresentation(GUID guid_representation, void *representation, + IMFMediaType **media_type) +{ + HRESULT hr; + + TRACE("%s, %p, %p\n", debugstr_guid(&guid_representation), representation, media_type); + + if (!IsEqualGUID(&guid_representation, &AM_MEDIA_TYPE_REPRESENTATION)) + return MF_E_UNSUPPORTED_REPRESENTATION; + if (!representation || !media_type) + return E_INVALIDARG; + + if (FAILED(hr = MFCreateMediaType(media_type))) + return hr; + if (FAILED(hr = MFInitMediaTypeFromAMMediaType(*media_type, representation))) + { + IMFMediaType_Release(*media_type); + *media_type = NULL; + } + + return hr; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index d8a6eb5ce83..57db3cdf9f6 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -59,7 +59,7 @@ @ stub MFCreateMediaBufferWrapper @ stdcall MFCreateMediaEvent(long ptr long ptr ptr) @ stdcall MFCreateMediaType(ptr) -@ stub MFCreateMediaTypeFromRepresentation +@ stdcall MFCreateMediaTypeFromRepresentation(int128 ptr ptr) @ stdcall MFCreateMemoryBuffer(long ptr) @ stub MFCreateMemoryStream @ stdcall MFCreatePathFromURL(wstr ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b9adb6c9a0a..4c5666cb0f7 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8525,6 +8525,56 @@ static void test_IMFMediaType_GetRepresentation(void) IMFMediaType_Release(media_type); } +static void test_MFCreateMediaTypeFromRepresentation(void) +{ + IMFMediaType *media_type; + AM_MEDIA_TYPE amt = {0}; + WAVEFORMATEX wfx = {0}; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaTypeFromRepresentation(GUID_NULL, &amt, &media_type); + ok(hr == MF_E_UNSUPPORTED_REPRESENTATION, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, NULL, &media_type); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, &media_type); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &GUID_NULL), "got %s.\n", debugstr_guid(&guid)); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &GUID_NULL), "got %s.\n", debugstr_guid(&guid)); + IMFMediaType_Release(media_type); + } + + amt.formattype = FORMAT_WaveFormatEx; + amt.majortype = MFMediaType_Audio; + amt.subtype = MFAudioFormat_PCM; + amt.pbFormat = (BYTE *)&wfx; + amt.cbFormat = sizeof(wfx); + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Audio), "got %s.\n", debugstr_guid(&guid)); + memset(&guid, 0xcd, sizeof(guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(IsEqualGUID(&guid, &MFAudioFormat_PCM), "got %s.\n", debugstr_guid(&guid)); + IMFMediaType_Release(media_type); +} + static void test_MFCreateDXSurfaceBuffer(void) { IDirect3DSurface9 *backbuffer = NULL, *surface; @@ -11791,6 +11841,7 @@ START_TEST(mfplat) test_MFCreateAMMediaTypeFromMFMediaType(); test_MFInitMediaTypeFromMFVideoFormat(); test_IMFMediaType_GetRepresentation(); + test_MFCreateMediaTypeFromRepresentation(); test_MFCreateDXSurfaceBuffer(); test_MFCreateTrackedSample(); test_MFFrameRateToAverageTimePerFrame(); diff --git a/include/mfapi.h b/include/mfapi.h index f986edd0d5a..0a9f7c6f415 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -549,6 +549,8 @@ HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HR HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); HRESULT WINAPI MFCreateAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID format_type, AM_MEDIA_TYPE **am_type); HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size); +HRESULT WINAPI MFCreateMediaTypeFromRepresentation(GUID guid_representation, void *representation, + IMFMediaType **media_type); HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateTempFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, IMFByteStream **bytestream); From 5dbac07a1deb9ab50784139ed6aa92810eb7ad53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Mar 2024 15:00:30 +0100 Subject: [PATCH 061/301] mfplat/mediatype: Use MFCreateWaveFormatExFromMFMediaType in init_am_media_type_audio_format. (cherry picked from commit 552cec94772a077065be9001e2df5db2245dec0a) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 60 +++++------------------------------------ 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 269445572bf..875f3dbcadf 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3996,7 +3996,7 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) { - UINT32 num_channels, value; + UINT32 num_channels; HRESULT hr; if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) @@ -4007,7 +4007,7 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us if (IsEqualGUID(&am_type->formattype, &FORMAT_WaveFormatEx) || IsEqualGUID(&am_type->formattype, &GUID_NULL)) { - WAVEFORMATEX *format; + UINT32 flags = 0; if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels))) num_channels = 0; @@ -4016,59 +4016,11 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us || SUCCEEDED(IMFMediaType_GetItem(media_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, NULL)) || SUCCEEDED(IMFMediaType_GetItem(media_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, NULL)) || num_channels > 2) - { - WAVEFORMATEXTENSIBLE *format_ext; - - am_type->cbFormat = sizeof(*format_ext) + user_size; - if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) - return E_OUTOFMEMORY; - format_ext = (WAVEFORMATEXTENSIBLE *)am_type->pbFormat; - memset(format_ext, 0, sizeof(*format_ext)); - - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, &value))) - format_ext->dwChannelMask = value; - else if (num_channels < ARRAY_SIZE(default_channel_mask)) - format_ext->dwChannelMask = default_channel_mask[num_channels]; - - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &value))) - format_ext->Samples.wValidBitsPerSample = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &value))) - format_ext->Samples.wSamplesPerBlock = value; - format_ext->SubFormat = am_type->subtype; - - format = &format_ext->Format; - format->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - format->cbSize = sizeof(*format_ext) - sizeof(*format) + user_size; - - if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, - (BYTE *)(format_ext + 1), user_size, NULL))) - return hr; - } - else - { - am_type->cbFormat = sizeof(*format) + user_size; - if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) - return E_OUTOFMEMORY; - format = (WAVEFORMATEX *)am_type->pbFormat; - memset(format, 0, sizeof(*format)); - - format->wFormatTag = am_type->subtype.Data1; - format->cbSize = user_size; - - if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, - (BYTE *)(format + 1), user_size, NULL))) - return hr; - } + flags = MFWaveFormatExConvertFlag_ForceExtensible; - format->nChannels = num_channels; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &value))) - format->nSamplesPerSec = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value))) - format->nAvgBytesPerSec = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value))) - format->nBlockAlign = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &value))) - format->wBitsPerSample = value; + if (FAILED(hr = MFCreateWaveFormatExFromMFMediaType(media_type, (WAVEFORMATEX **)&am_type->pbFormat, + (UINT32 *)&am_type->cbFormat, flags))) + return hr; am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); am_type->formattype = FORMAT_WaveFormatEx; From 6515aa12defb03520ef89cc36708af430b297e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Mar 2024 12:43:05 +0100 Subject: [PATCH 062/301] mf/tests: Check that pan scan and geometric apertures are set. (cherry picked from commit da2c20a2e688f395e42a5f3086a11833d26698ad) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index f11f4368cfb..3f91f2b727e 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4089,6 +4089,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4103,6 +4105,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4117,6 +4121,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4131,6 +4137,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4145,6 +4153,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), }, }; const MFT_OUTPUT_STREAM_INFO initial_output_info = From b37c5924c082d4460f78ee2e731f9bfc1ca9da34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Mar 2024 11:39:27 +0100 Subject: [PATCH 063/301] evr/tests: Split create_d3d_sample to a separate helper. (cherry picked from commit 1f589f63041cad0f000575baf57f25447df1e132) CW-Bug-Id: #20833 --- dlls/evr/tests/evr.c | 109 ++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 25fb1978443..a0aba91aa74 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -3318,6 +3318,66 @@ static void test_mixer_samples(void) DestroyWindow(window); } +static void create_d3d_sample(IDirect3DDeviceManager9 *manager, const GUID *subtype, IMFSample **sample) +{ + static const BITMAPINFOHEADER expect_header = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 96, .biHeight = 96, + .biPlanes = 1, .biBitCount = 32, + .biCompression = BI_RGB, + .biSizeImage = 96 * 96 * 4, + }; + DWORD data_size, frame_data_len; + D3DLOCKED_RECT d3d_rect = {0}; + IDirect3DSurface9 *surface; + const BYTE *frame_data; + LONG stride; + HRESULT hr; + + if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + load_resource(L"nv12frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header and RGB data from the dump */ + data_size = *(DWORD *)(frame_data + 2); + frame_data_len = frame_data_len - data_size; + frame_data = frame_data + data_size; + ok(frame_data_len == 13824, "got length %lu\n", frame_data_len); + } + else + { + load_resource(L"rgb32frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header from the dump */ + data_size = *(DWORD *)(frame_data + 2 + 2 * sizeof(DWORD)); + frame_data_len -= data_size; + frame_data += data_size; + ok(frame_data_len == 36864, "got length %lu\n", frame_data_len); + } + + surface = create_surface(manager, subtype->Data1, expect_header.biWidth, expect_header.biHeight); + ok(!!surface, "Failed to create input surface.\n"); + hr = IDirect3DSurface9_LockRect(surface, &d3d_rect, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + memcpy(d3d_rect.pBits, frame_data, frame_data_len); + else if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, expect_header.biWidth, &stride); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + frame_data += stride * expect_header.biHeight; + d3d_rect.pBits = (BYTE *)d3d_rect.pBits + d3d_rect.Pitch * expect_header.biHeight; + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight / 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + hr = IDirect3DSurface9_UnlockRect(surface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DSurface9_Release(surface); +} + static void test_presenter_orientation(const GUID *subtype) { IMFTopologyServiceLookupClient *lookup_client; @@ -3331,18 +3391,14 @@ static void test_presenter_orientation(const GUID *subtype) }; BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; IMFVideoDisplayControl *display_control; - DWORD diff, data_size, frame_data_len; IDirect3DDeviceManager9 *manager; - D3DLOCKED_RECT d3d_rect = {0}; IMFVideoPresenter *presenter; - IDirect3DSurface9 *surface; IMFMediaType *video_type; - const BYTE *frame_data; + DWORD diff, data_size; struct test_host host; IMFTransform *mixer; LONGLONG timestamp; IMFSample *sample; - LONG stride; HWND window; BYTE *data; HRESULT hr; @@ -3393,48 +3449,7 @@ static void test_presenter_orientation(const GUID *subtype) hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) - { - load_resource(L"nv12frame.bmp", &frame_data, &frame_data_len); - /* skip BMP header and RGB data from the dump */ - data_size = *(DWORD *)(frame_data + 2); - frame_data_len = frame_data_len - data_size; - frame_data = frame_data + data_size; - ok(frame_data_len == 13824, "got length %lu\n", frame_data_len); - } - else - { - load_resource(L"rgb32frame.bmp", &frame_data, &frame_data_len); - /* skip BMP header from the dump */ - data_size = *(DWORD *)(frame_data + 2 + 2 * sizeof(DWORD)); - frame_data_len -= data_size; - frame_data += data_size; - ok(frame_data_len == 36864, "got length %lu\n", frame_data_len); - } - - surface = create_surface(manager, subtype->Data1, expect_header.biWidth, expect_header.biHeight); - ok(!!surface, "Failed to create input surface.\n"); - hr = IDirect3DSurface9_LockRect(surface, &d3d_rect, NULL, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) - memcpy(d3d_rect.pBits, frame_data, frame_data_len); - else if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) - { - hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, expect_header.biWidth, &stride); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - frame_data += stride * expect_header.biHeight; - d3d_rect.pBits = (BYTE *)d3d_rect.pBits + d3d_rect.Pitch * expect_header.biHeight; - hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight / 2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } - hr = IDirect3DSurface9_UnlockRect(surface); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IDirect3DSurface9_Release(surface); - + create_d3d_sample(manager, subtype, &sample); hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); From 6d0b2bcd14eac854b1081910931cebfe701395ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Mar 2024 11:44:17 +0100 Subject: [PATCH 064/301] evr/tests: Split check_presenter_output to a separate helper. (cherry picked from commit c5f00392237c93d75066a5ab407c2fa97e34fd52) CW-Bug-Id: #20833 --- dlls/evr/tests/evr.c | 74 +++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index a0aba91aa74..abd507760c5 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -3378,6 +3378,46 @@ static void create_d3d_sample(IDirect3DDeviceManager9 *manager, const GUID *subt IDirect3DSurface9_Release(surface); } +#define check_presenter_output(a, b, c, d) check_presenter_output_(__LINE__, a, b, c, d) +static DWORD check_presenter_output_(int line, IMFVideoPresenter *presenter, const BITMAPINFOHEADER *expect_header, + const WCHAR *resource, const RECT *rect) +{ + BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; + IMFVideoDisplayControl *display_control; + DWORD diff, data_size; + LONGLONG timestamp; + BYTE *data; + HRESULT hr; + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFVideoDisplayControl, (void **)&display_control); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + if (hr == MF_E_INVALIDREQUEST) + { + Sleep(500); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + } + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFVideoDisplayControl_Release(display_control); + + ok_(__FILE__, line)(header.biSize == expect_header->biSize, "Unexpected biSize %#lx\n", header.biSize); + ok_(__FILE__, line)(header.biWidth == expect_header->biWidth, "Unexpected biWidth %#lx\n", header.biWidth); + ok_(__FILE__, line)(header.biHeight == expect_header->biHeight, "Unexpected biHeight %#lx\n", header.biHeight); + ok_(__FILE__, line)(header.biPlanes == expect_header->biPlanes, "Unexpected biPlanes %#x\n", header.biPlanes); + ok_(__FILE__, line)(header.biBitCount == expect_header->biBitCount, "Unexpected biBitCount %#x\n", header.biBitCount); + ok_(__FILE__, line)(header.biCompression == expect_header->biCompression, "Unexpected biCompression %#lx\n", header.biCompression); + ok_(__FILE__, line)(header.biSizeImage == expect_header->biSizeImage, "Unexpected biSizeImage %#lx\n", header.biSizeImage); + ok_(__FILE__, line)(header.biXPelsPerMeter == expect_header->biXPelsPerMeter, "Unexpected biXPelsPerMeter %#lx\n", header.biXPelsPerMeter); + ok_(__FILE__, line)(header.biYPelsPerMeter == expect_header->biYPelsPerMeter, "Unexpected biYPelsPerMeter %#lx\n", header.biYPelsPerMeter); + ok_(__FILE__, line)(header.biClrUsed == expect_header->biClrUsed, "Unexpected biClrUsed %#lx\n", header.biClrUsed); + ok_(__FILE__, line)(header.biClrImportant == expect_header->biClrImportant, "Unexpected biClrImportant %#lx\n", header.biClrImportant); + + diff = check_rgb32_data(resource, data, header.biSizeImage, rect); + CoTaskMemFree(data); + + return diff; +} + static void test_presenter_orientation(const GUID *subtype) { IMFTopologyServiceLookupClient *lookup_client; @@ -3389,19 +3429,15 @@ static void test_presenter_orientation(const GUID *subtype) .biCompression = BI_RGB, .biSizeImage = 96 * 96 * 4, }; - BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; - IMFVideoDisplayControl *display_control; IDirect3DDeviceManager9 *manager; IMFVideoPresenter *presenter; IMFMediaType *video_type; - DWORD diff, data_size; struct test_host host; IMFTransform *mixer; - LONGLONG timestamp; IMFSample *sample; HWND window; - BYTE *data; HRESULT hr; + DWORD diff; RECT rect; window = create_window(); @@ -3456,33 +3492,9 @@ static void test_presenter_orientation(const GUID *subtype) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFSample_Release(sample); - hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFVideoDisplayControl, (void **)&display_control); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); - if (hr == MF_E_INVALIDREQUEST) - { - Sleep(500); - hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); - } - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFVideoDisplayControl_Release(display_control); - - ok(header.biSize == expect_header.biSize, "Unexpected biSize %#lx\n", header.biSize); - ok(header.biWidth == expect_header.biWidth, "Unexpected biWidth %#lx\n", header.biWidth); - ok(header.biHeight == expect_header.biHeight, "Unexpected biHeight %#lx\n", header.biHeight); - ok(header.biPlanes == expect_header.biPlanes, "Unexpected biPlanes %#x\n", header.biPlanes); - ok(header.biBitCount == expect_header.biBitCount, "Unexpected biBitCount %#x\n", header.biBitCount); - ok(header.biCompression == expect_header.biCompression, "Unexpected biCompression %#lx\n", header.biCompression); - ok(header.biSizeImage == expect_header.biSizeImage, "Unexpected biSizeImage %#lx\n", header.biSizeImage); - ok(header.biXPelsPerMeter == expect_header.biXPelsPerMeter, "Unexpected biXPelsPerMeter %#lx\n", header.biXPelsPerMeter); - ok(header.biYPelsPerMeter == expect_header.biYPelsPerMeter, "Unexpected biYPelsPerMeter %#lx\n", header.biYPelsPerMeter); - ok(header.biClrUsed == expect_header.biClrUsed, "Unexpected biClrUsed %#lx\n", header.biClrUsed); - ok(header.biClrImportant == expect_header.biClrImportant, "Unexpected biClrImportant %#lx\n", header.biClrImportant); - - SetRect(&rect, 0, 0, header.biWidth, header.biHeight); - diff = check_rgb32_data(L"rgb32frame-flip.bmp", data, header.biSizeImage, &rect); + SetRect(&rect, 0, 0, expect_header.biWidth, expect_header.biHeight); + diff = check_presenter_output(presenter, &expect_header, L"rgb32frame-flip.bmp", &rect); ok(diff <= 5, "Unexpected %lu%% diff\n", diff); - CoTaskMemFree(data); hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From 44a41f2714be5b3207005c8030aa7723416ca968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Mar 2024 12:00:21 +0100 Subject: [PATCH 065/301] evr/tests: Add more video mixer input media type aperture tests. (cherry picked from commit d304e587894d69c2716c8e242a96ee56e141284b) CW-Bug-Id: #20833 --- dlls/evr/tests/evr.c | 208 ++++++++++++++++++++++++++++- dlls/evr/tests/resource.rc | 10 +- dlls/evr/tests/rgb32frame-crop.bmp | Bin 0 -> 7670 bytes 3 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 dlls/evr/tests/rgb32frame-crop.bmp diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index abd507760c5..59fdfcb8fae 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -41,7 +41,7 @@ static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *lengt static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) { - DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD x, y, size, diff = 0, width = rect->right, height = rect->bottom; /* skip BMP header from the dump */ size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); @@ -66,7 +66,7 @@ static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, co static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) { - DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD width = rect->right, height = rect->bottom; static const char magic[2] = "BM"; struct { @@ -3378,9 +3378,9 @@ static void create_d3d_sample(IDirect3DDeviceManager9 *manager, const GUID *subt IDirect3DSurface9_Release(surface); } -#define check_presenter_output(a, b, c, d) check_presenter_output_(__LINE__, a, b, c, d) +#define check_presenter_output(a, b, c, d) check_presenter_output_(__LINE__, a, b, c, d, FALSE) static DWORD check_presenter_output_(int line, IMFVideoPresenter *presenter, const BITMAPINFOHEADER *expect_header, - const WCHAR *resource, const RECT *rect) + const WCHAR *resource, const RECT *rect, BOOL todo) { BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; IMFVideoDisplayControl *display_control; @@ -3401,11 +3401,14 @@ static DWORD check_presenter_output_(int line, IMFVideoPresenter *presenter, con IMFVideoDisplayControl_Release(display_control); ok_(__FILE__, line)(header.biSize == expect_header->biSize, "Unexpected biSize %#lx\n", header.biSize); + todo_wine_if(todo) ok_(__FILE__, line)(header.biWidth == expect_header->biWidth, "Unexpected biWidth %#lx\n", header.biWidth); + todo_wine_if(todo) ok_(__FILE__, line)(header.biHeight == expect_header->biHeight, "Unexpected biHeight %#lx\n", header.biHeight); ok_(__FILE__, line)(header.biPlanes == expect_header->biPlanes, "Unexpected biPlanes %#x\n", header.biPlanes); ok_(__FILE__, line)(header.biBitCount == expect_header->biBitCount, "Unexpected biBitCount %#x\n", header.biBitCount); ok_(__FILE__, line)(header.biCompression == expect_header->biCompression, "Unexpected biCompression %#lx\n", header.biCompression); + todo_wine_if(todo) ok_(__FILE__, line)(header.biSizeImage == expect_header->biSizeImage, "Unexpected biSizeImage %#lx\n", header.biSizeImage); ok_(__FILE__, line)(header.biXPelsPerMeter == expect_header->biXPelsPerMeter, "Unexpected biXPelsPerMeter %#lx\n", header.biXPelsPerMeter); ok_(__FILE__, line)(header.biYPelsPerMeter == expect_header->biYPelsPerMeter, "Unexpected biYPelsPerMeter %#lx\n", header.biYPelsPerMeter); @@ -3512,6 +3515,202 @@ static void test_presenter_orientation(const GUID *subtype) DestroyWindow(window); } +static void test_mixer_video_aperture(void) +{ + IMFTopologyServiceLookupClient *lookup_client; + static const BITMAPINFOHEADER expect_header_crop = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 34, .biHeight = 56, + .biPlanes = 1, .biBitCount = 32, + .biCompression = BI_RGB, + .biSizeImage = 34 * 56 * 4, + }; + static const BITMAPINFOHEADER expect_header = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 96, .biHeight = 96, + .biPlanes = 1, .biBitCount = 32, + .biCompression = BI_RGB, + .biSizeImage = 96 * 96 * 4, + }; + const MFVideoArea aperture = {.Area = {.cx = 34, .cy = 56}}; + IDirect3DDeviceManager9 *manager; + IMFVideoPresenter *presenter; + IMFMediaType *video_type; + struct test_host host; + IMFTransform *mixer; + IMFSample *sample; + HWND window; + HRESULT hr; + DWORD diff; + RECT rect; + + window = create_window(); + + hr = MFCreateVideoMixer(NULL, &IID_IDirect3DDevice9, &IID_IMFTransform, (void **)&mixer); + ok(hr == S_OK, "Failed to create a mixer, hr %#lx.\n", hr); + hr = MFCreateVideoPresenter(NULL, &IID_IDirect3DDevice9, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + init_test_host(&host, mixer, presenter); + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, &host.IMFTopologyServiceLookup_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + /* Configure device and media types. */ + + hr = MFGetService((IUnknown *)presenter, &MR_VIDEO_ACCELERATION_SERVICE, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDeviceManager9_Release(manager); + + + /* MF_MT_MINIMUM_DISPLAY_APERTURE / MF_MT_PAN_SCAN_APERTURE have no effect */ + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetOutputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + create_d3d_sample(manager, &MFVideoFormat_RGB32, &sample); + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + SetRect(&rect, 0, 0, expect_header.biWidth, expect_header.biHeight); + diff = check_presenter_output(presenter, &expect_header, L"rgb32frame-flip.bmp", &rect); + ok(diff <= 5, "Unexpected %lu%% diff\n", diff); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + + /* MF_MT_PAN_SCAN_APERTURE has an effect only when enabled */ + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetOutputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_PAN_SCAN_ENABLED, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + create_d3d_sample(manager, &MFVideoFormat_RGB32, &sample); + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + SetRect(&rect, 0, 0, expect_header_crop.biWidth, expect_header_crop.biHeight); + diff = check_presenter_output_(__LINE__, presenter, &expect_header_crop, L"rgb32frame-crop.bmp", &rect, TRUE); + todo_wine ok(diff <= 5, "Unexpected %lu%% diff\n", diff); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + + /* MF_MT_GEOMETRIC_APERTURE has an effect */ + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + video_type = create_video_type(&MFVideoFormat_RGB32); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetOutputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + create_d3d_sample(manager, &MFVideoFormat_RGB32, &sample); + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + SetRect(&rect, 0, 0, expect_header_crop.biWidth, expect_header_crop.biHeight); + diff = check_presenter_output_(__LINE__, presenter, &expect_header_crop, L"rgb32frame-crop.bmp", &rect, TRUE); + todo_wine ok(diff <= 5, "Unexpected %lu%% diff\n", diff); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_ReleaseServicePointers(lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + IMFTransform_Release(mixer); + IMFVideoPresenter_Release(presenter); + + DestroyWindow(window); +} + static void test_MFIsFormatYUV(void) { static const DWORD formats[] = @@ -3715,6 +3914,7 @@ START_TEST(evr) test_presenter_media_type(); test_presenter_orientation(&MFVideoFormat_NV12); test_presenter_orientation(&MFVideoFormat_RGB32); + test_mixer_video_aperture(); test_presenter_shutdown(); test_mixer_output_rectangle(); test_mixer_zorder(); diff --git a/dlls/evr/tests/resource.rc b/dlls/evr/tests/resource.rc index 79b62304303..7537acfe5ac 100644 --- a/dlls/evr/tests/resource.rc +++ b/dlls/evr/tests/resource.rc @@ -20,14 +20,18 @@ #include "windef.h" -/* Generated from running the mf:transform tests on Windows */ +/* Generated from running the evr:evr tests on Windows */ /* @makedep: rgb32frame.bmp */ rgb32frame.bmp RCDATA rgb32frame.bmp -/* Generated from running the mf:transform tests on Windows */ +/* Generated from running the evr:evr tests on Windows */ /* @makedep: rgb32frame-flip.bmp */ rgb32frame-flip.bmp RCDATA rgb32frame-flip.bmp -/* Generated from running the mf:transform tests on Windows */ +/* Generated from running the evr:evr tests on Windows */ +/* @makedep: rgb32frame-crop.bmp */ +rgb32frame-crop.bmp RCDATA rgb32frame-crop.bmp + +/* Generated from running the evr:evr tests on Windows */ /* @makedep: nv12frame.bmp */ nv12frame.bmp RCDATA nv12frame.bmp diff --git a/dlls/evr/tests/rgb32frame-crop.bmp b/dlls/evr/tests/rgb32frame-crop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6cbaf72df609a7e439c7897e7a42ff76fa269bc6 GIT binary patch literal 7670 zcmeIzu?fOZ6ougR@8kVBHAS8t$?|KNC;H5dm349kq znsE7(x7*hXbk~M+O-tI+2n8o_@1J)!{b-S3-hmr%133*K_#-jzzzw(oH!!$?vIZ2) zTR_1p#!zsL2^0jsG4l@GfE&nZ;QTp2!K0Z%!7AQRaEcogAb9Ybci;xxKt=<{>I((4 b<_85&9?}Xfd=CXFC75^M2Hb!f7~a4iz_P>T literal 0 HcmV?d00001 From 0cb9fe154d7f02dd4fbab70bfe09325c9b57d1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Mar 2024 11:19:58 +0100 Subject: [PATCH 066/301] evr/mixer: Respect input media type MF_MT_GEOMETRIC_APERTURE. (cherry picked from commit b1cca5b52ad5dbcfb9547557040f7a380908da2f) CW-Bug-Id: #20833 --- dlls/evr/mixer.c | 52 +++++++++++++++++++++++++------------------- dlls/evr/presenter.c | 24 +++++++++++--------- dlls/evr/tests/evr.c | 4 ++-- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index 222fc538fec..deedf031472 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -45,7 +45,7 @@ struct input_stream IMFMediaType *media_type; MFVideoNormalizedRect rect; unsigned int zorder; - SIZE frame_size; + MFVideoArea aperture; IMFSample *sample; unsigned int sample_requested : 1; }; @@ -102,7 +102,6 @@ struct video_mixer COLORREF rgba; DXVA2_AYUVSample16 ayuv; } bkgnd_color; - MFVideoArea aperture; LONGLONG lower_bound; LONGLONG upper_bound; CRITICAL_SECTION cs; @@ -763,7 +762,7 @@ static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const if (count && !(flags & MFT_SET_TYPE_TEST_ONLY)) { - UINT32 fixed_samples, interlace_mode; + UINT32 fixed_samples, interlace_mode, width = video_desc->SampleWidth, height = video_desc->SampleHeight; MFVideoArea aperture; UINT64 par; @@ -775,12 +774,18 @@ static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); memset(&aperture, 0, sizeof(aperture)); - if (FAILED(IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture, + if (SUCCEEDED(IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture, sizeof(aperture), NULL))) { - aperture.Area.cx = video_desc->SampleWidth; - aperture.Area.cy = video_desc->SampleHeight; + width = aperture.OffsetX.value + aperture.Area.cx; + height = aperture.OffsetX.value + aperture.Area.cy; + } + else + { + aperture.Area.cx = width; + aperture.Area.cy = height; } + interlace_mode = video_mixer_get_interlace_mode_from_video_desc(video_desc); mf_get_attribute_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &par, (UINT64)1 << 32 | 1); mf_get_attribute_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &fixed_samples, 1); @@ -795,7 +800,7 @@ static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const MFCreateMediaType(&rt_media_type); IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)rt_media_type); IMFMediaType_SetGUID(rt_media_type, &MF_MT_SUBTYPE, &subtype); - IMFMediaType_SetUINT64(rt_media_type, &MF_MT_FRAME_SIZE, (UINT64)aperture.Area.cx << 32 | aperture.Area.cy); + IMFMediaType_SetUINT64(rt_media_type, &MF_MT_FRAME_SIZE, (UINT64)width << 32 | height); IMFMediaType_SetBlob(rt_media_type, &MF_MT_GEOMETRIC_APERTURE, (const UINT8 *)&aperture, sizeof(aperture)); IMFMediaType_SetBlob(rt_media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (const UINT8 *)&aperture, sizeof(aperture)); IMFMediaType_SetUINT32(rt_media_type, &MF_MT_INTERLACE_MODE, interlace_mode); @@ -884,8 +889,15 @@ static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DW if (mixer->inputs[0].media_type) IMFMediaType_Release(mixer->inputs[0].media_type); mixer->inputs[0].media_type = media_type; - mixer->inputs[0].frame_size.cx = video_desc.SampleWidth; - mixer->inputs[0].frame_size.cy = video_desc.SampleHeight; + + if (FAILED(IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&mixer->inputs[0].aperture, sizeof(mixer->inputs[0].aperture), NULL))) + { + memset(&mixer->inputs[0].aperture, 0, sizeof(mixer->inputs[0].aperture)); + mixer->inputs[0].aperture.Area.cx = video_desc.SampleWidth; + mixer->inputs[0].aperture.Area.cy = video_desc.SampleHeight; + } + IMFMediaType_AddRef(mixer->inputs[0].media_type); } CoTaskMemFree(guids); @@ -962,11 +974,6 @@ static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, D if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device, &video_desc, rt_format, MAX_MIXER_INPUT_SUBSTREAMS, &mixer->processor))) { - if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&mixer->aperture, - sizeof(mixer->aperture), NULL))) - { - memset(&mixer->aperture, 0, sizeof(mixer->aperture)); - } if (mixer->output.media_type) IMFMediaType_Release(mixer->output.media_type); mixer->output.media_type = type; @@ -1297,9 +1304,9 @@ static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt) DXVA2_VideoProcessBltParams params = { 0 }; MFVideoNormalizedRect zoom_rect; struct input_stream *stream; + MFVideoArea aperture; HRESULT hr = S_OK; unsigned int i; - RECT dst; if (FAILED(IMFAttributes_GetBlob(mixer->attributes, &VIDEO_ZOOM_RECT, (UINT8 *)&zoom_rect, sizeof(zoom_rect), NULL))) @@ -1308,8 +1315,11 @@ static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt) zoom_rect.right = zoom_rect.bottom = 1.0f; } - SetRect(&dst, 0, 0, mixer->aperture.Area.cx, mixer->aperture.Area.cy); - OffsetRect(&dst, mixer->aperture.OffsetX.value, mixer->aperture.OffsetY.value); + if (FAILED(IMFMediaType_GetBlob(mixer->output.media_type, &MF_MT_GEOMETRIC_APERTURE, + (UINT8 *)&aperture, sizeof(aperture), NULL))) + aperture = mixer->inputs[0].aperture; + SetRect(¶ms.TargetRect, 0, 0, aperture.Area.cx, aperture.Area.cy); + OffsetRect(¶ms.TargetRect, aperture.OffsetX.value, aperture.OffsetY.value); for (i = 0; i < mixer->input_count; ++i) { @@ -1326,8 +1336,9 @@ static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt) /* Full input frame corrected to full destination rectangle. */ - video_mixer_scale_rect(&sample->SrcRect, stream->frame_size.cx, stream->frame_size.cy, &zoom_rect); - CopyRect(&sample->DstRect, &dst); + video_mixer_scale_rect(&sample->SrcRect, stream->aperture.Area.cx, stream->aperture.Area.cy, &zoom_rect); + OffsetRect(&sample->SrcRect, stream->aperture.OffsetX.value, stream->aperture.OffsetY.value); + CopyRect(&sample->DstRect, ¶ms.TargetRect); video_mixer_correct_aspect_ratio(&sample->SrcRect, &sample->DstRect); if (video_mixer_rect_needs_scaling(&stream->rect)) @@ -1340,9 +1351,6 @@ static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt) if (SUCCEEDED(hr)) { - SetRect(¶ms.TargetRect, 0, 0, mixer->aperture.Area.cx, mixer->aperture.Area.cy); - OffsetRect(¶ms.TargetRect, mixer->aperture.OffsetX.value, mixer->aperture.OffsetY.value); - params.BackgroundColor = mixer->bkgnd_color.ayuv; params.Alpha = DXVA2_Fixed32OpaqueAlpha(); diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index dfbc61739cc..7ad59ccc958 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -361,7 +361,6 @@ static HRESULT video_presenter_configure_output_type(struct video_presenter *pre static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter) { IMFMediaType *media_type, *candidate_type; - MFVideoArea aperture = {{ 0 }}; unsigned int idx = 0; RECT rect; HRESULT hr; @@ -374,18 +373,23 @@ static HRESULT video_presenter_invalidate_media_type(struct video_presenter *pre video_presenter_get_native_video_size(presenter); - rect = presenter->dst_rect; - if (rect.left == 0 && rect.right == 0 && rect.bottom == 0 && rect.top == 0) + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &candidate_type))) { - rect.right = presenter->native_size.cx; - rect.bottom = presenter->native_size.cy; - } + MFVideoArea aperture = {{ 0 }}; - aperture.Area.cx = rect.right - rect.left; - aperture.Area.cy = rect.bottom - rect.top; + rect = presenter->dst_rect; + if (!IsRectEmpty(&rect)) + { + aperture.Area.cx = rect.right - rect.left; + aperture.Area.cy = rect.bottom - rect.top; + } + else if (FAILED(IMFMediaType_GetBlob(candidate_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture, + sizeof(aperture), NULL))) + { + aperture.Area.cx = presenter->native_size.cx; + aperture.Area.cy = presenter->native_size.cy; + } - while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &candidate_type))) - { /* FIXME: check that d3d device supports this format */ if (FAILED(hr = IMFMediaType_CopyAllItems(candidate_type, (IMFAttributes *)media_type))) diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 59fdfcb8fae..a684540d977 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -3692,8 +3692,8 @@ static void test_mixer_video_aperture(void) IMFSample_Release(sample); SetRect(&rect, 0, 0, expect_header_crop.biWidth, expect_header_crop.biHeight); - diff = check_presenter_output_(__LINE__, presenter, &expect_header_crop, L"rgb32frame-crop.bmp", &rect, TRUE); - todo_wine ok(diff <= 5, "Unexpected %lu%% diff\n", diff); + diff = check_presenter_output(presenter, &expect_header_crop, L"rgb32frame-crop.bmp", &rect); + ok(diff <= 5, "Unexpected %lu%% diff\n", diff); hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From b11b7e9c3f4628ca25e0db96df5251d8f7571964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Mar 2024 10:27:26 +0100 Subject: [PATCH 067/301] mf/session: Avoid leaking samples in transform_node_deliver_samples. (cherry picked from commit 593dcb1b5c78dbf0fc8146cba94372c78a1550b0) CW-Bug-Id: #20833 --- dlls/mf/session.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index ef707dea4de..8619835ddc3 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3290,7 +3290,10 @@ static void transform_node_deliver_samples(struct media_session *session, struct stream = &topo_node->u.transform.inputs[input]; if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + { session_deliver_sample_to_node(session, topo_node->node, input, sample); + IMFSample_Release(sample); + } else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) WARN("Failed to get node %p/%lu input, hr %#lx\n", topo_node->node, input, hr); else From d44d7c068eecbd53fff96a5ece0935be93c6e766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Mar 2024 11:14:35 +0100 Subject: [PATCH 068/301] mfplat: Append MFVIDEOFORMAT user data after the structure padding. Instead of using the last palette entry, which might be misaligned. (cherry picked from commit 26876b4a6edc2694320a4b4e715305bbb6997414) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 8 ++++++-- dlls/mfplat/tests/mfplat.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 875f3dbcadf..7fd667134b8 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3868,10 +3868,14 @@ HRESULT WINAPI MFInitMediaTypeFromMFVideoFormat(IMFMediaType *media_type, const if (format->compressedInfo.MaxKeyFrameSpacing) mediatype_set_uint32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, format->compressedInfo.MaxKeyFrameSpacing, &hr); - if ((palette_size = format->surfaceInfo.PaletteEntries * sizeof(*format->surfaceInfo.Palette))) + if (!(palette_size = format->surfaceInfo.PaletteEntries * sizeof(*format->surfaceInfo.Palette))) + user_data = format + 1; + else + { mediatype_set_blob(media_type, &MF_MT_PALETTE, (BYTE *)format->surfaceInfo.Palette, palette_size, &hr); + user_data = &format->surfaceInfo.Palette[format->surfaceInfo.PaletteEntries + 1]; + } - user_data = &format->surfaceInfo.Palette[format->surfaceInfo.PaletteEntries + 1]; if ((user_data_size = (BYTE *)format + format->dwSize - (BYTE *)user_data)) mediatype_set_blob(media_type, &MF_MT_USER_DATA, user_data, user_data_size, &hr); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 4c5666cb0f7..0bdc551545e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8449,6 +8449,20 @@ static void test_MFInitMediaTypeFromMFVideoFormat(void) ok(!memcmp(user_data, expect_user_data, value32), "Unexpected user data.\n"); IMFMediaType_DeleteAllItems(media_type); + /* check that user data follows MFVIDEOFORMAT struct, which is padded, when no palette is present */ + format_buf->surfaceInfo.PaletteEntries = 0; + memmove(format_buf + 1, expect_user_data, sizeof(expect_user_data)); + format_buf->dwSize = sizeof(*format_buf) + sizeof(expect_user_data); + hr = MFInitMediaTypeFromMFVideoFormat(media_type, format_buf, format_buf->dwSize); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value32 = 0xdeadbeef; + memset(&user_data, 0xcd, sizeof(user_data)); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(user_data), &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == sizeof(expect_user_data), "got %u.\n", value32); + ok(!memcmp(user_data, expect_user_data, value32), "Unexpected user data.\n"); + IMFMediaType_DeleteAllItems(media_type); + IMFMediaType_Release(media_type); } From 470417a45e203da09621422aa729ecfa6ff66c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 8 Apr 2024 14:01:22 +0200 Subject: [PATCH 069/301] mfmediaengine/tests: Test that effects allow converters between them. (cherry picked from commit a9871e4ad1b40512e654900072c5a043c42798ea) CW-Bug-Id: #20833 --- dlls/mfmediaengine/tests/mfmediaengine.c | 611 +++++++++++------------ 1 file changed, 286 insertions(+), 325 deletions(-) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 47130d8e436..7ced6167d61 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1377,33 +1377,39 @@ static void test_TransferVideoFrame(void) IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); } -struct passthrough_mft +struct test_transform { IMFTransform IMFTransform_iface; LONG refcount; - IMFMediaType *media_type_in, *media_type_out; - IMFSample *sample; - LONG processing_count; - UINT32 index; + IMFAttributes *attributes; + + UINT input_count; + IMFMediaType **input_types; + IMFMediaType *input_type; - CRITICAL_SECTION cs; + UINT output_count; + IMFMediaType **output_types; + IMFMediaType *output_type; + + IMFSample *sample; + UINT sample_count; }; -static struct passthrough_mft *impl_from_IMFTransform(IMFTransform *iface) +static struct test_transform *test_transform_from_IMFTransform(IMFTransform *iface) { - return CONTAINING_RECORD(iface, struct passthrough_mft, IMFTransform_iface); + return CONTAINING_RECORD(iface, struct test_transform, IMFTransform_iface); } -static HRESULT WINAPI passthrough_mft_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +static HRESULT WINAPI test_transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); + struct test_transform *transform = test_transform_from_IMFTransform(iface); - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IMFTransform)) + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IMFTransform)) { - *out = &impl->IMFTransform_iface; - IUnknown_AddRef((IUnknown *)*out); + IMFTransform_AddRef(&transform->IMFTransform_iface); + *out = &transform->IMFTransform_iface; return S_OK; } @@ -1411,389 +1417,313 @@ static HRESULT WINAPI passthrough_mft_QueryInterface(IMFTransform *iface, REFIID return E_NOINTERFACE; } -static ULONG WINAPI passthrough_mft_AddRef(IMFTransform *iface) +static ULONG WINAPI test_transform_AddRef(IMFTransform *iface) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&impl->refcount); + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); return refcount; } -static ULONG WINAPI passthrough_mft_Release(IMFTransform *iface) +static ULONG WINAPI test_transform_Release(IMFTransform *iface) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&impl->refcount); + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); if (!refcount) { - if (impl->media_type_out) IMFMediaType_Release(impl->media_type_out); - if (impl->media_type_in) IMFMediaType_Release(impl->media_type_in); - DeleteCriticalSection(&impl->cs); - free(impl); + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + free(transform); } return refcount; } -static HRESULT WINAPI passthrough_mft_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, +static HRESULT WINAPI test_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) { - *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; - return S_OK; + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +static HRESULT WINAPI test_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) { *inputs = *outputs = 1; return S_OK; } -static HRESULT WINAPI passthrough_mft_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, +static HRESULT WINAPI test_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) { return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +static HRESULT WINAPI test_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +static HRESULT WINAPI test_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - info->dwFlags = - MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | - MFT_OUTPUT_STREAM_WHOLE_SAMPLES | - MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | - MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER; - - info->cbAlignment = 0; - info->cbSize = 0; + memset(info, 0, sizeof(*info)); return S_OK; } -static HRESULT WINAPI passthrough_mft_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +static HRESULT WINAPI test_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { - return E_NOTIMPL; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*attributes = transform->attributes)) + return E_NOTIMPL; + IMFAttributes_AddRef(*attributes); + return S_OK; } -static HRESULT WINAPI passthrough_mft_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +static HRESULT WINAPI test_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +static HRESULT WINAPI test_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_DeleteInputStream(IMFTransform *iface, DWORD id) +static HRESULT WINAPI test_transform_DeleteInputStream(IMFTransform *iface, DWORD id) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +static HRESULT WINAPI test_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, +static HRESULT WINAPI test_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - static const GUID *types[] = { &MFMediaType_Video, &MFMediaType_Audio }; - HRESULT hr; - - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - if (index > ARRAY_SIZE(types) - 1) - return MF_E_NO_MORE_TYPES; - - if (SUCCEEDED(hr = MFCreateMediaType(type))) - hr = IMFMediaType_SetGUID(*type, &MF_MT_MAJOR_TYPE, types[index]); - - return hr; -} + struct test_transform *transform = test_transform_from_IMFTransform(iface); -static HRESULT WINAPI passthrough_mft_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; - - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - EnterCriticalSection(&impl->cs); - - if (index) + if (index >= transform->input_count) { - hr = MF_E_NO_MORE_TYPES; - } - else if (impl->media_type_out) - { - *type = impl->media_type_out; - IMFMediaType_AddRef(*type); - } - else if (impl->media_type_in) - { - *type = impl->media_type_in; - IMFMediaType_AddRef(*type); - } - else - { - hr = MF_E_TRANSFORM_TYPE_NOT_SET; + *type = NULL; + return MF_E_NO_MORE_TYPES; } - LeaveCriticalSection(&impl->cs); - - return hr; + *type = transform->input_types[index]; + IMFMediaType_AddRef(*type); + return S_OK; } -static HRESULT WINAPI passthrough_mft_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +static HRESULT WINAPI test_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; + struct test_transform *transform = test_transform_from_IMFTransform(iface); - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - EnterCriticalSection(&impl->cs); - - if (!(flags & MFT_SET_TYPE_TEST_ONLY)) + if (index >= transform->output_count) { - if (impl->media_type_in) - IMFMediaType_Release(impl->media_type_in); - - impl->media_type_in = type; - IMFMediaType_AddRef(impl->media_type_in); + *type = NULL; + return MF_E_NO_MORE_TYPES; } - LeaveCriticalSection(&impl->cs); - - return hr; -} - -static HRESULT WINAPI passthrough_mft_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - EnterCriticalSection(&impl->cs); - - if (impl->media_type_out) - IMFMediaType_Release(impl->media_type_out); - - impl->media_type_out = type; - IMFMediaType_AddRef(impl->media_type_out); - - LeaveCriticalSection(&impl->cs); - + *type = transform->output_types[index]; + IMFMediaType_AddRef(*type); return S_OK; } -static HRESULT WINAPI passthrough_mft_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +static HRESULT WINAPI test_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; - - if (id) - return MF_E_INVALIDSTREAMNUMBER; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + GUID subtype, desired; + HRESULT hr; - EnterCriticalSection(&impl->cs); - if (impl->media_type_in) + if (type) { - *type = impl->media_type_in; - IMFMediaType_AddRef(*type); + hr = IMFMediaType_GetGUID(transform->input_types[0], &MF_MT_SUBTYPE, &subtype); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &desired); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!IsEqualGUID(&subtype, &desired)) + return MF_E_INVALIDMEDIATYPE; } - else + + if (flags & MFT_SET_TYPE_TEST_ONLY) { - hr = MF_E_TRANSFORM_TYPE_NOT_SET; + todo_wine ok(0, "Unexpected %s call.\n", __func__); + return winetest_platform_is_wine ? S_OK : E_NOTIMPL; } - LeaveCriticalSection(&impl->cs); - - return hr; + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if ((transform->input_type = type)) + IMFMediaType_AddRef(transform->input_type); + return S_OK; } -static HRESULT WINAPI passthrough_mft_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +static HRESULT WINAPI test_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; - - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - EnterCriticalSection(&impl->cs); + struct test_transform *transform = test_transform_from_IMFTransform(iface); + GUID subtype, desired; + HRESULT hr; - if (impl->media_type_out) + if (type) { - *type = impl->media_type_out; - IMFMediaType_AddRef(*type); + hr = IMFMediaType_GetGUID(transform->output_types[0], &MF_MT_SUBTYPE, &subtype); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &desired); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!IsEqualGUID(&subtype, &desired)) + return MF_E_INVALIDMEDIATYPE; } - else + + if (flags & MFT_SET_TYPE_TEST_ONLY) { - hr = MF_E_TRANSFORM_TYPE_NOT_SET; + todo_wine ok(0, "Unexpected %s call.\n", __func__); + return winetest_platform_is_wine ? S_OK : E_NOTIMPL; } + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + if ((transform->output_type = type)) + IMFMediaType_AddRef(transform->output_type); + return S_OK; +} - LeaveCriticalSection(&impl->cs); +static HRESULT WINAPI test_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->input_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} - return hr; +static HRESULT WINAPI test_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->output_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; } -static HRESULT WINAPI passthrough_mft_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +static HRESULT WINAPI test_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_GetOutputStatus(IMFTransform *iface, DWORD *flags) +static HRESULT WINAPI test_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +static HRESULT WINAPI test_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +static HRESULT WINAPI test_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) { + ok(0, "Unexpected %s call.\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI passthrough_mft_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +static HRESULT WINAPI test_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - if (message == MFT_MESSAGE_COMMAND_FLUSH) - return E_NOTIMPL; - return S_OK; } -static HRESULT WINAPI passthrough_mft_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +static HRESULT WINAPI test_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; - - if (id) - return MF_E_INVALIDSTREAMNUMBER; - - EnterCriticalSection(&impl->cs); - if (impl->sample) - { - hr = MF_E_NOTACCEPTING; - } - else - { - impl->sample = sample; - IMFSample_AddRef(impl->sample); - } - - LeaveCriticalSection(&impl->cs); - - return hr; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (transform->sample) + return MF_E_NOTACCEPTING; + transform->sample = sample; + IMFSample_AddRef(transform->sample); + return S_OK; } -static HRESULT WINAPI passthrough_mft_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +static HRESULT WINAPI test_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *data, DWORD *status) { - struct passthrough_mft *impl = impl_from_IMFTransform(iface); - HRESULT hr = S_OK; - UINT32 val = 41; - - if (count != 1) - return E_INVALIDARG; - - EnterCriticalSection(&impl->cs); - - if (impl->sample) - { - hr = IMFSample_GetUINT32(impl->sample, &IID_IMFSample, &val); - - if (impl->index > 0) - { - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(val == impl->index, "Got unexpected value %u.\n", val); - } - else - { - ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - } - - IMFSample_SetUINT32(impl->sample, &IID_IMFSample, impl->index + 1); - - samples->pSample = impl->sample; - *status = samples[0].dwStatus = 0; - impl->processing_count++; - - impl->sample = NULL; - - hr = S_OK; - } - else - { - hr = MF_E_TRANSFORM_NEED_MORE_INPUT; - } - - LeaveCriticalSection(&impl->cs); - - return hr; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!transform->sample) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + transform->sample_count++; + data->pSample = transform->sample; + transform->sample = NULL; + *status = 0; + return S_OK; } -static const IMFTransformVtbl passthrough_mft_vtbl = -{ - passthrough_mft_QueryInterface, - passthrough_mft_AddRef, - passthrough_mft_Release, - passthrough_mft_GetStreamLimits, - passthrough_mft_GetStreamCount, - passthrough_mft_GetStreamIDs, - passthrough_mft_GetInputStreamInfo, - passthrough_mft_GetOutputStreamInfo, - passthrough_mft_GetAttributes, - passthrough_mft_GetInputStreamAttributes, - passthrough_mft_GetOutputStreamAttributes, - passthrough_mft_DeleteInputStream, - passthrough_mft_AddInputStreams, - passthrough_mft_GetInputAvailableType, - passthrough_mft_GetOutputAvailableType, - passthrough_mft_SetInputType, - passthrough_mft_SetOutputType, - passthrough_mft_GetInputCurrentType, - passthrough_mft_GetOutputCurrentType, - passthrough_mft_GetInputStatus, - passthrough_mft_GetOutputStatus, - passthrough_mft_SetOutputBounds, - passthrough_mft_ProcessEvent, - passthrough_mft_ProcessMessage, - passthrough_mft_ProcessInput, - passthrough_mft_ProcessOutput, +static UINT test_transform_get_sample_count(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + return transform->sample_count; +} + +static const IMFTransformVtbl test_transform_vtbl = +{ + test_transform_QueryInterface, + test_transform_AddRef, + test_transform_Release, + test_transform_GetStreamLimits, + test_transform_GetStreamCount, + test_transform_GetStreamIDs, + test_transform_GetInputStreamInfo, + test_transform_GetOutputStreamInfo, + test_transform_GetAttributes, + test_transform_GetInputStreamAttributes, + test_transform_GetOutputStreamAttributes, + test_transform_DeleteInputStream, + test_transform_AddInputStreams, + test_transform_GetInputAvailableType, + test_transform_GetOutputAvailableType, + test_transform_SetInputType, + test_transform_SetOutputType, + test_transform_GetInputCurrentType, + test_transform_GetOutputCurrentType, + test_transform_GetInputStatus, + test_transform_GetOutputStatus, + test_transform_SetOutputBounds, + test_transform_ProcessEvent, + test_transform_ProcessMessage, + test_transform_ProcessInput, + test_transform_ProcessOutput, }; -HRESULT passthrough_mft_create(UINT32 index, struct passthrough_mft **out) +static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **input_types, + UINT output_count, IMFMediaType **output_types, IMFTransform **out) { - struct passthrough_mft *impl; - - *out = NULL; + struct test_transform *transform; - if (!(impl = calloc(1, sizeof(*impl)))) + if (!(transform = calloc(1, sizeof(*transform)))) return E_OUTOFMEMORY; - - impl->IMFTransform_iface.lpVtbl = &passthrough_mft_vtbl; - impl->index = index; - impl->refcount = 1; - - InitializeCriticalSection(&impl->cs); - - *out = impl; + transform->IMFTransform_iface.lpVtbl = &test_transform_vtbl; + transform->refcount = 1; + + transform->input_count = input_count; + transform->input_types = input_types; + transform->input_type = input_types[0]; + IMFMediaType_AddRef(transform->input_type); + transform->output_count = output_count; + transform->output_types = output_types; + transform->output_type = output_types[0]; + IMFMediaType_AddRef(transform->output_type); + + *out = &transform->IMFTransform_iface; return S_OK; } static void test_effect(void) { - struct passthrough_mft *video_effect = NULL, *video_effect2 = NULL, *audio_effect = NULL, *audio_effect2 = NULL; + IMFTransform *video_effect = NULL, *video_effect2 = NULL, *audio_effect = NULL, *audio_effect2 = NULL; + IMFMediaType *video_i420, *video_rgb32, *audio_pcm; IMFMediaEngineEx *media_engine = NULL; struct test_transfer_notify *notify; ID3D11Texture2D *texture = NULL; @@ -1802,8 +1732,8 @@ static void test_effect(void) D3D11_TEXTURE2D_DESC desc; IMFByteStream *stream; IMFMediaSink *sink; + UINT token, count; RECT dst_rect; - UINT token; HRESULT hr; DWORD res; BSTR url; @@ -1812,6 +1742,42 @@ static void test_effect(void) notify = create_transfer_notify(); + hr = MFCreateMediaType(&video_i420); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_i420, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_i420, &MF_MT_SUBTYPE, &MFVideoFormat_I420); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(video_i420, &MF_MT_FRAME_SIZE, (UINT64)64 << 32 | 64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&video_rgb32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_rgb32, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_rgb32, &MF_MT_SUBTYPE, &MFVideoFormat_ARGB32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(video_rgb32, &MF_MT_FRAME_SIZE, (UINT64)64 << 32 | 64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&audio_pcm); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(audio_pcm, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(audio_pcm, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaType_SetUINT32(audio_pcm, &MF_MT_AUDIO_NUM_CHANNELS, 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(audio_pcm, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(audio_pcm, &MF_MT_AUDIO_BITS_PER_SAMPLE, 32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(audio_pcm, &MF_MT_AUDIO_BLOCK_ALIGNMENT, 8); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(audio_pcm, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 352800); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!(device = create_d3d11_device())) { skip("Failed to create a D3D11 device, skipping tests.\n"); @@ -1825,11 +1791,8 @@ static void test_effect(void) create_media_engine(¬ify->IMFMediaEngineNotify_iface, manager, DXGI_FORMAT_B8G8R8X8_UNORM, &IID_IMFMediaEngineEx, (void **)&media_engine); - IMFDXGIDeviceManager_Release(manager); - - if (!(notify->media_engine = media_engine)) - goto done; + notify->media_engine = media_engine; memset(&desc, 0, sizeof(desc)); desc.Width = 64; @@ -1844,46 +1807,44 @@ static void test_effect(void) hr = IMFMediaEngineEx_RemoveAllEffects(media_engine); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = passthrough_mft_create(0, &video_effect); + hr = test_transform_create(1, &video_rgb32, 1, &video_rgb32, &video_effect); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = passthrough_mft_create(1, &video_effect2); + hr = test_transform_create(1, &video_i420, 1, &video_i420, &video_effect2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)&video_effect->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)video_effect, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&video_effect->IMFTransform_iface, 2); + EXPECT_REF(video_effect, 2); - hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)&video_effect2->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)video_effect2, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&video_effect2->IMFTransform_iface, 2); + EXPECT_REF(video_effect2, 2); hr = IMFMediaEngineEx_RemoveAllEffects(media_engine); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&video_effect->IMFTransform_iface, 1); - EXPECT_REF(&video_effect2->IMFTransform_iface, 1); + EXPECT_REF(video_effect, 1); + EXPECT_REF(video_effect2, 1); - hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)&video_effect->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)video_effect, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&video_effect->IMFTransform_iface, 2); + EXPECT_REF(video_effect, 2); - hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)&video_effect2->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertVideoEffect(media_engine, (IUnknown *)video_effect2, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&video_effect2->IMFTransform_iface, 2); + EXPECT_REF(video_effect2, 2); - hr = passthrough_mft_create(0, &audio_effect); + hr = test_transform_create(1, &audio_pcm, 1, &audio_pcm, &audio_effect); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = passthrough_mft_create(1, &audio_effect2); + hr = test_transform_create(1, &audio_pcm, 1, &audio_pcm, &audio_effect2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaEngineEx_InsertAudioEffect(media_engine, (IUnknown *)&audio_effect->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertAudioEffect(media_engine, (IUnknown *)audio_effect, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&audio_effect->IMFTransform_iface, 2); + EXPECT_REF(audio_effect, 2); - hr = IMFMediaEngineEx_InsertAudioEffect(media_engine, (IUnknown *)&audio_effect2->IMFTransform_iface, FALSE); + hr = IMFMediaEngineEx_InsertAudioEffect(media_engine, (IUnknown *)audio_effect2, FALSE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(&audio_effect2->IMFTransform_iface, 2); + EXPECT_REF(audio_effect2, 2); url = SysAllocString(L"i420-64x64.avi"); hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url); @@ -1899,47 +1860,47 @@ static void test_effect(void) hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(video_effect->processing_count > 0, "Unexpected processing count %lu.\n", video_effect->processing_count); - ok(video_effect2->processing_count > 0, "Unexpected processing count %lu.\n", video_effect2->processing_count); + count = test_transform_get_sample_count(video_effect); + ok(count > 0, "Unexpected processing count %u.\n", count); + count = test_transform_get_sample_count(video_effect2); + ok(count > 0, "Unexpected processing count %u.\n", count); if (SUCCEEDED(hr = MFCreateAudioRenderer(NULL, &sink))) { - ok(audio_effect->processing_count > 0, "Unexpected processing count %lu.\n", audio_effect->processing_count); - ok(audio_effect2->processing_count > 0, "Unexpected processing count %lu.\n", audio_effect2->processing_count); + count = test_transform_get_sample_count(audio_effect); + ok(count > 0, "Unexpected processing count %u.\n", count); + count = test_transform_get_sample_count(audio_effect2); + ok(count > 0, "Unexpected processing count %u.\n", count); IMFMediaSink_Release(sink); } else if (hr == MF_E_NO_AUDIO_PLAYBACK_DEVICE) { - ok(!audio_effect->processing_count, "Unexpected processing count %lu.\n", audio_effect->processing_count); - ok(!audio_effect2->processing_count, "Unexpected processing count %lu.\n", audio_effect2->processing_count); + count = test_transform_get_sample_count(audio_effect); + ok(!count, "Unexpected processing count %u.\n", count); + count = test_transform_get_sample_count(audio_effect2); + ok(!count, "Unexpected processing count %u.\n", count); } -done: - if (media_engine) - { - IMFMediaEngineEx_Shutdown(media_engine); - - hr = IMFMediaEngineEx_RemoveAllEffects(media_engine); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEngineEx_Shutdown(media_engine); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEngineEx_RemoveAllEffects(media_engine); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + IMFMediaEngineEx_Release(media_engine); - IMFMediaEngineEx_Release(media_engine); - } + ID3D11Texture2D_Release(texture); - if (texture) - ID3D11Texture2D_Release(texture); - if (device) - ID3D11Device_Release(device); + IMFTransform_Release(audio_effect2); + IMFTransform_Release(audio_effect); + IMFTransform_Release(video_effect2); + IMFTransform_Release(video_effect); - if (audio_effect2) - IMFTransform_Release(&audio_effect2->IMFTransform_iface); - if (audio_effect) - IMFTransform_Release(&audio_effect->IMFTransform_iface); + ID3D11Device_Release(device); - if (video_effect2) - IMFTransform_Release(&video_effect2->IMFTransform_iface); - if (video_effect) - IMFTransform_Release(&video_effect->IMFTransform_iface); +done: + IMFMediaType_Release(audio_pcm); + IMFMediaType_Release(video_rgb32); + IMFMediaType_Release(video_i420); IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); } From 56dd79c347ba7336e37fad34584a7333712ec807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 16:14:24 +0200 Subject: [PATCH 070/301] mfmediaengine: Allow decoder / converter to be resolved between topology nodes. (cherry picked from commit fa23650ff25680b37b7fae5b96b372beab011ace) CW-Bug-Id: #20833 --- dlls/mfmediaengine/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 9e41d9dad84..d4b3dbbcf3e 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -1101,6 +1101,7 @@ static HRESULT media_engine_create_effects(struct effect *effects, size_t count, for (i = 0; i < count; ++i) { + UINT32 method = MF_CONNECT_ALLOW_DECODER; IMFTopologyNode *node = NULL; if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node))) @@ -1113,7 +1114,8 @@ static HRESULT media_engine_create_effects(struct effect *effects, size_t count, IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); if (effects[i].optional) - IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_AS_OPTIONAL); + method |= MF_CONNECT_AS_OPTIONAL; + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, method); IMFTopology_AddNode(topology, node); IMFTopologyNode_ConnectOutput(last, 0, node, 0); From 89eb2dfe89ffe83124c7a2cd4fd1bf6211d5008b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 May 2024 13:57:34 +0200 Subject: [PATCH 071/301] mfplat: Fix MFCreateMFVideoFormatFromMFMediaType videoInfo.VideoFlags masks. (cherry picked from commit 551d047ae4288dca14f78508385b3b4779c16dee) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 7fd667134b8..dacbd57eddb 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3319,9 +3319,9 @@ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MF sizeof(format->videoInfo.MinimumDisplayAperture), NULL); /* Video flags. */ - format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_PAD_CONTROL_FLAGS); - format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_SOURCE_CONTENT_HINT); - format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_DRM_FLAGS); + format->videoInfo.VideoFlags |= media_type_get_uint32(media_type, &MF_MT_PAD_CONTROL_FLAGS) & MFVideoFlag_PAD_TO_Mask; + format->videoInfo.VideoFlags |= (media_type_get_uint32(media_type, &MF_MT_SOURCE_CONTENT_HINT) << 2) & MFVideoFlag_SrcContentHintMask; + format->videoInfo.VideoFlags |= (media_type_get_uint32(media_type, &MF_MT_DRM_FLAGS) << 5) & (MFVideoFlag_AnalogProtected | MFVideoFlag_DigitallyProtected); if (media_type_get_uint32(media_type, &MF_MT_PAN_SCAN_ENABLED)) { format->videoInfo.VideoFlags |= MFVideoFlag_PanScanEnabled; From 149ee5450e6660759ca6a40bc82c846445ada5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 May 2024 15:24:00 +0200 Subject: [PATCH 072/301] mfplat: Use IMFMediaType_GetBlobSize instead of IMFMediaType_GetBlob. (cherry picked from commit 3404de3075c2cc2484e1bb37e43c24d7baed0ed1) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index dacbd57eddb..2664224423c 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4212,8 +4212,7 @@ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID f if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value))) am_type->lSampleSize = value; - if (FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, NULL, 0, &user_size)) - && hr != E_NOT_SUFFICIENT_BUFFER) + if (FAILED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_size))) user_size = 0; if (IsEqualGUID(&am_type->majortype, &MFMediaType_Audio)) From bce45ac8f8693d4c6ccae131b1e5f9bbdf4ea1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 May 2024 15:28:45 +0200 Subject: [PATCH 073/301] mfplat: Introduce a new init_video_info_header helper. (cherry picked from commit 704c510045b47c975fc6918dcb66640f86932d91) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 2664224423c..3177ae5fbd3 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4122,6 +4122,20 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, } } +static void init_video_info_header(VIDEOINFOHEADER *vih, const GUID *subtype, IMFMediaType *media_type) +{ + VIDEOINFOHEADER2 vih2 = {{0}}; + + init_video_info_header2(&vih2, subtype, media_type); + + vih->rcSource = vih2.rcSource; + vih->rcTarget = vih2.rcTarget; + vih->dwBitRate = vih2.dwBitRate; + vih->dwBitErrorRate = vih2.dwBitErrorRate; + vih->AvgTimePerFrame = vih2.AvgTimePerFrame; + vih->bmiHeader = vih2.bmiHeader; +} + static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) { HRESULT hr; @@ -4136,7 +4150,6 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) || IsEqualGUID(&am_type->formattype, &GUID_NULL)) { - VIDEOINFOHEADER2 vih = {{0}}; VIDEOINFOHEADER *format; am_type->cbFormat = sizeof(*format) + user_size; @@ -4145,13 +4158,7 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us format = (VIDEOINFOHEADER *)am_type->pbFormat; memset(format, 0, sizeof(*format)); - init_video_info_header2(&vih, &am_type->subtype, media_type); - format->rcSource = vih.rcSource; - format->rcTarget = vih.rcTarget; - format->dwBitRate = vih.dwBitRate; - format->dwBitErrorRate = vih.dwBitErrorRate; - format->AvgTimePerFrame = vih.AvgTimePerFrame; - format->bmiHeader = vih.bmiHeader; + init_video_info_header(format, &am_type->subtype, media_type); if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)(format + 1), user_size, NULL))) From 87e6f702df26e6d1d9db2128b9d1cdcdd78f16dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 May 2024 11:11:18 +0200 Subject: [PATCH 074/301] mfplat: Use media_type_get_uint32 in more places. (cherry picked from commit 00758a2e20cbff8780c5619762e0889e99ebdc9a) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 110 ++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 3177ae5fbd3..842827c5e34 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2974,13 +2974,19 @@ HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapper, IMFMediaType **ret) return S_OK; } +static UINT32 media_type_get_uint32(IMFMediaType *media_type, REFGUID guid) +{ + UINT32 value; + return SUCCEEDED(IMFMediaType_GetUINT32(media_type, guid, &value)) ? value : 0; +} + /*********************************************************************** * MFCreateWaveFormatExFromMFMediaType (mfplat.@) */ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVEFORMATEX **ret_format, UINT32 *size, UINT32 flags) { - UINT32 value, extra_size = 0, user_size; + UINT32 extra_size = 0, user_size; WAVEFORMATEX *format; GUID major, subtype, basetype = MFAudioFormat_Base; void *user_data; @@ -3004,7 +3010,7 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE user_size = 0; } - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, &value)) && value > 2 + if (media_type_get_uint32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS) > 2 && SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, NULL))) { if (SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, NULL))) @@ -3029,16 +3035,11 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE format->cbSize = user_size + extra_size; user_data = format + 1; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, &value))) - format->nChannels = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &value))) - format->nSamplesPerSec = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value))) - format->nAvgBytesPerSec = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value))) - format->nBlockAlign = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BITS_PER_SAMPLE, &value))) - format->wBitsPerSample = value; + format->nChannels = media_type_get_uint32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS); + format->nSamplesPerSec = media_type_get_uint32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND); + format->nAvgBytesPerSec = media_type_get_uint32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + format->nBlockAlign = media_type_get_uint32(mediatype, &MF_MT_AUDIO_BLOCK_ALIGNMENT); + format->wBitsPerSample = media_type_get_uint32(mediatype, &MF_MT_AUDIO_BITS_PER_SAMPLE); if (flags == MFWaveFormatExConvertFlag_ForceExtensible) { @@ -3048,13 +3049,11 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE format_ext->SubFormat = subtype; user_data = format_ext + 1; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &value))) - format_ext->Samples.wValidBitsPerSample = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &value))) - format_ext->Samples.wSamplesPerBlock = value; + format_ext->Samples.wValidBitsPerSample = media_type_get_uint32(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + format_ext->Samples.wSamplesPerBlock = media_type_get_uint32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_BLOCK); - if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, &value))) - format_ext->dwChannelMask = value; + if (SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, NULL))) + format_ext->dwChannelMask = media_type_get_uint32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK); else if (format_ext->Format.nChannels < ARRAY_SIZE(default_channel_mask)) format_ext->dwChannelMask = default_channel_mask[format_ext->Format.nChannels]; } @@ -3260,12 +3259,6 @@ HRESULT WINAPI MFCreateAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID return hr; } -static UINT32 media_type_get_uint32(IMFMediaType *media_type, REFGUID guid) -{ - UINT32 value; - return SUCCEEDED(IMFMediaType_GetUINT32(media_type, guid, &value)) ? value : 0; -} - /*********************************************************************** * MFCreateMFVideoFormatFromMFMediaType (mfplat.@) */ @@ -4000,7 +3993,6 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) { - UINT32 num_channels; HRESULT hr; if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) @@ -4011,10 +4003,7 @@ static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 us if (IsEqualGUID(&am_type->formattype, &FORMAT_WaveFormatEx) || IsEqualGUID(&am_type->formattype, &GUID_NULL)) { - UINT32 flags = 0; - - if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels))) - num_channels = 0; + UINT32 flags = 0, num_channels = media_type_get_uint32(media_type, &MF_MT_AUDIO_NUM_CHANNELS); if (SUCCEEDED(IMFMediaType_GetItem(media_type, &MF_MT_AUDIO_CHANNEL_MASK, NULL)) || SUCCEEDED(IMFMediaType_GetItem(media_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, NULL)) @@ -4042,7 +4031,7 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, { struct uncompressed_video_format *video_format = mf_get_video_format(subtype); DXVA_ExtendedFormat *format = (DXVA_ExtendedFormat *)&vih->dwControlFlags; - UINT32 image_size, bitrate, sample_size, width, height, value; + UINT32 image_size, width, height, value; UINT64 frame_size, frame_rate; vih->bmiHeader.biSize = sizeof(vih->bmiHeader); @@ -4054,14 +4043,11 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, else vih->bmiHeader.biCompression = subtype->Data1; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &bitrate))) - vih->dwBitRate = bitrate; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &bitrate))) - vih->dwBitErrorRate = bitrate; + vih->dwBitRate = media_type_get_uint32(media_type, &MF_MT_AVG_BITRATE); + vih->dwBitErrorRate = media_type_get_uint32(media_type, &MF_MT_AVG_BIT_ERROR_RATE); if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate)) && (frame_rate >> 32)) vih->AvgTimePerFrame = round(10000000. * (UINT32)frame_rate / (frame_rate >> 32)); - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) - vih->bmiHeader.biSizeImage = sample_size; + vih->bmiHeader.biSizeImage = media_type_get_uint32(media_type, &MF_MT_SAMPLE_SIZE); if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) { @@ -4069,7 +4055,7 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, INT32 stride; width = frame_size >> 32; - if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) + if (!(stride = media_type_get_uint32(media_type, &MF_MT_DEFAULT_STRIDE))) stride = width * (bottom_up ? -1 : 1); else if (video_format) stride /= video_format->bpp / 8; @@ -4088,37 +4074,29 @@ static void init_video_info_header2(VIDEOINFOHEADER2 *vih, const GUID *subtype, } } - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_CHROMA_SITING, &value))) - format->VideoChromaSubsampling = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE, &value))) - format->NominalRange = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_YUV_MATRIX, &value))) - format->VideoTransferMatrix = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_LIGHTING, &value))) - format->VideoLighting = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_VIDEO_PRIMARIES, &value))) - format->VideoPrimaries = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_TRANSFER_FUNCTION, &value))) - format->VideoTransferFunction = value; + format->VideoChromaSubsampling = media_type_get_uint32(media_type, &MF_MT_VIDEO_CHROMA_SITING); + format->NominalRange = media_type_get_uint32(media_type, &MF_MT_VIDEO_NOMINAL_RANGE); + format->VideoTransferMatrix = media_type_get_uint32(media_type, &MF_MT_YUV_MATRIX); + format->VideoLighting = media_type_get_uint32(media_type, &MF_MT_VIDEO_LIGHTING); + format->VideoPrimaries = media_type_get_uint32(media_type, &MF_MT_VIDEO_PRIMARIES); + format->VideoTransferFunction = media_type_get_uint32(media_type, &MF_MT_TRANSFER_FUNCTION); if (format->VideoChromaSubsampling || format->NominalRange || format->VideoTransferMatrix || format->VideoLighting || format->VideoPrimaries || format->VideoTransferFunction) format->SampleFormat = AMCONTROL_COLORINFO_PRESENT; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value))) + switch ((value = media_type_get_uint32(media_type, &MF_MT_INTERLACE_MODE))) { - switch (value) - { - case MFVideoInterlace_Progressive: - break; - case MFVideoInterlace_MixedInterlaceOrProgressive: - vih->dwInterlaceFlags = AMINTERLACE_DisplayModeBobOrWeave | AMINTERLACE_IsInterlaced; - break; - default: - FIXME("MF_MT_INTERLACE_MODE %u not implemented!\n", value); - vih->dwInterlaceFlags = AMINTERLACE_IsInterlaced; - break; - } + case MFVideoInterlace_Unknown: + case MFVideoInterlace_Progressive: + break; + case MFVideoInterlace_MixedInterlaceOrProgressive: + vih->dwInterlaceFlags = AMINTERLACE_DisplayModeBobOrWeave | AMINTERLACE_IsInterlaced; + break; + default: + FIXME("MF_MT_INTERLACE_MODE %u not implemented!\n", value); + vih->dwInterlaceFlags = AMINTERLACE_IsInterlaced; + break; } } @@ -4202,7 +4180,7 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us */ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID format, AM_MEDIA_TYPE *am_type) { - UINT32 value, user_size; + UINT32 user_size; HRESULT hr; TRACE("%p, %s, %p.\n", media_type, debugstr_mf_guid(&format), am_type); @@ -4214,10 +4192,8 @@ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID f || FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &am_type->subtype))) goto done; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) - am_type->bFixedSizeSamples = value; - if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value))) - am_type->lSampleSize = value; + am_type->bFixedSizeSamples = media_type_get_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES); + am_type->lSampleSize = media_type_get_uint32(media_type, &MF_MT_SAMPLE_SIZE); if (FAILED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_size))) user_size = 0; From b4fa580b2c8815275319b331b826d8fdb78c82f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 May 2024 10:35:36 +0200 Subject: [PATCH 075/301] mfplat: Factor AM_MEDIA_TYPE video format allocation. (cherry picked from commit 772ad6e8a96b990b3e39c4c2ad6b71bdc4c35417) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 74 +++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 842827c5e34..950732e26d0 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3991,7 +3991,7 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons return MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih2, sizeof(vih2), subtype); } -static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) +static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, IMFMediaType *media_type) { HRESULT hr; @@ -4114,7 +4114,28 @@ static void init_video_info_header(VIDEOINFOHEADER *vih, const GUID *subtype, IM vih->bmiHeader = vih2.bmiHeader; } -static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 user_size, IMFMediaType *media_type) +static UINT32 get_am_media_type_video_format_size(const GUID *format_type, IMFMediaType *media_type) +{ + if (IsEqualGUID(format_type, &FORMAT_VideoInfo)) + { + UINT32 size = sizeof(VIDEOINFOHEADER), user_size; + if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_size))) + size += user_size; + return size; + } + + if (IsEqualGUID(format_type, &FORMAT_VideoInfo2)) + { + UINT32 size = sizeof(VIDEOINFOHEADER2), user_size; + if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_size))) + size += user_size; + return size; + } + + return 0; +} + +static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaType *media_type) { HRESULT hr; @@ -4125,45 +4146,36 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us return MFCreateMFVideoFormatFromMFMediaType(media_type, (MFVIDEOFORMAT **)&am_type->pbFormat, (UINT32 *)&am_type->cbFormat); - if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo) - || IsEqualGUID(&am_type->formattype, &GUID_NULL)) - { - VIDEOINFOHEADER *format; + if (IsEqualGUID(&am_type->formattype, &GUID_NULL)) + am_type->formattype = FORMAT_VideoInfo; - am_type->cbFormat = sizeof(*format) + user_size; - if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) - return E_OUTOFMEMORY; - format = (VIDEOINFOHEADER *)am_type->pbFormat; - memset(format, 0, sizeof(*format)); + am_type->cbFormat = get_am_media_type_video_format_size(&am_type->formattype, media_type); + if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) + return E_OUTOFMEMORY; + memset(am_type->pbFormat, 0, am_type->cbFormat); + if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo)) + { + VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)am_type->pbFormat; init_video_info_header(format, &am_type->subtype, media_type); - if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, - (BYTE *)(format + 1), user_size, NULL))) + if (am_type->cbFormat > sizeof(*format) && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, + (BYTE *)(format + 1), am_type->cbFormat - sizeof(*format), NULL))) return hr; - format->bmiHeader.biSize += user_size; + format->bmiHeader.biSize += am_type->cbFormat - sizeof(*format); - am_type->formattype = FORMAT_VideoInfo; am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); } else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2)) { - VIDEOINFOHEADER2 *format; - - am_type->cbFormat = sizeof(*format) + user_size; - if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) - return E_OUTOFMEMORY; - format = (VIDEOINFOHEADER2 *)am_type->pbFormat; - memset(format, 0, sizeof(*format)); - + VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)am_type->pbFormat; init_video_info_header2(format, &am_type->subtype, media_type); - if (user_size && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, - (BYTE *)(format + 1), user_size, NULL))) + if (am_type->cbFormat > sizeof(*format) && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_USER_DATA, + (BYTE *)(format + 1), am_type->cbFormat - sizeof(*format), NULL))) return hr; - format->bmiHeader.biSize += user_size; + format->bmiHeader.biSize += am_type->cbFormat - sizeof(*format); - am_type->formattype = FORMAT_VideoInfo2; am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); } else @@ -4180,7 +4192,6 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, UINT32 us */ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID format, AM_MEDIA_TYPE *am_type) { - UINT32 user_size; HRESULT hr; TRACE("%p, %s, %p.\n", media_type, debugstr_mf_guid(&format), am_type); @@ -4195,13 +4206,10 @@ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID f am_type->bFixedSizeSamples = media_type_get_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES); am_type->lSampleSize = media_type_get_uint32(media_type, &MF_MT_SAMPLE_SIZE); - if (FAILED(IMFMediaType_GetBlobSize(media_type, &MF_MT_USER_DATA, &user_size))) - user_size = 0; - if (IsEqualGUID(&am_type->majortype, &MFMediaType_Audio)) - hr = init_am_media_type_audio_format(am_type, user_size, media_type); + hr = init_am_media_type_audio_format(am_type, media_type); else if (IsEqualGUID(&am_type->majortype, &MFMediaType_Video)) - hr = init_am_media_type_video_format(am_type, user_size, media_type); + hr = init_am_media_type_video_format(am_type, media_type); else { FIXME("Not implemented!\n"); From 27a599553347bd673ed401b44408858c19beb943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 May 2024 12:13:27 +0200 Subject: [PATCH 076/301] mfplat: Set AM_MEDIA_TYPE bTemporalCompression and bFixedSizeSamples. (cherry picked from commit 0b5c04c5178a48dfcf66bb13e1a8b855bbedb7ed) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 6 ++++++ dlls/mfplat/tests/mfplat.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 950732e26d0..d7477409323 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4137,6 +4137,7 @@ static UINT32 get_am_media_type_video_format_size(const GUID *format_type, IMFMe static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaType *media_type) { + struct uncompressed_video_format *video_format = mf_get_video_format(&am_type->subtype); HRESULT hr; if (IsEqualGUID(&am_type->formattype, &FORMAT_WaveFormatEx)) @@ -4165,6 +4166,8 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT format->bmiHeader.biSize += am_type->cbFormat - sizeof(*format); am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); + am_type->bFixedSizeSamples = !!video_format; + am_type->bTemporalCompression = !video_format; } else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2)) { @@ -4177,6 +4180,8 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT format->bmiHeader.biSize += am_type->cbFormat - sizeof(*format); am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); + am_type->bFixedSizeSamples = !!video_format; + am_type->bTemporalCompression = !video_format; } else { @@ -4203,6 +4208,7 @@ HRESULT WINAPI MFInitAMMediaTypeFromMFMediaType(IMFMediaType *media_type, GUID f || FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &am_type->subtype))) goto done; + am_type->bTemporalCompression = !media_type_get_uint32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT); am_type->bFixedSizeSamples = media_type_get_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES); am_type->lSampleSize = media_type_get_uint32(media_type, &MF_MT_SAMPLE_SIZE); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 0bdc551545e..3a1868599dc 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7383,6 +7383,9 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Audio), "got %s.\n", debugstr_guid(&am_type.majortype)); ok(IsEqualGUID(&am_type.subtype, &MFAudioFormat_PCM), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 0, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 1, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); ok(IsEqualGUID(&am_type.formattype, &FORMAT_WaveFormatEx), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(WAVEFORMATEX), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); @@ -7419,6 +7422,9 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 1, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 0, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); ok(IsEqualGUID(&am_type.formattype, &FORMAT_VideoInfo), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(VIDEOINFOHEADER), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); @@ -7426,6 +7432,9 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 1, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 0, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); ok(IsEqualGUID(&am_type.formattype, &FORMAT_VideoInfo2), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(VIDEOINFOHEADER2), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); @@ -7433,6 +7442,9 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); ok(IsEqualGUID(&am_type.subtype, &MFVideoFormat_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 0, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 1, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); ok(IsEqualGUID(&am_type.formattype, &FORMAT_MFVideoFormat), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(MFVIDEOFORMAT), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); From 8d1bc0fbe25e26308d76343c8890979b2b8bf873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 May 2024 10:57:54 +0200 Subject: [PATCH 077/301] mfplat: Implement FORMAT_MPEGVideo for MFInitAMMediaTypeFromMFMediaType. (cherry picked from commit dce8d8b55283eaeadef4e6904965d18569c62503) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 34 ++++++++++- dlls/mfplat/tests/mfplat.c | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index d7477409323..aa85c21f145 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4132,6 +4132,14 @@ static UINT32 get_am_media_type_video_format_size(const GUID *format_type, IMFMe return size; } + if (IsEqualGUID(format_type, &FORMAT_MPEGVideo)) + { + UINT32 size = sizeof(MPEG1VIDEOINFO), sequence_size; + if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, &sequence_size))) + size += sequence_size; + return size; + } + return 0; } @@ -4148,7 +4156,13 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT (UINT32 *)&am_type->cbFormat); if (IsEqualGUID(&am_type->formattype, &GUID_NULL)) - am_type->formattype = FORMAT_VideoInfo; + { + if (IsEqualGUID(&am_type->subtype, &MEDIASUBTYPE_MPEG1Payload) + || IsEqualGUID(&am_type->subtype, &MEDIASUBTYPE_MPEG1Packet)) + am_type->formattype = FORMAT_MPEGVideo; + else + am_type->formattype = FORMAT_VideoInfo; + } am_type->cbFormat = get_am_media_type_video_format_size(&am_type->formattype, media_type); if (!(am_type->pbFormat = CoTaskMemAlloc(am_type->cbFormat))) @@ -4183,6 +4197,24 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT am_type->bFixedSizeSamples = !!video_format; am_type->bTemporalCompression = !video_format; } + else if (IsEqualGUID(&am_type->formattype, &FORMAT_MPEGVideo)) + { + MPEG1VIDEOINFO *format = (MPEG1VIDEOINFO *)am_type->pbFormat; + + init_video_info_header(&format->hdr, &am_type->subtype, media_type); + format->hdr.bmiHeader.biSize = 0; + + format->dwStartTimeCode = media_type_get_uint32(media_type, &MF_MT_MPEG_START_TIME_CODE); + + if (am_type->cbFormat > sizeof(*format) && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, + format->bSequenceHeader, am_type->cbFormat - sizeof(*format), NULL))) + return hr; + format->cbSequenceHeader = am_type->cbFormat - sizeof(*format); + + am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); + am_type->bFixedSizeSamples = !!video_format; + am_type->bTemporalCompression = !video_format; + } else { WARN("Unknown format %s\n", debugstr_mf_guid(&am_type->formattype)); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3a1868599dc..b4c930ff434 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7346,11 +7346,13 @@ static void test_MFCreateMFVideoFormatFromMFMediaType(void) static void test_MFInitAMMediaTypeFromMFMediaType(void) { static const MFVideoArea aperture = {.OffsetX = {.fract = 1, .value = 2}, .OffsetY = {.fract = 3, .value = 4}, .Area={56,78}}; + static const BYTE dummy_mpeg_sequence[] = {0x04,0x05,0x06,0x07,0x08}; static const BYTE dummy_user_data[] = {0x01,0x02,0x03}; WAVEFORMATEXTENSIBLE *wave_format_ext; VIDEOINFOHEADER *video_info; WAVEFORMATEX *wave_format; + MPEG1VIDEOINFO *mpeg1_info; IMFMediaType *media_type, *other_type; AM_MEDIA_TYPE am_type; MFVideoArea *area; @@ -7448,6 +7450,16 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(IsEqualGUID(&am_type.formattype, &FORMAT_MFVideoFormat), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(MFVIDEOFORMAT), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MPEGVideo, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 1, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 0, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEGVideo), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + CoTaskMemFree(am_type.pbFormat); /* test WAVEFORMATEX mapping */ @@ -7977,6 +7989,116 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) CoTaskMemFree(am_type.pbFormat); IMFMediaType_Release(other_type); + IMFMediaType_DeleteAllItems(media_type); + + + /* MEDIASUBTYPE_MPEG1Packet and MEDIASUBTYPE_MPEG1Payload use FORMAT_MPEGVideo by default */ + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MEDIASUBTYPE_MPEG1Packet); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_MPEG1Packet), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 0, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 1, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEGVideo), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + CoTaskMemFree(am_type.pbFormat); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MEDIASUBTYPE_MPEG1Payload); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_MPEG1Payload), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(am_type.bFixedSizeSamples == 0, "got %u\n", am_type.bFixedSizeSamples); + ok(am_type.bTemporalCompression == 1, "got %u\n", am_type.bTemporalCompression); + ok(am_type.lSampleSize == 0, "got %lu\n", am_type.lSampleSize); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEGVideo), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->cbSequenceHeader == 0, "got %lu\n", mpeg1_info->cbSequenceHeader); + ok(mpeg1_info->dwStartTimeCode == 0, "got %lu\n", mpeg1_info->dwStartTimeCode); + ok(mpeg1_info->hdr.bmiHeader.biPlanes == 1, "got %u\n", mpeg1_info->hdr.bmiHeader.biPlanes); + ok(mpeg1_info->hdr.bmiHeader.biBitCount == 0, "got %u\n", mpeg1_info->hdr.bmiHeader.biBitCount); + todo_wine ok(mpeg1_info->hdr.bmiHeader.biCompression == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biCompression); + CoTaskMemFree(am_type.pbFormat); + + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)12 << 32 | 34); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->hdr.bmiHeader.biPlanes == 1, "got %u\n", mpeg1_info->hdr.bmiHeader.biPlanes); + ok(mpeg1_info->hdr.bmiHeader.biBitCount == 0, "got %u\n", mpeg1_info->hdr.bmiHeader.biBitCount); + ok(mpeg1_info->hdr.bmiHeader.biWidth == 12, "got %lu\n", mpeg1_info->hdr.bmiHeader.biWidth); + ok(mpeg1_info->hdr.bmiHeader.biHeight == 34, "got %lu\n", mpeg1_info->hdr.bmiHeader.biHeight); + ok(mpeg1_info->hdr.bmiHeader.biSizeImage == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biSizeImage); + ok(mpeg1_info->hdr.bmiHeader.biXPelsPerMeter == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biXPelsPerMeter); + ok(mpeg1_info->hdr.bmiHeader.biYPelsPerMeter == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biYPelsPerMeter); + CoTaskMemFree(am_type.pbFormat); + + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, (UINT64)12 << 32 | 34); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->hdr.bmiHeader.biXPelsPerMeter == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biXPelsPerMeter); + ok(mpeg1_info->hdr.bmiHeader.biYPelsPerMeter == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biYPelsPerMeter); + CoTaskMemFree(am_type.pbFormat); + + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->dwStartTimeCode == 1234, "got %lu\n", mpeg1_info->dwStartTimeCode); + CoTaskMemFree(am_type.pbFormat); + + /* MF_MT_USER_DATA is ignored */ + + hr = IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)dummy_user_data, sizeof(dummy_user_data)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->hdr.bmiHeader.biSize == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biSize); + ok(mpeg1_info->cbSequenceHeader == 0, "got %lu\n", mpeg1_info->cbSequenceHeader); + CoTaskMemFree(am_type.pbFormat); + + /* MF_MT_MPEG_SEQUENCE_HEADER is used instead in MPEG1VIDEOINFO */ + + hr = IMFMediaType_SetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, (BYTE *)dummy_mpeg_sequence, sizeof(dummy_mpeg_sequence)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO) + sizeof(dummy_mpeg_sequence), "got %lu\n", am_type.cbFormat); + mpeg1_info = (MPEG1VIDEOINFO *)am_type.pbFormat; + ok(mpeg1_info->hdr.bmiHeader.biSize == 0, "got %lu\n", mpeg1_info->hdr.bmiHeader.biSize); + ok(mpeg1_info->cbSequenceHeader == sizeof(dummy_mpeg_sequence), "got %lu\n", mpeg1_info->cbSequenceHeader); + ok(!memcmp(mpeg1_info->bSequenceHeader, dummy_mpeg_sequence, mpeg1_info->cbSequenceHeader), "got wrong data\n"); + CoTaskMemFree(am_type.pbFormat); + + /* MFVIDEOFORMAT loses MF_MT_MPEG_SEQUENCE_HEADER */ + + hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MFVideoFormat, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MFVIDEOFORMAT), "got %lu\n", am_type.cbFormat); + CoTaskMemFree(am_type.pbFormat); + + IMFMediaType_DeleteAllItems(media_type); + IMFMediaType_Release(media_type); } From 7b5343d0eb78c77e18f85ab6467e76fd136fdf69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 May 2024 10:57:54 +0200 Subject: [PATCH 078/301] mfplat: Implement FORMAT_MPEG2Video for MFInitAMMediaTypeFromMFMediaType. (cherry picked from commit ec0455b97a0faf9ca1dc0f08afd8aab75881f811) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 30 ++++++++++++++ dlls/mfplat/tests/mfplat.c | 83 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index aa85c21f145..202fbf34834 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4140,6 +4140,14 @@ static UINT32 get_am_media_type_video_format_size(const GUID *format_type, IMFMe return size; } + if (IsEqualGUID(format_type, &FORMAT_MPEG2Video)) + { + UINT32 size = sizeof(MPEG2VIDEOINFO), sequence_size; + if (SUCCEEDED(IMFMediaType_GetBlobSize(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, &sequence_size))) + size += sequence_size; + return size; + } + return 0; } @@ -4160,6 +4168,8 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT if (IsEqualGUID(&am_type->subtype, &MEDIASUBTYPE_MPEG1Payload) || IsEqualGUID(&am_type->subtype, &MEDIASUBTYPE_MPEG1Packet)) am_type->formattype = FORMAT_MPEGVideo; + else if (IsEqualGUID(&am_type->subtype, &MEDIASUBTYPE_MPEG2_VIDEO)) + am_type->formattype = FORMAT_MPEG2Video; else am_type->formattype = FORMAT_VideoInfo; } @@ -4215,6 +4225,26 @@ static HRESULT init_am_media_type_video_format(AM_MEDIA_TYPE *am_type, IMFMediaT am_type->bFixedSizeSamples = !!video_format; am_type->bTemporalCompression = !video_format; } + else if (IsEqualGUID(&am_type->formattype, &FORMAT_MPEG2Video)) + { + MPEG2VIDEOINFO *format = (MPEG2VIDEOINFO *)am_type->pbFormat; + + init_video_info_header2(&format->hdr, &am_type->subtype, media_type); + + format->dwStartTimeCode = media_type_get_uint32(media_type, &MF_MT_MPEG_START_TIME_CODE); + format->dwProfile = media_type_get_uint32(media_type, &MF_MT_MPEG2_PROFILE); + format->dwLevel = media_type_get_uint32(media_type, &MF_MT_MPEG2_LEVEL); + format->dwFlags = media_type_get_uint32(media_type, &MF_MT_MPEG2_FLAGS); + + if (am_type->cbFormat > sizeof(*format) && FAILED(hr = IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, + (BYTE *)format->dwSequenceHeader, am_type->cbFormat - sizeof(*format), NULL))) + return hr; + format->cbSequenceHeader = am_type->cbFormat - sizeof(*format); + + am_type->subtype = get_am_subtype_for_mf_subtype(am_type->subtype); + am_type->bFixedSizeSamples = !!video_format; + am_type->bTemporalCompression = !video_format; + } else { WARN("Unknown format %s\n", debugstr_mf_guid(&am_type->formattype)); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b4c930ff434..a1c152e08eb 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7353,6 +7353,7 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) VIDEOINFOHEADER *video_info; WAVEFORMATEX *wave_format; MPEG1VIDEOINFO *mpeg1_info; + MPEG2VIDEOINFO *mpeg2_info; IMFMediaType *media_type, *other_type; AM_MEDIA_TYPE am_type; MFVideoArea *area; @@ -7460,6 +7461,13 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEGVideo), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(MPEG1VIDEOINFO), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MPEG2Video, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_RGB32), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEG2Video), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO), "got %lu\n", am_type.cbFormat); + CoTaskMemFree(am_type.pbFormat); /* test WAVEFORMATEX mapping */ @@ -8100,6 +8108,81 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) IMFMediaType_DeleteAllItems(media_type); + /* MEDIASUBTYPE_MPEG2_VIDEO uses FORMAT_MPEG2Video by default */ + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MEDIASUBTYPE_MPEG2_VIDEO); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&am_type.majortype, &MFMediaType_Video), "got %s.\n", debugstr_guid(&am_type.majortype)); + ok(IsEqualGUID(&am_type.subtype, &MEDIASUBTYPE_MPEG2_VIDEO), "got %s.\n", debugstr_guid(&am_type.subtype)); + ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEG2Video), "got %s.\n", debugstr_guid(&am_type.formattype)); + ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg2_info = (MPEG2VIDEOINFO *)am_type.pbFormat; + ok(mpeg2_info->dwStartTimeCode == 0, "got %lu\n", mpeg2_info->dwStartTimeCode); + ok(mpeg2_info->dwProfile == 0, "got %lu\n", mpeg2_info->dwProfile); + ok(mpeg2_info->dwLevel == 0, "got %lu\n", mpeg2_info->dwLevel); + ok(mpeg2_info->dwFlags == 0, "got %lu\n", mpeg2_info->dwFlags); + ok(mpeg2_info->cbSequenceHeader == 0, "got %lu\n", mpeg2_info->cbSequenceHeader); + CoTaskMemFree(am_type.pbFormat); + + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, 6); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_LEVEL, 7); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_FLAGS, 8910); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg2_info = (MPEG2VIDEOINFO *)am_type.pbFormat; + ok(mpeg2_info->dwStartTimeCode == 1234, "got %lu\n", mpeg2_info->dwStartTimeCode); + ok(mpeg2_info->dwProfile == 6, "got %lu\n", mpeg2_info->dwProfile); + ok(mpeg2_info->dwLevel == 7, "got %lu\n", mpeg2_info->dwLevel); + ok(mpeg2_info->dwFlags == 8910, "got %lu\n", mpeg2_info->dwFlags); + CoTaskMemFree(am_type.pbFormat); + + /* MF_MT_USER_DATA is ignored */ + + hr = IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)dummy_user_data, sizeof(dummy_user_data)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO), "got %lu\n", am_type.cbFormat); + mpeg2_info = (MPEG2VIDEOINFO *)am_type.pbFormat; + ok(mpeg2_info->hdr.bmiHeader.biSize == sizeof(mpeg2_info->hdr.bmiHeader), "got %lu\n", mpeg2_info->hdr.bmiHeader.biSize); + ok(mpeg2_info->cbSequenceHeader == 0, "got %lu\n", mpeg2_info->cbSequenceHeader); + CoTaskMemFree(am_type.pbFormat); + + /* MF_MT_MPEG_SEQUENCE_HEADER is used instead in MPEG2VIDEOINFO */ + + hr = IMFMediaType_SetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, (BYTE *)dummy_mpeg_sequence, sizeof(dummy_mpeg_sequence)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO) + sizeof(dummy_mpeg_sequence), "got %lu\n", am_type.cbFormat); + mpeg2_info = (MPEG2VIDEOINFO *)am_type.pbFormat; + ok(mpeg2_info->hdr.bmiHeader.biSize == sizeof(mpeg2_info->hdr.bmiHeader), "got %lu\n", mpeg2_info->hdr.bmiHeader.biSize); + ok(mpeg2_info->cbSequenceHeader == sizeof(dummy_mpeg_sequence), "got %lu\n", mpeg2_info->cbSequenceHeader); + ok(!memcmp(mpeg2_info->dwSequenceHeader, dummy_mpeg_sequence, mpeg2_info->cbSequenceHeader), "got wrong data\n"); + CoTaskMemFree(am_type.pbFormat); + + /* MFVIDEOFORMAT loses MF_MT_MPEG_SEQUENCE_HEADER */ + + hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_MFVideoFormat, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(am_type.cbFormat == sizeof(MFVIDEOFORMAT), "got %lu\n", am_type.cbFormat); + CoTaskMemFree(am_type.pbFormat); + + IMFMediaType_DeleteAllItems(media_type); + + IMFMediaType_Release(media_type); } From 62664c138391ac5ebff859d31b59605d40eb359f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 17:25:38 +0200 Subject: [PATCH 079/301] mfplat: Implement MFInitMediaTypeFromMPEG1VideoInfo. (cherry picked from commit 8c77a1a09942b9fd84db229ddcda8e97cdbff744) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 25 ++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 113 +++++++++++++++++++++++++++++++++++++ include/mfapi.h | 3 + 4 files changed, 142 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 202fbf34834..cc786b21d63 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -31,6 +31,7 @@ #include "ksmedia.h" #include "amvideo.h" #include "wmcodecdsp.h" +#include "wmsdkidl.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -3991,6 +3992,27 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons return MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih2, sizeof(vih2), subtype); } +/*********************************************************************** + * MFInitMediaTypeFromMPEG1VideoInfo (mfplat.@) + */ +HRESULT WINAPI MFInitMediaTypeFromMPEG1VideoInfo(IMFMediaType *media_type, const MPEG1VIDEOINFO *vih, UINT32 size, + const GUID *subtype) +{ + HRESULT hr; + + TRACE("%p, %p, %u, %s.\n", media_type, vih, size, debugstr_guid(subtype)); + + if (FAILED(hr = MFInitMediaTypeFromVideoInfoHeader(media_type, &vih->hdr, sizeof(vih->hdr), subtype))) + return hr; + + if (vih->dwStartTimeCode) + mediatype_set_uint32(media_type, &MF_MT_MPEG_START_TIME_CODE, vih->dwStartTimeCode, &hr); + if (vih->cbSequenceHeader) + mediatype_set_blob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, vih->bSequenceHeader, vih->cbSequenceHeader, &hr); + + return hr; +} + static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, IMFMediaType *media_type) { HRESULT hr; @@ -4318,6 +4340,9 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM else if (IsEqualGUID(&am_type->formattype, &FORMAT_VideoInfo2) && am_type->cbFormat >= sizeof(VIDEOINFOHEADER2)) hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, (VIDEOINFOHEADER2 *)am_type->pbFormat, am_type->cbFormat, subtype); + else if (IsEqualGUID(&am_type->formattype, &FORMAT_MPEGVideo) + && am_type->cbFormat >= sizeof(MPEG1VIDEOINFO)) + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, (MPEG1VIDEOINFO *)am_type->pbFormat, am_type->cbFormat, subtype); else { FIXME("Unsupported format type %s / size %ld.\n", debugstr_guid(&am_type->formattype), am_type->cbFormat); diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 57db3cdf9f6..6babe6c6498 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -121,7 +121,7 @@ @ stdcall MFInitAttributesFromBlob(ptr ptr long) @ stdcall MFInitMediaTypeFromAMMediaType(ptr ptr) @ stdcall MFInitMediaTypeFromMFVideoFormat(ptr ptr long) -@ stub MFInitMediaTypeFromMPEG1VideoInfo +@ stdcall MFInitMediaTypeFromMPEG1VideoInfo(ptr ptr long ptr) @ stub MFInitMediaTypeFromMPEG2VideoInfo @ stdcall MFInitMediaTypeFromVideoInfoHeader2(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromVideoInfoHeader(ptr ptr long ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index a1c152e08eb..9bccc5cd968 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -11471,6 +11471,118 @@ static void test_MFInitMediaTypeFromVideoInfoHeader2(void) IMFMediaType_Release(media_type); } +static void test_MFInitMediaTypeFromMPEG1VideoInfo(void) +{ + IMFMediaType *media_type; + MPEG1VIDEOINFO vih; + BYTE buffer[64]; + UINT32 value32; + UINT64 value64; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&vih, 0, sizeof(vih)); + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, 0, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &GUID_NULL), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biWidth = 16; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biHeight = -32; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biHeight = 32; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == MFVideoInterlace_Progressive, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)1 << 32 | 1), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biXPelsPerMeter = 2; + vih.hdr.bmiHeader.biYPelsPerMeter = 3; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)1 << 32 | 1), "Unexpected value %#I64x.\n", value64); + + value32 = 0xdeadbeef; + vih.hdr.bmiHeader.biSizeImage = 12345; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwStartTimeCode = 1234; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1234, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetItem(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + memset(buffer, 0xcd, sizeof(buffer)); + vih.cbSequenceHeader = 1; + vih.bSequenceHeader[0] = 0xad; + hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, buffer, sizeof(buffer), &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1, "Unexpected value %#x.\n", value32); + ok(buffer[0] == 0xad, "Unexpected value %#x.\n", buffer[0]); + + IMFMediaType_Release(media_type); +} + static void test_MFInitMediaTypeFromAMMediaType(void) { static const MFVideoArea expect_aperture = {.OffsetX = {.value = 13}, .OffsetY = {.value = 46}, .Area = {.cx = 110, .cy = 410}}; @@ -12091,6 +12203,7 @@ START_TEST(mfplat) test_MFCreateVideoMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromVideoInfoHeader2(); + test_MFInitMediaTypeFromMPEG1VideoInfo(); test_MFInitMediaTypeFromAMMediaType(); test_MFCreatePathFromURL(); test_2dbuffer_copy(); diff --git a/include/mfapi.h b/include/mfapi.h index 0a9f7c6f415..8bd3fd6e4f9 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -510,6 +510,7 @@ typedef struct tagVIDEOINFOHEADER VIDEOINFOHEADER; struct tagVIDEOINFOHEADER2; typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; typedef struct _AMMediaType AM_MEDIA_TYPE; +typedef struct tagMPEG1VIDEOINFO MPEG1VIDEOINFO; HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue); @@ -600,6 +601,8 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader(IMFMediaType *media_type, cons UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, const VIDEOINFOHEADER2 *vih, UINT32 size, const GUID *subtype); +HRESULT WINAPI MFInitMediaTypeFromMPEG1VideoInfo(IMFMediaType *media_type, const MPEG1VIDEOINFO *vih, + UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInitVideoFormat_RGB(MFVIDEOFORMAT *format, DWORD width, DWORD height, DWORD d3dformat); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); From 73433f51e31abdb9f3c8cdf784ac2600dc5492b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 18:04:21 +0200 Subject: [PATCH 080/301] mfplat: Implement MFInitMediaTypeFromMPEG2VideoInfo. (cherry picked from commit 9fac5897651e9d04e28bbd58021d7aabfc93bcf9) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 31 ++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 143 +++++++++++++++++++++++++++++++++++++ include/mfapi.h | 3 + 4 files changed, 178 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index cc786b21d63..22b8bb90821 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -4013,6 +4013,34 @@ HRESULT WINAPI MFInitMediaTypeFromMPEG1VideoInfo(IMFMediaType *media_type, const return hr; } +/*********************************************************************** + * MFInitMediaTypeFromMPEG2VideoInfo (mfplat.@) + */ +HRESULT WINAPI MFInitMediaTypeFromMPEG2VideoInfo(IMFMediaType *media_type, const MPEG2VIDEOINFO *vih, UINT32 size, + const GUID *subtype) +{ + HRESULT hr; + + TRACE("%p, %p, %u, %s.\n", media_type, vih, size, debugstr_guid(subtype)); + + if (FAILED(hr = MFInitMediaTypeFromVideoInfoHeader2(media_type, &vih->hdr, sizeof(vih->hdr), subtype))) + return hr; + + if (vih->dwStartTimeCode) + mediatype_set_uint32(media_type, &MF_MT_MPEG_START_TIME_CODE, vih->dwStartTimeCode, &hr); + if (vih->cbSequenceHeader) + mediatype_set_blob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, (BYTE *)vih->dwSequenceHeader, vih->cbSequenceHeader, &hr); + + if (vih->dwProfile) + mediatype_set_uint32(media_type, &MF_MT_MPEG2_PROFILE, vih->dwProfile, &hr); + if (vih->dwLevel) + mediatype_set_uint32(media_type, &MF_MT_MPEG2_LEVEL, vih->dwLevel, &hr); + if (vih->dwFlags) + mediatype_set_uint32(media_type, &MF_MT_MPEG2_FLAGS, vih->dwFlags, &hr); + + return hr; +} + static HRESULT init_am_media_type_audio_format(AM_MEDIA_TYPE *am_type, IMFMediaType *media_type) { HRESULT hr; @@ -4343,6 +4371,9 @@ HRESULT WINAPI MFInitMediaTypeFromAMMediaType(IMFMediaType *media_type, const AM else if (IsEqualGUID(&am_type->formattype, &FORMAT_MPEGVideo) && am_type->cbFormat >= sizeof(MPEG1VIDEOINFO)) hr = MFInitMediaTypeFromMPEG1VideoInfo(media_type, (MPEG1VIDEOINFO *)am_type->pbFormat, am_type->cbFormat, subtype); + else if (IsEqualGUID(&am_type->formattype, &FORMAT_MPEG2Video) + && am_type->cbFormat >= sizeof(MPEG2VIDEOINFO)) + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, (MPEG2VIDEOINFO *)am_type->pbFormat, am_type->cbFormat, subtype); else { FIXME("Unsupported format type %s / size %ld.\n", debugstr_guid(&am_type->formattype), am_type->cbFormat); diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 6babe6c6498..e311b3cf493 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -122,7 +122,7 @@ @ stdcall MFInitMediaTypeFromAMMediaType(ptr ptr) @ stdcall MFInitMediaTypeFromMFVideoFormat(ptr ptr long) @ stdcall MFInitMediaTypeFromMPEG1VideoInfo(ptr ptr long ptr) -@ stub MFInitMediaTypeFromMPEG2VideoInfo +@ stdcall MFInitMediaTypeFromMPEG2VideoInfo(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromVideoInfoHeader2(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromVideoInfoHeader(ptr ptr long ptr) @ stdcall MFInitMediaTypeFromWaveFormatEx(ptr ptr long) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 9bccc5cd968..19edbe41e8a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -11583,6 +11583,148 @@ static void test_MFInitMediaTypeFromMPEG1VideoInfo(void) IMFMediaType_Release(media_type); } +static void test_MFInitMediaTypeFromMPEG2VideoInfo(void) +{ + IMFMediaType *media_type; + MPEG2VIDEOINFO vih; + DWORD buffer[64]; + UINT32 value32; + UINT64 value64; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&vih, 0, sizeof(vih)); + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, 0, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&guid, &GUID_NULL), "Unexpected guid %s.\n", debugstr_guid(&guid)); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biWidth = 16; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biHeight = -32; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biHeight = 32; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value64 == ((UINT64)16 << 32 | 32), "Unexpected value %#I64x.\n", value64); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_INTERLACE_MODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == MFVideoInterlace_Progressive, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + vih.hdr.bmiHeader.biXPelsPerMeter = 2; + vih.hdr.bmiHeader.biYPelsPerMeter = 3; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64); + todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.hdr.bmiHeader.biSizeImage = 12345; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 12345, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, &value32); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwStartTimeCode = 1234; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1234, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetItem(media_type, &MF_MT_MPEG2_PROFILE, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwProfile = 1234; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_PROFILE, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1234, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetItem(media_type, &MF_MT_MPEG2_LEVEL, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwLevel = 1234; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_LEVEL, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1234, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetItem(media_type, &MF_MT_MPEG2_FLAGS, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + vih.dwFlags = 1234; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_FLAGS, &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 1234, "Unexpected value %#x.\n", value32); + hr = IMFMediaType_GetItem(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + value32 = 0xdeadbeef; + memset(buffer, 0xcd, sizeof(buffer)); + vih.cbSequenceHeader = 3; + vih.dwSequenceHeader[0] = 0xabcdef; + hr = MFInitMediaTypeFromMPEG2VideoInfo(media_type, &vih, sizeof(vih), &GUID_NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, (BYTE *)buffer, sizeof(buffer), &value32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value32 == 3, "Unexpected value %#x.\n", value32); + ok(buffer[0] == 0xcdabcdef, "Unexpected value %#lx.\n", buffer[0]); + + IMFMediaType_Release(media_type); +} + static void test_MFInitMediaTypeFromAMMediaType(void) { static const MFVideoArea expect_aperture = {.OffsetX = {.value = 13}, .OffsetY = {.value = 46}, .Area = {.cx = 110, .cy = 410}}; @@ -12204,6 +12346,7 @@ START_TEST(mfplat) test_MFInitMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromVideoInfoHeader2(); test_MFInitMediaTypeFromMPEG1VideoInfo(); + test_MFInitMediaTypeFromMPEG2VideoInfo(); test_MFInitMediaTypeFromAMMediaType(); test_MFCreatePathFromURL(); test_2dbuffer_copy(); diff --git a/include/mfapi.h b/include/mfapi.h index 8bd3fd6e4f9..2e1c2345418 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -511,6 +511,7 @@ struct tagVIDEOINFOHEADER2; typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; typedef struct _AMMediaType AM_MEDIA_TYPE; typedef struct tagMPEG1VIDEOINFO MPEG1VIDEOINFO; +typedef struct tagMPEG2VIDEOINFO MPEG2VIDEOINFO; HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue); @@ -603,6 +604,8 @@ HRESULT WINAPI MFInitMediaTypeFromVideoInfoHeader2(IMFMediaType *media_type, con UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromMPEG1VideoInfo(IMFMediaType *media_type, const MPEG1VIDEOINFO *vih, UINT32 size, const GUID *subtype); +HRESULT WINAPI MFInitMediaTypeFromMPEG2VideoInfo(IMFMediaType *media_type, const MPEG2VIDEOINFO *vih, + UINT32 size, const GUID *subtype); HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInitVideoFormat_RGB(MFVIDEOFORMAT *format, DWORD width, DWORD height, DWORD d3dformat); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); From 29da1575376ce2d42a80a612bf3386846b1e0c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 11:21:08 +0200 Subject: [PATCH 081/301] mfplat: Implement MFCreateVideoMediaType. (cherry picked from commit bf64ae2627fee37836d6fecf587b72919230b888) CW-Bug-Id: #20833 --- dlls/evr/evr.spec | 2 +- dlls/mfplat/mediatype.c | 24 ++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- include/mfapi.h | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/dlls/evr/evr.spec b/dlls/evr/evr.spec index 0a3a3fb6d42..7383589573b 100644 --- a/dlls/evr/evr.spec +++ b/dlls/evr/evr.spec @@ -8,7 +8,7 @@ @ stub MFConvertToFP16Array @ stdcall -import MFCopyImage(ptr long ptr long long long) @ stdcall -import MFCreateDXSurfaceBuffer(ptr ptr long ptr) -@ stub MFCreateVideoMediaType +@ stdcall -import MFCreateVideoMediaType(ptr ptr) @ stub MFCreateVideoMediaTypeFromBitMapInfoHeader @ stdcall -import MFCreateVideoMediaTypeFromSubtype(ptr ptr) @ stub MFCreateVideoMediaTypeFromVideoInfoHeader2 diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 22b8bb90821..fa69ed3b9c0 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3763,6 +3763,30 @@ static const GUID * get_mf_subtype_for_am_subtype(const GUID *subtype) return subtype; } +HRESULT WINAPI MFCreateVideoMediaType(const MFVIDEOFORMAT *format, IMFVideoMediaType **media_type) +{ + struct media_type *object; + HRESULT hr; + + TRACE("%p, %p.\n", format, media_type); + + if (!media_type) + return E_INVALIDARG; + + if (FAILED(hr = create_media_type(&object))) + return hr; + + if (FAILED(hr = MFInitMediaTypeFromMFVideoFormat(&object->IMFMediaType_iface, format, format->dwSize))) + { + IMFMediaType_Release(&object->IMFMediaType_iface); + return hr; + } + + *media_type = &object->IMFVideoMediaType_iface; + + return hr; +} + /*********************************************************************** * MFCreateVideoMediaTypeFromVideoInfoHeader (mfplat.@) */ diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index e311b3cf493..d61e18491d3 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -76,7 +76,7 @@ @ stdcall MFCreateTransformActivate(ptr) @ stub MFCreateURLFromPath @ stub MFCreateUdpSockets -@ stub MFCreateVideoMediaType +@ stdcall MFCreateVideoMediaType(ptr ptr) @ stub MFCreateVideoMediaTypeFromBitMapInfoHeader @ stub MFCreateVideoMediaTypeFromBitMapInfoHeaderEx @ stdcall MFCreateVideoMediaTypeFromSubtype(ptr ptr) diff --git a/include/mfapi.h b/include/mfapi.h index 2e1c2345418..86fdcb2b8e4 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -556,6 +556,7 @@ HRESULT WINAPI MFCreateMediaTypeFromRepresentation(GUID guid_representation, voi HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateTempFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, IMFByteStream **bytestream); +HRESULT WINAPI MFCreateVideoMediaType(const MFVIDEOFORMAT *format, IMFVideoMediaType **media_type); HRESULT WINAPI MFCreateVideoMediaTypeFromSubtype(const GUID *subtype, IMFVideoMediaType **media_type); #ifdef _KSMEDIA_ From 34320d3d2c5f986ac72c44bd31ce2156f18a26f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 8 Apr 2024 17:17:22 +0200 Subject: [PATCH 082/301] include: Add MFTOPOLOGY_DXVA_MODE enum definition. CW-Bug-Id: #20833 --- include/mfidl.idl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/mfidl.idl b/include/mfidl.idl index b3201b12d84..666af53c6e3 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -131,6 +131,13 @@ typedef enum _MF_VIDEO_PROCESSOR_ALGORITHM_TYPE MF_VIDEO_PROCESSOR_ALGORITHM_MRF_CRF_444 = 1, } MF_VIDEO_PROCESSOR_ALGORITHM_TYPE; +typedef enum MFTOPOLOGY_DXVA_MODE +{ + MFTOPOLOGY_DXVA_DEFAULT = 0, + MFTOPOLOGY_DXVA_NONE = 1, + MFTOPOLOGY_DXVA_FULL = 2, +} MFTOPOLOGY_DXVA_MODE; + [ object, uuid(2eb1e945-18b8-4139-9b1a-d5d584818530), From dde40612a8524f9554713d52621d4566b4419b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:48 +0100 Subject: [PATCH 083/301] Revert "HACK: winegstreamer: Register the video processor MFT as a decoder." This reverts commit a7657b93413d541d94bdeda45a699a9526d961ac. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0c2e37abe8a..0e77afde3d3 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -507,19 +507,6 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(video_decoder_output_types), video_decoder_output_types, }, - { - /* HACK: Register the video processor as a decoder too as - * the media source currently always decodes. - */ - CLSID_VideoProcessorMFT, - MFT_CATEGORY_VIDEO_DECODER, - L"Null Decoder", - MFT_ENUM_FLAG_SYNCMFT, - ARRAY_SIZE(video_processor_input_types), - video_processor_input_types, - ARRAY_SIZE(video_processor_output_types), - video_processor_output_types, - }, }; unsigned int i; From 8627f8e4881d125d678b9a46ea5452ba1c2f611f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:50 +0100 Subject: [PATCH 084/301] Revert "winegstreamer: Register more VIDEO_EFFECT DMO classes." This reverts commit 27e322103ca311a3d05cf4f5caab70636da8c15f. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 33 --------------------------------- include/wmcodecdsp.idl | 15 --------------- 2 files changed, 48 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0e77afde3d3..a4cf2dfcd99 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -444,39 +444,6 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(resampler_types), resampler_types, }, - { - CLSID_CFrameRateConvertDmo, - MFT_CATEGORY_VIDEO_EFFECT, - L"Frame Rate Converter", - MFT_ENUM_FLAG_SYNCMFT, - /* FIXME: check the actual media types */ - ARRAY_SIZE(color_convert_input_types), - color_convert_input_types, - ARRAY_SIZE(color_convert_output_types), - color_convert_output_types, - }, - { - CLSID_CResizerDMO, - MFT_CATEGORY_VIDEO_EFFECT, - L"Resizer MFT", - MFT_ENUM_FLAG_SYNCMFT, - /* FIXME: check the actual media types */ - ARRAY_SIZE(color_convert_input_types), - color_convert_input_types, - ARRAY_SIZE(color_convert_output_types), - color_convert_output_types, - }, - { - CLSID_CColorControlDmo, - MFT_CATEGORY_VIDEO_EFFECT, - L"Color Control", - MFT_ENUM_FLAG_SYNCMFT, - /* FIXME: check the actual media types */ - ARRAY_SIZE(color_convert_input_types), - color_convert_input_types, - ARRAY_SIZE(color_convert_output_types), - color_convert_output_types, - }, { CLSID_CColorConvertDMO, MFT_CATEGORY_VIDEO_EFFECT, diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl index 7e91015f19e..a6f350ea2fc 100644 --- a/include/wmcodecdsp.idl +++ b/include/wmcodecdsp.idl @@ -72,21 +72,6 @@ coclass CWMAEncMediaObject {} ] coclass AACMFTEncoder {} -[ - uuid(01f36ce2-0907-4d8b-979d-f151be91c883) -] -coclass CFrameRateConvertDmo {} - -[ - uuid(1ea1ea14-48f4-4054-ad1a-e8aee10ac805) -] -coclass CResizerDMO {} - -[ - uuid(798059f0-89ca-4160-b325-aeb48efe4f9a) -] -coclass CColorControlDmo {} - [ uuid(98230571-0087-4204-b020-3282538e57d3) ] From 2953c5ab89c51262a344db749d194b34ef8738e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:53 +0100 Subject: [PATCH 085/301] Revert "winegstreamer: Expose the generic video decoder transform." This reverts commit 9a96d36988e87b2507ad31e6794f1f5ddac639f4. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 1 - dlls/winegstreamer/mfplat.c | 30 -------------------- dlls/winegstreamer/video_decoder.c | 21 -------------- dlls/winegstreamer/winegstreamer_classes.idl | 6 ---- 4 files changed, 58 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index bce9b5d2fe4..c894fd0b1ae 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -189,7 +189,6 @@ unsigned int wg_format_get_stride(const struct wg_format *format); bool wg_video_format_is_rgb(enum wg_video_format format); HRESULT audio_decoder_create(REFIID riid, void **ret); -HRESULT video_decoder_create(REFIID riid, void **ret); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index a4cf2dfcd99..f681d4a0f1f 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -129,7 +129,6 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerByteStreamHandler2 = {0x317df619, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerAudioDecoder = {0x480b1517, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; -static const GUID CLSID_GStreamerVideoDecoder = {0x480b1518, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; @@ -141,7 +140,6 @@ static const struct class_object class_objects[] = { { &CLSID_GStreamerAudioDecoder, &audio_decoder_create }, - { &CLSID_GStreamerVideoDecoder, &video_decoder_create }, { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_GStreamerByteStreamHandler2, &gstreamer_byte_stream_handler_2_create }, @@ -353,24 +351,6 @@ HRESULT mfplat_DllRegisterServer(void) {MFMediaType_Audio, MFAudioFormat_PCM}, }; - MFT_REGISTER_TYPE_INFO video_decoder_input_types[] = - { - {MFMediaType_Video, MFVideoFormat_GStreamer}, - {MFMediaType_Video, MFVideoFormat_IV50}, - }; - MFT_REGISTER_TYPE_INFO video_decoder_output_types[] = - { - {MFMediaType_Video, MFVideoFormat_YV12}, - {MFMediaType_Video, MFVideoFormat_YUY2}, - {MFMediaType_Video, MFVideoFormat_NV11}, - {MFMediaType_Video, MFVideoFormat_NV12}, - {MFMediaType_Video, MFVideoFormat_RGB32}, - {MFMediaType_Video, MFVideoFormat_RGB24}, - {MFMediaType_Video, MFVideoFormat_RGB565}, - {MFMediaType_Video, MFVideoFormat_RGB555}, - {MFMediaType_Video, MFVideoFormat_RGB8}, - }; - struct mft { GUID clsid; @@ -464,16 +444,6 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(audio_decoder_output_types), audio_decoder_output_types, }, - { - CLSID_GStreamerVideoDecoder, - MFT_CATEGORY_VIDEO_DECODER, - L"Wine Video Decoder MFT", - MFT_ENUM_FLAG_SYNCMFT, - ARRAY_SIZE(video_decoder_input_types), - video_decoder_input_types, - ARRAY_SIZE(video_decoder_output_types), - video_decoder_output_types, - }, }; unsigned int i; diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index ad48e91df35..cc33a5c4272 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -34,11 +34,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); -extern GUID MFVideoFormat_GStreamer; -static const GUID *const video_decoder_input_types[] = -{ - &MFVideoFormat_GStreamer, -}; static const GUID *const video_decoder_output_types[] = { &MFVideoFormat_NV12, @@ -867,22 +862,6 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U return hr; } -HRESULT video_decoder_create(REFIID riid, void **out) -{ - IMFTransform *iface; - HRESULT hr; - - TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); - - if (FAILED(hr = video_decoder_create_with_types(video_decoder_input_types, ARRAY_SIZE(video_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) - return hr; - - hr = IMFTransform_QueryInterface(iface, riid, out); - IMFTransform_Release(iface); - return hr; -} - static const GUID *const h264_decoder_input_types[] = { &MFVideoFormat_H264, diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index dc56ad2b0ab..2ef6d994274 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -95,12 +95,6 @@ coclass GStreamerByteStreamHandler2 {} ] coclass GStreamerAudioDecoder {} -[ - threading(both), - uuid(480b1518-c8e9-4eae-b006-e6300718d85d) -] -coclass GStreamerVideoDecoder {} - [ threading(both), uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) From f41d912f8621cbdf31179d2902eab76f03c72f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:54 +0100 Subject: [PATCH 086/301] Revert "winegstreamer: Ignore input / output fps mismatch in video_processor." This reverts commit 0dfbb87378b70526b3bcf876e1f567db7b4dd591. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_processor.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 1cbb37dafc7..3075bf997d2 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -102,13 +102,6 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - /* prevent fps differences from failing to connect the elements */ - if (output_format.u.video.fps_d || output_format.u.video.fps_n) - { - input_format.u.video.fps_d = output_format.u.video.fps_d; - input_format.u.video.fps_n = output_format.u.video.fps_n; - } - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; From db451c72ae869336f8167b99ec76b6f61432a9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:04 +0100 Subject: [PATCH 087/301] Revert "winegstreamer: Introduce a generic audio decoder transform." This reverts commit 8608e399f0ad44a2529f22d15634f288c9987677. CW-Bug-Id: #20833 --- dlls/winegstreamer/audio_decoder.c | 38 -------------------- dlls/winegstreamer/gst_private.h | 1 - dlls/winegstreamer/mfplat.c | 22 ------------ dlls/winegstreamer/winegstreamer_classes.idl | 6 ---- 4 files changed, 67 deletions(-) diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/audio_decoder.c index e65dcabaaba..c7258dac8f9 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -613,9 +613,6 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; - decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; - decoder->refcount = 1; - decoder->input_types = (WAVEFORMATEXTENSIBLE *)aac_decoder_input_types; decoder->input_type_count = ARRAY_SIZE(aac_decoder_input_types); @@ -625,44 +622,9 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) return hr; } - *ret = &decoder->IMFTransform_iface; - TRACE("Created decoder %p\n", *ret); - return S_OK; -} - -static WAVEFORMATEXTENSIBLE audio_decoder_input_types[] = -{ -#define MAKE_WAVEFORMATEXTENSIBLE(format) \ - {.Format = {.wFormatTag = WAVE_FORMAT_EXTENSIBLE, .nChannels = 6, .nSamplesPerSec = 48000, .nAvgBytesPerSec = 1152000, \ - .nBlockAlign = 24, .wBitsPerSample = 32, .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)}, \ - .SubFormat = {format,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}}} - - MAKE_WAVEFORMATEXTENSIBLE(MAKEFOURCC('G','S','T','a')), - -#undef MAKE_WAVEFORMATEXTENSIBLE -}; - -HRESULT audio_decoder_create(REFIID riid, void **ret) -{ - struct audio_decoder *decoder; - HRESULT hr; - - TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - - if (!(decoder = calloc(1, sizeof(*decoder)))) - return E_OUTOFMEMORY; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; - decoder->input_types = audio_decoder_input_types; - decoder->input_type_count = ARRAY_SIZE(audio_decoder_input_types); - - if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) - { - free(decoder); - return hr; - } - *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index c894fd0b1ae..84857c5adfa 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -188,7 +188,6 @@ unsigned int wg_format_get_stride(const struct wg_format *format); bool wg_video_format_is_rgb(enum wg_video_format format); -HRESULT audio_decoder_create(REFIID riid, void **ret); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index f681d4a0f1f..9545c445aea 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -128,7 +128,6 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerByteStreamHandler2 = {0x317df619, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; -static const GUID CLSID_GStreamerAudioDecoder = {0x480b1517, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; @@ -139,7 +138,6 @@ static const struct class_object } class_objects[] = { - { &CLSID_GStreamerAudioDecoder, &audio_decoder_create }, { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_GStreamerByteStreamHandler2, &gstreamer_byte_stream_handler_2_create }, @@ -341,16 +339,6 @@ HRESULT mfplat_DllRegisterServer(void) {MFMediaType_Video, MFVideoFormat_NV11}, }; - MFT_REGISTER_TYPE_INFO audio_decoder_input_types[] = - { - {MFMediaType_Audio, MFAudioFormat_GStreamer}, - }; - MFT_REGISTER_TYPE_INFO audio_decoder_output_types[] = - { - {MFMediaType_Audio, MFAudioFormat_Float}, - {MFMediaType_Audio, MFAudioFormat_PCM}, - }; - struct mft { GUID clsid; @@ -434,16 +422,6 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(color_convert_output_types), color_convert_output_types, }, - { - CLSID_GStreamerAudioDecoder, - MFT_CATEGORY_AUDIO_DECODER, - L"Wine Audio Decoder MFT", - MFT_ENUM_FLAG_SYNCMFT, - ARRAY_SIZE(audio_decoder_input_types), - audio_decoder_input_types, - ARRAY_SIZE(audio_decoder_output_types), - audio_decoder_output_types, - }, }; unsigned int i; diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 2ef6d994274..493e6cff2b0 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -89,12 +89,6 @@ coclass GStreamerByteStreamHandler {} ] coclass GStreamerByteStreamHandler2 {} -[ - threading(both), - uuid(480b1517-c8e9-4eae-b006-e6300718d85d) -] -coclass GStreamerAudioDecoder {} - [ threading(both), uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) From 1a30cde48c278a655e99ac44cf58a5e31f82e7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:06 +0100 Subject: [PATCH 088/301] Revert "winegstreamer: Rename aac_decoder to audio_decoder." This reverts commit fbea0ea230e34c36869882fe6277c5cd673337b5. CW-Bug-Id: #20833 --- dlls/winegstreamer/Makefile.in | 2 +- .../{audio_decoder.c => aac_decoder.c} | 50 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) rename dlls/winegstreamer/{audio_decoder.c => aac_decoder.c} (92%) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index f76a7fb35f2..a177fa0e849 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -7,7 +7,7 @@ UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) SOURCES = \ - audio_decoder.c \ + aac_decoder.c \ color_convert.c \ main.c \ media_sink.c \ diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/aac_decoder.c similarity index 92% rename from dlls/winegstreamer/audio_decoder.c rename to dlls/winegstreamer/aac_decoder.c index c7258dac8f9..5844de33ceb 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -34,7 +34,7 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); #define NEXT_WAVEFORMATEXTENSIBLE(format) (WAVEFORMATEXTENSIBLE *)((BYTE *)(&(format)->Format + 1) + (format)->Format.cbSize) -static WAVEFORMATEXTENSIBLE const audio_decoder_output_types[] = +static WAVEFORMATEXTENSIBLE const aac_decoder_output_types[] = { {.Format = {.wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 48000, .nChannels = 2}}, {.Format = {.wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 48000, .nChannels = 2}}, @@ -51,7 +51,7 @@ static const UINT32 default_channel_mask[7] = KSAUDIO_SPEAKER_5POINT1, }; -struct audio_decoder +struct aac_decoder { IMFTransform IMFTransform_iface; LONG refcount; @@ -66,12 +66,12 @@ struct audio_decoder struct wg_sample_queue *wg_sample_queue; }; -static struct audio_decoder *impl_from_IMFTransform(IMFTransform *iface) +static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) { - return CONTAINING_RECORD(iface, struct audio_decoder, IMFTransform_iface); + return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); } -static HRESULT try_create_wg_transform(struct audio_decoder *decoder) +static HRESULT try_create_wg_transform(struct aac_decoder *decoder) { struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; @@ -96,7 +96,7 @@ static HRESULT try_create_wg_transform(struct audio_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -115,7 +115,7 @@ static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedIncrement(&decoder->refcount); TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); return refcount; @@ -123,7 +123,7 @@ static ULONG WINAPI transform_AddRef(IMFTransform *iface) static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedDecrement(&decoder->refcount); TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); @@ -228,7 +228,7 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); const WAVEFORMATEXTENSIBLE *format = decoder->input_types; UINT count = decoder->input_type_count; @@ -245,7 +245,7 @@ static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); UINT32 channel_count, sample_rate; WAVEFORMATEXTENSIBLE wfx = {{0}}; IMFMediaType *media_type; @@ -260,7 +260,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - wfx = audio_decoder_output_types[index % ARRAY_SIZE(audio_decoder_output_types)]; + wfx = aac_decoder_output_types[index % ARRAY_SIZE(aac_decoder_output_types)]; if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) || !channel_count) @@ -271,15 +271,15 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (channel_count >= ARRAY_SIZE(default_channel_mask)) return MF_E_INVALIDMEDIATYPE; - if (channel_count > 2 && index >= ARRAY_SIZE(audio_decoder_output_types)) + if (channel_count > 2 && index >= ARRAY_SIZE(aac_decoder_output_types)) { /* If there are more than two channels in the input type GetOutputAvailableType additionally lists * types with 2 channels. */ - index -= ARRAY_SIZE(audio_decoder_output_types); + index -= ARRAY_SIZE(aac_decoder_output_types); channel_count = 2; } - if (index >= ARRAY_SIZE(audio_decoder_output_types)) + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; wfx.Format.nChannels = channel_count; @@ -322,7 +322,7 @@ static BOOL matches_format(const WAVEFORMATEXTENSIBLE *a, const WAVEFORMATEXTENS static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); UINT32 size, count = decoder->input_type_count; WAVEFORMATEXTENSIBLE *format, wfx; HRESULT hr; @@ -362,7 +362,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); WAVEFORMATEXTENSIBLE *format, wfx; UINT32 size; HRESULT hr; @@ -381,10 +381,10 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF wfx = *format; CoTaskMemFree(format); - for (i = 0; i < ARRAY_SIZE(audio_decoder_output_types); ++i) - if (matches_format(&audio_decoder_output_types[i], &wfx)) + for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) + if (matches_format(&aac_decoder_output_types[i], &wfx)) break; - if (i == ARRAY_SIZE(audio_decoder_output_types)) + if (i == ARRAY_SIZE(aac_decoder_output_types)) return MF_E_INVALIDMEDIATYPE; if (!wfx.Format.wBitsPerSample || !wfx.Format.nChannels || !wfx.Format.nSamplesPerSec) @@ -411,7 +411,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *type; HRESULT hr; @@ -433,7 +433,7 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *type; HRESULT hr; @@ -455,7 +455,7 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); bool accepts_input; TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); @@ -496,7 +496,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); @@ -509,7 +509,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - struct audio_decoder *decoder = impl_from_IMFTransform(iface); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; HRESULT hr; @@ -599,7 +599,7 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4}; struct wg_transform_attrs attrs = {0}; wg_transform_t transform; - struct audio_decoder *decoder; + struct aac_decoder *decoder; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); From 4e2ffe64d663839aada199438fb181ffbfb5aa58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:23 +0100 Subject: [PATCH 089/301] Revert "winegstreamer: Translate generic audio / video encoded media types." This reverts commit b98066788e613d9eba4e1b69dcedb2a63a947cbf. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 138 +----------------------------------- 1 file changed, 2 insertions(+), 136 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 9545c445aea..53269aededa 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -45,8 +45,6 @@ DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); -DEFINE_MEDIATYPE_GUID(MFAudioFormat_GStreamer,MAKEFOURCC('G','S','T','a')); -DEFINE_MEDIATYPE_GUID(MFVideoFormat_GStreamer,MAKEFOURCC('G','S','T','v')); extern GUID MEDIASUBTYPE_VC1S; @@ -571,74 +569,6 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * return NULL; } -static IMFMediaType *mf_media_type_from_wg_format_audio_encoded(const struct wg_format *format) -{ - IMFMediaType *type; - UINT32 value; - HRESULT hr; - - if (FAILED(MFCreateMediaType(&type))) - return NULL; - if (FAILED(hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFAudioFormat_GStreamer))) - goto done; - - value = format->u.audio_encoded.rate; - if (value && FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, value))) - goto done; - value = format->u.audio_encoded.channels; - if (value && FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, value))) - goto done; - if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.audio_encoded.caps, - strlen(format->u.audio_encoded.caps) + 1))) - goto done; - -done: - if (FAILED(hr)) - { - IMFMediaType_Release(type); - return NULL; - } - return type; -} - -static IMFMediaType *mf_media_type_from_wg_format_video_encoded(const struct wg_format *format) -{ - UINT64 frame_rate, frame_size; - IMFMediaType *type; - HRESULT hr; - - if (FAILED(MFCreateMediaType(&type))) - return NULL; - if (FAILED(hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_GStreamer))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_VIDEO_ROTATION, MFVideoRotationFormat_0))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(type, &MF_MT_COMPRESSED, TRUE))) - goto done; - - frame_size = (UINT64)format->u.video_encoded.width << 32 | format->u.video_encoded.height; - if (FAILED(hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, frame_size))) - goto done; - frame_rate = (UINT64)format->u.video_encoded.fps_n << 32 | format->u.video_encoded.fps_d; - if (FAILED(hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_RATE, frame_rate))) - goto done; - if (FAILED(hr = IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (BYTE *)format->u.video_encoded.caps, - strlen(format->u.video_encoded.caps) + 1))) - goto done; - -done: - if (FAILED(hr)) - { - IMFMediaType_Release(type); - return NULL; - } - return type; -} - IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) { switch (format->major_type) @@ -646,11 +576,13 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: + case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: + case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: @@ -658,13 +590,9 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO: return mf_media_type_from_wg_format_audio(format); - case WG_MAJOR_TYPE_AUDIO_ENCODED: - return mf_media_type_from_wg_format_audio_encoded(format); case WG_MAJOR_TYPE_VIDEO: return mf_media_type_from_wg_format_video(format); - case WG_MAJOR_TYPE_VIDEO_ENCODED: - return mf_media_type_from_wg_format_video_encoded(format); } assert(0); @@ -760,29 +688,6 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUI format->u.audio_mpeg4.codec_data_len = codec_data_size; } -static void mf_media_type_to_wg_format_audio_encoded(IMFMediaType *type, struct wg_format *format) -{ - UINT32 caps_len; - BYTE *caps; - HRESULT hr; - - memset(format, 0, sizeof(*format)); - format->major_type = WG_MAJOR_TYPE_AUDIO_ENCODED; - - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &format->u.audio_encoded.rate))) - WARN("Failed to get MF_MT_AUDIO_SAMPLES_PER_SECOND for type %p, hr %#lx.\n", type, hr); - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &format->u.audio_encoded.channels))) - WARN("Failed to get MF_MT_AUDIO_NUM_CHANNELS for type %p, hr %#lx.\n", type, hr); - - if (FAILED(hr = IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &caps, &caps_len))) - WARN("Failed to get MF_MT_USER_DATA for type %p, hr %#lx.\n", type, hr); - else - { - strcpy(format->u.audio_encoded.caps, (char *)caps); - CoTaskMemFree(caps); - } -} - static enum wg_video_format mf_video_format_to_wg(const GUID *subtype) { unsigned int i; @@ -1021,41 +926,6 @@ static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subty format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN; } -static void mf_media_type_to_wg_format_video_encoded(IMFMediaType *type, struct wg_format *format) -{ - UINT64 frame_rate, frame_size; - UINT32 caps_len; - HRESULT hr; - BYTE *caps; - - memset(format, 0, sizeof(*format)); - format->major_type = WG_MAJOR_TYPE_VIDEO_ENCODED; - - if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - WARN("Failed to get MF_MT_FRAME_SIZE for type %p, hr %#lx.\n", type, hr); - else - { - format->u.video_encoded.width = frame_size >> 32; - format->u.video_encoded.height = (UINT32)frame_size; - } - - if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) - WARN("Failed to get MF_MT_FRAME_RATE for type %p, hr %#lx.\n", type, hr); - else - { - format->u.video_encoded.fps_n = frame_rate >> 32; - format->u.video_encoded.fps_d = (UINT32)frame_rate; - } - - if (FAILED(hr = IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &caps, &caps_len))) - WARN("Failed to get MF_MT_USER_DATA for type %p, hr %#lx.\n", type, hr); - else - { - strcpy(format->u.video_encoded.caps, (char *)caps); - CoTaskMemFree(caps); - } -} - void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -1083,8 +953,6 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) mf_media_type_to_wg_format_audio_mpeg4(type, &subtype, format); - else if (IsEqualGUID(&subtype, &MFAudioFormat_GStreamer)) - mf_media_type_to_wg_format_audio_encoded(type, format); else mf_media_type_to_wg_format_audio(type, &subtype, format); } @@ -1104,8 +972,6 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) || IsEqualGUID(&subtype, &MFVideoFormat_WVC1) || IsEqualGUID(&subtype, &MEDIASUBTYPE_VC1S)) mf_media_type_to_wg_format_wmv(type, &subtype, format); - else if (IsEqualGUID(&subtype, &MFVideoFormat_GStreamer)) - mf_media_type_to_wg_format_video_encoded(type, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } From b65c5f049523bada8770a8aab362d2516c404f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:25 +0100 Subject: [PATCH 090/301] Revert "winegstreamer: Skip encoded formats in format_is_compressed." This reverts commit 3dcb087767194196ae5e336cd14cde131e28cbc5. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 6ed3e4d9a4c..bfe1eaec8f0 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -148,9 +148,7 @@ static bool format_is_compressed(struct wg_format *format) { return format->major_type != WG_MAJOR_TYPE_UNKNOWN && format->major_type != WG_MAJOR_TYPE_VIDEO - && format->major_type != WG_MAJOR_TYPE_AUDIO - && format->major_type != WG_MAJOR_TYPE_VIDEO_ENCODED - && format->major_type != WG_MAJOR_TYPE_AUDIO_ENCODED; + && format->major_type != WG_MAJOR_TYPE_AUDIO; } static NTSTATUS wg_parser_get_stream_count(void *args) From 3c620393fe5cee19bd64e323103244dffaa59f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:27 +0100 Subject: [PATCH 091/301] Revert "winegstreamer: Support generic audio / video encoded format." This reverts commit 77f74e7ad626ebcaea69d762d0b3ef7973162c0e. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 2 -- dlls/winegstreamer/quartz_parser.c | 4 --- dlls/winegstreamer/unixlib.h | 14 -------- dlls/winegstreamer/wg_format.c | 56 ------------------------------ dlls/winegstreamer/wg_transform.c | 6 +--- dlls/winegstreamer/wm_reader.c | 8 ----- 6 files changed, 1 insertion(+), 89 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 53269aededa..ccf07783e76 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -576,13 +576,11 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index c386c671520..f8cbdd586ef 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -467,10 +467,8 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) return format->u.audio_wma.rate * format->u.audio_wma.channels * format->u.audio_wma.depth / 8; case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: - case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format->major_type); return 0; @@ -731,10 +729,8 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool switch (format->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: - case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index fe21a24f6f5..ba227ca2c61 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -37,14 +37,12 @@ enum wg_major_type WG_MAJOR_TYPE_AUDIO_MPEG1, WG_MAJOR_TYPE_AUDIO_MPEG4, WG_MAJOR_TYPE_AUDIO_WMA, - WG_MAJOR_TYPE_AUDIO_ENCODED, WG_MAJOR_TYPE_VIDEO, WG_MAJOR_TYPE_VIDEO_CINEPAK, WG_MAJOR_TYPE_VIDEO_H264, WG_MAJOR_TYPE_VIDEO_WMV, WG_MAJOR_TYPE_VIDEO_INDEO, WG_MAJOR_TYPE_VIDEO_MPEG1, - WG_MAJOR_TYPE_VIDEO_ENCODED, }; typedef UINT32 wg_audio_format; @@ -130,12 +128,6 @@ struct wg_format unsigned char codec_data[64]; UINT8 is_xma; } audio_wma; - struct - { - uint32_t channels; - uint32_t rate; - char caps[512]; - } audio_encoded; struct { @@ -181,12 +173,6 @@ struct wg_format int32_t width, height; uint32_t fps_n, fps_d; } video_mpeg1; - struct - { - int32_t width, height; - uint32_t fps_n, fps_d; - char caps[512]; - } video_encoded; } u; }; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 7cf93830d11..b1f503bf066 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -267,25 +267,6 @@ static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCap gst_buffer_unmap(codec_data, &map); } -static void wg_format_from_caps_audio_encoded(struct wg_format *format, const GstCaps *caps, - const GstAudioInfo *info) -{ - gchar *str; - gint len; - - format->major_type = WG_MAJOR_TYPE_AUDIO_ENCODED; - format->u.audio_encoded.rate = info->rate; - format->u.audio_encoded.channels = info->channels; - - str = gst_caps_to_string(caps); - len = strlen(str) + 1; - if (len >= ARRAY_SIZE(format->u.audio_encoded.caps)) - GST_FIXME("wg_format.audio_encoded.caps buffer is too small, need %u bytes", len); - else - memcpy(format->u.audio_encoded.caps, str, len); - g_free(str); -} - static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -411,27 +392,6 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC format->u.video_mpeg1.fps_d = fps_d; } -static void wg_format_from_caps_video_encoded(struct wg_format *format, const GstCaps *caps, - const GstVideoInfo *info) -{ - gchar *str; - gint len; - - format->major_type = WG_MAJOR_TYPE_VIDEO_ENCODED; - format->u.video_encoded.width = info->width; - format->u.video_encoded.height = info->height; - format->u.video_encoded.fps_n = info->fps_n; - format->u.video_encoded.fps_d = info->fps_d; - - str = gst_caps_to_string(caps); - len = strlen(str) + 1; - if (len >= ARRAY_SIZE(format->u.video_encoded.caps)) - GST_FIXME("wg_format.video_encoded.caps buffer is too small, need %u bytes", len); - else - memcpy(format->u.video_encoded.caps, str, len); - g_free(str); -} - void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -450,11 +410,6 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) wg_format_from_caps_audio_mpeg1(format, caps); else if (!strcmp(name, "audio/x-wma")) wg_format_from_caps_audio_wma(format, caps); - else - { - GST_FIXME("Using fallback for encoded audio caps %" GST_PTR_FORMAT ".", caps); - wg_format_from_caps_audio_encoded(format, caps, &audio_info); - } } else if (g_str_has_prefix(name, "video/") && gst_video_info_from_caps(&video_info, caps)) { @@ -466,11 +421,6 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) wg_format_from_caps_video_wmv(format, caps); else if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) wg_format_from_caps_video_mpeg1(format, caps); - else - { - GST_FIXME("Using fallback for encoded video caps %" GST_PTR_FORMAT ".", caps); - wg_format_from_caps_video_encoded(format, caps, &video_info); - } } else { @@ -920,8 +870,6 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_audio_mpeg4(format); case WG_MAJOR_TYPE_AUDIO_WMA: return wg_format_to_caps_audio_wma(format); - case WG_MAJOR_TYPE_AUDIO_ENCODED: - return gst_caps_from_string(format->u.audio_encoded.caps); case WG_MAJOR_TYPE_VIDEO: return wg_format_to_caps_video(format); case WG_MAJOR_TYPE_VIDEO_CINEPAK: @@ -934,8 +882,6 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_video_indeo(format); case WG_MAJOR_TYPE_VIDEO_MPEG1: return wg_format_to_caps_video_mpeg1(format); - case WG_MAJOR_TYPE_VIDEO_ENCODED: - return gst_caps_from_string(format->u.video_encoded.caps); } assert(0); return NULL; @@ -951,11 +897,9 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_ENCODED: GST_FIXME("Format %u not implemented!", a->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 754140e96a2..e9e31212d87 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -404,12 +404,10 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { - case WG_MAJOR_TYPE_AUDIO_ENCODED: + case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_VIDEO_ENCODED: - case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: @@ -489,13 +487,11 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_ENCODED: GST_FIXME("Format %u not implemented!", output_format.major_type); goto out; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 3afd021bcac..7db90e0d84b 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1676,10 +1676,6 @@ static const char *get_major_type_string(enum wg_major_type type) return "indeo"; case WG_MAJOR_TYPE_VIDEO_MPEG1: return "mpeg1-video"; - case WG_MAJOR_TYPE_AUDIO_ENCODED: - return "unknown-audio"; - case WG_MAJOR_TYPE_VIDEO_ENCODED: - return "unknown-video"; case WG_MAJOR_TYPE_UNKNOWN: return "unknown"; } @@ -2050,13 +2046,11 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format.major_type); break; case WG_MAJOR_TYPE_UNKNOWN: @@ -2095,13 +2089,11 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_AUDIO_ENCODED: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: - case WG_MAJOR_TYPE_VIDEO_ENCODED: FIXME("Format %u not implemented!\n", format.major_type); /* fallthrough */ case WG_MAJOR_TYPE_AUDIO: From 58a17bb8ec195959dace3b32167cb576647ab3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 10:24:42 +0100 Subject: [PATCH 092/301] Revert "winegstreamer: Call gst_audio_info_from_caps for all audio formats." This reverts commit 841ac075f26a403006df0199b1e375e7f911e471. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_format.c | 54 +++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index b1f503bf066..66cfb97372f 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -396,31 +396,43 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); const char *name = gst_structure_get_name(structure); - GstAudioInfo audio_info; - GstVideoInfo video_info; gboolean parsed; memset(format, 0, sizeof(*format)); - if (g_str_has_prefix(name, "audio/") && gst_audio_info_from_caps(&audio_info, caps)) - { - if (GST_AUDIO_INFO_FORMAT(&audio_info) != GST_AUDIO_FORMAT_ENCODED) - wg_format_from_audio_info(format, &audio_info); - else if (!strcmp(name, "audio/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) - wg_format_from_caps_audio_mpeg1(format, caps); - else if (!strcmp(name, "audio/x-wma")) - wg_format_from_caps_audio_wma(format, caps); - } - else if (g_str_has_prefix(name, "video/") && gst_video_info_from_caps(&video_info, caps)) - { - if (GST_VIDEO_INFO_FORMAT(&video_info) != GST_VIDEO_FORMAT_ENCODED) - wg_format_from_video_info(format, &video_info); - else if (!strcmp(name, "video/x-cinepak")) - wg_format_from_caps_video_cinepak(format, caps); - else if (!strcmp(name, "video/x-wmv")) - wg_format_from_caps_video_wmv(format, caps); - else if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) - wg_format_from_caps_video_mpeg1(format, caps); + if (!strcmp(name, "audio/x-raw")) + { + GstAudioInfo info; + + if (gst_audio_info_from_caps(&info, caps)) + wg_format_from_audio_info(format, &info); + } + else if (!strcmp(name, "video/x-raw")) + { + GstVideoInfo info; + + if (gst_video_info_from_caps(&info, caps)) + wg_format_from_video_info(format, &info); + } + else if (!strcmp(name, "audio/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) + { + wg_format_from_caps_audio_mpeg1(format, caps); + } + else if (!strcmp(name, "audio/x-wma")) + { + wg_format_from_caps_audio_wma(format, caps); + } + else if (!strcmp(name, "video/x-cinepak")) + { + wg_format_from_caps_video_cinepak(format, caps); + } + else if (!strcmp(name, "video/x-wmv")) + { + wg_format_from_caps_video_wmv(format, caps); + } + else if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) + { + wg_format_from_caps_video_mpeg1(format, caps); } else { From 64a6cb2b26a3d078c5128e20af54fed9af6631aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:54 +0100 Subject: [PATCH 093/301] Revert "winegstreamer: Rename struct h264_decoder to struct video_decoder." This reverts commit caf1db51967aeb3d131ce790276d5e3398839de7. CW-Bug-Id: #20833 --- dlls/winegstreamer/Makefile.in | 2 +- .../{video_decoder.c => h264_decoder.c} | 54 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) rename dlls/winegstreamer/{video_decoder.c => h264_decoder.c} (94%) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index a177fa0e849..7b427fb0c44 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -9,6 +9,7 @@ UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) SOURCES = \ aac_decoder.c \ color_convert.c \ + h264_decoder.c \ main.c \ media_sink.c \ media_source.c \ @@ -19,7 +20,6 @@ SOURCES = \ resampler.c \ rsrc.rc \ unixlib.c \ - video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/h264_decoder.c similarity index 94% rename from dlls/winegstreamer/video_decoder.c rename to dlls/winegstreamer/h264_decoder.c index cc33a5c4272..e7a6fabe575 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -43,7 +43,7 @@ static const GUID *const video_decoder_output_types[] = &MFVideoFormat_YUY2, }; -struct video_decoder +struct h264_decoder { IMFTransform IMFTransform_iface; LONG refcount; @@ -72,12 +72,12 @@ struct video_decoder IMFMediaBuffer *temp_buffer; }; -static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) +static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) { - return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); + return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); } -static HRESULT try_create_wg_transform(struct video_decoder *decoder) +static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput * return values, it calls them in a specific order and expects the decoder @@ -124,7 +124,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) return S_OK; } -static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, +static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, IMFMediaType **media_type) { IMFMediaType *default_type = decoder->output_type; @@ -198,7 +198,7 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI return hr; } -static HRESULT init_allocator(struct video_decoder *decoder) +static HRESULT init_allocator(struct h264_decoder *decoder) { HRESULT hr; @@ -217,7 +217,7 @@ static HRESULT init_allocator(struct video_decoder *decoder) return S_OK; } -static void uninit_allocator(struct video_decoder *decoder) +static void uninit_allocator(struct h264_decoder *decoder) { IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator); decoder->allocator_initialized = FALSE; @@ -225,7 +225,7 @@ static void uninit_allocator(struct video_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -245,7 +245,7 @@ static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedIncrement(&decoder->refcount); TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); @@ -255,7 +255,7 @@ static ULONG WINAPI transform_AddRef(IMFTransform *iface) static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedDecrement(&decoder->refcount); TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); @@ -309,7 +309,7 @@ static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_si static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); @@ -319,7 +319,7 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); @@ -329,7 +329,7 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); @@ -348,7 +348,7 @@ static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DW static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes); @@ -376,7 +376,7 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); @@ -389,7 +389,7 @@ static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); @@ -403,7 +403,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); GUID major, subtype; UINT64 frame_size; HRESULT hr; @@ -453,7 +453,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); UINT64 frame_size, stream_frame_size; GUID major, subtype; HRESULT hr; @@ -513,7 +513,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); HRESULT hr; TRACE("iface %p, id %#lx, type %p\n", iface, id, type); @@ -529,7 +529,7 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); HRESULT hr; TRACE("iface %p, id %#lx, type %p\n", iface, id, type); @@ -545,7 +545,7 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); @@ -576,7 +576,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); HRESULT hr; TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); @@ -612,7 +612,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); @@ -622,7 +622,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); } -static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMFSample *src_sample) +static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample) { MFT_OUTPUT_DATA_BUFFER output[1]; IMFSample *sample; @@ -652,7 +652,7 @@ static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMF return S_OK; } -static HRESULT handle_stream_type_change(struct video_decoder *decoder, const struct wg_format *format) +static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format) { UINT64 frame_size, frame_rate; GUID subtype; @@ -680,7 +680,7 @@ static HRESULT handle_stream_type_change(struct video_decoder *decoder, const st static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); struct wg_format wg_format; UINT32 sample_size; LONGLONG duration; @@ -796,7 +796,7 @@ static const IMFTransformVtbl transform_vtbl = static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) { - struct video_decoder *decoder; + struct h264_decoder *decoder; HRESULT hr; if (!(decoder = calloc(1, sizeof(*decoder)))) From 832d2cbe4578b74948f79c5fbc24f8fdd355eb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:54 +0100 Subject: [PATCH 094/301] Revert "winegstreamer: Use the H264 decoder to implement the IV50 decoder." This reverts commit c3792c209e5b53094c25cb978b7ee3c0f8a9b92d. CW-Bug-Id: #20833 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/h264_decoder.c | 35 +- dlls/winegstreamer/video_decoder.c | 502 +++++++++++++++++++++++++++++ 3 files changed, 504 insertions(+), 34 deletions(-) create mode 100644 dlls/winegstreamer/video_decoder.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 7b427fb0c44..2bb3a709468 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -20,6 +20,7 @@ SOURCES = \ resampler.c \ rsrc.rc \ unixlib.c \ + video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index e7a6fabe575..6b7906fd6a9 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -1,7 +1,6 @@ -/* Generic Video Decoder Transform +/* H264 Decoder Transform * * Copyright 2022 RĂ©mi Bernon for CodeWeavers - * Copyright 2023 Shaun Ren for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -116,10 +115,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) } if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; - } return S_OK; } @@ -903,32 +899,3 @@ HRESULT h264_decoder_create(REFIID riid, void **out) IMFTransform_Release(iface); return hr; } - -extern GUID MFVideoFormat_IV50; -static const GUID *const iv50_decoder_input_types[] = -{ - &MFVideoFormat_IV50, -}; -static const GUID *const iv50_decoder_output_types[] = -{ - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_NV11, - &MFVideoFormat_NV12, - &MFVideoFormat_RGB32, - &MFVideoFormat_RGB24, - &MFVideoFormat_RGB565, - &MFVideoFormat_RGB555, - &MFVideoFormat_RGB8, -}; - -HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) -{ - TRACE("out %p.\n", out); - - if (!init_gstreamer()) - return E_FAIL; - - return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), out); -} diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c new file mode 100644 index 00000000000..f24c25e03f2 --- /dev/null +++ b/dlls/winegstreamer/video_decoder.c @@ -0,0 +1,502 @@ +/* Generic Video Decoder Transform + * + * Copyright 2022 RĂ©mi Bernon for CodeWeavers + * Copyright 2023 Shaun Ren for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + +static const GUID *const input_types[] = +{ + &MFVideoFormat_IV50, +}; +static const GUID *const output_types[] = +{ + &MFVideoFormat_YV12, + &MFVideoFormat_YUY2, + &MFVideoFormat_NV11, + &MFVideoFormat_NV12, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + +struct video_decoder +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFMediaType *input_type; + IMFMediaType *output_type; + + struct wg_format wg_format; + wg_transform_t wg_transform; + struct wg_sample_queue *wg_sample_queue; +}; + +static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); +} + +static HRESULT try_create_wg_transform(struct video_decoder *decoder) +{ + struct wg_transform_attrs attrs = {0}; + struct wg_format input_format; + struct wg_format output_format; + + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + mf_media_type_to_wg_format(decoder->output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); + return E_FAIL; + } + + return S_OK; +} + +static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + + wg_sample_queue_destroy(decoder->wg_sample_queue); + free(decoder); + } + + return refcount; +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + FIXME("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", + iface, input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + FIXME("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return E_INVALIDARG; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(input_types); ++i) + if (IsEqualGUID(&subtype, input_types[i])) + break; + if (i == ARRAY_SIZE(input_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) || + (frame_size >> 32) == 0 || (UINT32)frame_size == 0) + return MF_E_INVALIDMEDIATYPE; + + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + IMFMediaType_AddRef((decoder->input_type = type)); + + return S_OK; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + struct wg_format output_format; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(output_types); ++i) + if (IsEqualGUID(&subtype, output_types[i])) + break; + if (i == ARRAY_SIZE(output_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + IMFMediaType_AddRef((decoder->output_type = type)); + + if (decoder->wg_transform) + { + mf_media_type_to_wg_format(decoder->output_type, &output_format); + + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN + || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return MF_E_INVALIDMEDIATYPE; + } + } + else if (FAILED(hr = try_create_wg_transform(decoder))) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return hr; + } + + decoder->wg_format.u.video.width = frame_size >> 32; + decoder->wg_format.u.video.height = (UINT32)frame_size; + + return hr; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + return S_OK; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + hr = wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); + + return hr; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct wg_format wg_format; + UINT32 sample_size; + UINT64 frame_rate; + GUID subtype; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count != 1) + return E_INVALIDARG; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = samples->dwStatus = 0; + if (!samples->pSample) + return E_INVALIDARG; + + if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, + sample_size, &wg_format, &samples->dwStatus))) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + { + decoder->wg_format = wg_format; + + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + /* keep the frame rate that was requested, GStreamer doesn't provide any */ + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) + { + decoder->wg_format.u.video.fps_n = frame_rate >> 32; + decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; + } + + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + } + + return hr; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) +{ + struct video_decoder *decoder; + HRESULT hr; + + TRACE("out %p.\n", out); + + if (!init_gstreamer()) + return E_FAIL; + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; + + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->refcount = 1; + + decoder->wg_format.u.video.fps_d = 1; + decoder->wg_format.u.video.fps_n = 1; + + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + goto failed; + + *out = &decoder->IMFTransform_iface; + TRACE("created decoder %p.\n", *out); + return S_OK; + +failed: + free(decoder); + return hr; +} From 5c63d621e055d62b5b17601f4659ed3c3477a7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:55 +0100 Subject: [PATCH 095/301] Revert "ir50_32: Use the proper hr value for stream format change." This reverts commit 01823cf0bc8ba449c6dd6ea5ec760bd8259b3cb4. CW-Bug-Id: #20833 --- dlls/ir50_32/ir50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 69700359e99..65c93f7fe5e 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -252,7 +252,7 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD mft_buf.pSample = out_sample; hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); - if ( hr == MF_E_TRANSFORM_STREAM_CHANGE ) + if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); if ( SUCCEEDED(hr) ) From bd2a36564f65ae56c900fe2ce6c4800f612b7dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:55 +0100 Subject: [PATCH 096/301] Revert "winegstreamer: Use MFCalculateImageSize to compute output info size." This reverts commit cd234ee21b8a42748498176cc53a490b32974074. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 6b7906fd6a9..5b040720476 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -436,7 +436,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) WARN("Failed to update stream type frame size, hr %#lx\n", hr); - MFCalculateImageSize(decoder->output_types[0], frame_size >> 32, frame_size, (UINT32 *)&decoder->output_info.cbSize); + decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; } if (decoder->wg_transform) @@ -651,7 +651,6 @@ static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFS static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format) { UINT64 frame_size, frame_rate; - GUID subtype; HRESULT hr; if (decoder->stream_type) @@ -665,9 +664,7 @@ static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const str if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size))) return hr; - if (FAILED(hr = IMFMediaType_GetGUID(decoder->stream_type, &MF_MT_SUBTYPE, &subtype))) - return hr; - MFCalculateImageSize(&subtype, frame_size >> 32, frame_size, (UINT32 *)&decoder->output_info.cbSize); + decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; uninit_allocator(decoder); return MF_E_TRANSFORM_STREAM_CHANGE; From 9ef3679240ee86c6e69497e92480d126f581a23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:55 +0100 Subject: [PATCH 097/301] Revert "winegstreamer: Use GUID arrays for H264 decoder media types." This reverts commit 717153865765f83da2dbd2ab9d950a4de8174886. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 108 ++++++++++++------------------ 1 file changed, 41 insertions(+), 67 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 5b040720476..cf5052cc853 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -33,7 +33,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); -static const GUID *const video_decoder_output_types[] = +#define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) + +static const GUID *const h264_decoder_input_types[] = +{ + &MFVideoFormat_H264, + &MFVideoFormat_H264_ES, +}; +static const GUID *const h264_decoder_output_types[] = { &MFVideoFormat_NV12, &MFVideoFormat_YV12, @@ -50,11 +57,6 @@ struct h264_decoder IMFAttributes *attributes; IMFAttributes *output_attributes; - UINT input_type_count; - const GUID *const *input_types; - UINT output_type_count; - const GUID *const *output_types; - UINT64 sample_time; IMFMediaType *input_type; MFT_INPUT_STREAM_INFO input_info; @@ -372,14 +374,12 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); *type = NULL; - if (index >= decoder->input_type_count) + if (index >= ARRAY_SIZE(h264_decoder_input_types)) return MF_E_NO_MORE_TYPES; - return MFCreateVideoMediaTypeFromSubtype(decoder->input_types[index], (IMFVideoMediaType **)type); + return MFCreateVideoMediaTypeFromSubtype(h264_decoder_input_types[index], (IMFVideoMediaType **)type); } static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, @@ -392,9 +392,9 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR *type = NULL; if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - if (index >= decoder->output_type_count) + if (index >= ARRAY_SIZE(h264_decoder_output_types)) return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, decoder->output_types[index], type); + return create_output_media_type(decoder, h264_decoder_output_types[index], type); } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) @@ -414,10 +414,10 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (!IsEqualGUID(&major, &MFMediaType_Video)) return MF_E_INVALIDMEDIATYPE; - for (i = 0; i < decoder->input_type_count; ++i) - if (IsEqualGUID(&subtype, decoder->input_types[i])) + for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i) + if (IsEqualGUID(&subtype, h264_decoder_input_types[i])) break; - if (i == decoder->input_type_count) + if (i == ARRAY_SIZE(h264_decoder_input_types)) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; @@ -467,10 +467,10 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (!IsEqualGUID(&major, &MFMediaType_Video)) return MF_E_INVALIDMEDIATYPE; - for (i = 0; i < decoder->output_type_count; ++i) - if (IsEqualGUID(&subtype, decoder->output_types[i])) + for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i) + if (IsEqualGUID(&subtype, h264_decoder_output_types[i])) break; - if (i == decoder->output_type_count) + if (i == ARRAY_SIZE(h264_decoder_output_types)) return MF_E_INVALIDMEDIATYPE; if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) @@ -786,23 +786,39 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, }; -static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) +HRESULT h264_decoder_create(REFIID riid, void **ret) { + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_I420, + .width = 1920, + .height = 1080, + }, + }; + static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; struct h264_decoder *decoder; HRESULT hr; + TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); + + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; - decoder->input_type_count = input_type_count; - decoder->input_types = input_types; - decoder->output_type_count = output_type_count; - decoder->output_types = output_types; - decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->input_info.cbSize = 0x1000; @@ -854,45 +870,3 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U free(decoder); return hr; } - -static const GUID *const h264_decoder_input_types[] = -{ - &MFVideoFormat_H264, - &MFVideoFormat_H264_ES, -}; - -HRESULT h264_decoder_create(REFIID riid, void **out) -{ - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, - }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; - IMFTransform *iface; - HRESULT hr; - - TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - - if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) - return hr; - - hr = IMFTransform_QueryInterface(iface, riid, out); - IMFTransform_Release(iface); - return hr; -} From c9e4885e6cd485c598fb708b8f0e8118d45f7969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:56 +0100 Subject: [PATCH 098/301] Revert "winegstreamer: Remove unnecessary create_output_media_type checks." This reverts commit e4cb607f6ae5289645f2e5dbaae8e355c4d64f2e. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 118 ++++++++++++++++++------------ 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index cf5052cc853..390451f3ac4 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -135,54 +135,82 @@ static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) return hr; - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) - ratio = (UINT64)1920 << 32 | 1080; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) - goto done; + if (FAILED(IMFVideoMediaType_GetUINT64(video_type, &MF_MT_FRAME_SIZE, &ratio))) + { + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) + ratio = (UINT64)1920 << 32 | 1080; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) + goto done; + } width = ratio >> 32; height = ratio; - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) - ratio = (UINT64)30000 << 32 | 1001; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) - goto done; - - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) - ratio = (UINT64)1 << 32 | 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) - goto done; - - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) - goto done; - - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) - value = MFVideoInterlace_MixedInterlaceOrProgressive; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) - value = 0; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) - goto done; - - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) - goto done; - - if (SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FRAME_RATE, NULL))) + { + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) + ratio = (UINT64)30000 << 32 | 1001; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) + { + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) + ratio = (UINT64)1 << 32 | 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_SAMPLE_SIZE, NULL))) + { + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_DEFAULT_STRIDE, NULL))) + { + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_INTERLACE_MODE, NULL))) + { + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) + value = MFVideoInterlace_MixedInterlaceOrProgressive; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) + { + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + value = 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_VIDEO_ROTATION, NULL))) + { + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) + value = 0; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) + { + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) + value = 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) + goto done; + } + + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) + && SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, From bf0ddfe16d26ae912fbe8127d96d8855c417339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:56 +0100 Subject: [PATCH 099/301] Revert "winegstreamer: Use MFCreateVideoMediaTypeFromSubtype in GetOutputAvailableType." This reverts commit e297f0ba75b9a83c7acbd84850939aaab96a6f49. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 116 +++++++++++++++++------------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 390451f3ac4..5935e85dff2 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -122,106 +122,102 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) return S_OK; } -static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, - IMFMediaType **media_type) +static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type) { IMFMediaType *default_type = decoder->output_type; - IMFVideoMediaType *video_type; UINT32 value, width, height; MFVideoArea aperture; UINT64 ratio; + GUID subtype; HRESULT hr; - if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) return hr; - if (FAILED(IMFVideoMediaType_GetUINT64(video_type, &MF_MT_FRAME_SIZE, &ratio))) + if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) ratio = (UINT64)1920 << 32 | 1080; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio))) + return hr; } width = ratio >> 32; height = ratio; - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FRAME_RATE, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) ratio = (UINT64)1 << 32 | 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_SAMPLE_SIZE, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) { - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) - goto done; + if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_DEFAULT_STRIDE, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) { - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) - goto done; + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_INTERLACE_MODE, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL))) { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) + if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) value = MFVideoInterlace_MixedInterlaceOrProgressive; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_VIDEO_ROTATION, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL))) { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) + if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) value = 0; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) + if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) - goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) + return hr; } - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) - && SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) + && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) - goto done; + return hr; } - IMFMediaType_AddRef((*media_type = (IMFMediaType *)video_type)); -done: - IMFVideoMediaType_Release(video_type); - return hr; + return S_OK; } static HRESULT init_allocator(struct h264_decoder *decoder) @@ -414,15 +410,37 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR DWORD index, IMFMediaType **type) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + IMFMediaType *media_type; + const GUID *output_type; + HRESULT hr; TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - *type = NULL; if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = NULL; + if (index >= ARRAY_SIZE(h264_decoder_output_types)) return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, h264_decoder_output_types[index], type); + output_type = h264_decoder_output_types[index]; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) + goto done; + + hr = fill_output_media_type(decoder, media_type); + +done: + if (SUCCEEDED(hr)) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) From 3df783a406c0ca208efdbd55edacd9090bedcd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 10:51:56 +0100 Subject: [PATCH 100/301] Revert "winegstreamer: Use MFCreateVideoMediaTypeFromSubtype in GetInputAvailableType." This reverts commit 9c862139acf40f99d060b5a3a53c32ef40e4b2f0. CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 5935e85dff2..6d618279817 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -398,12 +398,27 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { + IMFMediaType *media_type; + const GUID *subtype; + HRESULT hr; + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); *type = NULL; + if (index >= ARRAY_SIZE(h264_decoder_input_types)) return MF_E_NO_MORE_TYPES; - return MFCreateVideoMediaTypeFromSubtype(h264_decoder_input_types[index], (IMFVideoMediaType **)type); + subtype = h264_decoder_input_types[index]; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) && + SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; } static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, From c85f464748b7ce57024bbaad9bdcf75442353b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 17:19:44 +0200 Subject: [PATCH 101/301] Revert "HACK: winegstreamer/wma_decoder: Support XMAudio2 input format in WMA decoder." This reverts commit bdba19f58a4d135da2c2153aa1d58c9b74422526. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 11 +---------- dlls/winegstreamer/quartz_parser.c | 14 ++------------ dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/wg_format.c | 18 ++++-------------- dlls/winegstreamer/wma_decoder.c | 3 --- 5 files changed, 7 insertions(+), 40 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index ccf07783e76..208fddaf394 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -42,7 +42,6 @@ DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0 DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); -DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); @@ -749,7 +748,6 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID { UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; BYTE codec_data[64]; - bool is_xma = false; UINT32 version; if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) @@ -791,11 +789,6 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID version = 3; else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) version = 4; - else if (IsEqualGUID(subtype, &MFAudioFormat_XMAudio2)) - { - version = 2; - is_xma = true; - } else { assert(0); @@ -811,7 +804,6 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID format->u.audio_wma.block_align = block_align; format->u.audio_wma.codec_data_len = codec_data_len; memcpy(format->u.audio_wma.codec_data, codec_data, codec_data_len); - format->u.audio_wma.is_xma = is_xma; } static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_format *format) @@ -946,8 +938,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || - IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless) || - IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) + IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) mf_media_type_to_wg_format_audio_mpeg4(type, &subtype, format); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index f8cbdd586ef..8d5ae6e7762 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -41,7 +41,6 @@ static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; -static const GUID MEDIASUBTYPE_XMAUDIO2 = {0x0166, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; extern const GUID MFVideoFormat_ABGR32; struct parser @@ -303,11 +302,6 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form subtype = &MEDIASUBTYPE_WMAUDIO2; codec_data_len = WMAUDIO2_WFX_EXTRA_BYTES; fmt_tag = WAVE_FORMAT_WMAUDIO2; - if (format->u.audio_wma.is_xma) - { - subtype = &MEDIASUBTYPE_XMAUDIO2; - fmt_tag = 0x0166; - } break; case 3: subtype = &MEDIASUBTYPE_WMAUDIO3; @@ -875,8 +869,7 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct return true; } -static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format, - bool is_xma) +static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format) { const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; @@ -902,7 +895,6 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format else assert(false); format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio_wma.is_xma = is_xma; format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; format->u.audio_wma.rate = audio_format->nSamplesPerSec; format->u.audio_wma.depth = audio_format->wBitsPerSample; @@ -1083,9 +1075,7 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) - return amt_to_wg_format_audio_wma(mt, format, false); - if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_XMAUDIO2)) - return amt_to_wg_format_audio_wma(mt, format, true); + return amt_to_wg_format_audio_wma(mt, format); return amt_to_wg_format_audio(mt, format); } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index ba227ca2c61..00087ef0502 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -126,7 +126,6 @@ struct wg_format uint32_t block_align; uint32_t codec_data_len; unsigned char codec_data[64]; - UINT8 is_xma; } audio_wma; struct diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 66cfb97372f..f27653f8f41 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -643,20 +643,10 @@ static GstCaps *wg_format_to_caps_audio_wma(const struct wg_format *format) GstBuffer *buffer; GstCaps *caps; - if (format->u.audio_wma.is_xma) - { - if (!(caps = gst_caps_new_empty_simple("audio/x-xma"))) - return NULL; - if (format->u.audio_wma.version) - gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); - } - else - { - if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) - return NULL; - if (format->u.audio_wma.version) - gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); - } + if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) + return NULL; + if (format->u.audio_wma.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); if (format->u.audio_wma.bitrate) gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio_wma.bitrate, NULL); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index a4380d3a3b5..3737e24291d 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -30,15 +30,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(wmadec); -extern const GUID MFAudioFormat_XMAudio2; - static const GUID *const wma_decoder_input_types[] = { &MEDIASUBTYPE_MSAUDIO1, &MFAudioFormat_WMAudioV8, &MFAudioFormat_WMAudioV9, &MFAudioFormat_WMAudio_Lossless, - &MFAudioFormat_XMAudio2, }; static const GUID *const wma_decoder_output_types[] = { From ed6b456cc7ff171b762f7f40501c8e94d72efe9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 17:21:23 +0200 Subject: [PATCH 102/301] Revert "HACK: winegstreamer/wmv_decoder: Implement WMVDecMediaObject pass-through DMO." This reverts commit 4b928e219d60f20282c831bec0c512ac66dec7d7. CW-Bug-Id: #20833 --- dlls/winegstreamer/wmv_decoder.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index edd6c744e94..d13b5a065ed 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -28,6 +28,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +WINE_DECLARE_DEBUG_CHANNEL(winediag); extern const GUID MEDIASUBTYPE_VC1S; @@ -485,6 +486,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); struct wg_format wg_format; + unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -509,8 +511,15 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) return DMO_E_TYPE_NOT_ACCEPTED; + for (i = 0; i < ARRAY_SIZE(wmv_decoder_input_types); ++i) + if (IsEqualGUID(&type->subtype, wmv_decoder_input_types[i])) + break; + if (i == ARRAY_SIZE(wmv_decoder_input_types)) + return DMO_E_TYPE_NOT_ACCEPTED; + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return DMO_E_TYPE_NOT_ACCEPTED; + assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO_WMV); if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; @@ -867,11 +876,35 @@ static const IPropertyStoreVtbl property_store_vtbl = HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) { + static const struct wg_format input_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO_WMV, + .u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3, + }; + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_NV12, + .width = 1920, + .height = 1080, + }, + }; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; struct wmv_decoder *decoder; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) From aa1c941fc8d75f64af581f368d1bd9e4ec8b16ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 May 2024 10:47:21 +0200 Subject: [PATCH 103/301] Revert "HACK: winegstreamer/wma_decoder: Allow WMA decoder DMO to pass-through buffers." This reverts commit 3ea5fe4ba7575a7849a98bb24c588bd842e149db. CW-Bug-Id: #20833 --- dlls/winegstreamer/wma_decoder.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 3737e24291d..915878efed7 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -29,6 +29,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wmadec); +WINE_DECLARE_DEBUG_CHANNEL(winediag); static const GUID *const wma_decoder_input_types[] = { @@ -710,6 +711,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { struct wma_decoder *decoder = impl_from_IMediaObject(iface); struct wg_format wg_format; + unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -736,8 +738,15 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) return DMO_E_TYPE_NOT_ACCEPTED; + for (i = 0; i < ARRAY_SIZE(wma_decoder_input_types); ++i) + if (IsEqualGUID(&type->subtype, wma_decoder_input_types[i])) + break; + if (i == ARRAY_SIZE(wma_decoder_input_types)) + return DMO_E_TYPE_NOT_ACCEPTED; + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return DMO_E_TYPE_NOT_ACCEPTED; + assert(wg_format.major_type == WG_MAJOR_TYPE_AUDIO_WMA); if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; @@ -1028,11 +1037,32 @@ static const IPropertyBagVtbl property_bag_vtbl = HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) { + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_AUDIO, + .u.audio = + { + .format = WG_AUDIO_FORMAT_F32LE, + .channel_mask = 1, + .channels = 1, + .rate = 44100, + }, + }; + static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_WMA}; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; struct wma_decoder *decoder; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; From 9a8424ae030a0f065a87275be499c84d0a56f8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 May 2024 10:47:59 +0200 Subject: [PATCH 104/301] Revert "HACK: winegstreamer/media_source: Don't flip RGB for Media Foundation clients." This reverts commit a2e20ee412e84cb2e3b059b1885f04fa635e775c. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 3 +-- dlls/winegstreamer/main.c | 4 +--- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 3 --- dlls/winegstreamer/wg_parser.c | 2 +- dlls/winegstreamer/wm_reader.c | 10 +++++----- 7 files changed, 10 insertions(+), 16 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 84857c5adfa..061afc8a6c0 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -84,8 +84,7 @@ wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index); void wg_parser_stream_get_preferred_format(wg_parser_stream_t stream, struct wg_format *format); void wg_parser_stream_get_codec_format(wg_parser_stream_t stream, struct wg_format *format); -void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format, - uint32_t flags); +void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format); void wg_parser_stream_disable(wg_parser_stream_t stream); bool wg_parser_stream_get_buffer(wg_parser_t parser, wg_parser_stream_t stream, diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 992f6b3ae98..418856bc38d 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -202,14 +202,12 @@ void wg_parser_stream_get_codec_format(wg_parser_stream_t stream, struct wg_form WINE_UNIX_CALL(unix_wg_parser_stream_get_codec_format, ¶ms); } -void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format, - uint32_t flags) +void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format) { struct wg_parser_stream_enable_params params = { .stream = stream, .format = format, - .flags = flags, }; TRACE("stream %#I64x, format %p.\n", stream, format); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index a4ac0085dea..47195172a24 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -606,7 +606,7 @@ static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - wg_parser_stream_enable(stream->wg_stream, &format, 0); + wg_parser_stream_enable(stream->wg_stream, &format); if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 8d5ae6e7762..17e526a2ecb 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1438,7 +1438,7 @@ static HRESULT parser_init_stream(struct strmbase_filter *iface) { ret = amt_to_wg_format(&source->pin.pin.mt, &format); assert(ret); - wg_parser_stream_enable(source->wg_stream, &format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(source->wg_stream, &format); } else { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 00087ef0502..83241d67a33 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -284,13 +284,10 @@ struct wg_parser_stream_get_codec_format_params struct wg_format *format; }; -#define STREAM_ENABLE_FLAG_FLIP_RGB 0x1 - struct wg_parser_stream_enable_params { wg_parser_stream_t stream; const struct wg_format *format; - uint32_t flags; }; struct wg_parser_stream_get_buffer_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index bfe1eaec8f0..bff82d38b4a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -268,7 +268,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) if (format->major_type == WG_MAJOR_TYPE_VIDEO) { - bool flip = (params->flags & STREAM_ENABLE_FLAG_FLIP_RGB) && (format->u.video.height < 0); + bool flip = (format->u.video.height < 0); gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 7db90e0d84b..79251f8ebc9 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1527,7 +1527,7 @@ static HRESULT init_stream(struct wm_reader *reader) stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; } } - wg_parser_stream_enable(stream->wg_stream, &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(stream->wg_stream, &stream->format); } /* We probably discarded events because streams weren't enabled yet. @@ -1602,7 +1602,7 @@ static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed) stream->reader = reader; wg_parser_stream_get_preferred_format(stream->wg_stream, &format); if (stream->selection == WMT_ON) - wg_parser_stream_enable(stream->wg_stream, read_compressed ? &format : &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(stream->wg_stream, read_compressed ? &format : &stream->format); } /* We probably discarded events because streams weren't enabled yet. @@ -2370,7 +2370,7 @@ static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, } stream->format = format; - wg_parser_stream_enable(stream->wg_stream, &format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(stream->wg_stream, &format); /* Re-decode any buffers that might have been generated with the old format. * @@ -2520,11 +2520,11 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface, { struct wg_format format; wg_parser_stream_get_preferred_format(stream->wg_stream, &format); - wg_parser_stream_enable(stream->wg_stream, &format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(stream->wg_stream, &format); } else { - wg_parser_stream_enable(stream->wg_stream, &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); + wg_parser_stream_enable(stream->wg_stream, &stream->format); } } } From 1861e4fe171f3b557ba0ae009fd9fb1a9c57ff7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 11:44:51 +0100 Subject: [PATCH 105/301] winegstreamer: Use MFCreateVideoMediaTypeFromSubtype in GetInputAvailableType. (cherry picked from commit 86d82c733435402e5150ba985dc1965d9830f736) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 6d618279817..5935e85dff2 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -398,27 +398,12 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - IMFMediaType *media_type; - const GUID *subtype; - HRESULT hr; - TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); *type = NULL; - if (index >= ARRAY_SIZE(h264_decoder_input_types)) return MF_E_NO_MORE_TYPES; - subtype = h264_decoder_input_types[index]; - - if (FAILED(hr = MFCreateMediaType(&media_type))) - return hr; - - if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) && - SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) - IMFMediaType_AddRef((*type = media_type)); - - IMFMediaType_Release(media_type); - return hr; + return MFCreateVideoMediaTypeFromSubtype(h264_decoder_input_types[index], (IMFVideoMediaType **)type); } static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, From bb0808b33ae919f64209a16d2aa68081a65e0f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 11:52:09 +0100 Subject: [PATCH 106/301] winegstreamer: Use MFCreateVideoMediaTypeFromSubtype in GetOutputAvailableType. (cherry picked from commit 71f5bce785a11fa9902d19604d0447a3cf454874) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 122 ++++++++++++++---------------- 1 file changed, 55 insertions(+), 67 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 5935e85dff2..c3ad7444d99 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -122,102 +122,112 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) return S_OK; } -static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type) +static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, + IMFMediaType **media_type) { IMFMediaType *default_type = decoder->output_type; + IMFVideoMediaType *video_type; UINT32 value, width, height; MFVideoArea aperture; UINT64 ratio; - GUID subtype; HRESULT hr; - if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) return hr; - if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio))) + if (FAILED(IMFVideoMediaType_GetUINT64(video_type, &MF_MT_FRAME_SIZE, &ratio))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) ratio = (UINT64)1920 << 32 | 1080; - if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) + goto done; } width = ratio >> 32; height = ratio; - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FRAME_RATE, NULL))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; - if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) { if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) ratio = (UINT64)1 << 32 | 1; - if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_SAMPLE_SIZE, NULL))) { - if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value))) - return hr; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) - return hr; + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_DEFAULT_STRIDE, NULL))) { - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value))) - return hr; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) - return hr; + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_INTERLACE_MODE, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) value = MFVideoInterlace_MixedInterlaceOrProgressive; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) value = 1; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_VIDEO_ROTATION, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) value = 0; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) value = 1; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) - return hr; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) + goto done; } - if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) - && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) + && SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { - if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) - return hr; + goto done; } - return S_OK; +done: + if (SUCCEEDED(hr)) + *media_type = (IMFMediaType *)video_type; + else + { + IMFVideoMediaType_Release(video_type); + *media_type = NULL; + } + + return hr; } static HRESULT init_allocator(struct h264_decoder *decoder) @@ -410,37 +420,15 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR DWORD index, IMFMediaType **type) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); - IMFMediaType *media_type; - const GUID *output_type; - HRESULT hr; TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + *type = NULL; if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - - *type = NULL; - if (index >= ARRAY_SIZE(h264_decoder_output_types)) return MF_E_NO_MORE_TYPES; - output_type = h264_decoder_output_types[index]; - - if (FAILED(hr = MFCreateMediaType(&media_type))) - return hr; - - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) - goto done; - - hr = fill_output_media_type(decoder, media_type); - -done: - if (SUCCEEDED(hr)) - IMFMediaType_AddRef((*type = media_type)); - - IMFMediaType_Release(media_type); - return hr; + return create_output_media_type(decoder, h264_decoder_output_types[index], type); } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) From ac4f847ddb7c6422d1b9f2a41434de6a41fe51b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 11:57:46 +0100 Subject: [PATCH 107/301] winegstreamer: Remove unnecessary create_output_media_type checks. (cherry picked from commit 5bf6af0c39d8ec8591ec2ba4ea872d7f3bad4fbb) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 118 ++++++++++++------------------ 1 file changed, 45 insertions(+), 73 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c3ad7444d99..f7031dda930 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -135,82 +135,54 @@ static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) return hr; - if (FAILED(IMFVideoMediaType_GetUINT64(video_type, &MF_MT_FRAME_SIZE, &ratio))) - { - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) - ratio = (UINT64)1920 << 32 | 1080; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) - goto done; - } + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) + ratio = (UINT64)1920 << 32 | 1080; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) + goto done; width = ratio >> 32; height = ratio; - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FRAME_RATE, NULL))) - { - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) - ratio = (UINT64)30000 << 32 | 1001; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) - { - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) - ratio = (UINT64)1 << 32 | 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_SAMPLE_SIZE, NULL))) - { - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_DEFAULT_STRIDE, NULL))) - { - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_INTERLACE_MODE, NULL))) - { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) - value = MFVideoInterlace_MixedInterlaceOrProgressive; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) - { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_VIDEO_ROTATION, NULL))) - { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) - value = 0; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) - { - if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) - value = 1; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) - goto done; - } - - if (FAILED(IMFVideoMediaType_GetItem(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) - && SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) + ratio = (UINT64)30000 << 32 | 1001; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) + goto done; + + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) + ratio = (UINT64)1 << 32 | 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) + goto done; + + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) + goto done; + + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) + goto done; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + goto done; + + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) + value = MFVideoInterlace_MixedInterlaceOrProgressive; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_INTERLACE_MODE, value))) + goto done; + + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + value = 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) + goto done; + + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) + value = 0; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_ROTATION, value))) + goto done; + + if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) + value = 1; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) + goto done; + + if (SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, From 598d8a1efd53241a3251056dafa5ac9cfae4afba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 12:00:01 +0100 Subject: [PATCH 108/301] winegstreamer: Use GUID arrays for H264 decoder media types. (cherry picked from commit a6d77cfd06d633695a566e073a3a0e731e216760) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 108 ++++++++++++++++++------------ 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index f7031dda930..6f33c76c525 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -33,14 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); -#define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) - -static const GUID *const h264_decoder_input_types[] = -{ - &MFVideoFormat_H264, - &MFVideoFormat_H264_ES, -}; -static const GUID *const h264_decoder_output_types[] = +static const GUID *const video_decoder_output_types[] = { &MFVideoFormat_NV12, &MFVideoFormat_YV12, @@ -57,6 +50,11 @@ struct h264_decoder IMFAttributes *attributes; IMFAttributes *output_attributes; + UINT input_type_count; + const GUID *const *input_types; + UINT output_type_count; + const GUID *const *output_types; + UINT64 sample_time; IMFMediaType *input_type; MFT_INPUT_STREAM_INFO input_info; @@ -380,12 +378,14 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); *type = NULL; - if (index >= ARRAY_SIZE(h264_decoder_input_types)) + if (index >= decoder->input_type_count) return MF_E_NO_MORE_TYPES; - return MFCreateVideoMediaTypeFromSubtype(h264_decoder_input_types[index], (IMFVideoMediaType **)type); + return MFCreateVideoMediaTypeFromSubtype(decoder->input_types[index], (IMFVideoMediaType **)type); } static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, @@ -398,9 +398,9 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR *type = NULL; if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - if (index >= ARRAY_SIZE(h264_decoder_output_types)) + if (index >= decoder->output_type_count) return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, h264_decoder_output_types[index], type); + return create_output_media_type(decoder, decoder->output_types[index], type); } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) @@ -420,10 +420,10 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (!IsEqualGUID(&major, &MFMediaType_Video)) return MF_E_INVALIDMEDIATYPE; - for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i) - if (IsEqualGUID(&subtype, h264_decoder_input_types[i])) + for (i = 0; i < decoder->input_type_count; ++i) + if (IsEqualGUID(&subtype, decoder->input_types[i])) break; - if (i == ARRAY_SIZE(h264_decoder_input_types)) + if (i == decoder->input_type_count) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; @@ -473,10 +473,10 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (!IsEqualGUID(&major, &MFMediaType_Video)) return MF_E_INVALIDMEDIATYPE; - for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i) - if (IsEqualGUID(&subtype, h264_decoder_output_types[i])) + for (i = 0; i < decoder->output_type_count; ++i) + if (IsEqualGUID(&subtype, decoder->output_types[i])) break; - if (i == ARRAY_SIZE(h264_decoder_output_types)) + if (i == decoder->output_type_count) return MF_E_INVALIDMEDIATYPE; if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) @@ -792,39 +792,23 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, }; -HRESULT h264_decoder_create(REFIID riid, void **ret) +static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, + const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) { - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, - }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct h264_decoder *decoder; HRESULT hr; - TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->input_type_count = input_type_count; + decoder->input_types = input_types; + decoder->output_type_count = output_type_count; + decoder->output_types = output_types; + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->input_info.cbSize = 0x1000; @@ -876,3 +860,45 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) free(decoder); return hr; } + +static const GUID *const h264_decoder_input_types[] = +{ + &MFVideoFormat_H264, + &MFVideoFormat_H264_ES, +}; + +HRESULT h264_decoder_create(REFIID riid, void **out) +{ + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_I420, + .width = 1920, + .height = 1080, + }, + }; + static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; + IMFTransform *iface; + HRESULT hr; + + TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); + + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + + if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) + return hr; + + hr = IMFTransform_QueryInterface(iface, riid, out); + IMFTransform_Release(iface); + return hr; +} From c6b4e30325c57a2d23861f217d9c3b2b2337fcb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 17 Feb 2024 08:56:27 +0100 Subject: [PATCH 109/301] winegstreamer: Complete H264 current output type reported attributes. (cherry picked from commit 6599f2ff90f674dd86c86710055925c351668201) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 33 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 6f33c76c525..bf12d5b9d0c 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -121,9 +121,9 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) } static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, - IMFMediaType **media_type) + IMFMediaType *output_type, IMFMediaType **media_type) { - IMFMediaType *default_type = decoder->output_type; + IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; IMFVideoMediaType *video_type; UINT32 value, width, height; MFVideoArea aperture; @@ -133,31 +133,31 @@ static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID if (FAILED(hr = MFCreateVideoMediaTypeFromSubtype(subtype, &video_type))) return hr; - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_SIZE, &ratio))) ratio = (UINT64)1920 << 32 | 1080; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ratio))) goto done; width = ratio >> 32; height = ratio; - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) goto done; - if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) + if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) ratio = (UINT64)1 << 32 | 1; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) goto done; - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) + if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_SAMPLE_SIZE, &value))) + hr = MFCalculateImageSize(subtype, width, height, &value); + if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) goto done; - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value))) - goto done; - if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) + hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); + if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) goto done; if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) @@ -180,7 +180,7 @@ static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) goto done; - if (SUCCEEDED(IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) { if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, @@ -400,7 +400,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR return MF_E_TRANSFORM_TYPE_NOT_SET; if (index >= decoder->output_type_count) return MF_E_NO_MORE_TYPES; - return create_output_media_type(decoder, decoder->output_types[index], type); + return create_output_media_type(decoder, decoder->output_types[index], NULL, type); } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) @@ -532,17 +532,16 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + GUID subtype; HRESULT hr; TRACE("iface %p, id %#lx, type %p\n", iface, id, type); if (!decoder->output_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) + if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) return hr; - - return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type); + return create_output_media_type(decoder, &subtype, decoder->output_type, type); } static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) From 6ad7eec80468560762dbf529a5066a1f3c14cf9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Feb 2024 11:13:45 +0100 Subject: [PATCH 110/301] winegstreamer: Use MFCalculateImageSize to compute output info size. (cherry picked from commit 9a591bf4fee2a4eec098c0d1b2cb10d3cec8ddcd) CW-Bug-Id: #20833 --- dlls/winegstreamer/h264_decoder.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index bf12d5b9d0c..6ef39345811 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -403,6 +403,23 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR return create_output_media_type(decoder, decoder->output_types[index], NULL, type); } +static HRESULT update_output_info_size(struct h264_decoder *decoder, UINT32 width, UINT32 height) +{ + HRESULT hr = E_FAIL; + UINT32 i, size; + + decoder->output_info.cbSize = 0; + + for (i = 0; i < decoder->output_type_count; ++i) + { + if (FAILED(hr = MFCalculateImageSize(decoder->output_types[i], width, height, &size))) + return hr; + decoder->output_info.cbSize = max(size, decoder->output_info.cbSize); + } + + return hr; +} + static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); @@ -442,7 +459,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) WARN("Failed to update stream type frame size, hr %#lx\n", hr); - decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; + return update_output_info_size(decoder, frame_size >> 32, frame_size); } if (decoder->wg_transform) @@ -669,7 +686,8 @@ static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const str if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size))) return hr; - decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; + if (FAILED(hr = update_output_info_size(decoder, frame_size >> 32, frame_size))) + return hr; uninit_allocator(decoder); return MF_E_TRANSFORM_STREAM_CHANGE; From 7d0dc318b20fd3dacf7749ab1430a0cb4bd9bd42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Nov 2023 00:08:42 +0100 Subject: [PATCH 111/301] ir50_32: Use the proper hr value for stream format change. (cherry picked from commit e1b21bf1e9e673526c6b2ad036ef2cc059191422) CW-Bug-Id: #20833 --- dlls/ir50_32/ir50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 65c93f7fe5e..69700359e99 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -252,7 +252,7 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD mft_buf.pSample = out_sample; hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); - if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) + if ( hr == MF_E_TRANSFORM_STREAM_CHANGE ) hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); if ( SUCCEEDED(hr) ) From e0b5657019ea31941f18008ad47de7c4b99cf981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 12:11:54 +0100 Subject: [PATCH 112/301] winegstreamer: Use the H264 decoder to implement the IV50 decoder. (cherry picked from commit ae584ac620e01d6519883a973efc64ae6b22ae29) CW-Bug-Id: #20833 --- MAINTAINERS | 1 - dlls/winegstreamer/Makefile.in | 1 - dlls/winegstreamer/h264_decoder.c | 35 +- dlls/winegstreamer/video_decoder.c | 502 ----------------------------- 4 files changed, 34 insertions(+), 505 deletions(-) delete mode 100644 dlls/winegstreamer/video_decoder.c diff --git a/MAINTAINERS b/MAINTAINERS index 59873f6804c..9796148a637 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -221,7 +221,6 @@ F: dlls/winegstreamer/h264_decoder.c F: dlls/winegstreamer/media_source.c F: dlls/winegstreamer/mfplat.c F: dlls/winegstreamer/resampler.c -F: dlls/winegstreamer/video_decoder.c F: dlls/winegstreamer/video_processor.c F: dlls/winegstreamer/wg_source.c F: dlls/winegstreamer/wg_sample.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 2bb3a709468..7b427fb0c44 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -20,7 +20,6 @@ SOURCES = \ resampler.c \ rsrc.rc \ unixlib.c \ - video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 6ef39345811..2354a50e5b3 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -1,6 +1,7 @@ -/* H264 Decoder Transform +/* Generic Video Decoder Transform * * Copyright 2022 RĂ©mi Bernon for CodeWeavers + * Copyright 2023 Shaun Ren for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -115,7 +116,10 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) } if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; + } return S_OK; } @@ -919,3 +923,32 @@ HRESULT h264_decoder_create(REFIID riid, void **out) IMFTransform_Release(iface); return hr; } + +extern GUID MFVideoFormat_IV50; +static const GUID *const iv50_decoder_input_types[] = +{ + &MFVideoFormat_IV50, +}; +static const GUID *const iv50_decoder_output_types[] = +{ + &MFVideoFormat_YV12, + &MFVideoFormat_YUY2, + &MFVideoFormat_NV11, + &MFVideoFormat_NV12, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) +{ + TRACE("out %p.\n", out); + + if (!init_gstreamer()) + return E_FAIL; + + return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), out); +} diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c deleted file mode 100644 index f24c25e03f2..00000000000 --- a/dlls/winegstreamer/video_decoder.c +++ /dev/null @@ -1,502 +0,0 @@ -/* Generic Video Decoder Transform - * - * Copyright 2022 RĂ©mi Bernon for CodeWeavers - * Copyright 2023 Shaun Ren for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "gst_private.h" - -#include "mfapi.h" -#include "mferror.h" -#include "mfobjects.h" -#include "mftransform.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); - -static const GUID *const input_types[] = -{ - &MFVideoFormat_IV50, -}; -static const GUID *const output_types[] = -{ - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_NV11, - &MFVideoFormat_NV12, - &MFVideoFormat_RGB32, - &MFVideoFormat_RGB24, - &MFVideoFormat_RGB565, - &MFVideoFormat_RGB555, - &MFVideoFormat_RGB8, -}; - -struct video_decoder -{ - IMFTransform IMFTransform_iface; - LONG refcount; - - IMFMediaType *input_type; - IMFMediaType *output_type; - - struct wg_format wg_format; - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; -}; - -static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) -{ - return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); -} - -static HRESULT try_create_wg_transform(struct video_decoder *decoder) -{ - struct wg_transform_attrs attrs = {0}; - struct wg_format input_format; - struct wg_format output_format; - - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(decoder->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); - return E_FAIL; - } - - return S_OK; -} - -static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IMFTransform)) - *out = &decoder->IMFTransform_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI transform_AddRef(IMFTransform *iface) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&decoder->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); - - return refcount; -} - -static ULONG WINAPI transform_Release(IMFTransform *iface) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&decoder->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) - { - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - - wg_sample_queue_destroy(decoder->wg_sample_queue); - free(decoder); - } - - return refcount; -} - -static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, - DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) -{ - FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", - iface, input_minimum, input_maximum, output_minimum, output_maximum); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -{ - FIXME("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, - DWORD output_size, DWORD *outputs) -{ - FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", - iface, input_size, inputs, output_size, outputs); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -{ - FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) -{ - FIXME("iface %p, id %#lx.\n", iface, id); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -{ - FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, - DWORD index, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - GUID major, subtype; - UINT64 frame_size; - HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return E_INVALIDARG; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return MF_E_INVALIDMEDIATYPE; - - for (i = 0; i < ARRAY_SIZE(input_types); ++i) - if (IsEqualGUID(&subtype, input_types[i])) - break; - if (i == ARRAY_SIZE(input_types)) - return MF_E_INVALIDMEDIATYPE; - - if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) || - (frame_size >> 32) == 0 || (UINT32)frame_size == 0) - return MF_E_INVALIDMEDIATYPE; - - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - - if (decoder->output_type) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - } - - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - IMFMediaType_AddRef((decoder->input_type = type)); - - return S_OK; -} - -static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - GUID major, subtype; - UINT64 frame_size; - struct wg_format output_format; - HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (!decoder->input_type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return hr; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return MF_E_INVALIDMEDIATYPE; - - for (i = 0; i < ARRAY_SIZE(output_types); ++i) - if (IsEqualGUID(&subtype, output_types[i])) - break; - if (i == ARRAY_SIZE(output_types)) - return MF_E_INVALIDMEDIATYPE; - - if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - return hr; - - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - IMFMediaType_AddRef((decoder->output_type = type)); - - if (decoder->wg_transform) - { - mf_media_type_to_wg_format(decoder->output_type, &output_format); - - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - return MF_E_INVALIDMEDIATYPE; - } - } - else if (FAILED(hr = try_create_wg_transform(decoder))) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - return hr; - } - - decoder->wg_format.u.video.width = frame_size >> 32; - decoder->wg_format.u.video.height = (UINT32)frame_size; - - return hr; -} - -static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -{ - FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) -{ - FIXME("iface %p, flags %p stub!\n", iface, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -{ - TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -{ - FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -{ - FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); - return S_OK; -} - -static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - HRESULT hr; - - TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - hr = wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); - - return hr; -} - -static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -{ - struct video_decoder *decoder = impl_from_IMFTransform(iface); - struct wg_format wg_format; - UINT32 sample_size; - UINT64 frame_rate; - GUID subtype; - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); - - if (count != 1) - return E_INVALIDARG; - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *status = samples->dwStatus = 0; - if (!samples->pSample) - return E_INVALIDARG; - - if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) - return hr; - if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, - decoder->wg_format.u.video.height, &sample_size))) - return hr; - - if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, - sample_size, &wg_format, &samples->dwStatus))) - wg_sample_queue_flush(decoder->wg_sample_queue, false); - - if (hr == MF_E_TRANSFORM_STREAM_CHANGE) - { - decoder->wg_format = wg_format; - - if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, - decoder->wg_format.u.video.height, &sample_size))) - return hr; - - /* keep the frame rate that was requested, GStreamer doesn't provide any */ - if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) - { - decoder->wg_format.u.video.fps_n = frame_rate >> 32; - decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; - } - - samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - } - - return hr; -} - -static const IMFTransformVtbl transform_vtbl = -{ - transform_QueryInterface, - transform_AddRef, - transform_Release, - transform_GetStreamLimits, - transform_GetStreamCount, - transform_GetStreamIDs, - transform_GetInputStreamInfo, - transform_GetOutputStreamInfo, - transform_GetAttributes, - transform_GetInputStreamAttributes, - transform_GetOutputStreamAttributes, - transform_DeleteInputStream, - transform_AddInputStreams, - transform_GetInputAvailableType, - transform_GetOutputAvailableType, - transform_SetInputType, - transform_SetOutputType, - transform_GetInputCurrentType, - transform_GetOutputCurrentType, - transform_GetInputStatus, - transform_GetOutputStatus, - transform_SetOutputBounds, - transform_ProcessEvent, - transform_ProcessMessage, - transform_ProcessInput, - transform_ProcessOutput, -}; - -HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) -{ - struct video_decoder *decoder; - HRESULT hr; - - TRACE("out %p.\n", out); - - if (!init_gstreamer()) - return E_FAIL; - - if (!(decoder = calloc(1, sizeof(*decoder)))) - return E_OUTOFMEMORY; - - decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; - decoder->refcount = 1; - - decoder->wg_format.u.video.fps_d = 1; - decoder->wg_format.u.video.fps_n = 1; - - if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) - goto failed; - - *out = &decoder->IMFTransform_iface; - TRACE("created decoder %p.\n", *out); - return S_OK; - -failed: - free(decoder); - return hr; -} From 5fcd3f7670d21ca6872b31b5c5d1b13fe520ccb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 12:14:03 +0100 Subject: [PATCH 113/301] winegstreamer: Rename struct h264_decoder to struct video_decoder. (cherry picked from commit 437d304c7249f55329c14b3d30533e98daa62291) CW-Bug-Id: #20833 --- MAINTAINERS | 2 +- dlls/winegstreamer/Makefile.in | 2 +- .../{h264_decoder.c => video_decoder.c} | 56 +++++++++---------- 3 files changed, 30 insertions(+), 30 deletions(-) rename dlls/winegstreamer/{h264_decoder.c => video_decoder.c} (93%) diff --git a/MAINTAINERS b/MAINTAINERS index 9796148a637..c4afb5da88c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -217,10 +217,10 @@ P: Zebediah Figura F: dlls/mf/tests/transform.c F: dlls/winegstreamer/aac_decoder.c F: dlls/winegstreamer/color_convert.c -F: dlls/winegstreamer/h264_decoder.c F: dlls/winegstreamer/media_source.c F: dlls/winegstreamer/mfplat.c F: dlls/winegstreamer/resampler.c +F: dlls/winegstreamer/video_decoder.c F: dlls/winegstreamer/video_processor.c F: dlls/winegstreamer/wg_source.c F: dlls/winegstreamer/wg_sample.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 7b427fb0c44..a177fa0e849 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -9,7 +9,6 @@ UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) SOURCES = \ aac_decoder.c \ color_convert.c \ - h264_decoder.c \ main.c \ media_sink.c \ media_source.c \ @@ -20,6 +19,7 @@ SOURCES = \ resampler.c \ rsrc.rc \ unixlib.c \ + video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/video_decoder.c similarity index 93% rename from dlls/winegstreamer/h264_decoder.c rename to dlls/winegstreamer/video_decoder.c index 2354a50e5b3..d363f7b1d9d 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -43,7 +43,7 @@ static const GUID *const video_decoder_output_types[] = &MFVideoFormat_YUY2, }; -struct h264_decoder +struct video_decoder { IMFTransform IMFTransform_iface; LONG refcount; @@ -72,12 +72,12 @@ struct h264_decoder IMFMediaBuffer *temp_buffer; }; -static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); + return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); } -static HRESULT try_create_wg_transform(struct h264_decoder *decoder) +static HRESULT try_create_wg_transform(struct video_decoder *decoder) { /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput * return values, it calls them in a specific order and expects the decoder @@ -124,7 +124,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) return S_OK; } -static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID *subtype, +static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, IMFMediaType *output_type, IMFMediaType **media_type) { IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; @@ -204,7 +204,7 @@ static HRESULT create_output_media_type(struct h264_decoder *decoder, const GUID return hr; } -static HRESULT init_allocator(struct h264_decoder *decoder) +static HRESULT init_allocator(struct video_decoder *decoder) { HRESULT hr; @@ -223,7 +223,7 @@ static HRESULT init_allocator(struct h264_decoder *decoder) return S_OK; } -static void uninit_allocator(struct h264_decoder *decoder) +static void uninit_allocator(struct video_decoder *decoder) { IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator); decoder->allocator_initialized = FALSE; @@ -231,7 +231,7 @@ static void uninit_allocator(struct h264_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -251,7 +251,7 @@ static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedIncrement(&decoder->refcount); TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); @@ -261,7 +261,7 @@ static ULONG WINAPI transform_AddRef(IMFTransform *iface) static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedDecrement(&decoder->refcount); TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); @@ -315,7 +315,7 @@ static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_si static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); @@ -325,7 +325,7 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); @@ -335,7 +335,7 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); @@ -354,7 +354,7 @@ static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DW static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes); @@ -382,7 +382,7 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); @@ -395,7 +395,7 @@ static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); @@ -407,7 +407,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR return create_output_media_type(decoder, decoder->output_types[index], NULL, type); } -static HRESULT update_output_info_size(struct h264_decoder *decoder, UINT32 width, UINT32 height) +static HRESULT update_output_info_size(struct video_decoder *decoder, UINT32 width, UINT32 height) { HRESULT hr = E_FAIL; UINT32 i, size; @@ -426,7 +426,7 @@ static HRESULT update_output_info_size(struct h264_decoder *decoder, UINT32 widt static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); GUID major, subtype; UINT64 frame_size; HRESULT hr; @@ -476,7 +476,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); UINT64 frame_size, stream_frame_size; GUID major, subtype; HRESULT hr; @@ -536,7 +536,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); HRESULT hr; TRACE("iface %p, id %#lx, type %p\n", iface, id, type); @@ -552,7 +552,7 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); GUID subtype; HRESULT hr; @@ -567,7 +567,7 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); @@ -598,7 +598,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); HRESULT hr; TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); @@ -634,7 +634,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); @@ -644,7 +644,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); } -static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample) +static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMFSample *src_sample) { MFT_OUTPUT_DATA_BUFFER output[1]; IMFSample *sample; @@ -674,7 +674,7 @@ static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFS return S_OK; } -static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format) +static HRESULT handle_stream_type_change(struct video_decoder *decoder, const struct wg_format *format) { UINT64 frame_size, frame_rate; HRESULT hr; @@ -700,7 +700,7 @@ static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const str static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct video_decoder *decoder = impl_from_IMFTransform(iface); struct wg_format wg_format; UINT32 sample_size; LONGLONG duration; @@ -816,7 +816,7 @@ static const IMFTransformVtbl transform_vtbl = static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) { - struct h264_decoder *decoder; + struct video_decoder *decoder; HRESULT hr; if (!(decoder = calloc(1, sizeof(*decoder)))) From 9da89c40db7ae8e0db3e2f7db87d9c54938f73eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Feb 2024 08:23:10 +0100 Subject: [PATCH 114/301] winegstreamer: Introduce a new set_sample_flags_from_buffer helper. (cherry picked from commit b2ea55a0f047074f1305be8af05bda8ce3b2f90c) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 47 +++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e9e31212d87..28bc39db62d 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -763,6 +763,31 @@ static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample * return STATUS_SUCCESS; } +static void set_sample_flags_from_buffer(struct wg_sample *sample, GstBuffer *buffer, gsize total_size) +{ + if (GST_BUFFER_PTS_IS_VALID(buffer)) + { + sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; + sample->pts = GST_BUFFER_PTS(buffer) / 100; + } + if (GST_BUFFER_DURATION_IS_VALID(buffer)) + { + GstClockTime duration = GST_BUFFER_DURATION(buffer) / 100; + + duration = (duration * sample->size) / total_size; + GST_BUFFER_DURATION(buffer) -= duration * 100; + if (GST_BUFFER_PTS_IS_VALID(buffer)) + GST_BUFFER_PTS(buffer) += duration * 100; + + sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; + sample->duration = duration; + } + if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) + sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT; + if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT)) + sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY; +} + static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample) { @@ -795,27 +820,7 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi return status; } - if (GST_BUFFER_PTS_IS_VALID(buffer)) - { - sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; - sample->pts = GST_BUFFER_PTS(buffer) / 100; - } - if (GST_BUFFER_DURATION_IS_VALID(buffer)) - { - GstClockTime duration = GST_BUFFER_DURATION(buffer) / 100; - - duration = (duration * sample->size) / total_size; - GST_BUFFER_DURATION(buffer) -= duration * 100; - if (GST_BUFFER_PTS_IS_VALID(buffer)) - GST_BUFFER_PTS(buffer) += duration * 100; - - sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; - sample->duration = duration; - } - if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) - sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT; - if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT)) - sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY; + set_sample_flags_from_buffer(sample, buffer, total_size); if (needs_copy) { From 22dc9050134985ea99db30c7744e33759632891c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Feb 2024 08:25:39 +0100 Subject: [PATCH 115/301] winegstreamer: Introduce a new sample_needs_buffer_copy helper. (cherry picked from commit 4a6a3b90d28e1d5d9c3969770e338c301e18027e) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 28bc39db62d..2e190567b6f 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -788,13 +788,10 @@ static void set_sample_flags_from_buffer(struct wg_sample *sample, GstBuffer *bu sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY; } -static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, - struct wg_sample *sample) +static bool sample_needs_buffer_copy(struct wg_sample *sample, GstBuffer *buffer, gsize *total_size) { - gsize total_size; - bool needs_copy; - NTSTATUS status; GstMapInfo info; + bool needs_copy; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) { @@ -803,10 +800,20 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi return STATUS_UNSUCCESSFUL; } needs_copy = info.data != wg_sample_data(sample); - total_size = sample->size = info.size; + *total_size = sample->size = info.size; gst_buffer_unmap(buffer, &info); - if (!needs_copy) + return needs_copy; +} + +static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, + struct wg_sample *sample) +{ + gsize total_size; + NTSTATUS status; + bool needs_copy; + + if (!(needs_copy = sample_needs_buffer_copy(sample, buffer, &total_size))) status = STATUS_SUCCESS; else if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); From 9ed241f993fe07407b29461b6d9d8e0d05c7d6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Feb 2024 08:30:32 +0100 Subject: [PATCH 116/301] winegstreamer: Split read_transform_output_data in two helpers. (cherry picked from commit d54399b6a0209387c5fb203d43dd91a53f62317b) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 52 ++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 2e190567b6f..bbab6dad9d8 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -737,7 +737,7 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ return status; } -static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, +static NTSTATUS copy_buffer(GstBuffer *buffer, struct wg_sample *sample, gsize *total_size) { GstMapInfo info; @@ -806,8 +806,8 @@ static bool sample_needs_buffer_copy(struct wg_sample *sample, GstBuffer *buffer return needs_copy; } -static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, - struct wg_sample *sample) +static NTSTATUS read_transform_output_video(struct wg_sample *sample, GstBuffer *buffer, + GstCaps *caps, gsize plane_align) { gsize total_size; NTSTATUS status; @@ -815,10 +815,8 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi if (!(needs_copy = sample_needs_buffer_copy(sample, buffer, &total_size))) status = STATUS_SUCCESS; - else if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) - status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); else - status = copy_buffer(buffer, caps, sample, &total_size); + status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); if (status) { @@ -830,12 +828,37 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi set_sample_flags_from_buffer(sample, buffer, total_size); if (needs_copy) + GST_WARNING("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); + else if (sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + GST_ERROR("Partial read %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); + else + GST_INFO("Read %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); + + return STATUS_SUCCESS; +} + +static NTSTATUS read_transform_output(struct wg_sample *sample, GstBuffer *buffer) +{ + gsize total_size; + NTSTATUS status; + bool needs_copy; + + if (!(needs_copy = sample_needs_buffer_copy(sample, buffer, &total_size))) + status = STATUS_SUCCESS; + else + status = copy_buffer(buffer, sample, &total_size); + + if (status) { - if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) - GST_WARNING("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); - else - GST_INFO("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); + GST_ERROR("Failed to copy buffer %"GST_PTR_FORMAT, buffer); + sample->size = 0; + return status; } + + set_sample_flags_from_buffer(sample, buffer, total_size); + + if (needs_copy) + GST_INFO("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); else if (sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) GST_ERROR("Partial read %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); else @@ -926,8 +949,13 @@ NTSTATUS wg_transform_read_data(void *args) return STATUS_SUCCESS; } - if ((status = read_transform_output_data(output_buffer, output_caps, - transform->attrs.output_plane_align, sample))) + if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO) + status = read_transform_output_video(sample, output_buffer, output_caps, + transform->attrs.output_plane_align); + else + status = read_transform_output(sample, output_buffer); + + if (status) { wg_allocator_release_sample(transform->allocator, sample, false); return status; From 7d87ce8cf371d26d45307c93679d549ecd4c96b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Apr 2024 10:39:44 +0200 Subject: [PATCH 117/301] winegstreamer: Pass optional GstVideoInfo to read_transform_output_video. Instead of computing them in copy_video_buffer. (cherry picked from commit c4db5e23dd23d9f3bd0bd7a6f057bdfde98d1e69) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 59 ++++++++++++++----------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index bbab6dad9d8..eda07151628 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -683,25 +683,14 @@ NTSTATUS wg_transform_push_data(void *args) return STATUS_SUCCESS; } -static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, - struct wg_sample *sample, gsize *total_size) +static NTSTATUS copy_video_buffer(GstBuffer *buffer, const GstVideoInfo *src_video_info, + const GstVideoInfo *dst_video_info, struct wg_sample *sample, gsize *total_size) { NTSTATUS status = STATUS_UNSUCCESSFUL; GstVideoFrame src_frame, dst_frame; - GstVideoInfo src_info, dst_info; - GstVideoAlignment align; GstBuffer *dst_buffer; - if (!gst_video_info_from_caps(&src_info, caps)) - { - GST_ERROR("Failed to get video info from caps."); - return STATUS_UNSUCCESSFUL; - } - - dst_info = src_info; - align_video_info_planes(plane_align, &dst_info, &align); - - if (sample->max_size < dst_info.size) + if (sample->max_size < dst_video_info->size) { GST_ERROR("Output buffer is too small."); return STATUS_BUFFER_TOO_SMALL; @@ -713,14 +702,14 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ GST_ERROR("Failed to wrap wg_sample into GstBuffer"); return STATUS_UNSUCCESSFUL; } - gst_buffer_set_size(dst_buffer, dst_info.size); - *total_size = sample->size = dst_info.size; + gst_buffer_set_size(dst_buffer, dst_video_info->size); + *total_size = sample->size = dst_video_info->size; - if (!gst_video_frame_map(&src_frame, &src_info, buffer, GST_MAP_READ)) + if (!gst_video_frame_map(&src_frame, src_video_info, buffer, GST_MAP_READ)) GST_ERROR("Failed to map source frame."); else { - if (!gst_video_frame_map(&dst_frame, &dst_info, dst_buffer, GST_MAP_WRITE)) + if (!gst_video_frame_map(&dst_frame, dst_video_info, dst_buffer, GST_MAP_WRITE)) GST_ERROR("Failed to map destination frame."); else { @@ -737,8 +726,7 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ return status; } -static NTSTATUS copy_buffer(GstBuffer *buffer, struct wg_sample *sample, - gsize *total_size) +static NTSTATUS copy_buffer(GstBuffer *buffer, struct wg_sample *sample, gsize *total_size) { GstMapInfo info; @@ -807,7 +795,7 @@ static bool sample_needs_buffer_copy(struct wg_sample *sample, GstBuffer *buffer } static NTSTATUS read_transform_output_video(struct wg_sample *sample, GstBuffer *buffer, - GstCaps *caps, gsize plane_align) + const GstVideoInfo *src_video_info, const GstVideoInfo *dst_video_info) { gsize total_size; NTSTATUS status; @@ -816,7 +804,7 @@ static NTSTATUS read_transform_output_video(struct wg_sample *sample, GstBuffer if (!(needs_copy = sample_needs_buffer_copy(sample, buffer, &total_size))) status = STATUS_SUCCESS; else - status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); + status = copy_video_buffer(buffer, src_video_info, dst_video_info, sample, &total_size); if (status) { @@ -891,8 +879,10 @@ NTSTATUS wg_transform_read_data(void *args) { struct wg_transform_read_data_params *params = args; struct wg_transform *transform = get_transform(params->transform); + GstVideoInfo src_video_info, dst_video_info; struct wg_sample *sample = params->sample; struct wg_format *format = params->format; + GstVideoAlignment align = {0}; GstBuffer *output_buffer; GstCaps *output_caps; bool discard_data; @@ -910,6 +900,18 @@ NTSTATUS wg_transform_read_data(void *args) output_buffer = gst_sample_get_buffer(transform->output_sample); output_caps = gst_sample_get_caps(transform->output_sample); + if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO) + { + gsize plane_align = transform->attrs.output_plane_align; + + if (!gst_video_info_from_caps(&src_video_info, output_caps)) + GST_ERROR("Failed to get video info from %"GST_PTR_FORMAT, output_caps); + dst_video_info = src_video_info; + + /* set the desired output buffer alignment on the dest video info */ + align_video_info_planes(plane_align, &dst_video_info, &align); + } + if (GST_MINI_OBJECT_FLAG_IS_SET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED)) { GST_MINI_OBJECT_FLAG_UNSET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED); @@ -918,17 +920,10 @@ NTSTATUS wg_transform_read_data(void *args) if (format) { - gsize plane_align = transform->attrs.output_plane_align; - GstVideoAlignment align; - GstVideoInfo info; - wg_format_from_caps(format, output_caps); - if (format->major_type == WG_MAJOR_TYPE_VIDEO - && gst_video_info_from_caps(&info, output_caps)) + if (format->major_type == WG_MAJOR_TYPE_VIDEO) { - align_video_info_planes(plane_align, &info, &align); - GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, align.padding_top, align.padding_right, align.padding_bottom); @@ -950,8 +945,8 @@ NTSTATUS wg_transform_read_data(void *args) } if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO) - status = read_transform_output_video(sample, output_buffer, output_caps, - transform->attrs.output_plane_align); + status = read_transform_output_video(sample, output_buffer, + &src_video_info, &dst_video_info); else status = read_transform_output(sample, output_buffer); From 80440a2fa16cc8ed3f726c9085a0d814818084ab Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 Apr 2024 20:07:38 -0600 Subject: [PATCH 118/301] winegstreamer: Destroy wg_transform in video_decoder/transform_SetInputType(). (cherry picked from commit 718642478f29338c92f6dadd6c75523088028fdc) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index d363f7b1d9d..027a1d4a165 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -463,7 +463,8 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) WARN("Failed to update stream type frame size, hr %#lx\n", hr); - return update_output_info_size(decoder, frame_size >> 32, frame_size); + if (FAILED(hr = update_output_info_size(decoder, frame_size >> 32, frame_size))) + return hr; } if (decoder->wg_transform) From 4883e9732512208963a1fbc5fc7ecdee81125bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Feb 2024 09:33:01 +0100 Subject: [PATCH 119/301] winegstreamer: Release sink caps in the error path. (cherry picked from commit 8ae8063743398e2a179f7171a3c86169cc7cdbb2) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index eda07151628..f3bda0db50e 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -338,7 +338,7 @@ NTSTATUS wg_transform_create(void *args) struct wg_format output_format = *params->output_format; struct wg_format input_format = *params->input_format; GstElement *first = NULL, *last = NULL, *element; - GstCaps *raw_caps = NULL, *src_caps = NULL; + GstCaps *sink_caps = NULL, *src_caps = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; GstPadTemplate *template = NULL; struct wg_transform *transform; @@ -399,7 +399,7 @@ NTSTATUS wg_transform_create(void *args) * raw output media type should be enough. */ media_type = gst_structure_get_name(gst_caps_get_structure(transform->output_caps, 0)); - if (!(raw_caps = gst_caps_new_empty_simple(media_type))) + if (!(sink_caps = gst_caps_new_empty_simple(media_type))) goto out; switch (input_format.major_type) @@ -412,12 +412,9 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_MPEG1: - if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, sink_caps)) || !append_element(transform->container, element, &first, &last)) - { - gst_caps_unref(raw_caps); goto out; - } set_max_threads(element); break; @@ -427,12 +424,9 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", input_format.major_type); - gst_caps_unref(raw_caps); goto out; } - gst_caps_unref(raw_caps); - switch (output_format.major_type) { case WG_MAJOR_TYPE_AUDIO: @@ -540,6 +534,7 @@ NTSTATUS wg_transform_create(void *args) goto out; gst_caps_unref(src_caps); + gst_caps_unref(sink_caps); GST_INFO("Created winegstreamer transform %p.", transform); params->transform = (wg_transform_t)(ULONG_PTR)transform; @@ -554,6 +549,8 @@ NTSTATUS wg_transform_create(void *args) gst_object_unref(transform->my_src); if (src_caps) gst_caps_unref(src_caps); + if (sink_caps) + gst_caps_unref(sink_caps); if (transform->allocator) wg_allocator_destroy(transform->allocator); if (transform->drain_query) From 8d03ffa09e7aa45257e36ce6d0ecb6163753b704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Mar 2024 12:32:32 +0100 Subject: [PATCH 120/301] winegstreamer: Append an optional parser before decoders. (cherry picked from commit 7c7e55892e51bb9e351e7512ceeddac0b9d1b325) CW-Bug-Id: #20833 --- dlls/quartz/tests/mpegaudio.c | 4 ++++ dlls/quartz/tests/mpegvideo.c | 28 +++++++++------------------- dlls/winegstreamer/wg_transform.c | 20 ++++++++++++++++++-- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/dlls/quartz/tests/mpegaudio.c b/dlls/quartz/tests/mpegaudio.c index 804cbbcc3d1..9fa6796e096 100644 --- a/dlls/quartz/tests/mpegaudio.c +++ b/dlls/quartz/tests/mpegaudio.c @@ -905,6 +905,7 @@ 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; + BOOL todo_time; }; static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -1012,7 +1013,9 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample ok(hr == S_OK, "Got hr %#lx.\n", hr); if (filter->got_sample == 1) { + todo_wine_if(filter->todo_time) ok(start == filter->expected_start_time, "Got start time %s.\n", wine_dbgstr_longlong(start)); + todo_wine_if(filter->todo_time) ok(stop == filter->expected_stop_time, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); } @@ -1510,6 +1513,7 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, testsink->expected_start_time = 0; testsink->expected_stop_time = 120000; + testsink->todo_time = TRUE; hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMemInputPin_Receive(input, sample); diff --git a/dlls/quartz/tests/mpegvideo.c b/dlls/quartz/tests/mpegvideo.c index 1f17ddbe636..08c59e169fb 100644 --- a/dlls/quartz/tests/mpegvideo.c +++ b/dlls/quartz/tests/mpegvideo.c @@ -834,7 +834,6 @@ 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; - BOOL todo_stop_time; }; static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -942,7 +941,7 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample { ok(start == filter->expected_start_time, "Got start time %s, expected %s.\n", wine_dbgstr_longlong(start), wine_dbgstr_longlong(filter->expected_start_time)); - todo_wine_if(filter->todo_stop_time) + todo_wine ok(stop == filter->expected_stop_time, "Got stop time %s, expected %s.\n", wine_dbgstr_longlong(stop), wine_dbgstr_longlong(filter->expected_stop_time)); } @@ -1226,7 +1225,7 @@ static void test_send_video(IMemInputPin *input, IMediaSample *sample) /* gst-launch-1.0 -v videotestsrc pattern=black num-buffers=10 ! video/x-raw,width=32,height=24 ! mpeg2enc ! filesink location=empty-es2.mpg */ /* then truncate to taste */ /* each 00 00 01 b3 or 00 00 01 00 starts a new frame, except the first 00 00 01 00 after a 00 00 01 b3 */ - static const BYTE empty_mpg_frame1[] = { + static const BYTE empty_mpg_frames[] = { 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, 0x02, 0xbf, 0x60, 0x9c, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xff, 0xf8, @@ -1235,27 +1234,22 @@ static void test_send_video(IMemInputPin *input, IMediaSample *sample) 0x41, 0x28, 0x88, 0x13, 0xb9, 0x6f, 0xcf, 0xc1, 0x04, 0x03, 0xa0, 0x11, 0xb1, 0x41, 0x28, 0x88, 0x13, 0xb9, 0x6f, 0xa1, 0x4b, 0x9f, 0x48, 0x04, 0x10, 0x0e, 0x80, 0x46, 0xc5, 0x04, 0xa2, 0x20, 0x4e, 0xe5, 0x80, 0x41, 0x00, 0xe8, 0x04, 0x6c, 0x50, 0x4a, 0x22, 0x04, 0xee, 0x58, - }; - static const BYTE empty_mpg_frame2[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x57, 0xff, 0xf9, 0x80, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x79, 0xc0, 0x00, 0x00, 0x01, 0x02, 0x0a, 0x79, 0xc0, - }; - static const BYTE empty_mpg_frame3[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x97, 0xff, 0xf9, 0x80, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x79, 0xc0, - 0x00, 0x00, 0x01, 0x02, 0x0a, 0x79, 0xc0, 0x00, 0x00, 0x01, 0xb7, + 0x00, 0x00, 0x01, 0x02, 0x0a, 0x79, 0xc0, + }; + static const BYTE empty_mpg_eos[] = { + 0x00, 0x00, 0x01, 0xb7, }; HRESULT hr; IPin *pin; - /* frame 1 - it's a complete frame, but due to how MPEG framing works, the decoder doesn't know that */ - /* frame 2 - new frame starts, frame 1 can be emitted - but Wine gets confused by colorimetry and returns an error */ - /* frame 3 - Wine emits frames 1 and 2 */ - /* meanwhile, native won't emit anything until an unknown-sized internal buffer is filled, or EOS is announced */ - test_send_sample(input, sample, empty_mpg_frame1, ARRAY_SIZE(empty_mpg_frame1), FALSE); - test_send_sample(input, sample, empty_mpg_frame2, ARRAY_SIZE(empty_mpg_frame2), TRUE); - test_send_sample(input, sample, empty_mpg_frame3, ARRAY_SIZE(empty_mpg_frame3), FALSE); + /* native won't emit anything until an unknown-sized internal buffer is filled, or EOS is announced */ + test_send_sample(input, sample, empty_mpg_frames, ARRAY_SIZE(empty_mpg_frames), TRUE); + test_send_sample(input, sample, empty_mpg_eos, ARRAY_SIZE(empty_mpg_eos), FALSE); hr = IMemInputPin_QueryInterface(input, &IID_IPin, (void **)&pin); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1304,7 +1298,6 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input, sink->expected_start_time = 0; sink->expected_stop_time = 0; - sink->todo_stop_time = FALSE; hr = IMediaSample_SetTime(sample, &sink->expected_start_time, &sink->expected_stop_time); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1342,7 +1335,6 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input, sink->expected_start_time = 22222; sink->expected_stop_time = 22222; - sink->todo_stop_time = TRUE; test_send_video(input, sample); ok(sink->got_sample >= 1, "Got %u calls to Receive().\n", sink->got_sample); ok(sink->got_eos == 1, "Got %u calls to EndOfStream().\n", sink->got_eos); @@ -1412,7 +1404,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, testsink->expected_start_time = 0; testsink->expected_stop_time = 0; - testsink->todo_stop_time = TRUE; test_send_video(input, sample); ok(testsink->got_sample >= 1, "Got %u calls to Receive().\n", testsink->got_sample); testsink->got_sample = 0; @@ -1440,7 +1431,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, testsink->expected_start_time = 0; testsink->expected_stop_time = 0; - testsink->todo_stop_time = TRUE; test_send_video(input, sample); ok(testsink->got_sample >= 1, "Got %u calls to Receive().\n", testsink->got_sample); testsink->got_sample = 0; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f3bda0db50e..f518dd1f5e9 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -338,7 +338,7 @@ NTSTATUS wg_transform_create(void *args) struct wg_format output_format = *params->output_format; struct wg_format input_format = *params->input_format; GstElement *first = NULL, *last = NULL, *element; - GstCaps *sink_caps = NULL, *src_caps = NULL; + GstCaps *sink_caps = NULL, *src_caps = NULL, *parsed_caps = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; GstPadTemplate *template = NULL; struct wg_transform *transform; @@ -394,6 +394,10 @@ NTSTATUS wg_transform_create(void *args) gst_pad_set_query_function(transform->my_sink, transform_sink_query_cb); gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); + media_type = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); + if (!(parsed_caps = gst_caps_new_empty_simple(media_type))) + goto out; + /* Since we append conversion elements, we don't want to filter decoders * based on the actual output caps now. Matching decoders with the * raw output media type should be enough. @@ -412,7 +416,16 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_MPEG1: - if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, sink_caps)) + if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, src_caps, parsed_caps)) + && !append_element(transform->container, element, &first, &last)) + goto out; + else + { + gst_caps_unref(parsed_caps); + parsed_caps = gst_caps_ref(src_caps); + } + + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, parsed_caps, sink_caps)) || !append_element(transform->container, element, &first, &last)) goto out; set_max_threads(element); @@ -533,6 +546,7 @@ NTSTATUS wg_transform_create(void *args) || !push_event(transform->my_src, event)) goto out; + gst_caps_unref(parsed_caps); gst_caps_unref(src_caps); gst_caps_unref(sink_caps); @@ -549,6 +563,8 @@ NTSTATUS wg_transform_create(void *args) gst_object_unref(transform->my_src); if (src_caps) gst_caps_unref(src_caps); + if (parsed_caps) + gst_caps_unref(parsed_caps); if (sink_caps) gst_caps_unref(sink_caps); if (transform->allocator) From 023303eb9a15f97f88f0cd3e4b82a53b67b8f2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Mar 2024 14:15:34 +0100 Subject: [PATCH 121/301] winegstreamer: Create the transform parsed caps from wg_format. (cherry picked from commit 3668a466758d21220a26a7afcebffa64c7fccd4a) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 55 ++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f518dd1f5e9..23dc758e20c 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -332,6 +332,59 @@ static bool wg_format_video_is_flipped(const struct wg_format *format) return format->major_type == WG_MAJOR_TYPE_VIDEO && (format->u.video.height < 0); } +static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char *media_type) +{ + GstCaps *parsed_caps; + + if (!(parsed_caps = gst_caps_new_empty_simple(media_type))) + return NULL; + + switch (format->major_type) + { + case WG_MAJOR_TYPE_AUDIO_MPEG1: + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, + "layer", G_TYPE_INT, format->u.audio_mpeg1.layer, NULL); + break; + case WG_MAJOR_TYPE_AUDIO_MPEG4: + gst_caps_set_simple(parsed_caps, "framed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 4, NULL); + break; + case WG_MAJOR_TYPE_AUDIO_WMA: + gst_caps_set_simple(parsed_caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); + break; + case WG_MAJOR_TYPE_VIDEO_H264: + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, NULL); + break; + case WG_MAJOR_TYPE_VIDEO_MPEG1: + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, NULL); + break; + case WG_MAJOR_TYPE_VIDEO_WMV: + switch (format->u.video_wmv.format) + { + case WG_WMV_VIDEO_FORMAT_WMV1: + gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 1, NULL); + break; + case WG_WMV_VIDEO_FORMAT_WMV2: + gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 2, NULL); + break; + case WG_WMV_VIDEO_FORMAT_WMV3: + case WG_WMV_VIDEO_FORMAT_WMVA: + case WG_WMV_VIDEO_FORMAT_WVC1: + gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 3, NULL); + break; + default: + GST_WARNING("Unknown WMV format %u.", format->u.video_wmv.format); + break; + } + break; + case WG_MAJOR_TYPE_AUDIO: + case WG_MAJOR_TYPE_VIDEO: + case WG_MAJOR_TYPE_UNKNOWN: + break; + } + + return parsed_caps; +} + NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; @@ -395,7 +448,7 @@ NTSTATUS wg_transform_create(void *args) gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); media_type = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); - if (!(parsed_caps = gst_caps_new_empty_simple(media_type))) + if (!(parsed_caps = transform_get_parsed_caps(&input_format, media_type))) goto out; /* Since we append conversion elements, we don't want to filter decoders From f68f462177a19a107fd3f15edfe350cd85a4c173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Mar 2024 11:22:13 +0100 Subject: [PATCH 122/301] winegstreamer: Fallback to input caps only when no parser was found. (cherry picked from commit d7cf25dcd49c44e066658bf5752f4c429906323b) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 23dc758e20c..fc817eec2d6 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -472,7 +472,7 @@ NTSTATUS wg_transform_create(void *args) if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, src_caps, parsed_caps)) && !append_element(transform->container, element, &first, &last)) goto out; - else + else if (!element) { gst_caps_unref(parsed_caps); parsed_caps = gst_caps_ref(src_caps); From b097415944fc3e67540f2b1c4ecde27c0716edd3 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 2 Apr 2024 09:39:46 +0800 Subject: [PATCH 123/301] winegstreamer: Merge audio_mpeg1 into audio field. (cherry picked from commit 29dfcb99080812332d805fa041820f6f41794575) CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 26 +++++++++++++------------- dlls/winegstreamer/quartz_transform.c | 4 ++-- dlls/winegstreamer/unixlib.h | 11 +++++------ dlls/winegstreamer/wg_format.c | 12 ++++++------ dlls/winegstreamer/wg_transform.c | 2 +- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 17e526a2ecb..b0f7f998d38 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -230,7 +230,7 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->majortype = MEDIATYPE_Audio; mt->formattype = FORMAT_WaveFormatEx; - switch (format->u.audio_mpeg1.layer) + switch (format->u.audio.layer) { case 1: case 2: @@ -245,10 +245,10 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->cbFormat = sizeof(*wave_format); mt->pbFormat = (BYTE *)wave_format; wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEG; - wave_format->wfx.nChannels = format->u.audio_mpeg1.channels; - wave_format->wfx.nSamplesPerSec = format->u.audio_mpeg1.rate; + wave_format->wfx.nChannels = format->u.audio.channels; + wave_format->wfx.nSamplesPerSec = format->u.audio.rate; wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX); - wave_format->fwHeadLayer = format->u.audio_mpeg1.layer; + wave_format->fwHeadLayer = format->u.audio.layer; return true; } @@ -264,8 +264,8 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->cbFormat = sizeof(*wave_format); mt->pbFormat = (BYTE *)wave_format; wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; - wave_format->wfx.nChannels = format->u.audio_mpeg1.channels; - wave_format->wfx.nSamplesPerSec = format->u.audio_mpeg1.rate; + wave_format->wfx.nChannels = format->u.audio.channels; + wave_format->wfx.nSamplesPerSec = format->u.audio.rate; wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX); /* FIXME: We can't get most of the MPEG data from the caps. We may have * to manually parse the header. */ @@ -441,7 +441,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) } case WG_MAJOR_TYPE_AUDIO_MPEG1: - switch (format->u.audio_mpeg1.layer) + switch (format->u.audio.layer) { case 1: return 56000; @@ -841,9 +841,9 @@ static bool amt_to_wg_format_audio_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio_mpeg1.channels = audio_format->wfx.nChannels; - format->u.audio_mpeg1.rate = audio_format->wfx.nSamplesPerSec; - format->u.audio_mpeg1.layer = audio_format->fwHeadLayer; + format->u.audio.channels = audio_format->wfx.nChannels; + format->u.audio.rate = audio_format->wfx.nSamplesPerSec; + format->u.audio.layer = audio_format->fwHeadLayer; return true; } @@ -863,9 +863,9 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio_mpeg1.channels = audio_format->wfx.nChannels; - format->u.audio_mpeg1.rate = audio_format->wfx.nSamplesPerSec; - format->u.audio_mpeg1.layer = 3; + format->u.audio.channels = audio_format->wfx.nChannels; + format->u.audio.rate = audio_format->wfx.nSamplesPerSec; + format->u.audio.layer = 3; return true; } diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 5189c0b22d3..784bf6f9411 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -758,7 +758,7 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio_mpeg1 = + .u.audio = { .layer = 2, .channels = 1, @@ -1036,7 +1036,7 @@ HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio_mpeg1 = + .u.audio = { .layer = 3, .channels = 1, diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 83241d67a33..77303d83032 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -96,6 +96,10 @@ struct wg_format union { + /* Valid members for different audio formats: + * + * Uncompressed(PCM): channels, channel_mask, rate. + * MPEG1: channels, rate, layer. */ struct { wg_audio_format format; @@ -103,13 +107,8 @@ struct wg_format uint32_t channels; uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; - } audio; - struct - { uint32_t layer; - uint32_t rate; - uint32_t channels; - } audio_mpeg1; + } audio; struct { uint32_t payload_type; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index f27653f8f41..9fd8256a248 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -198,9 +198,9 @@ static void wg_format_from_caps_audio_mpeg1(struct wg_format *format, const GstC } format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; - format->u.audio_mpeg1.layer = layer; - format->u.audio_mpeg1.channels = channels; - format->u.audio_mpeg1.rate = rate; + format->u.audio.layer = layer; + format->u.audio.channels = channels; + format->u.audio.rate = rate; } static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCaps *caps) @@ -510,9 +510,9 @@ static GstCaps *wg_format_to_caps_audio_mpeg1(const struct wg_format *format) return NULL; gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); - gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->u.audio_mpeg1.layer, NULL); - gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio_mpeg1.rate, NULL); - gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio_mpeg1.channels, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->u.audio.layer, NULL); + gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio.rate, NULL); + gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio.channels, NULL); gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); return caps; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index fc817eec2d6..6d5ca156e26 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -343,7 +343,7 @@ static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char * { case WG_MAJOR_TYPE_AUDIO_MPEG1: gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, - "layer", G_TYPE_INT, format->u.audio_mpeg1.layer, NULL); + "layer", G_TYPE_INT, format->u.audio.layer, NULL); break; case WG_MAJOR_TYPE_AUDIO_MPEG4: gst_caps_set_simple(parsed_caps, "framed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 4, NULL); From f385c1af543d4bafcfd30cc2b89baa4d0538e500 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 2 Apr 2024 10:27:47 +0800 Subject: [PATCH 124/301] winegstreamer: Merge audio_mpeg4 into audio field. (cherry picked from commit 256e9afc9751da7489a8b202f0c35f057a8297e6) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 12 ++++++------ dlls/winegstreamer/unixlib.h | 8 +++----- dlls/winegstreamer/wg_format.c | 8 ++++---- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 208fddaf394..cc71fee0c1d 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -667,22 +667,22 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUI raw_aac = IsEqualGUID(subtype, &MFAudioFormat_RAW_AAC); if (!raw_aac) codec_data_size -= min(codec_data_size, sizeof(HEAACWAVEINFO) - sizeof(WAVEFORMATEX)); - if (codec_data_size > sizeof(format->u.audio_mpeg4.codec_data)) + if (codec_data_size > sizeof(format->u.audio.codec_data)) { FIXME("Codec data needs %u bytes.\n", codec_data_size); return; } if (raw_aac) - memcpy(format->u.audio_mpeg4.codec_data, (BYTE *)(&wfx->wfInfo.wfx + 1), codec_data_size); + memcpy(format->u.audio.codec_data, (BYTE *)(&wfx->wfInfo.wfx + 1), codec_data_size); else - memcpy(format->u.audio_mpeg4.codec_data, wfx->pbAudioSpecificConfig, codec_data_size); + memcpy(format->u.audio.codec_data, wfx->pbAudioSpecificConfig, codec_data_size); format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG4; - if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio_mpeg4.payload_type))) - format->u.audio_mpeg4.payload_type = 0; + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio.payload_type))) + format->u.audio.payload_type = 0; - format->u.audio_mpeg4.codec_data_len = codec_data_size; + format->u.audio.codec_data_len = codec_data_size; } static enum wg_video_format mf_video_format_to_wg(const GUID *subtype) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 77303d83032..472b37f9816 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -99,7 +99,8 @@ struct wg_format /* Valid members for different audio formats: * * Uncompressed(PCM): channels, channel_mask, rate. - * MPEG1: channels, rate, layer. */ + * MPEG1: channels, rate, layer. + * MPEG4: payload_type, codec_data_len, codec_data. */ struct { wg_audio_format format; @@ -108,13 +109,10 @@ struct wg_format uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; uint32_t layer; - } audio; - struct - { uint32_t payload_type; uint32_t codec_data_len; unsigned char codec_data[64]; - } audio_mpeg4; + } audio; struct { uint32_t version; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 9fd8256a248..95a96ee95fb 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -528,7 +528,7 @@ static GstCaps *wg_format_to_caps_audio_mpeg4(const struct wg_format *format) gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); - switch (format->u.audio_mpeg4.payload_type) + switch (format->u.audio.payload_type) { case 0: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); break; case 1: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); break; @@ -538,10 +538,10 @@ static GstCaps *wg_format_to_caps_audio_mpeg4(const struct wg_format *format) /* FIXME: Use gst_codec_utils_aac_caps_set_level_and_profile from GStreamer pbutils library */ - if (format->u.audio_mpeg4.codec_data_len) + if (format->u.audio.codec_data_len) { - buffer = gst_buffer_new_and_alloc(format->u.audio_mpeg4.codec_data_len); - gst_buffer_fill(buffer, 0, format->u.audio_mpeg4.codec_data, format->u.audio_mpeg4.codec_data_len); + buffer = gst_buffer_new_and_alloc(format->u.audio.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.audio.codec_data, format->u.audio.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } From cc7d5132a80a3f0843b8070ba967aa6240804986 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 2 Apr 2024 10:34:58 +0800 Subject: [PATCH 125/301] winegstreamer: Merge audio_wma into audio field. (cherry picked from commit 2c88b69fe221e66704a7409b8b8734cb2b32a8f3) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 16 ++++---- dlls/winegstreamer/quartz_parser.c | 64 +++++++++++++++--------------- dlls/winegstreamer/unixlib.h | 19 ++++----- dlls/winegstreamer/wg_format.c | 54 ++++++++++++------------- dlls/winegstreamer/wg_transform.c | 2 +- dlls/winegstreamer/wma_decoder.c | 18 ++++----- 6 files changed, 84 insertions(+), 89 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index cc71fee0c1d..f2902409f15 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -796,14 +796,14 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID } format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio_wma.version = version; - format->u.audio_wma.bitrate = bytes_per_second * 8; - format->u.audio_wma.rate = rate; - format->u.audio_wma.depth = depth; - format->u.audio_wma.channels = channels; - format->u.audio_wma.block_align = block_align; - format->u.audio_wma.codec_data_len = codec_data_len; - memcpy(format->u.audio_wma.codec_data, codec_data, codec_data_len); + format->u.audio.version = version; + format->u.audio.bitrate = bytes_per_second * 8; + format->u.audio.rate = rate; + format->u.audio.depth = depth; + format->u.audio.channels = channels; + format->u.audio.block_align = block_align; + format->u.audio.codec_data_len = codec_data_len; + memcpy(format->u.audio.codec_data, codec_data, codec_data_len); } static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_format *format) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index b0f7f998d38..0a7c3e97d98 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -291,7 +291,7 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form mt->majortype = MEDIATYPE_Audio; mt->formattype = FORMAT_WaveFormatEx; - switch (format->u.audio_wma.version) + switch (format->u.audio.version) { case 1: subtype = &MEDIASUBTYPE_MSAUDIO1; @@ -325,21 +325,21 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form mt->subtype = *subtype; mt->bFixedSizeSamples = TRUE; - mt->lSampleSize = format->u.audio_wma.block_align; + mt->lSampleSize = format->u.audio.block_align; mt->cbFormat = size; mt->pbFormat = (BYTE *)wave_format; wave_format->wFormatTag = fmt_tag; - wave_format->nChannels = format->u.audio_wma.channels; - wave_format->nSamplesPerSec = format->u.audio_wma.rate; - wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8; - wave_format->nBlockAlign = format->u.audio_wma.block_align; - wave_format->wBitsPerSample = format->u.audio_wma.depth; + wave_format->nChannels = format->u.audio.channels; + wave_format->nSamplesPerSec = format->u.audio.rate; + wave_format->nAvgBytesPerSec = format->u.audio.bitrate / 8; + wave_format->nBlockAlign = format->u.audio.block_align; + wave_format->wBitsPerSample = format->u.audio.depth; wave_format->cbSize = codec_data_len; - if (format->u.audio_wma.codec_data_len == codec_data_len) - memcpy(wave_format+1, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); + if (format->u.audio.codec_data_len == codec_data_len) + memcpy(wave_format+1, format->u.audio.codec_data, format->u.audio.codec_data_len); else - FIXME("Unexpected codec_data length; got %u, expected %lu\n", format->u.audio_wma.codec_data_len, codec_data_len); + FIXME("Unexpected codec_data length; got %u, expected %lu\n", format->u.audio.codec_data_len, codec_data_len); return true; } @@ -458,7 +458,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) /* Estimated max size of a compressed audio frame. * There's no way to no way to know the real upper bound, * so let's just use one second of decompressed size and hope it works. */ - return format->u.audio_wma.rate * format->u.audio_wma.channels * format->u.audio_wma.depth / 8; + return format->u.audio.rate * format->u.audio.channels * format->u.audio.depth / 8; case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: @@ -885,33 +885,33 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format } if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) - format->u.audio_wma.version = 1; + format->u.audio.version = 1; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) - format->u.audio_wma.version = 2; + format->u.audio.version = 2; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) - format->u.audio_wma.version = 3; + format->u.audio.version = 3; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) - format->u.audio_wma.version = 4; + format->u.audio.version = 4; else assert(false); format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; - format->u.audio_wma.rate = audio_format->nSamplesPerSec; - format->u.audio_wma.depth = audio_format->wBitsPerSample; - format->u.audio_wma.channels = audio_format->nChannels; - format->u.audio_wma.block_align = audio_format->nBlockAlign; - - format->u.audio_wma.codec_data_len = 0; - if (format->u.audio_wma.version == 1) - format->u.audio_wma.codec_data_len = 4; - if (format->u.audio_wma.version == 2) - format->u.audio_wma.codec_data_len = 10; - if (format->u.audio_wma.version == 3) - format->u.audio_wma.codec_data_len = 18; - if (format->u.audio_wma.version == 4) - format->u.audio_wma.codec_data_len = 18; - if (mt->cbFormat >= sizeof(WAVEFORMATEX) + format->u.audio_wma.codec_data_len) - memcpy(format->u.audio_wma.codec_data, audio_format+1, format->u.audio_wma.codec_data_len); + format->u.audio.bitrate = audio_format->nAvgBytesPerSec * 8; + format->u.audio.rate = audio_format->nSamplesPerSec; + format->u.audio.depth = audio_format->wBitsPerSample; + format->u.audio.channels = audio_format->nChannels; + format->u.audio.block_align = audio_format->nBlockAlign; + + format->u.audio.codec_data_len = 0; + if (format->u.audio.version == 1) + format->u.audio.codec_data_len = 4; + if (format->u.audio.version == 2) + format->u.audio.codec_data_len = 10; + if (format->u.audio.version == 3) + format->u.audio.codec_data_len = 18; + if (format->u.audio.version == 4) + format->u.audio.codec_data_len = 18; + if (mt->cbFormat >= sizeof(WAVEFORMATEX) + format->u.audio.codec_data_len) + memcpy(format->u.audio.codec_data, audio_format+1, format->u.audio.codec_data_len); else FIXME("Too small format block, can't copy codec data\n"); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 472b37f9816..d0f742befc9 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -100,7 +100,9 @@ struct wg_format * * Uncompressed(PCM): channels, channel_mask, rate. * MPEG1: channels, rate, layer. - * MPEG4: payload_type, codec_data_len, codec_data. */ + * MPEG4: payload_type, codec_data_len, codec_data. + * WMA: channels, rate, bitrate, depth, block_align, version, layer, + * payload_type, codec_data_len, codec_data */ struct { wg_audio_format format; @@ -108,22 +110,15 @@ struct wg_format uint32_t channels; uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; - uint32_t layer; - uint32_t payload_type; - uint32_t codec_data_len; - unsigned char codec_data[64]; - } audio; - struct - { - uint32_t version; uint32_t bitrate; - uint32_t rate; uint32_t depth; - uint32_t channels; uint32_t block_align; + uint32_t version; + uint32_t layer; + uint32_t payload_type; uint32_t codec_data_len; unsigned char codec_data[64]; - } audio_wma; + } audio; struct { diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 95a96ee95fb..be19be9e837 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -249,18 +249,18 @@ static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCap } format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - format->u.audio_wma.version = version; - format->u.audio_wma.bitrate = bitrate; - format->u.audio_wma.rate = rate; - format->u.audio_wma.depth = depth; - format->u.audio_wma.channels = channels; - format->u.audio_wma.block_align = block_align; + format->u.audio.version = version; + format->u.audio.bitrate = bitrate; + format->u.audio.rate = rate; + format->u.audio.depth = depth; + format->u.audio.channels = channels; + format->u.audio.block_align = block_align; gst_buffer_map(codec_data, &map, GST_MAP_READ); - if (map.size <= sizeof(format->u.audio_wma.codec_data)) + if (map.size <= sizeof(format->u.audio.codec_data)) { - format->u.audio_wma.codec_data_len = map.size; - memcpy(format->u.audio_wma.codec_data, map.data, map.size); + format->u.audio.codec_data_len = map.size; + memcpy(format->u.audio.codec_data, map.data, map.size); } else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); @@ -645,29 +645,29 @@ static GstCaps *wg_format_to_caps_audio_wma(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) return NULL; - if (format->u.audio_wma.version) - gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); - - if (format->u.audio_wma.bitrate) - gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio_wma.bitrate, NULL); - if (format->u.audio_wma.rate) - gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio_wma.rate, NULL); - if (format->u.audio_wma.depth) - gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.audio_wma.depth, NULL); - if (format->u.audio_wma.channels) - gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio_wma.channels, NULL); - if (format->u.audio_wma.block_align) - gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.audio_wma.block_align, NULL); - - if (format->u.audio_wma.codec_data_len) - { - if (!(buffer = gst_buffer_new_and_alloc(format->u.audio_wma.codec_data_len))) + if (format->u.audio.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); + + if (format->u.audio.bitrate) + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio.bitrate, NULL); + if (format->u.audio.rate) + gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio.rate, NULL); + if (format->u.audio.depth) + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.audio.depth, NULL); + if (format->u.audio.channels) + gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio.channels, NULL); + if (format->u.audio.block_align) + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.audio.block_align, NULL); + + if (format->u.audio.codec_data_len) + { + if (!(buffer = gst_buffer_new_and_alloc(format->u.audio.codec_data_len))) { gst_caps_unref(caps); return NULL; } - gst_buffer_fill(buffer, 0, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.audio.codec_data, format->u.audio.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 6d5ca156e26..cfe3fc3c282 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -349,7 +349,7 @@ static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char * gst_caps_set_simple(parsed_caps, "framed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 4, NULL); break; case WG_MAJOR_TYPE_AUDIO_WMA: - gst_caps_set_simple(parsed_caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); + gst_caps_set_simple(parsed_caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); break; case WG_MAJOR_TYPE_VIDEO_H264: gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, NULL); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 915878efed7..0f68e2ff0c8 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -317,19 +317,19 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, - decoder->input_format.u.audio_wma.channels))) + decoder->input_format.u.audio.channels))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, - decoder->input_format.u.audio_wma.rate))) + decoder->input_format.u.audio.rate))) goto done; - block_alignment = sample_size * decoder->input_format.u.audio_wma.channels / 8; + block_alignment = sample_size * decoder->input_format.u.audio.channels / 8; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, - decoder->input_format.u.audio_wma.rate * block_alignment))) + decoder->input_format.u.audio.rate * block_alignment))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) @@ -446,7 +446,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - decoder->input_format.u.audio_wma.depth = sample_size; + decoder->input_format.u.audio.depth = sample_size; mf_media_type_to_wg_format(type, &decoder->output_format); decoder->output_buf_size = 1024 * block_alignment * channel_count; @@ -693,13 +693,13 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde memset(type->pbFormat, 0, type->cbFormat); wfx = (WAVEFORMATEX *)type->pbFormat; - if (decoder->input_format.u.audio_wma.depth == 32) + if (decoder->input_format.u.audio.depth == 32) wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; else wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = decoder->input_format.u.audio_wma.channels; - wfx->nSamplesPerSec = decoder->input_format.u.audio_wma.rate; - wfx->wBitsPerSample = decoder->input_format.u.audio_wma.depth; + wfx->nChannels = decoder->input_format.u.audio.channels; + wfx->nSamplesPerSec = decoder->input_format.u.audio.rate; + wfx->wBitsPerSample = decoder->input_format.u.audio.depth; wfx->nAvgBytesPerSec = wfx->nChannels * wfx->nSamplesPerSec * wfx->wBitsPerSample / 8; wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; From 0872965b5704de59a1672f516915dc384c7a8907 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 6 Mar 2024 08:50:27 +0800 Subject: [PATCH 126/301] mf/tests: Test AvgTimePerFrame for WMV decoder DMO. (cherry picked from commit 732ed628192ea9560de8af965d9f398745079dfb) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 51 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 3f91f2b727e..4a0b759c593 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -442,8 +442,8 @@ void init_media_type(IMFMediaType *mediatype, const struct attribute_desc *desc, } } -static void init_dmo_media_type_video(DMO_MEDIA_TYPE *media_type, - const GUID *subtype, const LONG width, const LONG height) +static void init_dmo_media_type_video(DMO_MEDIA_TYPE *media_type, const GUID *subtype, + const LONG width, const LONG height, const REFERENCE_TIME time_per_frame) { UINT32 image_size = 0, extra_bytes = subtype_to_extra_bytes(subtype); VIDEOINFOHEADER *header = (VIDEOINFOHEADER *)(media_type + 1); @@ -460,6 +460,7 @@ static void init_dmo_media_type_video(DMO_MEDIA_TYPE *media_type, header->rcTarget.left = 0; header->rcTarget.right = width; header->rcTarget.bottom = height; + header->AvgTimePerFrame = time_per_frame; header->bmiHeader.biSize = sizeof(header->bmiHeader); header->bmiHeader.biWidth = width; header->bmiHeader.biHeight = height; @@ -1348,6 +1349,7 @@ static void check_video_info_header_(int line, VIDEOINFOHEADER *info, const VIDE expected->rcTarget.left, expected->rcTarget.top, expected->rcTarget.right, expected->rcTarget.bottom); check_member_(__FILE__, line, *info, *expected, "%lu", dwBitRate); check_member_(__FILE__, line, *info, *expected, "%lu", dwBitErrorRate); + todo_wine_if(expected->AvgTimePerFrame) check_member_(__FILE__, line, *info, *expected, "%I64d", AvgTimePerFrame); check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biSize); check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biWidth); @@ -1475,11 +1477,11 @@ static void check_dmo_get_output_size_info_video_(int line, IMediaObject *dmo, hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); ok_(__FILE__, line)(hr == S_OK, "Failed to clear output type, hr %#lx.\n", hr); - init_dmo_media_type_video(type, input_subtype, width, height); + init_dmo_media_type_video(type, input_subtype, width, height, 0); hr = IMediaObject_SetInputType(dmo, 0, type, 0); ok_(__FILE__, line)(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(type, output_subtype, width, height); + init_dmo_media_type_video(type, output_subtype, width, height, 0); hr = IMediaObject_SetOutputType(dmo, 0, type, 0); todo_wine_if(IsEqualGUID(output_subtype, &MEDIASUBTYPE_NV11) || IsEqualGUID(output_subtype, &MEDIASUBTYPE_IYUV)) @@ -6120,7 +6122,7 @@ static void test_wmv_decoder_dmo_input_type(void) good_input_type = (void *)buffer_good_input; bad_input_type = (void *)buffer_bad_input; - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); memset(bad_input_type, 0, sizeof(buffer_bad_input)); header = (void *)(good_input_type + 1); @@ -6226,7 +6228,7 @@ static void test_wmv_decoder_dmo_input_type(void) winetest_push_context("type %lu", i); - init_dmo_media_type_video(good_input_type, subtype, width, height); + init_dmo_media_type_video(good_input_type, subtype, width, height, 0); hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_CLEAR); @@ -6239,7 +6241,7 @@ static void test_wmv_decoder_dmo_input_type(void) winetest_pop_context(); } - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); header->dwBitRate = 0xdeadbeef; header->dwBitErrorRate = 0xdeadbeef; header->AvgTimePerFrame = 0xdeadbeef; @@ -6251,31 +6253,31 @@ static void test_wmv_decoder_dmo_input_type(void) hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); good_input_type->majortype = MFMediaType_Default; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, &MEDIASUBTYPE_None, width, height); + init_dmo_media_type_video(good_input_type, &MEDIASUBTYPE_None, width, height, 0); hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); good_input_type->formattype = FORMAT_None; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); good_input_type->cbFormat = 1; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); good_input_type->pbFormat = NULL; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); header->bmiHeader.biSize = 0; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); todo_wine @@ -6289,7 +6291,7 @@ static void test_wmv_decoder_dmo_input_type(void) todo_wine ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); header->bmiHeader.biWidth = 0; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); todo_wine @@ -6306,7 +6308,7 @@ static void test_wmv_decoder_dmo_input_type(void) hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); header->bmiHeader.biHeight = 0; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); todo_wine @@ -6322,7 +6324,7 @@ static void test_wmv_decoder_dmo_input_type(void) hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(good_input_type, input_subtype, width, height); + init_dmo_media_type_video(good_input_type, input_subtype, width, height, 0); header->bmiHeader.biCompression = 0; hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY); todo_wine @@ -6349,6 +6351,7 @@ static void test_wmv_decoder_dmo_output_type(void) char buffer_good_output[2048], buffer_bad_output[2048], buffer_input[2048]; DMO_MEDIA_TYPE *good_output_type, *bad_output_type, *input_type, type; const GUID* input_subtype = &MEDIASUBTYPE_WMV1; + REFERENCE_TIME time_per_frame = 10000000; LONG width = 16, height = 16; DWORD count, i, ret; IMediaObject *dmo; @@ -6377,7 +6380,7 @@ static void test_wmv_decoder_dmo_output_type(void) input_type = (void *)buffer_input; good_output_type = (void *)buffer_good_output; bad_output_type = (void *)buffer_bad_output; - init_dmo_media_type_video(input_type, input_subtype, width, height); + init_dmo_media_type_video(input_type, input_subtype, width, height, time_per_frame); memset(bad_output_type, 0, sizeof(buffer_bad_output)); /* Test GetOutputType. */ @@ -6413,7 +6416,7 @@ static void test_wmv_decoder_dmo_output_type(void) while (SUCCEEDED(hr = IMediaObject_GetOutputType(dmo, 0, ++i, &type))) { winetest_push_context("type %lu", i); - init_dmo_media_type_video(good_output_type, wmv_decoder_output_subtypes[i], width, height); + init_dmo_media_type_video(good_output_type, wmv_decoder_output_subtypes[i], width, height, time_per_frame); check_dmo_media_type(&type, good_output_type); MoFreeMediaType(&type); winetest_pop_context(); @@ -6422,7 +6425,7 @@ static void test_wmv_decoder_dmo_output_type(void) ok(i == count, "%lu types.\n", i); /* Test SetOutputType. */ - init_dmo_media_type_video(good_output_type, &MEDIASUBTYPE_RGB24, width, height); + init_dmo_media_type_video(good_output_type, &MEDIASUBTYPE_RGB24, width, height, time_per_frame); hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0); @@ -6642,10 +6645,10 @@ static void test_wmv_decoder_media_object(void) memcpy(input_media_buffer->data, wmv_data, wmv_data_length); input_media_buffer->length = wmv_data_length; - init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height); + init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height, 0); hr = IMediaObject_SetInputType(media_object, 0, type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height); + init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height, 0); hr = IMediaObject_SetOutputType(media_object, 0, type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); @@ -6713,12 +6716,10 @@ static void test_wmv_decoder_media_object(void) ok(output_media_buffer->length == 0, "Unexpected length %#lx.\n", output_media_buffer->length); /* Test ProcessOutput with setting framerate. */ - init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height); - ((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 100000; + init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height, 100000); hr = IMediaObject_SetInputType(media_object, 0, type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height); - ((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 200000; + init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height, 200000); hr = IMediaObject_SetOutputType(media_object, 0, type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); From 69e867cf9e89ae1138f43563686d41e9e55cd65d Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 5 Mar 2024 18:29:57 +0800 Subject: [PATCH 127/301] winegstreamer: Set AvgTimePerFrame in GetOutputType() for WMV decoder. Krkr2 game engine need AvgTimePerFrame to calculate video frame time. (cherry picked from commit ff0cd457b48b2fc5482bb0df9f9307cf3a3450fe) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 1 - dlls/winegstreamer/wmv_decoder.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 4a0b759c593..6a4653cccee 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -1349,7 +1349,6 @@ static void check_video_info_header_(int line, VIDEOINFOHEADER *info, const VIDE expected->rcTarget.left, expected->rcTarget.top, expected->rcTarget.right, expected->rcTarget.bottom); check_member_(__FILE__, line, *info, *expected, "%lu", dwBitRate); check_member_(__FILE__, line, *info, *expected, "%lu", dwBitErrorRate); - todo_wine_if(expected->AvgTimePerFrame) check_member_(__FILE__, line, *info, *expected, "%I64d", AvgTimePerFrame); check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biSize); check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biWidth); diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index d13b5a065ed..ee77309aae4 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -470,6 +470,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->rcSource.bottom = height; info->rcTarget.right = width; info->rcTarget.bottom = height; + info->AvgTimePerFrame = MulDiv(10000000, decoder->input_format.u.video_wmv.fps_d, + decoder->input_format.u.video_wmv.fps_n); info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = width; info->bmiHeader.biHeight = height; From 50fb6c01b1dfd00607ebd849e0a3a54f6d4af715 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 3 Apr 2024 09:07:22 +0800 Subject: [PATCH 128/301] winegstreamer: Merge video_cinepak into video field. (cherry picked from commit b3a46a94a36728f21d40587a1b42432d990e2ec9) CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 8 ++++---- dlls/winegstreamer/unixlib.h | 12 +++++------- dlls/winegstreamer/wg_format.c | 26 +++++++++++++------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 0a7c3e97d98..d08250e45d8 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -395,7 +395,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) /* Both ffmpeg's encoder and a Cinepak file seen in the wild report * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, * but as long as every sample fits into our allocator, we're fine. */ - return format->u.video_cinepak.width * format->u.video_cinepak.height * 3; + return format->u.video.width * format->u.video.height * 3; case WG_MAJOR_TYPE_VIDEO_MPEG1: /* Estimated max size of a compressed video frame. @@ -616,11 +616,11 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_ mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - if ((frame_time = MulDiv(10000000, format->u.video_cinepak.fps_d, format->u.video_cinepak.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - video_format->bmiHeader.biWidth = format->u.video_cinepak.width; - video_format->bmiHeader.biHeight = format->u.video_cinepak.height; + video_format->bmiHeader.biWidth = format->u.video.width; + video_format->bmiHeader.biHeight = format->u.video.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biBitCount = 24; video_format->bmiHeader.biCompression = mt->subtype.Data1; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index d0f742befc9..f0c64e93765 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -120,9 +120,14 @@ struct wg_format unsigned char codec_data[64]; } audio; + /* Valid members for different video formats: + * + * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. + * CINEPAK: width, height, fps_n, fps_d. */ struct { wg_video_format format; + /* Positive height indicates top-down video; negative height * indicates bottom-up video. */ int32_t width, height; @@ -130,13 +135,6 @@ struct wg_format RECT padding; } video; struct - { - uint32_t width; - uint32_t height; - uint32_t fps_n; - uint32_t fps_d; - } video_cinepak; - struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index be19be9e837..d2ad0fe93cd 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -289,10 +289,10 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs } format->major_type = WG_MAJOR_TYPE_VIDEO_CINEPAK; - format->u.video_cinepak.width = width; - format->u.video_cinepak.height = height; - format->u.video_cinepak.fps_n = fps_n; - format->u.video_cinepak.fps_d = fps_d; + format->u.video.width = width; + format->u.video.height = height; + format->u.video.fps_n = fps_n; + format->u.video.fps_d = fps_d; } static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCaps *caps) @@ -628,12 +628,12 @@ static GstCaps *wg_format_to_caps_video_cinepak(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-cinepak"))) return NULL; - if (format->u.video_cinepak.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_cinepak.width, NULL); - if (format->u.video_cinepak.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_cinepak.height, NULL); - if (format->u.video_cinepak.fps_d || format->u.video_cinepak.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_cinepak.fps_n, format->u.video_cinepak.fps_d, NULL); + if (format->u.video.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); + if (format->u.video.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); + if (format->u.video.fps_d || format->u.video.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); return caps; } @@ -853,7 +853,7 @@ static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_mpeg1.width, NULL); if (format->u.video_mpeg1.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_mpeg1.height, NULL); - if (format->u.video_mpeg1.fps_d || format->u.video_cinepak.fps_n) + if (format->u.video_mpeg1.fps_d || format->u.video.fps_n) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_mpeg1.fps_n, format->u.video_mpeg1.fps_d, NULL); return caps; } @@ -921,8 +921,8 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_VIDEO_CINEPAK: /* Do not compare FPS. */ - return a->u.video_cinepak.width == b->u.video_cinepak.width - && a->u.video_cinepak.height == b->u.video_cinepak.height; + return a->u.video.width == b->u.video.width + && a->u.video.height == b->u.video.height; case WG_MAJOR_TYPE_VIDEO_WMV: /* Do not compare FPS. */ From d310870c70f8608d231aaed85fbb6986e4b1a1e6 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 3 Apr 2024 09:18:03 +0800 Subject: [PATCH 129/301] winegstreamer: Merge video_h264 into video field. (cherry picked from commit 654dc1158bc02123b761ff552cf9f422d9b0ed36) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 22 +++++++++++----------- dlls/winegstreamer/unixlib.h | 10 +++------- dlls/winegstreamer/wg_format.c | 26 +++++++++++++------------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index f2902409f15..80ff686bf81 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -817,33 +817,33 @@ static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video_h264.width = frame_size >> 32; - format->u.video_h264.height = (UINT32)frame_size; + format->u.video.width = frame_size >> 32; + format->u.video.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video_h264.fps_n = frame_rate >> 32; - format->u.video_h264.fps_d = (UINT32)frame_rate; + format->u.video.fps_n = frame_rate >> 32; + format->u.video.fps_d = (UINT32)frame_rate; } else { - format->u.video_h264.fps_n = 1; - format->u.video_h264.fps_d = 1; + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; } if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) - format->u.video_h264.profile = profile; + format->u.video.profile = profile; if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) - format->u.video_h264.level = level; + format->u.video.level = level; if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_MPEG_SEQUENCE_HEADER, &codec_data, &codec_data_len))) { - if (codec_data_len <= sizeof(format->u.video_h264.codec_data)) + if (codec_data_len <= sizeof(format->u.video.codec_data)) { - format->u.video_h264.codec_data_len = codec_data_len; - memcpy(format->u.video_h264.codec_data, codec_data, codec_data_len); + format->u.video.codec_data_len = codec_data_len; + memcpy(format->u.video.codec_data, codec_data, codec_data_len); } else { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index f0c64e93765..22a13cbd5a5 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -123,7 +123,8 @@ struct wg_format /* Valid members for different video formats: * * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. - * CINEPAK: width, height, fps_n, fps_d. */ + * CINEPAK: width, height, fps_n, fps_d. + * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. */ struct { wg_video_format format; @@ -133,16 +134,11 @@ struct wg_format int32_t width, height; uint32_t fps_n, fps_d; RECT padding; - } video; - struct - { - int32_t width, height; - uint32_t fps_n, fps_d; uint32_t profile; uint32_t level; uint32_t codec_data_len; unsigned char codec_data[64]; - } video_h264; + } video; struct { wg_wmv_video_format format; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index d2ad0fe93cd..a2fae9e02b7 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -685,20 +685,20 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) return NULL; gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); - if (format->u.video_h264.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_h264.width, NULL); - if (format->u.video_h264.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_h264.height, NULL); - if (format->u.video_h264.fps_n || format->u.video_h264.fps_d) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_h264.fps_n, format->u.video_h264.fps_d, NULL); + if (format->u.video.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); + if (format->u.video.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); + if (format->u.video.fps_n || format->u.video.fps_d) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); - switch (format->u.video_h264.profile) + switch (format->u.video.profile) { case eAVEncH264VProfile_Main: profile = "main"; break; case eAVEncH264VProfile_High: profile = "high"; break; case eAVEncH264VProfile_444: profile = "high-4:4:4"; break; default: - GST_FIXME("H264 profile attribute %u not implemented.", format->u.video_h264.profile); + GST_FIXME("H264 profile attribute %u not implemented.", format->u.video.profile); /* fallthrough */ case eAVEncH264VProfile_unknown: profile = "baseline"; @@ -706,7 +706,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) } gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); - switch (format->u.video_h264.level) + switch (format->u.video.level) { case eAVEncH264VLevel1: level = "1"; break; case eAVEncH264VLevel1_1: level = "1.1"; break; @@ -725,7 +725,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) case eAVEncH264VLevel5_1: level = "5.1"; break; case eAVEncH264VLevel5_2: level = "5.2"; break; default: - GST_FIXME("H264 level attribute %u not implemented.", format->u.video_h264.level); + GST_FIXME("H264 level attribute %u not implemented.", format->u.video.level); /* fallthrough */ case 0: level = NULL; @@ -734,9 +734,9 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) if (level) gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); - if (format->u.video_h264.codec_data_len) + if (format->u.video.codec_data_len) { - if (!(buffer = gst_buffer_new_and_alloc(format->u.video_h264.codec_data_len))) + if (!(buffer = gst_buffer_new_and_alloc(format->u.video.codec_data_len))) { gst_caps_unref(caps); return NULL; @@ -744,7 +744,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) GST_BUFFER_PTS(buffer) = 0; GST_BUFFER_DTS(buffer) = 0; - gst_buffer_fill(buffer, 0, format->u.video_h264.codec_data, format->u.video_h264.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.video.codec_data, format->u.video.codec_data_len); gst_caps_set_simple(caps, "streamheader", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } From bf52d95fa8537f841c5d9d9a63a5021b6642f4c5 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 3 Apr 2024 09:35:48 +0800 Subject: [PATCH 130/301] winegstreamer: Merge video_wmv into video field. (cherry picked from commit 6e90dff6e791beb93f8ec64fa2a5a97b39c1191e) CW-Bug-Id: #20833 --- dlls/winegstreamer/main.c | 9 +--- dlls/winegstreamer/mfplat.c | 28 +++++----- dlls/winegstreamer/quartz_parser.c | 83 ++++++++++++++++-------------- dlls/winegstreamer/unixlib.h | 26 +++------- dlls/winegstreamer/wg_format.c | 70 ++++++++++++------------- dlls/winegstreamer/wg_transform.c | 14 ++--- dlls/winegstreamer/wmv_decoder.c | 10 ++-- 7 files changed, 113 insertions(+), 127 deletions(-) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 418856bc38d..c34ecd704af 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -845,14 +845,7 @@ bool wg_video_format_is_rgb(enum wg_video_format format) case WG_VIDEO_FORMAT_RGB16: return true; - case WG_VIDEO_FORMAT_AYUV: - case WG_VIDEO_FORMAT_I420: - case WG_VIDEO_FORMAT_NV12: - case WG_VIDEO_FORMAT_UYVY: - case WG_VIDEO_FORMAT_YUY2: - case WG_VIDEO_FORMAT_YV12: - case WG_VIDEO_FORMAT_YVYU: - case WG_VIDEO_FORMAT_UNKNOWN: + default: break; } diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 80ff686bf81..0bf5f4798bc 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -885,35 +885,35 @@ static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subty UINT64 frame_rate, frame_size; format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video_wmv.width = 0; - format->u.video_wmv.height = 0; - format->u.video_wmv.fps_n = 1; - format->u.video_wmv.fps_d = 1; + format->u.video.width = 0; + format->u.video.height = 0; + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video_wmv.width = (UINT32)(frame_size >> 32); - format->u.video_wmv.height = (UINT32)frame_size; + format->u.video.width = (UINT32)(frame_size >> 32); + format->u.video.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video_wmv.fps_n = (UINT32)(frame_rate >> 32); - format->u.video_wmv.fps_d = (UINT32)frame_rate; + format->u.video.fps_n = (UINT32)(frame_rate >> 32); + format->u.video.fps_d = (UINT32)frame_rate; } if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; + format->u.video.format = WG_VIDEO_FORMAT_WMV1; else if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV2; + format->u.video.format = WG_VIDEO_FORMAT_WMV2; else if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3; + format->u.video.format = WG_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMVA; + format->u.video.format = WG_VIDEO_FORMAT_WMVA; else if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WVC1; + format->u.video.format = WG_VIDEO_FORMAT_WVC1; else - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN; + format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; } void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index d08250e45d8..2af820f6f2f 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -374,8 +374,8 @@ static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */ - case WG_VIDEO_FORMAT_UNKNOWN: - FIXME("Cannot guess maximum sample size for unknown video format.\n"); + default: + FIXME("Cannot guess maximum sample size for video format %d.\n", format); return 0; } @@ -406,7 +406,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, - format->u.video_wmv.width, format->u.video_wmv.height); + format->u.video.width, format->u.video.height); case WG_MAJOR_TYPE_AUDIO: { @@ -493,6 +493,11 @@ static const GUID *wg_video_format_get_mediasubtype(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return &MEDIASUBTYPE_YUY2; case WG_VIDEO_FORMAT_YV12: return &MEDIASUBTYPE_YV12; case WG_VIDEO_FORMAT_YVYU: return &MEDIASUBTYPE_YVYU; + case WG_VIDEO_FORMAT_WMV1: return &MEDIASUBTYPE_WMV1; + case WG_VIDEO_FORMAT_WMV2: return &MEDIASUBTYPE_WMV2; + case WG_VIDEO_FORMAT_WMV3: return &MEDIASUBTYPE_WMV3; + case WG_VIDEO_FORMAT_WMVA: return &MEDIASUBTYPE_WMVA; + case WG_VIDEO_FORMAT_WVC1: return &MEDIASUBTYPE_WVC1; } assert(0); @@ -517,10 +522,10 @@ static DWORD wg_video_format_get_compression(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return mmioFOURCC('Y','U','Y','2'); case WG_VIDEO_FORMAT_YV12: return mmioFOURCC('Y','V','1','2'); case WG_VIDEO_FORMAT_YVYU: return mmioFOURCC('Y','V','Y','U'); + default: + ERR("Cannot get compression for video format %d.", format); + return 0; } - - assert(0); - return 0; } static WORD wg_video_format_get_depth(enum wg_video_format format) @@ -541,10 +546,10 @@ static WORD wg_video_format_get_depth(enum wg_video_format format) case WG_VIDEO_FORMAT_YUY2: return 16; case WG_VIDEO_FORMAT_YV12: return 12; case WG_VIDEO_FORMAT_YVYU: return 16; + default: + ERR("Cannot get depth for video format %d.", format); + return 0; } - - assert(0); - return 0; } static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) @@ -635,29 +640,29 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form uint32_t frame_time; const GUID *subtype; - switch (format->u.video_wmv.format) + switch (format->u.video.format) { - case WG_WMV_VIDEO_FORMAT_WMV1: + case WG_VIDEO_FORMAT_WMV1: subtype = &MEDIASUBTYPE_WMV1; break; - case WG_WMV_VIDEO_FORMAT_WMV2: + case WG_VIDEO_FORMAT_WMV2: subtype = &MEDIASUBTYPE_WMV2; break; - case WG_WMV_VIDEO_FORMAT_WMV3: + case WG_VIDEO_FORMAT_WMV3: subtype = &MEDIASUBTYPE_WMV3; break; - case WG_WMV_VIDEO_FORMAT_WMVA: + case WG_VIDEO_FORMAT_WMVA: subtype = &MEDIASUBTYPE_WMVA; break; - case WG_WMV_VIDEO_FORMAT_WVC1: + case WG_VIDEO_FORMAT_WVC1: subtype = &MEDIASUBTYPE_WVC1; break; default: - WARN("Invalid WMV format %u.\n", format->u.video_wmv.format); + WARN("Invalid WMV format %u.\n", format->u.video.format); return false; } - if (!(video_format = CoTaskMemAlloc(sizeof(*video_format) + format->u.video_wmv.codec_data_len))) + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format) + format->u.video.codec_data_len))) return false; mt->majortype = MEDIATYPE_Video; @@ -666,22 +671,22 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form mt->bTemporalCompression = TRUE; mt->lSampleSize = 0; mt->formattype = FORMAT_VideoInfo; - mt->cbFormat = sizeof(*video_format) + format->u.video_wmv.codec_data_len; + mt->cbFormat = sizeof(*video_format) + format->u.video.codec_data_len; mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - SetRect(&video_format->rcSource, 0, 0, format->u.video_wmv.width, format->u.video_wmv.height); + SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height); video_format->rcTarget = video_format->rcSource; - if ((frame_time = MulDiv(10000000, format->u.video_wmv.fps_d, format->u.video_wmv.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; - video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + format->u.video_wmv.codec_data_len; - video_format->bmiHeader.biWidth = format->u.video_wmv.width; - video_format->bmiHeader.biHeight = format->u.video_wmv.height; + video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + format->u.video.codec_data_len; + video_format->bmiHeader.biWidth = format->u.video.width; + video_format->bmiHeader.biHeight = format->u.video.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biCompression = mt->subtype.Data1; video_format->bmiHeader.biBitCount = 24; video_format->dwBitRate = 0; - memcpy(video_format+1, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len); + memcpy(video_format+1, format->u.video.codec_data, format->u.video.codec_data_len); return true; } @@ -993,31 +998,31 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format } format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video_wmv.width = video_format->bmiHeader.biWidth; - format->u.video_wmv.height = video_format->bmiHeader.biHeight; - format->u.video_wmv.fps_n = 10000000; - format->u.video_wmv.fps_d = video_format->AvgTimePerFrame; + format->u.video.width = video_format->bmiHeader.biWidth; + format->u.video.height = video_format->bmiHeader.biHeight; + format->u.video.fps_n = 10000000; + format->u.video.fps_d = video_format->AvgTimePerFrame; if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; + format->u.video.format = WG_VIDEO_FORMAT_WMV1; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV2; + format->u.video.format = WG_VIDEO_FORMAT_WMV2; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV3)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3; + format->u.video.format = WG_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMVA; + format->u.video.format = WG_VIDEO_FORMAT_WMVA; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WVC1)) - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WVC1; + format->u.video.format = WG_VIDEO_FORMAT_WVC1; else - format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN; + format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; - format->u.video_wmv.codec_data_len = mt->cbFormat - sizeof(VIDEOINFOHEADER); - if (format->u.video_wmv.codec_data_len > sizeof(format->u.video_wmv.codec_data)) + format->u.video.codec_data_len = mt->cbFormat - sizeof(VIDEOINFOHEADER); + if (format->u.video.codec_data_len > sizeof(format->u.video.codec_data)) { - ERR("Too big codec_data value (%u).\n", format->u.video_wmv.codec_data_len); - format->u.video_wmv.codec_data_len = 0; + ERR("Too big codec_data value (%u).\n", format->u.video.codec_data_len); + format->u.video.codec_data_len = 0; } - memcpy(format->u.video_wmv.codec_data, video_format+1, format->u.video_wmv.codec_data_len); + memcpy(format->u.video.codec_data, video_format+1, format->u.video.codec_data_len); return true; } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 22a13cbd5a5..4d7cc6250fb 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -77,17 +77,12 @@ enum wg_video_format WG_VIDEO_FORMAT_YUY2, WG_VIDEO_FORMAT_YV12, WG_VIDEO_FORMAT_YVYU, -}; -typedef UINT32 wg_wmv_video_format; -enum wg_wmv_video_format -{ - WG_WMV_VIDEO_FORMAT_UNKNOWN, - WG_WMV_VIDEO_FORMAT_WMV1, - WG_WMV_VIDEO_FORMAT_WMV2, - WG_WMV_VIDEO_FORMAT_WMV3, - WG_WMV_VIDEO_FORMAT_WMVA, - WG_WMV_VIDEO_FORMAT_WVC1, + WG_VIDEO_FORMAT_WMV1, + WG_VIDEO_FORMAT_WMV2, + WG_VIDEO_FORMAT_WMV3, + WG_VIDEO_FORMAT_WMVA, + WG_VIDEO_FORMAT_WVC1, }; struct wg_format @@ -124,7 +119,8 @@ struct wg_format * * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. * CINEPAK: width, height, fps_n, fps_d. - * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. */ + * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. + * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. */ struct { wg_video_format format; @@ -140,14 +136,6 @@ struct wg_format unsigned char codec_data[64]; } video; struct - { - wg_wmv_video_format format; - int32_t width, height; - uint32_t fps_n, fps_d; - uint32_t codec_data_len; - unsigned char codec_data[64]; - } video_wmv; - struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index a2fae9e02b7..15f29ea8ed6 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -300,8 +300,8 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap const GstStructure *structure = gst_caps_get_structure(caps, 0); gint width, height, fps_n, fps_d, wmv_version = 0; gchar format_buffer[5] = {'W','M','V','0',0}; - enum wg_wmv_video_format wmv_format; const gchar *wmv_format_str = NULL; + enum wg_video_format video_format; const GValue *codec_data_value; GstBuffer *codec_data; GstMapInfo map; @@ -325,17 +325,17 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap wmv_format_str = format_buffer; } if (!strcmp(wmv_format_str, "WMV1")) - wmv_format = WG_WMV_VIDEO_FORMAT_WMV1; + video_format = WG_VIDEO_FORMAT_WMV1; else if (!strcmp(wmv_format_str, "WMV2")) - wmv_format = WG_WMV_VIDEO_FORMAT_WMV2; + video_format = WG_VIDEO_FORMAT_WMV2; else if (!strcmp(wmv_format_str, "WMV3")) - wmv_format = WG_WMV_VIDEO_FORMAT_WMV3; + video_format = WG_VIDEO_FORMAT_WMV3; else if (!strcmp(wmv_format_str, "WMVA")) - wmv_format = WG_WMV_VIDEO_FORMAT_WMVA; + video_format = WG_VIDEO_FORMAT_WMVA; else if (!strcmp(wmv_format_str, "WVC1")) - wmv_format = WG_WMV_VIDEO_FORMAT_WVC1; + video_format = WG_VIDEO_FORMAT_WVC1; else - wmv_format = WG_WMV_VIDEO_FORMAT_UNKNOWN; + video_format = WG_VIDEO_FORMAT_UNKNOWN; if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) { @@ -344,19 +344,19 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap } format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video_wmv.width = width; - format->u.video_wmv.height = height; - format->u.video_wmv.format = wmv_format; - format->u.video_wmv.fps_n = fps_n; - format->u.video_wmv.fps_d = fps_d; + format->u.video.width = width; + format->u.video.height = height; + format->u.video.format = video_format; + format->u.video.fps_n = fps_n; + format->u.video.fps_d = fps_d; if ((codec_data_value = gst_structure_get_value(structure, "codec_data")) && (codec_data = gst_value_get_buffer(codec_data_value))) { gst_buffer_map(codec_data, &map, GST_MAP_READ); - if (map.size <= sizeof(format->u.video_wmv.codec_data)) + if (map.size <= sizeof(format->u.video.codec_data)) { - format->u.video_wmv.codec_data_len = map.size; - memcpy(format->u.video_wmv.codec_data, map.data, map.size); + format->u.video.codec_data_len = map.size; + memcpy(format->u.video.codec_data, map.data, map.size); } else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); @@ -762,32 +762,32 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-wmv"))) return NULL; - switch (format->u.video_wmv.format) + switch (format->u.video.format) { - case WG_WMV_VIDEO_FORMAT_WMV1: + case WG_VIDEO_FORMAT_WMV1: wmv_format = "WMV1"; wmv_version = 1; break; - case WG_WMV_VIDEO_FORMAT_WMV2: + case WG_VIDEO_FORMAT_WMV2: wmv_format = "WMV2"; wmv_version = 2; break; - case WG_WMV_VIDEO_FORMAT_WMV3: + case WG_VIDEO_FORMAT_WMV3: wmv_format = "WMV3"; wmv_version = 3; break; - case WG_WMV_VIDEO_FORMAT_WMVA: + case WG_VIDEO_FORMAT_WMVA: wmv_format = "WMVA"; wmv_version = 3; break; - case WG_WMV_VIDEO_FORMAT_WVC1: + case WG_VIDEO_FORMAT_WVC1: wmv_format = "WVC1"; wmv_version = 3; break; default: - GST_WARNING("Unknown WMV format %u.", format->u.video_wmv.format); + GST_WARNING("Unknown WMV format %u.", format->u.video.format); /* fallthrough */ - case WG_WMV_VIDEO_FORMAT_UNKNOWN: + case WG_VIDEO_FORMAT_UNKNOWN: wmv_format = NULL; wmv_version = 0; break; @@ -797,22 +797,22 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) gst_caps_set_simple(caps, "format", G_TYPE_STRING, wmv_format, NULL); if (wmv_version) gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, wmv_version, NULL); - if (format->u.video_wmv.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_wmv.width, NULL); - if (format->u.video_wmv.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_wmv.height, NULL); - if (format->u.video_wmv.fps_d || format->u.video_wmv.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_wmv.fps_n, format->u.video_wmv.fps_d, NULL); + if (format->u.video.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); + if (format->u.video.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); + if (format->u.video.fps_d || format->u.video.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); - if (format->u.video_wmv.codec_data_len) + if (format->u.video.codec_data_len) { - if (!(buffer = gst_buffer_new_and_alloc(format->u.video_wmv.codec_data_len))) + if (!(buffer = gst_buffer_new_and_alloc(format->u.video.codec_data_len))) { gst_caps_unref(caps); return NULL; } - gst_buffer_fill(buffer, 0, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.video.codec_data, format->u.video.codec_data_len); gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); gst_buffer_unref(buffer); } @@ -926,9 +926,9 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_VIDEO_WMV: /* Do not compare FPS. */ - return a->u.video_wmv.format == b->u.video_wmv.format - && a->u.video_wmv.width == b->u.video_wmv.width - && a->u.video_wmv.height == b->u.video_wmv.height; + return a->u.video.format == b->u.video.format + && a->u.video.width == b->u.video.width + && a->u.video.height == b->u.video.height; } assert(0); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index cfe3fc3c282..4c57a084bd1 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -358,21 +358,21 @@ static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char * gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, NULL); break; case WG_MAJOR_TYPE_VIDEO_WMV: - switch (format->u.video_wmv.format) + switch (format->u.video.format) { - case WG_WMV_VIDEO_FORMAT_WMV1: + case WG_VIDEO_FORMAT_WMV1: gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 1, NULL); break; - case WG_WMV_VIDEO_FORMAT_WMV2: + case WG_VIDEO_FORMAT_WMV2: gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 2, NULL); break; - case WG_WMV_VIDEO_FORMAT_WMV3: - case WG_WMV_VIDEO_FORMAT_WMVA: - case WG_WMV_VIDEO_FORMAT_WVC1: + case WG_VIDEO_FORMAT_WMV3: + case WG_VIDEO_FORMAT_WMVA: + case WG_VIDEO_FORMAT_WVC1: gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 3, NULL); break; default: - GST_WARNING("Unknown WMV format %u.", format->u.video_wmv.format); + GST_WARNING("Unknown WMV format %u.", format->u.video.format); break; } break; diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index ee77309aae4..ea8b4b19eb6 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -445,8 +445,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde if (!wg_format_is_set(&decoder->input_format)) return DMO_E_TYPE_NOT_SET; - width = decoder->input_format.u.video_wmv.width; - height = abs(decoder->input_format.u.video_wmv.height); + width = decoder->input_format.u.video.width; + height = abs(decoder->input_format.u.video.height); subtype = wmv_decoder_output_types[type_index].subtype; if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) { @@ -470,8 +470,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->rcSource.bottom = height; info->rcTarget.right = width; info->rcTarget.bottom = height; - info->AvgTimePerFrame = MulDiv(10000000, decoder->input_format.u.video_wmv.fps_d, - decoder->input_format.u.video_wmv.fps_n); + info->AvgTimePerFrame = MulDiv(10000000, decoder->input_format.u.video.fps_d, + decoder->input_format.u.video.fps_n); info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = width; info->bmiHeader.biHeight = height; @@ -881,7 +881,7 @@ HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_VIDEO_WMV, - .u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3, + .u.video.format = WG_VIDEO_FORMAT_WMV3, }; static const struct wg_format output_format = { From 8fe79f23607db8dceff31daef02a7ca5e688b567 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 3 Apr 2024 10:13:31 +0800 Subject: [PATCH 131/301] winegstreamer: Merge video_indeo into video field. (cherry picked from commit 8ff54f9d342f4015d6ffd615fbb671558d2df329) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 14 +++++++------- dlls/winegstreamer/unixlib.h | 10 +++------- dlls/winegstreamer/wg_format.c | 16 ++++++++-------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0bf5f4798bc..3128363fe29 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -862,22 +862,22 @@ static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video_indeo.width = frame_size >> 32; - format->u.video_indeo.height = (UINT32)frame_size; + format->u.video.width = frame_size >> 32; + format->u.video.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video_indeo.fps_n = frame_rate >> 32; - format->u.video_indeo.fps_d = (UINT32)frame_rate; + format->u.video.fps_n = frame_rate >> 32; + format->u.video.fps_d = (UINT32)frame_rate; } else { - format->u.video_indeo.fps_n = 1; - format->u.video_indeo.fps_d = 1; + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; } - format->u.video_indeo.version = version; + format->u.video.version = version; } static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 4d7cc6250fb..4de7efa6065 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -120,7 +120,8 @@ struct wg_format * Uncompressed(RGB and YUV): width, height, fps_n, fps_d, padding. * CINEPAK: width, height, fps_n, fps_d. * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. - * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. */ + * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. + * INDEO: width, height, fps_n, fps_d, version. */ struct { wg_video_format format; @@ -132,16 +133,11 @@ struct wg_format RECT padding; uint32_t profile; uint32_t level; + uint32_t version; uint32_t codec_data_len; unsigned char codec_data[64]; } video; struct - { - int32_t width, height; - uint32_t fps_n, fps_d; - uint32_t version; - } video_indeo; - struct { int32_t width, height; uint32_t fps_n, fps_d; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 15f29ea8ed6..6bea9026f2a 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -827,14 +827,14 @@ static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) if (!(caps = gst_caps_new_empty_simple("video/x-indeo"))) return NULL; - if (format->u.video_indeo.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_indeo.width, NULL); - if (format->u.video_indeo.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_indeo.height, NULL); - if (format->u.video_indeo.fps_d || format->u.video_indeo.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_indeo.fps_n, format->u.video_indeo.fps_d, NULL); - if (format->u.video_indeo.version) - gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video_indeo.version, NULL); + if (format->u.video.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); + if (format->u.video.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); + if (format->u.video.fps_d || format->u.video.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + if (format->u.video.version) + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video.version, NULL); return caps; } From 7531c8a25b318cb346e25dcab8856def27a1414c Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 3 Apr 2024 10:17:22 +0800 Subject: [PATCH 132/301] winegstreamer: Merge video_mpeg1 into video field. (cherry picked from commit bb7796885177ca08444a824f5ae92ec91a14fb52) CW-Bug-Id: #20833 --- dlls/winegstreamer/quartz_parser.c | 19 ++++++++----------- dlls/winegstreamer/quartz_transform.c | 2 +- dlls/winegstreamer/unixlib.h | 8 ++------ dlls/winegstreamer/wg_format.c | 20 ++++++++++---------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 2af820f6f2f..7b8d7c87cce 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -398,13 +398,10 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) return format->u.video.width * format->u.video.height * 3; case WG_MAJOR_TYPE_VIDEO_MPEG1: + case WG_MAJOR_TYPE_VIDEO_WMV: /* Estimated max size of a compressed video frame. * There's no way to no way to know the real upper bound, * so let's just use the decompressed size and hope it works. */ - return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, - format->u.video_mpeg1.width, format->u.video_mpeg1.height); - - case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, format->u.video.width, format->u.video.height); @@ -708,11 +705,11 @@ static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo mt->pbFormat = (BYTE *)video_format; memset(video_format, 0, sizeof(*video_format)); - if ((frame_time = MulDiv(10000000, format->u.video_mpeg1.fps_d, format->u.video_mpeg1.fps_n)) != -1) + if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) video_format->hdr.AvgTimePerFrame = frame_time; video_format->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - video_format->hdr.bmiHeader.biWidth = format->u.video_mpeg1.width; - video_format->hdr.bmiHeader.biHeight = format->u.video_mpeg1.height; + video_format->hdr.bmiHeader.biWidth = format->u.video.width; + video_format->hdr.bmiHeader.biHeight = format->u.video.height; video_format->hdr.bmiHeader.biPlanes = 1; video_format->hdr.bmiHeader.biBitCount = 12; video_format->hdr.bmiHeader.biCompression = mt->subtype.Data1; @@ -1042,10 +1039,10 @@ static bool amt_to_wg_format_video_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form } format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; - format->u.video_mpeg1.width = video_format->hdr.bmiHeader.biWidth; - format->u.video_mpeg1.height = video_format->hdr.bmiHeader.biHeight; - format->u.video_mpeg1.fps_n = 10000000; - format->u.video_mpeg1.fps_d = video_format->hdr.AvgTimePerFrame; + format->u.video.width = video_format->hdr.bmiHeader.biWidth; + format->u.video.height = video_format->hdr.bmiHeader.biHeight; + format->u.video.fps_n = 10000000; + format->u.video.fps_d = video_format->hdr.AvgTimePerFrame; return true; } diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 784bf6f9411..ad0c3077733 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -907,7 +907,7 @@ HRESULT mpeg_video_codec_create(IUnknown *outer, IUnknown **out) static const struct wg_format input_format = { .major_type = WG_MAJOR_TYPE_VIDEO_MPEG1, - .u.video_mpeg1 = {}, + .u.video = {}, }; struct wg_transform_attrs attrs = {0}; wg_transform_t transform; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 4de7efa6065..8d5fe404d8f 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -121,7 +121,8 @@ struct wg_format * CINEPAK: width, height, fps_n, fps_d. * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data. * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data. - * INDEO: width, height, fps_n, fps_d, version. */ + * INDEO: width, height, fps_n, fps_d, version. + * MPEG1: width, height, fps_n, fps_d. */ struct { wg_video_format format; @@ -137,11 +138,6 @@ struct wg_format uint32_t codec_data_len; unsigned char codec_data[64]; } video; - struct - { - int32_t width, height; - uint32_t fps_n, fps_d; - } video_mpeg1; } u; }; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 6bea9026f2a..12f3a2c0ecf 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -386,10 +386,10 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC } format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; - format->u.video_mpeg1.width = width; - format->u.video_mpeg1.height = height; - format->u.video_mpeg1.fps_n = fps_n; - format->u.video_mpeg1.fps_d = fps_d; + format->u.video.width = width; + format->u.video.height = height; + format->u.video.fps_n = fps_n; + format->u.video.fps_d = fps_d; } void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) @@ -849,12 +849,12 @@ static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format) gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); gst_caps_set_simple(caps, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - if (format->u.video_mpeg1.width) - gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_mpeg1.width, NULL); - if (format->u.video_mpeg1.height) - gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_mpeg1.height, NULL); - if (format->u.video_mpeg1.fps_d || format->u.video.fps_n) - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_mpeg1.fps_n, format->u.video_mpeg1.fps_d, NULL); + if (format->u.video.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); + if (format->u.video.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); + if (format->u.video.fps_d || format->u.video.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); return caps; } From deebbd72db6b62e1d5ecf54a76a375405d9ec6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 Apr 2024 11:52:49 +0200 Subject: [PATCH 133/301] winegstreamer: Set other aperture attributes on video media types. (cherry picked from commit 73b6049c8a320d24d5f6cc93274cee39aa93b36c) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 20 ++++++++++---------- dlls/winegstreamer/mfplat.c | 4 ++++ dlls/winegstreamer/video_decoder.c | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 6a4653cccee..d1d52d62458 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4090,8 +4090,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4106,8 +4106,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4122,8 +4122,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4138,8 +4138,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4154,8 +4154,8 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16, .todo = TRUE), - ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16, .todo = TRUE), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), }, }; const MFT_OUTPUT_STREAM_INFO initial_output_info = diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 3128363fe29..84391a9f5d1 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -558,6 +558,10 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * IMFMediaType_SetBlob(type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)); + IMFMediaType_SetBlob(type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&aperture, sizeof(aperture)); + IMFMediaType_SetBlob(type, &MF_MT_PAN_SCAN_APERTURE, + (BYTE *)&aperture, sizeof(aperture)); } return type; diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 027a1d4a165..bda7997e93b 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -192,6 +192,22 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI goto done; } + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) + { + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, + (BYTE *)&aperture, sizeof(aperture)))) + goto done; + } + + if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) + { + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, + (BYTE *)&aperture, sizeof(aperture)))) + goto done; + } + done: if (SUCCEEDED(hr)) *media_type = (IMFMediaType *)video_type; From 5fb39e4889507cf2157660a7b4f94a3fd743729b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 Apr 2024 11:53:45 +0200 Subject: [PATCH 134/301] winegstreamer: Always set aperture attributes on video decoder output types. (cherry picked from commit 0567f993081708dc1fe2f8b421fdcca82b2c9e25) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 38 +++++++++++++----------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index bda7997e93b..9cb9d5dcdd7 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -128,9 +128,9 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI IMFMediaType *output_type, IMFMediaType **media_type) { IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; + MFVideoArea default_aperture = {{0}}, aperture; IMFVideoMediaType *video_type; UINT32 value, width, height; - MFVideoArea aperture; UINT64 ratio; HRESULT hr; @@ -144,6 +144,9 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI width = ratio >> 32; height = ratio; + default_aperture.Area.cx = width; + default_aperture.Area.cy = height; + if (FAILED(IMFMediaType_GetUINT64(stream_type, &MF_MT_FRAME_RATE, &ratio))) ratio = (UINT64)30000 << 32 | 1001; if (FAILED(hr = IMFVideoMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ratio))) @@ -184,29 +187,20 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) goto done; - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } + if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) + aperture = default_aperture; + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) + goto done; - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } + if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) + aperture = default_aperture; + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_GEOMETRIC_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) + goto done; - if (SUCCEEDED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, - (BYTE *)&aperture, sizeof(aperture), &value))) - { - if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, - (BYTE *)&aperture, sizeof(aperture)))) - goto done; - } + if (FAILED(IMFMediaType_GetBlob(stream_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture), &value))) + aperture = default_aperture; + if (FAILED(hr = IMFVideoMediaType_SetBlob(video_type, &MF_MT_PAN_SCAN_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) + goto done; done: if (SUCCEEDED(hr)) From 6b6ab635893267dc3756daea25151e8fdc4e19af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 23:03:31 +0100 Subject: [PATCH 135/301] winegstreamer: Introduce a new wg_transform_create_quartz helper. (cherry picked from commit cc395ce83f1e2dd64b0dff75a36ad421e02ed572) CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/main.c | 15 +++++++++++++++ dlls/winegstreamer/quartz_transform.c | 13 +++---------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 061afc8a6c0..223c9398f0c 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -120,6 +120,8 @@ void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select); wg_transform_t wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format, const struct wg_transform_attrs *attrs); +HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, + const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index c34ecd704af..99f968c226b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -549,6 +549,21 @@ wg_transform_t wg_transform_create(const struct wg_format *input_format, return params.transform; } +HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_type, const AM_MEDIA_TYPE *output_type, + const struct wg_transform_attrs *attrs, wg_transform_t *transform) +{ + struct wg_format input_format, output_format; + + if (!amt_to_wg_format(input_type, &input_format)) + return E_FAIL; + if (!amt_to_wg_format(output_type, &output_format)) + return E_FAIL; + + if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) + return E_FAIL; + return S_OK; +} + void wg_transform_destroy(wg_transform_t transform) { TRACE("transform %#I64x.\n", transform); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index ad0c3077733..b85b24f4278 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -98,26 +98,19 @@ static HRESULT transform_query_interface(struct strmbase_filter *iface, REFIID i static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; HRESULT hr; if (filter->source.pin.peer) { - if (!amt_to_wg_format(&filter->sink.pin.mt, &input_format)) - return E_FAIL; - - if (!amt_to_wg_format(&filter->source.pin.mt, &output_format)) - return E_FAIL; - if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr; - filter->transform = wg_transform_create(&input_format, &output_format, &attrs); - if (!filter->transform) + if (FAILED(hr = wg_transform_create_quartz(&filter->sink.pin.mt, &filter->source.pin.mt, + &attrs, &filter->transform))) { wg_sample_queue_destroy(filter->sample_queue); - return E_FAIL; + return hr; } hr = IMemAllocator_Commit(filter->source.pAllocator); From f60aade743cebd8085c11b1bdb0a70c7799bd702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 Apr 2024 13:24:02 +0200 Subject: [PATCH 136/301] winegstreamer: Use DMO_MEDIA_TYPE in the WMV decoder. (cherry picked from commit 0b34df89926ce3bead6cbbafd9a5597f13745169) CW-Bug-Id: #20833 --- dlls/winegstreamer/wmv_decoder.c | 80 +++++++++++++++++++------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index ea8b4b19eb6..b8c952da070 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -81,19 +81,14 @@ struct wmv_decoder IUnknown *outer; LONG refcount; - struct wg_format input_format; - struct wg_format output_format; + DMO_MEDIA_TYPE input_type; + DMO_MEDIA_TYPE output_type; GUID output_subtype; wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; }; -static bool wg_format_is_set(struct wg_format *format) -{ - return format->major_type != WG_MAJOR_TYPE_UNKNOWN; -} - static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct wmv_decoder, IUnknown_inner); @@ -428,6 +423,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde DMO_MEDIA_TYPE *type) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + UINT64 frame_size, frame_rate; + IMFMediaType *media_type; VIDEOINFOHEADER *info; const GUID *subtype; LONG width, height; @@ -442,15 +439,25 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde return DMO_E_NO_MORE_ITEMS; if (!type) return S_OK; - if (!wg_format_is_set(&decoder->input_format)) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - width = decoder->input_format.u.video.width; - height = abs(decoder->input_format.u.video.height); + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->input_type, &media_type))) + return hr; + + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + frame_size = 0; + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = (UINT64)1 << 32 | 1; + + width = frame_size >> 32; + height = (UINT32)frame_size; subtype = wmv_decoder_output_types[type_index].subtype; if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) { FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); + IMFMediaType_Release(media_type); return hr; } @@ -470,8 +477,7 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->rcSource.bottom = height; info->rcTarget.right = width; info->rcTarget.bottom = height; - info->AvgTimePerFrame = MulDiv(10000000, decoder->input_format.u.video.fps_d, - decoder->input_format.u.video.fps_n); + info->AvgTimePerFrame = MulDiv(10000000, frame_rate >> 32, (UINT32)frame_rate); info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = width; info->bmiHeader.biHeight = height; @@ -480,6 +486,7 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->bmiHeader.biCompression = wmv_decoder_output_types[type_index].compression; info->bmiHeader.biSizeImage = image_size; + IMFMediaType_Release(media_type); return S_OK; } @@ -487,7 +494,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index const DMO_MEDIA_TYPE *type, DWORD flags) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_format wg_format; + IMFMediaType *media_type; unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -499,7 +506,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { if (flags & DMO_SET_TYPEF_CLEAR) { - memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + FreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -519,14 +527,16 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (i == ARRAY_SIZE(wmv_decoder_input_types)) return DMO_E_TYPE_NOT_ACCEPTED; - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO_WMV); + IMFMediaType_Release(media_type); if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - decoder->input_format = wg_format; + FreeMediaType(&decoder->input_type); + CopyMediaType(&decoder->input_type, type); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -541,8 +551,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); struct wg_transform_attrs attrs = {0}; - struct wg_format wg_format; + IMFMediaType *media_type; unsigned int i; + HRESULT hr; TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); @@ -553,7 +564,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { if (flags & DMO_SET_TYPEF_CLEAR) { - memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -564,7 +576,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde return E_POINTER; } - if (!wg_format_is_set(&decoder->input_format)) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) @@ -576,15 +588,16 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (i == ARRAY_SIZE(wmv_decoder_output_types)) return DMO_E_TYPE_NOT_ACCEPTED; - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO); + IMFMediaType_Release(media_type); if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - decoder->output_subtype = type->subtype; - decoder->output_format = wg_format; + FreeMediaType(&decoder->output_type); + CopyMediaType(&decoder->output_type, type); /* Set up wg_transform. */ if (decoder->wg_transform) @@ -592,8 +605,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = 0; } - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, type, + &attrs, &decoder->wg_transform))) + return hr; return S_OK; } @@ -621,22 +635,22 @@ static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD i static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; HRESULT hr; TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); if (index > 0) return DMO_E_INVALIDSTREAMINDEX; - if (!wg_format_is_set(&decoder->output_format)) + if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - if (FAILED(hr = MFCalculateImageSize(&decoder->output_subtype, - decoder->output_format.u.video.width, abs(decoder->output_format.u.video.height), (UINT32 *)size))) - { - FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(&decoder->output_subtype)); + if (FAILED(hr = MFCreateMediaType(&media_type))) return hr; - } - *alignment = 1; + if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->output_type)) + && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) + *alignment = 1; + IMFMediaType_Release(media_type); return S_OK; } From c4916ad08479eb2f50b7cf455c97691a65bff3ea Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Fri, 12 Apr 2024 10:37:29 +0800 Subject: [PATCH 137/301] winegstreamer: Implement mf_media_type_to_wg_format_video_wmv. (cherry picked from commit a93bea3be6f5b97ce49531de0e65b6a162adb8a1) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 57 +++++++++++++++++++++----------- dlls/winegstreamer/wmv_decoder.c | 3 +- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 84391a9f5d1..ce696b3fb4b 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -44,6 +44,7 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); +DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); extern GUID MEDIASUBTYPE_VC1S; @@ -884,40 +885,58 @@ static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t format->u.video.version = version; } -static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +static void mf_media_type_to_wg_format_video_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT64 frame_rate, frame_size; + UINT32 codec_data_len; + BYTE *codec_data; + memset(format, 0, sizeof(*format)); format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - format->u.video.width = 0; - format->u.video.height = 0; - format->u.video.fps_n = 1; - format->u.video.fps_d = 1; if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - format->u.video.width = (UINT32)(frame_size >> 32); + format->u.video.width = frame_size >> 32; format->u.video.height = (UINT32)frame_size; } if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) { - format->u.video.fps_n = (UINT32)(frame_rate >> 32); + format->u.video.fps_n = frame_rate >> 32; format->u.video.fps_d = (UINT32)frame_rate; } + else + { + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; + } - if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) + if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV1)) format->u.video.format = WG_VIDEO_FORMAT_WMV1; - else if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV2)) format->u.video.format = WG_VIDEO_FORMAT_WMV2; - else if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV3)) format->u.video.format = WG_VIDEO_FORMAT_WMV3; else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) format->u.video.format = WG_VIDEO_FORMAT_WMVA; - else if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WVC1)) format->u.video.format = WG_VIDEO_FORMAT_WVC1; else format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + + if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &codec_data, &codec_data_len))) + { + if (codec_data_len <= sizeof(format->u.video.codec_data)) + { + format->u.video.codec_data_len = codec_data_len; + memcpy(format->u.video.codec_data, codec_data, codec_data_len); + } + else + { + WARN("Codec data buffer too small, codec data size %u.\n", codec_data_len); + } + CoTaskMemFree(codec_data); + } } void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) @@ -955,16 +974,16 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) mf_media_type_to_wg_format_video_h264(type, format); else if (IsEqualGUID(&subtype, &MFVideoFormat_IV50)) mf_media_type_to_wg_format_video_indeo(type, 5, format); - else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV1) - || IsEqualGUID(&subtype, &MFVideoFormat_WMV2) - || IsEqualGUID(&subtype, &MFVideoFormat_WMV3) + else if (IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV2) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVP) || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVP2) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVR) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) - || IsEqualGUID(&subtype, &MFVideoFormat_WVC1) - || IsEqualGUID(&subtype, &MEDIASUBTYPE_VC1S)) - mf_media_type_to_wg_format_wmv(type, &subtype, format); + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV_Unknown) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVC1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV3) + || IsEqualGUID(&subtype, &MFVideoFormat_VC1S)) + mf_media_type_to_wg_format_video_wmv(type, &subtype, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index b8c952da070..446641f0298 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -31,8 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); extern const GUID MEDIASUBTYPE_VC1S; - -DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); +extern const GUID MEDIASUBTYPE_WMV_Unknown; struct decoder_type { From 5369e68cdbc4dd85bb2bcf0808683ac5898eee42 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Fri, 12 Apr 2024 17:44:40 +0800 Subject: [PATCH 138/301] winegstreamer/video_decoder: Set input/output infos in h264_decoder_create. (cherry picked from commit 2d5ec70958866c7e63ce6c35c985aaba5a25b56e) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 9cb9d5dcdd7..ea8d48a32c7 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -841,13 +841,6 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->output_type_count = output_type_count; decoder->output_types = output_types; - decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->input_info.cbSize = 0x1000; - decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->output_info.cbSize = 1920 * 1088 * 2; - if (FAILED(hr = MFCreateMediaType(&decoder->stream_type))) goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) @@ -913,6 +906,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; struct wg_transform_attrs attrs = {0}; + struct video_decoder *decoder; wg_transform_t transform; IMFTransform *iface; HRESULT hr; @@ -929,6 +923,14 @@ HRESULT h264_decoder_create(REFIID riid, void **out) if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) return hr; + decoder = impl_from_IMFTransform(iface); + + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->input_info.cbSize = 0x1000; + decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->output_info.cbSize = 1920 * 1088 * 2; hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface); From 25e9e48fb279d3f81861845728283e886f32dc41 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 24 Apr 2024 10:31:51 +0800 Subject: [PATCH 139/301] winegstreamer/video_decoder: Change decoder attributes. (cherry picked from commit 08fa6367b05dc1ff7ef4310e91c3e5cc29ec035f) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 4 ++-- dlls/winegstreamer/video_decoder.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index d1d52d62458..2a90c49f96e 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3932,9 +3932,9 @@ static void test_h264_decoder(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MF_LOW_LATENCY, 0), - ATTR_UINT32(MF_SA_D3D_AWARE, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D_AWARE, 1), ATTR_UINT32(MF_SA_D3D11_AWARE, 1), - ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE), + ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0), /* more H264 decoder specific attributes from CODECAPI */ ATTR_UINT32(AVDecVideoAcceleration_H264, 1), {0}, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index ea8d48a32c7..015c4b3cb7c 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -845,11 +845,11 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, FALSE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, TRUE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, + &MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, FALSE))) goto failed; { @@ -925,6 +925,12 @@ HRESULT h264_decoder_create(REFIID riid, void **out) return hr; decoder = impl_from_IMFTransform(iface); + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) + { + IMFTransform_Release(iface); + return hr; + } + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->input_info.cbSize = 0x1000; From f0fe5abf84eaaf7c21d66c230ba90c3bcfc6a718 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Mon, 15 Apr 2024 11:01:44 +0800 Subject: [PATCH 140/301] winegstreamer/video_decoder: Add wg_transform_attrs member. (cherry picked from commit 930eabfff9d38de0e8804eb00c73eda0de776293) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 015c4b3cb7c..5c2cc579692 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -64,6 +64,7 @@ struct video_decoder IMFMediaType *stream_type; wg_transform_t wg_transform; + struct wg_transform_attrs wg_transform_attrs; struct wg_sample_queue *wg_sample_queue; IMFVideoSampleAllocatorEx *allocator; @@ -84,12 +85,6 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) * transform to be able to queue its input buffers. We need to use a buffer list * to match its expectations. */ - struct wg_transform_attrs attrs = - { - .output_plane_align = 15, - .input_queue_length = 15, - .allow_size_change = TRUE, - }; struct wg_format input_format; struct wg_format output_format; UINT32 low_latency; @@ -107,15 +102,15 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) return MF_E_INVALIDMEDIATYPE; if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) - attrs.low_latency = !!low_latency; + decoder->wg_transform_attrs.low_latency = !!low_latency; { const char *sgi; if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100") || !strcmp(sgi, "2555360") || !strcmp(sgi, "1630110"))) - attrs.low_latency = FALSE; + decoder->wg_transform_attrs.low_latency = FALSE; } - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &decoder->wg_transform_attrs))) { ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; @@ -867,6 +862,9 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) goto failed; + decoder->wg_transform_attrs.output_plane_align = 15; + decoder->wg_transform_attrs.input_queue_length = 15; + *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; @@ -938,6 +936,8 @@ HRESULT h264_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; + decoder->wg_transform_attrs.allow_size_change = TRUE; + hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface); return hr; From 4889d59bdd664e55ac5b850ea3c89777e2a4fc6b Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 17 Apr 2024 17:04:48 +0800 Subject: [PATCH 141/301] winegstreamer/video_decoder: Support aggregation. (cherry picked from commit 181b609f565125a5774f7cf852d81286697c9b12) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 134 ++++++++++++++++++----------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 5c2cc579692..90bc31f7aa6 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -45,7 +45,9 @@ static const GUID *const video_decoder_output_types[] = struct video_decoder { + IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; + IUnknown *outer; LONG refcount; IMFAttributes *attributes; @@ -73,6 +75,79 @@ struct video_decoder IMFMediaBuffer *temp_buffer; }; +static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IUnknown_inner); +} + +static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = &decoder->IUnknown_inner; + else if (IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI unknown_AddRef(IUnknown *iface) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; +} + +static ULONG WINAPI unknown_Release(IUnknown *iface) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + IMFTransform_Release(decoder->copier); + IMFVideoSampleAllocatorEx_Release(decoder->allocator); + if (decoder->temp_buffer) + IMFMediaBuffer_Release(decoder->temp_buffer); + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + if (decoder->output_attributes) + IMFAttributes_Release(decoder->output_attributes); + if (decoder->attributes) + IMFAttributes_Release(decoder->attributes); + wg_sample_queue_destroy(decoder->wg_sample_queue); + free(decoder); + } + + return refcount; +} + +static const IUnknownVtbl unknown_vtbl = +{ + unknown_QueryInterface, + unknown_AddRef, + unknown_Release, +}; + static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -236,62 +311,17 @@ static void uninit_allocator(struct video_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IMFTransform)) - *out = &decoder->IMFTransform_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; + return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); } static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&decoder->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); - - return refcount; + return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); } static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&decoder->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) - { - IMFTransform_Release(decoder->copier); - IMFVideoSampleAllocatorEx_Release(decoder->allocator); - if (decoder->temp_buffer) - IMFMediaBuffer_Release(decoder->temp_buffer); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - if (decoder->output_attributes) - IMFAttributes_Release(decoder->output_attributes); - if (decoder->attributes) - IMFAttributes_Release(decoder->attributes); - wg_sample_queue_destroy(decoder->wg_sample_queue); - free(decoder); - } - - return refcount; + return IUnknown_Release(impl_from_IMFTransform(iface)->outer); } static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, @@ -820,7 +850,7 @@ static const IMFTransformVtbl transform_vtbl = }; static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) + const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) { struct video_decoder *decoder; HRESULT hr; @@ -828,8 +858,10 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; + decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->outer = outer ? outer : &decoder->IUnknown_inner; decoder->input_type_count = input_type_count; decoder->input_types = input_types; @@ -919,7 +951,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) return hr; decoder = impl_from_IMFTransform(iface); @@ -969,5 +1001,5 @@ HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) return E_FAIL; return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), out); + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); } From f3fb05c2a5b9308aa993dd19cf6cf8722971e428 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Thu, 11 Apr 2024 15:50:21 +0800 Subject: [PATCH 142/301] winegstreamer/video_decoder: Use video_decoder to implement wmv decoder. (cherry picked from commit e7225aaa94509ba7521993af597dee14510c506e) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 69 ++- dlls/winegstreamer/Makefile.in | 1 - dlls/winegstreamer/video_decoder.c | 750 ++++++++++++++++++++++- dlls/winegstreamer/wmv_decoder.c | 942 ----------------------------- 4 files changed, 792 insertions(+), 970 deletions(-) delete mode 100644 dlls/winegstreamer/wmv_decoder.c diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2a90c49f96e..8fdc81605b6 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -681,6 +681,7 @@ static void check_mft_set_input_type_required_(int line, IMFTransform *transform hr = IMFMediaType_DeleteItem(media_type, attr->key); ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr); hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); + todo_wine_if(attr->todo) ok_(__FILE__, line)(FAILED(hr) == attr->required, "SetInputType returned %#lx.\n", hr); hr = IMFMediaType_SetItem(media_type, attr->key, &attr->value); ok_(__FILE__, line)(hr == S_OK, "SetItem returned %#lx\n", hr); @@ -1285,7 +1286,7 @@ static DWORD check_mf_sample_(const char *file, int line, IMFSample *sample, con timestamp = 0xdeadbeef; hr = IMFSample_GetSampleDuration(sample, ×tamp); ok_(file, line)(hr == S_OK, "GetSampleDuration returned %#lx\n", hr); - todo_wine_if(expect->todo_duration && expect->todo_duration == timestamp) + todo_wine_if(expect->todo_duration) ok_(file, line)(llabs(timestamp - expect->sample_duration) <= 1, "got sample duration %I64d\n", timestamp); @@ -5602,7 +5603,7 @@ static void test_wmv_decoder(void) ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_INTERLACE_MODE, 2), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), {0}, }; const media_type_desc expect_available_outputs[] = @@ -5714,7 +5715,7 @@ static void test_wmv_decoder(void) { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE), - ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE, .todo = TRUE), {0}, }; const struct attribute_desc output_type_desc[] = @@ -5760,7 +5761,7 @@ static void test_wmv_decoder(void) ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), {0}, }; const struct attribute_desc expect_output_type_desc[] = @@ -5828,6 +5829,7 @@ static void test_wmv_decoder(void) .cbSize = 0x9000, .cbAlignment = 1, }; + const MFT_INPUT_STREAM_INFO empty_input_info = {0}; const struct attribute_desc output_sample_attributes[] = { @@ -5849,12 +5851,21 @@ static void test_wmv_decoder(void) .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_nv12, + .todo_duration = TRUE, + }; + const struct sample_desc output_sample_desc_nv12_todo_time = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 333333, + .buffer_count = 1, .buffers = &output_buffer_desc_nv12, + .todo_time = TRUE, .todo_duration = TRUE, }; const struct sample_desc output_sample_desc_rgb = { .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_rgb, + .todo_time = TRUE, .todo_duration = TRUE, }; const struct transform_desc @@ -5886,7 +5897,7 @@ static void test_wmv_decoder(void) .expect_output_type_desc = expect_output_type_desc, .expect_input_info = &expect_input_info, .expect_output_info = &expect_output_info, - .output_sample_desc = &output_sample_desc_nv12, + .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", .delta = 0, }, @@ -5929,6 +5940,8 @@ static void test_wmv_decoder(void) MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_WMV1}; IMFSample *input_sample, *output_sample; + MFT_OUTPUT_STREAM_INFO output_info; + MFT_INPUT_STREAM_INFO input_info; IMFCollection *output_samples; IMFMediaType *media_type; IMFTransform *transform; @@ -5965,13 +5978,27 @@ static void test_wmv_decoder(void) check_mft_optional_methods(transform, 1); check_mft_get_attributes(transform, expect_attributes, TRUE); + + memset(&input_info, 0xcd, sizeof(input_info)); + hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); todo_wine - check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetInputStreamInfo returned %#lx\n", hr); + check_member(input_info, empty_input_info, "%I64d", hnsMaxLatency); + check_member(input_info, empty_input_info, "%#lx", dwFlags); + check_member(input_info, empty_input_info, "%#lx", cbSize); + check_member(input_info, empty_input_info, "%#lx", cbMaxLookahead); + check_member(input_info, empty_input_info, "%#lx", cbAlignment); + + memset(&output_info, 0xcd, sizeof(output_info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); todo_wine - check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_output_info); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputStreamInfo returned %#lx\n", hr); + todo_wine + check_member(output_info, empty_output_info, "%#lx", dwFlags); + check_member(output_info, empty_output_info, "%#lx", cbSize); + check_member(output_info, empty_output_info, "%#lx", cbAlignment); hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type); - todo_wine ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr); i = -1; @@ -5985,9 +6012,7 @@ static void test_wmv_decoder(void) ok(!ret, "Release returned %lu\n", ret); winetest_pop_context(); } - todo_wine ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); - todo_wine ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i); if (hr == E_NOTIMPL) @@ -6021,10 +6046,28 @@ static void test_wmv_decoder(void) check_mft_set_output_type_required(transform, transform_tests[j].output_type_desc); check_mft_set_output_type(transform, transform_tests[j].output_type_desc, S_OK); - check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, FALSE); + check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, TRUE); - check_mft_get_input_stream_info(transform, S_OK, transform_tests[j].expect_input_info); - check_mft_get_output_stream_info(transform, S_OK, transform_tests[j].expect_output_info); + memset(&input_info, 0xcd, sizeof(input_info)); + hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); + ok(hr == S_OK, "GetInputStreamInfo returned %#lx\n", hr); + check_member(input_info, *transform_tests[j].expect_input_info, "%I64d", hnsMaxLatency); + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", dwFlags); + todo_wine + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbSize); + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbMaxLookahead); + todo_wine + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbAlignment); + + memset(&output_info, 0xcd, sizeof(output_info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); + ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); + todo_wine + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", dwFlags); + todo_wine_if(transform_tests[j].expect_output_info == &expect_output_info) + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbSize); + todo_wine + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbAlignment); load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index a177fa0e849..20bd6ef5fa7 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -32,7 +32,6 @@ SOURCES = \ winegstreamer_classes.idl \ wm_reader.c \ wma_decoder.c \ - wmv_decoder.c \ media-converter/audioconv.c \ media-converter/audioconvbin.c \ media-converter/fossilize.c \ diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 90bc31f7aa6..f730839ef57 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -24,6 +24,8 @@ #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" +#include "mediaerr.h" +#include "wmcodecdsp.h" #include "wine/debug.h" @@ -34,6 +36,35 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); +struct subtype_info +{ + const GUID *subtype; + WORD bpp; + DWORD compression; +}; + +static const struct subtype_info subtype_info_list[] = +{ + { &MFVideoFormat_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, + { &MFVideoFormat_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, + { &MFVideoFormat_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, + { &MFVideoFormat_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, + { &MFVideoFormat_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, + { &MFVideoFormat_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, + { &MFVideoFormat_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, + { &MFVideoFormat_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, + { &MFVideoFormat_RGB8, 8, BI_RGB }, + { &MFVideoFormat_RGB555, 16, BI_RGB }, + { &MFVideoFormat_RGB565, 16, BI_BITFIELDS }, + { &MFVideoFormat_RGB24, 24, BI_RGB }, + { &MFVideoFormat_RGB32, 32, BI_RGB }, + { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, + { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, + { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, + { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, + { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, +}; + static const GUID *const video_decoder_output_types[] = { &MFVideoFormat_NV12, @@ -47,6 +78,9 @@ struct video_decoder { IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; + IMediaObject IMediaObject_iface; + IPropertyBag IPropertyBag_iface; + IPropertyStore IPropertyStore_iface; IUnknown *outer; LONG refcount; @@ -73,6 +107,9 @@ struct video_decoder BOOL allocator_initialized; IMFTransform *copier; IMFMediaBuffer *temp_buffer; + + DMO_MEDIA_TYPE dmo_input_type; + DMO_MEDIA_TYPE dmo_output_type; }; static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) @@ -90,6 +127,12 @@ static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void * *out = &decoder->IUnknown_inner; else if (IsEqualGUID(iid, &IID_IMFTransform)) *out = &decoder->IMFTransform_iface; + else if (IsEqualGUID(iid, &IID_IMediaObject) && decoder->IMediaObject_iface.lpVtbl) + *out = &decoder->IMediaObject_iface; + else if (IsEqualGUID(iid, &IID_IPropertyBag) && decoder->IPropertyBag_iface.lpVtbl) + *out = &decoder->IPropertyBag_iface; + else if (IsEqualGUID(iid, &IID_IPropertyStore) && decoder->IPropertyStore_iface.lpVtbl) + *out = &decoder->IPropertyStore_iface; else { *out = NULL; @@ -148,6 +191,48 @@ static const IUnknownVtbl unknown_vtbl = unknown_Release, }; +static WORD get_subtype_bpp(const GUID *subtype) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) + { + if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) + return subtype_info_list[i].bpp; + } + + return 0; +} + +static DWORD get_subtype_compression(const GUID *subtype) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) + { + if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) + return subtype_info_list[i].compression; + } + + return 0; +} + +static const GUID *get_dmo_subtype(const GUID *subtype) +{ + if (IsEqualGUID(subtype, &MFVideoFormat_RGB8)) + return &MEDIASUBTYPE_RGB8; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB555)) + return &MEDIASUBTYPE_RGB555; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB565)) + return &MEDIASUBTYPE_RGB565; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB24)) + return &MEDIASUBTYPE_RGB24; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + return &MEDIASUBTYPE_RGB32; + else + return subtype; +} + static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -200,6 +285,7 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI IMFMediaType *default_type = decoder->output_type, *stream_type = output_type ? output_type : decoder->stream_type; MFVideoArea default_aperture = {{0}}, aperture; IMFVideoMediaType *video_type; + LONG default_stride, stride; UINT32 value, width, height; UINT64 ratio; HRESULT hr; @@ -232,9 +318,20 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_SAMPLE_SIZE, value))) goto done; - if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) - hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); - if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) + /* WMV decoder uses positive stride by default, and enforces it for YUV formats, + * accepts negative stride for RGB if specified */ + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, &default_stride))) + goto done; + if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) + stride = abs(default_stride); + else if (default_stride > 0) + stride = abs(stride); + if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, stride))) + goto done; + + if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_VIDEO_NOMINAL_RANGE, (UINT32 *)&value))) + value = MFNominalRange_Wide; + if (FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_VIDEO_NOMINAL_RANGE, value))) goto done; if (!default_type || FAILED(IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) @@ -849,8 +946,547 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, }; +static inline struct video_decoder *impl_from_IMediaObject(IMediaObject *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IMediaObject_iface); +} + +static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) +{ + return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); +} + +static ULONG WINAPI media_object_AddRef(IMediaObject *iface) +{ + return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); +} + +static ULONG WINAPI media_object_Release(IMediaObject *iface) +{ + return IUnknown_Release(impl_from_IMediaObject(iface)->outer); +} + +static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) +{ + TRACE("iface %p, input %p, output %p.\n", iface, input, output); + + if (!input || !output) + return E_POINTER; + + *input = *output = 1; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= decoder->input_type_count) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *get_dmo_subtype(decoder->input_types[type_index]); + type->bFixedSizeSamples = FALSE; + type->bTemporalCompression = TRUE; + type->lSampleSize = 0; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + UINT64 frame_size, frame_rate; + IMFMediaType *media_type; + VIDEOINFOHEADER *info; + const GUID *subtype; + LONG width, height; + UINT32 image_size; + HRESULT hr; + + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= decoder->output_type_count) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->dmo_input_type, &media_type))) + return hr; + + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + frame_size = 0; + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = (UINT64)1 << 32 | 1; + + width = frame_size >> 32; + height = (UINT32)frame_size; + subtype = get_dmo_subtype(decoder->output_types[type_index]); + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) + { + FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); + IMFMediaType_Release(media_type); + return hr; + } + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *subtype; + type->bFixedSizeSamples = TRUE; + type->bTemporalCompression = FALSE; + type->lSampleSize = image_size; + type->formattype = FORMAT_VideoInfo; + type->cbFormat = sizeof(VIDEOINFOHEADER); + type->pbFormat = CoTaskMemAlloc(type->cbFormat); + memset(type->pbFormat, 0, type->cbFormat); + + info = (VIDEOINFOHEADER *)type->pbFormat; + info->rcSource.right = width; + info->rcSource.bottom = height; + info->rcTarget.right = width; + info->rcTarget.bottom = height; + if (frame_rate) + MFFrameRateToAverageTimePerFrame(frame_rate >> 32, frame_rate, (UINT64 *)&info->AvgTimePerFrame); + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = get_subtype_bpp(subtype); + info->bmiHeader.biCompression = get_subtype_compression(subtype); + info->bmiHeader.biSizeImage = image_size; + + IMFMediaType_Release(media_type); + return S_OK; +} + +static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + unsigned int i; + + TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + FreeMediaType(&decoder->dmo_input_type); + memset(&decoder->dmo_input_type, 0, sizeof(decoder->dmo_input_type)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return DMO_E_TYPE_NOT_ACCEPTED; + } + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < decoder->input_type_count; ++i) + if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->input_types[i]))) + break; + if (i == decoder->input_type_count) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) + return DMO_E_TYPE_NOT_ACCEPTED; + IMFMediaType_Release(media_type); + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + FreeMediaType(&decoder->dmo_input_type); + CopyMediaType(&decoder->dmo_input_type, type); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; +} + +static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + unsigned int i; + HRESULT hr; + + TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + FreeMediaType(&decoder->dmo_output_type); + memset(&decoder->dmo_output_type, 0, sizeof(decoder->dmo_output_type)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return E_POINTER; + } + + if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < decoder->output_type_count; ++i) + if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->output_types[i]))) + break; + if (i == decoder->output_type_count) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) + return DMO_E_TYPE_NOT_ACCEPTED; + IMFMediaType_Release(media_type); + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + FreeMediaType(&decoder->dmo_output_type); + CopyMediaType(&decoder->dmo_output_type, type); + + /* Set up wg_transform. */ + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + if (FAILED(hr = wg_transform_create_quartz(&decoder->dmo_input_type, type, + &decoder->wg_transform_attrs, &decoder->wg_transform))) + return hr; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, + DWORD *lookahead, DWORD *alignment) +{ + FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, + lookahead, alignment); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + HRESULT hr; + + TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&decoder->dmo_output_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->dmo_output_type)) + && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) + *alignment = 1; + IMFMediaType_Release(media_type); + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) +{ + FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) +{ + FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_Flush(IMediaObject *iface) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p.\n", iface); + + if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) + return hr; + + wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); + + return S_OK; +} + +static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) +{ + TRACE("iface %p, index %lu.\n", iface, index); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + return S_OK; +} + +static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) +{ + TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!flags) + return E_POINTER; + + *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; + + return S_OK; +} + +static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, + IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, + index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); +} + +static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, + DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) + hr = wg_transform_read_dmo(decoder->wg_transform, buffers); + + if (SUCCEEDED(hr)) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + return hr; +} + +static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) +{ + FIXME("iface %p, lock %ld stub!\n", iface, lock); + return E_NOTIMPL; +} + +static const IMediaObjectVtbl media_object_vtbl = +{ + media_object_QueryInterface, + media_object_AddRef, + media_object_Release, + media_object_GetStreamCount, + media_object_GetInputStreamInfo, + media_object_GetOutputStreamInfo, + media_object_GetInputType, + media_object_GetOutputType, + media_object_SetInputType, + media_object_SetOutputType, + media_object_GetInputCurrentType, + media_object_GetOutputCurrentType, + media_object_GetInputSizeInfo, + media_object_GetOutputSizeInfo, + media_object_GetInputMaxLatency, + media_object_SetInputMaxLatency, + media_object_Flush, + media_object_Discontinuity, + media_object_AllocateStreamingResources, + media_object_FreeStreamingResources, + media_object_GetInputStatus, + media_object_ProcessInput, + media_object_ProcessOutput, + media_object_Lock, +}; + +static inline struct video_decoder *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IPropertyBag_iface); +} + +static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); +} + +static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); +} + +static ULONG WINAPI property_bag_Release(IPropertyBag *iface) +{ + return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); +} + +static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, + IErrorLog *error_log) +{ + FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) +{ + FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); + return S_OK; +} + +static const IPropertyBagVtbl property_bag_vtbl = +{ + property_bag_QueryInterface, + property_bag_AddRef, + property_bag_Release, + property_bag_Read, + property_bag_Write, +}; + +static inline struct video_decoder *impl_from_IPropertyStore(IPropertyStore *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IPropertyStore_iface); +} + +static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); +} + +static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); +} + +static ULONG WINAPI property_store_Release(IPropertyStore *iface) +{ + return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); +} + +static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) +{ + FIXME("iface %p, count %p stub!\n", iface, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) +{ + FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const IPropertyStoreVtbl property_store_vtbl = +{ + property_store_QueryInterface, + property_store_AddRef, + property_store_Release, + property_store_GetCount, + property_store_GetAt, + property_store_GetValue, + property_store_SetValue, + property_store_Commit, +}; + static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) + const GUID *const *output_types, UINT output_type_count, IUnknown *outer, struct video_decoder **out) { struct video_decoder *decoder; HRESULT hr; @@ -897,8 +1533,8 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.input_queue_length = 15; - *ret = &decoder->IMFTransform_iface; - TRACE("Created decoder %p\n", *ret); + *out = decoder; + TRACE("Created decoder %p\n", decoder); return S_OK; failed: @@ -938,7 +1574,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) struct wg_transform_attrs attrs = {0}; struct video_decoder *decoder; wg_transform_t transform; - IMFTransform *iface; HRESULT hr; TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); @@ -951,13 +1586,12 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) return hr; - decoder = impl_from_IMFTransform(iface); if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) { - IMFTransform_Release(iface); + IMFTransform_Release(&decoder->IMFTransform_iface); return hr; } @@ -970,8 +1604,10 @@ HRESULT h264_decoder_create(REFIID riid, void **out) decoder->wg_transform_attrs.allow_size_change = TRUE; - hr = IMFTransform_QueryInterface(iface, riid, out); - IMFTransform_Release(iface); + TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); + + hr = IMFTransform_QueryInterface(&decoder->IMFTransform_iface, riid, out); + IMFTransform_Release(&decoder->IMFTransform_iface); return hr; } @@ -995,11 +1631,97 @@ static const GUID *const iv50_decoder_output_types[] = HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) { + struct video_decoder *decoder; + HRESULT hr; + TRACE("out %p.\n", out); if (!init_gstreamer()) return E_FAIL; - return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); + if (FAILED(hr = video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, &decoder))) + return hr; + + TRACE("Created iv50 transform %p.\n", &decoder->IMFTransform_iface); + + *out = &decoder->IMFTransform_iface; + return S_OK; +} + +extern const GUID MEDIASUBTYPE_VC1S; +extern const GUID MEDIASUBTYPE_WMV_Unknown; +static const GUID *const wmv_decoder_input_types[] = +{ + &MEDIASUBTYPE_WMV1, + &MEDIASUBTYPE_WMV2, + &MEDIASUBTYPE_WMVA, + &MEDIASUBTYPE_WMVP, + &MEDIASUBTYPE_WVP2, + &MEDIASUBTYPE_WMV_Unknown, + &MEDIASUBTYPE_WVC1, + &MEDIASUBTYPE_WMV3, + &MEDIASUBTYPE_VC1S, +}; +static const GUID *const wmv_decoder_output_types[] = +{ + &MFVideoFormat_NV12, + &MFVideoFormat_YV12, + &MFVideoFormat_IYUV, + &MFVideoFormat_I420, + &MFVideoFormat_YUY2, + &MFVideoFormat_UYVY, + &MFVideoFormat_YVYU, + &MFVideoFormat_NV11, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + +HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) +{ + static const struct wg_format input_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO_WMV, + .u.video.format = WG_VIDEO_FORMAT_WMV3, + }; + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_NV12, + .width = 1920, + .height = 1080, + }, + }; + struct wg_transform_attrs attrs = {0}; + struct video_decoder *decoder; + wg_transform_t transform; + HRESULT hr; + + TRACE("outer %p, out %p.\n", outer, out); + + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + + if (FAILED(hr = video_decoder_create_with_types(wmv_decoder_input_types, ARRAY_SIZE(wmv_decoder_input_types), + wmv_decoder_output_types, ARRAY_SIZE(wmv_decoder_output_types), outer, &decoder))) + return hr; + + decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; + decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; + decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; + + TRACE("Created wmv transform %p, media object %p.\n", + &decoder->IMFTransform_iface, &decoder->IMediaObject_iface); + + *out = &decoder->IUnknown_inner; + return S_OK; } diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c deleted file mode 100644 index 446641f0298..00000000000 --- a/dlls/winegstreamer/wmv_decoder.c +++ /dev/null @@ -1,942 +0,0 @@ -/* Copyright 2022 RĂ©mi Bernon for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "gst_private.h" - -#include "mfapi.h" -#include "mferror.h" -#include "mediaerr.h" -#include "mfobjects.h" -#include "mftransform.h" -#include "wmcodecdsp.h" -#include "initguid.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -WINE_DECLARE_DEBUG_CHANNEL(winediag); - -extern const GUID MEDIASUBTYPE_VC1S; -extern const GUID MEDIASUBTYPE_WMV_Unknown; - -struct decoder_type -{ - const GUID *subtype; - WORD bpp; - DWORD compression; -}; - -static const GUID *const wmv_decoder_input_types[] = -{ - &MEDIASUBTYPE_WMV1, - &MEDIASUBTYPE_WMV2, - &MEDIASUBTYPE_WMVA, - &MEDIASUBTYPE_WMVP, - &MEDIASUBTYPE_WVP2, - &MEDIASUBTYPE_WMV_Unknown, - &MEDIASUBTYPE_WVC1, - &MEDIASUBTYPE_WMV3, - &MEDIASUBTYPE_VC1S, -}; - -static const struct decoder_type wmv_decoder_output_types[] = -{ - { &MEDIASUBTYPE_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, - { &MEDIASUBTYPE_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, - { &MEDIASUBTYPE_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, - { &MEDIASUBTYPE_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, - { &MEDIASUBTYPE_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, - { &MEDIASUBTYPE_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, - { &MEDIASUBTYPE_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, - { &MEDIASUBTYPE_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, - { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, - { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, - { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, - { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, - { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, -}; - -struct wmv_decoder -{ - IUnknown IUnknown_inner; - IMFTransform IMFTransform_iface; - IMediaObject IMediaObject_iface; - IPropertyBag IPropertyBag_iface; - IPropertyStore IPropertyStore_iface; - IUnknown *outer; - LONG refcount; - - DMO_MEDIA_TYPE input_type; - DMO_MEDIA_TYPE output_type; - GUID output_subtype; - - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; -}; - -static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IUnknown_inner); -} - -static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown)) - *out = &impl->IUnknown_inner; - else if (IsEqualGUID(iid, &IID_IMFTransform)) - *out = &impl->IMFTransform_iface; - else if (IsEqualGUID(iid, &IID_IMediaObject)) - *out = &impl->IMediaObject_iface; - else if (IsEqualIID(iid, &IID_IPropertyBag)) - *out = &impl->IPropertyBag_iface; - else if (IsEqualIID(iid, &IID_IPropertyStore)) - *out = &impl->IPropertyStore_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI unknown_AddRef(IUnknown *iface) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&impl->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI unknown_Release(IUnknown *iface) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&impl->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount); - - if (!refcount) - { - if (impl->wg_transform) - wg_transform_destroy(impl->wg_transform); - wg_sample_queue_destroy(impl->wg_sample_queue); - free(impl); - } - - return refcount; -} - -static const IUnknownVtbl unknown_vtbl = -{ - unknown_QueryInterface, - unknown_AddRef, - unknown_Release, -}; - -static struct wmv_decoder *impl_from_IMFTransform(IMFTransform *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IMFTransform_iface); -} - -static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); -} - -static ULONG WINAPI transform_AddRef(IMFTransform *iface) -{ - return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); -} - -static ULONG WINAPI transform_Release(IMFTransform *iface) -{ - return IUnknown_Release(impl_from_IMFTransform(iface)->outer); -} - -static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, - DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) -{ - TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", - iface, input_minimum, input_maximum, output_minimum, output_maximum); - *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -{ - TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); - *inputs = *outputs = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, - DWORD output_size, DWORD *outputs) -{ - TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, - input_size, inputs, output_size, outputs); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -{ - FIXME("iface %p, attributes %p stub!\n", iface, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) -{ - TRACE("iface %p, id %#lx.\n", iface, id); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -{ - TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -{ - FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) -{ - FIXME("iface %p, flags %p stub!\n", iface, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -{ - TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -{ - FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -{ - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -{ - FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -{ - FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); - return E_NOTIMPL; -} - -static const IMFTransformVtbl transform_vtbl = -{ - transform_QueryInterface, - transform_AddRef, - transform_Release, - transform_GetStreamLimits, - transform_GetStreamCount, - transform_GetStreamIDs, - transform_GetInputStreamInfo, - transform_GetOutputStreamInfo, - transform_GetAttributes, - transform_GetInputStreamAttributes, - transform_GetOutputStreamAttributes, - transform_DeleteInputStream, - transform_AddInputStreams, - transform_GetInputAvailableType, - transform_GetOutputAvailableType, - transform_SetInputType, - transform_SetOutputType, - transform_GetInputCurrentType, - transform_GetOutputCurrentType, - transform_GetInputStatus, - transform_GetOutputStatus, - transform_SetOutputBounds, - transform_ProcessEvent, - transform_ProcessMessage, - transform_ProcessInput, - transform_ProcessOutput, -}; - -static inline struct wmv_decoder *impl_from_IMediaObject(IMediaObject *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IMediaObject_iface); -} - -static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) -{ - return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); -} - -static ULONG WINAPI media_object_AddRef(IMediaObject *iface) -{ - return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); -} - -static ULONG WINAPI media_object_Release(IMediaObject *iface) -{ - return IUnknown_Release(impl_from_IMediaObject(iface)->outer); -} - -static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) -{ - TRACE("iface %p, input %p, output %p.\n", iface, input, output); - - if (!input || !output) - return E_POINTER; - - *input = *output = 1; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *wmv_decoder_input_types[type_index]; - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - UINT64 frame_size, frame_rate; - IMFMediaType *media_type; - VIDEOINFOHEADER *info; - const GUID *subtype; - LONG width, height; - UINT32 image_size; - HRESULT hr; - - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= ARRAY_SIZE(wmv_decoder_output_types)) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - &decoder->input_type, &media_type))) - return hr; - - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) - frame_size = 0; - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) - frame_rate = (UINT64)1 << 32 | 1; - - width = frame_size >> 32; - height = (UINT32)frame_size; - subtype = wmv_decoder_output_types[type_index].subtype; - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) - { - FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); - IMFMediaType_Release(media_type); - return hr; - } - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *subtype; - type->bFixedSizeSamples = TRUE; - type->bTemporalCompression = FALSE; - type->lSampleSize = image_size; - type->formattype = FORMAT_VideoInfo; - type->cbFormat = sizeof(VIDEOINFOHEADER); - type->pbFormat = CoTaskMemAlloc(type->cbFormat); - memset(type->pbFormat, 0, type->cbFormat); - - info = (VIDEOINFOHEADER *)type->pbFormat; - info->rcSource.right = width; - info->rcSource.bottom = height; - info->rcTarget.right = width; - info->rcTarget.bottom = height; - info->AvgTimePerFrame = MulDiv(10000000, frame_rate >> 32, (UINT32)frame_rate); - info->bmiHeader.biSize = sizeof(info->bmiHeader); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = wmv_decoder_output_types[type_index].bpp; - info->bmiHeader.biCompression = wmv_decoder_output_types[type_index].compression; - info->bmiHeader.biSizeImage = image_size; - - IMFMediaType_Release(media_type); - return S_OK; -} - -static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - unsigned int i; - - TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->input_type); - memset(&decoder->input_type, 0, sizeof(decoder->input_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return DMO_E_TYPE_NOT_ACCEPTED; - } - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < ARRAY_SIZE(wmv_decoder_input_types); ++i) - if (IsEqualGUID(&type->subtype, wmv_decoder_input_types[i])) - break; - if (i == ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->input_type); - CopyMediaType(&decoder->input_type, type); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - - return S_OK; -} - -static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_transform_attrs attrs = {0}; - IMFMediaType *media_type; - unsigned int i; - HRESULT hr; - - TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->output_type); - memset(&decoder->output_type, 0, sizeof(decoder->output_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return E_POINTER; - } - - if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < ARRAY_SIZE(wmv_decoder_output_types); ++i) - if (IsEqualGUID(&type->subtype, wmv_decoder_output_types[i].subtype)) - break; - if (i == ARRAY_SIZE(wmv_decoder_output_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->output_type); - CopyMediaType(&decoder->output_type, type); - - /* Set up wg_transform. */ - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, type, - &attrs, &decoder->wg_transform))) - return hr; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, - DWORD *lookahead, DWORD *alignment) -{ - FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, - lookahead, alignment); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - HRESULT hr; - - TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(&media_type))) - return hr; - if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->output_type)) - && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) - *alignment = 1; - IMFMediaType_Release(media_type); - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) -{ - FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) -{ - FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_Flush(IMediaObject *iface) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p.\n", iface); - - if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) - return hr; - - wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); - - return S_OK; -} - -static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) -{ - TRACE("iface %p, index %lu.\n", iface, index); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - return S_OK; -} - -static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) -{ - TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (!flags) - return E_POINTER; - - *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; - - return S_OK; -} - -static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, - IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - - TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); -} - -static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, - DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) - hr = wg_transform_read_dmo(decoder->wg_transform, buffers); - - if (SUCCEEDED(hr)) - wg_sample_queue_flush(decoder->wg_sample_queue, false); - - return hr; -} - -static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) -{ - FIXME("iface %p, lock %ld stub!\n", iface, lock); - return E_NOTIMPL; -} - -static const IMediaObjectVtbl media_object_vtbl = -{ - media_object_QueryInterface, - media_object_AddRef, - media_object_Release, - media_object_GetStreamCount, - media_object_GetInputStreamInfo, - media_object_GetOutputStreamInfo, - media_object_GetInputType, - media_object_GetOutputType, - media_object_SetInputType, - media_object_SetOutputType, - media_object_GetInputCurrentType, - media_object_GetOutputCurrentType, - media_object_GetInputSizeInfo, - media_object_GetOutputSizeInfo, - media_object_GetInputMaxLatency, - media_object_SetInputMaxLatency, - media_object_Flush, - media_object_Discontinuity, - media_object_AllocateStreamingResources, - media_object_FreeStreamingResources, - media_object_GetInputStatus, - media_object_ProcessInput, - media_object_ProcessOutput, - media_object_Lock, -}; - -static inline struct wmv_decoder *impl_from_IPropertyBag(IPropertyBag *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyBag_iface); -} - -static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); -} - -static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); -} - -static ULONG WINAPI property_bag_Release(IPropertyBag *iface) -{ - return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); -} - -static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, - IErrorLog *error_log) -{ - FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) -{ - FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); - return S_OK; -} - -static const IPropertyBagVtbl property_bag_vtbl = -{ - property_bag_QueryInterface, - property_bag_AddRef, - property_bag_Release, - property_bag_Read, - property_bag_Write, -}; - -static inline struct wmv_decoder *impl_from_IPropertyStore(IPropertyStore *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyStore_iface); -} - -static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); -} - -static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); -} - -static ULONG WINAPI property_store_Release(IPropertyStore *iface) -{ - return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); -} - -static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) -{ - FIXME("iface %p, count %p stub!\n", iface, count); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) -{ - FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static const IPropertyStoreVtbl property_store_vtbl = -{ - property_store_QueryInterface, - property_store_AddRef, - property_store_Release, - property_store_GetCount, - property_store_GetAt, - property_store_GetValue, - property_store_SetValue, - property_store_Commit, -}; - -HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) -{ - static const struct wg_format input_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO_WMV, - .u.video.format = WG_VIDEO_FORMAT_WMV3, - }; - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, - }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; - struct wmv_decoder *decoder; - HRESULT hr; - - TRACE("outer %p, out %p.\n", outer, out); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - - if (!(decoder = calloc(1, sizeof(*decoder)))) - return E_OUTOFMEMORY; - if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) - { - free(decoder); - return hr; - } - - decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; - decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; - decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; - decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; - decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; - decoder->refcount = 1; - decoder->outer = outer ? outer : &decoder->IUnknown_inner; - - *out = &decoder->IUnknown_inner; - TRACE("Created %p\n", *out); - return S_OK; -} From 4ab97184135a59c9c985d1ccb1ad963992b870e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 Apr 2024 15:49:03 +0200 Subject: [PATCH 143/301] mf/tests: Use a separate field for buffer_desc image size and compare rect. (cherry picked from commit f5c9dea15e3fe4bc0b55c3a1b69bd164170e4eac) CW-Bug-Id: #20833 --- dlls/mf/tests/mf.c | 8 ++- dlls/mf/tests/mf_test.h | 29 ++++---- dlls/mf/tests/transform.c | 143 ++++++++++++++++++++------------------ 3 files changed, 98 insertions(+), 82 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0a34329bd75..1d7e7f4c909 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -5095,7 +5095,9 @@ static void test_sample_grabber_orientation(GUID subtype) { const struct buffer_desc buffer_desc_rgb32 = { - .length = 64 * 64 * 4, .compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 64, .bottom = 64}, + .length = 64 * 64 * 4, + .compare = compare_rgb32, .compare_rect = {.right = 64, .bottom = 64}, + .dump = dump_rgb32, .size = {.cx = 64, .cy = 64}, }; const struct sample_desc sample_desc_rgb32 = { @@ -5107,7 +5109,9 @@ static void test_sample_grabber_orientation(GUID subtype) { const struct buffer_desc buffer_desc_nv12 = { - .length = 64 * 64 * 3 / 2, .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 64, .bottom = 64}, + .length = 64 * 64 * 3 / 2, + .compare = compare_nv12, .compare_rect = {.right = 64, .bottom = 64}, + .dump = dump_nv12, .size = {.cx = 64, .cy = 64}, }; const struct sample_desc sample_desc_nv12 = { diff --git a/dlls/mf/tests/mf_test.h b/dlls/mf/tests/mf_test.h index 5a247e4a0ef..324815e3e8b 100644 --- a/dlls/mf/tests/mf_test.h +++ b/dlls/mf/tests/mf_test.h @@ -74,28 +74,29 @@ extern void check_attributes_(const char *file, int line, IMFAttributes *attribu const struct attribute_desc *desc, ULONG limit); extern void init_media_type(IMFMediaType *mediatype, const struct attribute_desc *desc, ULONG limit); -typedef DWORD (*compare_cb)(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_nv12(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_i420(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_rgb24(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_rgb16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); -extern DWORD compare_pcm16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect); +typedef DWORD (*compare_cb)(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_nv12(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_i420(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_rgb32(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_rgb24(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_rgb16(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); +extern DWORD compare_pcm16(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect); -typedef void (*dump_cb)(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); -extern void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); -extern void dump_rgb24(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); -extern void dump_rgb16(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); -extern void dump_nv12(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); -extern void dump_i420(const BYTE *data, DWORD length, const RECT *rect, HANDLE output); +typedef void (*dump_cb)(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); +extern void dump_rgb32(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); +extern void dump_rgb24(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); +extern void dump_rgb16(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); +extern void dump_nv12(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); +extern void dump_i420(const BYTE *data, DWORD length, const SIZE *size, HANDLE output); struct buffer_desc { DWORD length; BOOL todo_length; compare_cb compare; + RECT compare_rect; dump_cb dump; - RECT rect; + SIZE size; }; struct sample_desc diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 8fdc81605b6..5d2c01a7e73 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -867,14 +867,14 @@ static HRESULT check_mft_process_output_(int line, IMFTransform *transform, IMFS return ret; } -DWORD compare_nv12(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_nv12(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD x, y, data_size, diff = 0, width = size->cx, height = size->cy; /* skip BMP header and RGB data from the dump */ - size = *(DWORD *)(expect + 2); - *length = *length + size; - expect = expect + size; + data_size = *(DWORD *)(expect + 2); + *length = *length + data_size; + expect = expect + data_size; for (y = 0; y < height; y++, data += width, expect += width) { @@ -897,18 +897,18 @@ DWORD compare_nv12(const BYTE *data, DWORD *length, const RECT *rect, const BYTE } } - size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2; - return diff * 100 / 256 / size; + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2; + return diff * 100 / 256 / data_size; } -DWORD compare_i420(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_i420(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - DWORD i, x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD i, x, y, data_size, diff = 0, width = size->cx, height = size->cy; /* skip BMP header and RGB data from the dump */ - size = *(DWORD *)(expect + 2); - *length = *length + size; - expect = expect + size; + data_size = *(DWORD *)(expect + 2); + *length = *length + data_size; + expect = expect + data_size; for (y = 0; y < height; y++, data += width, expect += width) { @@ -930,18 +930,18 @@ DWORD compare_i420(const BYTE *data, DWORD *length, const RECT *rect, const BYTE } } - size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2; - return diff * 100 / 256 / size; + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2; + return diff * 100 / 256 / data_size; } -static DWORD compare_rgb(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect, UINT bits) +static DWORD compare_rgb(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect, UINT bits) { - DWORD x, y, step = bits / 8, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD x, y, step = bits / 8, data_size, diff = 0, width = size->cx, height = size->cy; /* skip BMP header from the dump */ - size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); - *length = *length + size; - expect = expect + size; + data_size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + data_size; + expect = expect + data_size; for (y = 0; y < height; y++, data += width * step, expect += width * step) { @@ -955,49 +955,49 @@ static DWORD compare_rgb(const BYTE *data, DWORD *length, const RECT *rect, cons } } - size = (rect->right - rect->left) * (rect->bottom - rect->top) * min(step, 3); - return diff * 100 / 256 / size; + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * min(step, 3); + return diff * 100 / 256 / data_size; } -DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_rgb32(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - return compare_rgb(data, length, rect, expect, 32); + return compare_rgb(data, length, size, rect, expect, 32); } -DWORD compare_rgb24(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_rgb24(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - return compare_rgb(data, length, rect, expect, 24); + return compare_rgb(data, length, size, rect, expect, 24); } -DWORD compare_rgb16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_rgb16(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - return compare_rgb(data, length, rect, expect, 16); + return compare_rgb(data, length, size, rect, expect, 16); } -DWORD compare_pcm16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +DWORD compare_pcm16(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { const INT16 *data_pcm = (INT16 *)data, *expect_pcm = (INT16 *)expect; - DWORD i, size = *length / 2, diff = 0; + DWORD i, data_size = *length / 2, diff = 0; - for (i = 0; i < size; i++) + for (i = 0; i < data_size; i++) diff += abs((int)*expect_pcm++ - (int)*data_pcm++); - return diff * 100 / 65536 / size; + return diff * 100 / 65536 / data_size; } -static DWORD compare_bytes(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +static DWORD compare_bytes(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - DWORD i, size = *length, diff = 0; + DWORD i, data_size = *length, diff = 0; - for (i = 0; i < size; i++) + for (i = 0; i < data_size; i++) diff += abs((int)*expect++ - (int)*data++); - return diff * 100 / 256 / size; + return diff * 100 / 256 / data_size; } -static void dump_rgb(const BYTE *data, DWORD length, const RECT *rect, HANDLE output, UINT bits) +static void dump_rgb(const BYTE *data, DWORD length, const SIZE *size, HANDLE output, UINT bits) { - DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD width = size->cx, height = size->cy; static const char magic[2] = "BM"; struct { @@ -1028,24 +1028,24 @@ static void dump_rgb(const BYTE *data, DWORD length, const RECT *rect, HANDLE ou ok(written == length, "written %lu bytes\n", written); } -void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +void dump_rgb32(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) { - return dump_rgb(data, length, rect, output, 32); + return dump_rgb(data, length, size, output, 32); } -void dump_rgb24(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +void dump_rgb24(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) { - return dump_rgb(data, length, rect, output, 24); + return dump_rgb(data, length, size, output, 24); } -void dump_rgb16(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +void dump_rgb16(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) { - return dump_rgb(data, length, rect, output, 16); + return dump_rgb(data, length, size, output, 16); } -void dump_nv12(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +void dump_nv12(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) { - DWORD written, x, y, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD written, x, y, width = size->cx, height = size->cy; BYTE *rgb32_data = malloc(width * height * 4), *rgb32 = rgb32_data; BOOL ret; @@ -1057,7 +1057,7 @@ void dump_nv12(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) *rgb32++ = 0xff; } - dump_rgb32(rgb32_data, width * height * 4, rect, output); + dump_rgb32(rgb32_data, width * height * 4, size, output); free(rgb32_data); ret = WriteFile(output, data, length, &written, NULL); @@ -1065,9 +1065,9 @@ void dump_nv12(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) ok(written == length, "written %lu bytes\n", written); } -void dump_i420(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +void dump_i420(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) { - DWORD written, x, y, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD written, x, y, width = size->cx, height = size->cy; BYTE *rgb32_data = malloc(width * height * 4), *rgb32 = rgb32_data; BOOL ret; @@ -1079,7 +1079,7 @@ void dump_i420(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) *rgb32++ = 0xff; } - dump_rgb32(rgb32_data, width * height * 4, rect, output); + dump_rgb32(rgb32_data, width * height * 4, size, output); free(rgb32_data); ret = WriteFile(output, data, length, &written, NULL); @@ -1152,7 +1152,7 @@ static void dump_mf_media_buffer(IMFMediaBuffer *buffer, const struct buffer_des ok(hr == S_OK, "Lock returned %#lx\n", hr); if (buffer_desc->dump) - buffer_desc->dump(data, length, &buffer_desc->rect, output); + buffer_desc->dump(data, length, &buffer_desc->size, output); else { if (buffer_desc->length == -1) @@ -1220,9 +1220,9 @@ static DWORD check_mf_media_buffer_(const char *file, int line, IMFMediaBuffer * todo_wine_if(expect->todo_length) ok_(file, line)(0, "missing %#lx bytes\n", length - *expect_data_len); else if (!expect->compare) - diff = compare_bytes(data, &length, NULL, *expect_data); + diff = compare_bytes(data, &length, NULL, NULL, *expect_data); else - diff = expect->compare(data, &length, &expect->rect, *expect_data); + diff = expect->compare(data, &length, &expect->size, &expect->compare_rect, *expect_data); } hr = IMFMediaBuffer_Unlock(buffer); @@ -1454,9 +1454,9 @@ static DWORD check_dmo_output_data_buffer_(int line, DMO_OUTPUT_DATA_BUFFER *out if (data_length < buffer_length) ok_(__FILE__, line)(0, "Missing %#lx bytes\n", buffer_length - data_length); else if (!buffer_desc->compare) - diff = compare_bytes(buffer, &buffer_length, NULL, data); + diff = compare_bytes(buffer, &buffer_length, NULL, NULL, data); else - diff = buffer_desc->compare(buffer, &buffer_length, &buffer_desc->rect, data); + diff = buffer_desc->compare(buffer, &buffer_length, &buffer_desc->size, &buffer_desc->compare_rect, data); return diff; } @@ -4192,7 +4192,8 @@ static void test_h264_decoder(void) const struct buffer_desc output_buffer_desc_nv12 = { .length = actual_width * actual_height * 3 / 2, - .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84}, + .compare = compare_nv12, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_nv12, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc output_sample_desc_nv12 = { @@ -4203,7 +4204,8 @@ static void test_h264_decoder(void) const struct buffer_desc output_buffer_desc_i420 = { .length = actual_width * actual_height * 3 / 2, - .compare = compare_i420, .dump = dump_i420, .rect = {.right = 82, .bottom = 84}, + .compare = compare_i420, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_i420, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc expect_output_sample_i420 = { @@ -5839,12 +5841,14 @@ static void test_wmv_decoder(void) const struct buffer_desc output_buffer_desc_nv12 = { .length = actual_width * actual_height * 3 / 2, - .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84}, + .compare = compare_nv12, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_nv12, .size = {.cx = actual_width, .cy = actual_height}, }; const struct buffer_desc output_buffer_desc_rgb = { .length = actual_width * actual_height * 4, - .compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 82, .bottom = 84}, + .compare = compare_rgb32, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_rgb32, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc output_sample_desc_nv12 = { @@ -6629,7 +6633,8 @@ static void test_wmv_decoder_media_object(void) const struct buffer_desc output_buffer_desc_nv12 = { .length = data_width * data_height * 3 / 2, - .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84}, + .compare = compare_nv12, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_nv12, .size = {.cx = data_width, .cy = data_height}, }; DWORD in_count, out_count, size, alignment, wmv_data_length, status, expected_status, diff; struct media_buffer *input_media_buffer = NULL, *output_media_buffer = NULL; @@ -7023,7 +7028,8 @@ static void test_color_convert(void) const struct buffer_desc output_buffer_desc = { .length = actual_width * actual_height * 4, - .compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 82, .bottom = 84}, + .compare = compare_rgb32, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_rgb32, .size = {.cx = actual_width, .cy = actual_height}, }; const struct attribute_desc output_sample_attributes[] = { @@ -7439,7 +7445,8 @@ static void test_video_processor(void) const struct buffer_desc rgb32_buffer_desc = { .length = actual_width * actual_height * 4, - .compare = compare_rgb32, .dump = dump_rgb32, .rect = {.top = 12, .right = 82, .bottom = 96}, + .compare = compare_rgb32, .compare_rect = {.top = 12, .right = 82, .bottom = 96}, + .dump = dump_rgb32, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc rgb32_sample_desc = { @@ -7451,7 +7458,8 @@ static void test_video_processor(void) const struct buffer_desc rgb555_buffer_desc = { .length = actual_width * actual_height * 2, - .compare = compare_rgb16, .dump = dump_rgb16, .rect = {.top = 12, .right = 82, .bottom = 96}, + .compare = compare_rgb16, .compare_rect = {.top = 12, .right = 82, .bottom = 96}, + .dump = dump_rgb16, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc rgb555_sample_desc = { @@ -7463,7 +7471,8 @@ static void test_video_processor(void) const struct buffer_desc nv12_buffer_desc = { .length = actual_width * actual_height * 3 / 2, - .compare = compare_nv12, .dump = dump_nv12, .rect = {.top = 12, .right = 82, .bottom = 96}, + .compare = compare_nv12, .compare_rect = {.top = 12, .right = 82, .bottom = 96}, + .dump = dump_nv12, .size = {.cx = actual_width, .cy = actual_height}, }; const struct sample_desc nv12_sample_desc = { @@ -8404,7 +8413,8 @@ static void test_h264_with_dxgi_manager(void) const struct buffer_desc output_buffer_desc_nv12 = { .length = aligned_width * aligned_height * 3 / 2, - .compare = compare_nv12, .dump = dump_nv12, .rect = {.top=0, .left=0, .right = set_width, .bottom = set_height}, + .compare = compare_nv12, .compare_rect = {.right = set_width, .bottom = set_height}, + .dump = dump_nv12, .size = {.cx = aligned_width, .cy = aligned_height}, }; const struct sample_desc output_sample_desc_nv12 = { @@ -8820,8 +8830,9 @@ static void test_iv50_decoder(void) }; const struct buffer_desc rgb_buffer_desc = { - .length = 96 * 96 * 3, .compare = compare_rgb24, .dump = dump_rgb24, - .rect = {.right = 82, .bottom = 84}, + .length = 96 * 96 * 3, + .compare = compare_rgb24, .compare_rect = {.right = 82, .bottom = 84}, + .dump = dump_rgb24, .size = {.cx = 96, .cy = 96}, }; const struct sample_desc rgb_sample_desc = { From 9f365f6b4bbab66daee417b2a61d7f45800ee0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Apr 2024 15:37:32 +0200 Subject: [PATCH 144/301] evr/tests: Sync compare_rgb32 / dump_rgb32 helpers with mf tests. (cherry picked from commit b157f805823d07d2f509fd3423c7db8816c00272) CW-Bug-Id: #20833 --- dlls/evr/tests/evr.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index a684540d977..4674221b86d 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -39,34 +39,39 @@ static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *lengt *length = SizeofResource(GetModuleHandleW(NULL), resource); } -static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +static DWORD compare_rgb(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect, UINT bits) { - DWORD x, y, size, diff = 0, width = rect->right, height = rect->bottom; + DWORD x, y, step = bits / 8, data_size, diff = 0, width = size->cx, height = size->cy; /* skip BMP header from the dump */ - size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); - *length = *length + size; - expect = expect + size; + data_size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + data_size; + expect = expect + data_size; - for (y = 0; y < height; y++, data += width * 4, expect += width * 4) + for (y = 0; y < height; y++, data += width * step, expect += width * step) { if (y < rect->top || y >= rect->bottom) continue; for (x = 0; x < width; x++) { if (x < rect->left || x >= rect->right) continue; - diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]); - diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]); - diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]); + diff += abs((int)expect[step * x + 0] - (int)data[step * x + 0]); + diff += abs((int)expect[step * x + 1] - (int)data[step * x + 1]); + if (step >= 3) diff += abs((int)expect[step * x + 2] - (int)data[step * x + 2]); } } - size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3; - return diff * 100 / 256 / size; + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * min(step, 3); + return diff * 100 / 256 / data_size; } -static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +static DWORD compare_rgb32(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - DWORD width = rect->right, height = rect->bottom; + return compare_rgb(data, length, size, rect, expect, 32); +} + +static void dump_rgb(const BYTE *data, DWORD length, const SIZE *size, HANDLE output, UINT bits) +{ + DWORD width = size->cx, height = size->cy; static const char magic[2] = "BM"; struct { @@ -80,7 +85,7 @@ static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE .biHeader = { .biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1, - .biBitCount = 32, .biCompression = BI_RGB, .biSizeImage = width * height * 4, + .biBitCount = bits, .biCompression = BI_RGB, .biSizeImage = width * height * (bits / 8), }, }; DWORD written; @@ -97,9 +102,15 @@ static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE ok(written == length, "written %lu bytes\n", written); } +static void dump_rgb32(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) +{ + return dump_rgb(data, length, size, output, 32); +} + #define check_rgb32_data(a, b, c, d) check_rgb32_data_(__LINE__, a, b, c, d) static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect) { + SIZE size = {rect->right, rect->bottom}; WCHAR output_path[MAX_PATH]; const BYTE *expect_data; HRSRC resource; @@ -109,7 +120,7 @@ static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data lstrcatW(output_path, filename); output = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError()); - dump_rgb32(data, length, rect, output); + dump_rgb32(data, length, &size, output); trace("created %s\n", debugstr_w(output_path)); CloseHandle(output); @@ -117,7 +128,7 @@ static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); - return compare_rgb32(data, &length, rect, expect_data); + return compare_rgb32(data, &length, &size, rect, expect_data); } static void set_rect(MFVideoNormalizedRect *rect, float left, float top, float right, float bottom) From 6560b038be903a270616de7caf4087f2d66e77c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Apr 2024 15:37:50 +0200 Subject: [PATCH 145/301] mfmediaengine/tests: Sync compare_rgb32 / dump_rgb32 helpers with mf tests. (cherry picked from commit 101d82c3402d1d6023f4ad7c9d5399f6628d472c) CW-Bug-Id: #20833 --- dlls/mfmediaengine/tests/mfmediaengine.c | 50 ++++++++++++++---------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 7ced6167d61..63a7e139193 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -72,34 +72,39 @@ static BOOL compare_double(double a, double b, double allowed_error) return fabs(a - b) <= allowed_error; } -static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +static DWORD compare_rgb(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect, UINT bits) { - DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + DWORD x, y, step = bits / 8, data_size, diff = 0, width = size->cx, height = size->cy; /* skip BMP header from the dump */ - size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); - *length = *length + size; - expect = expect + size; + data_size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + data_size; + expect = expect + data_size; - for (y = 0; y < height; y++, data += width * 4, expect += width * 4) + for (y = 0; y < height; y++, data += width * step, expect += width * step) { if (y < rect->top || y >= rect->bottom) continue; for (x = 0; x < width; x++) { if (x < rect->left || x >= rect->right) continue; - diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]); - diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]); - diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]); + diff += abs((int)expect[step * x + 0] - (int)data[step * x + 0]); + diff += abs((int)expect[step * x + 1] - (int)data[step * x + 1]); + if (step >= 3) diff += abs((int)expect[step * x + 2] - (int)data[step * x + 2]); } } - size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3; - return diff * 100 / 256 / size; + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * min(step, 3); + return diff * 100 / 256 / data_size; } -static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +static DWORD compare_rgb32(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) { - DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + return compare_rgb(data, length, size, rect, expect, 32); +} + +static void dump_rgb(const BYTE *data, DWORD length, const SIZE *size, HANDLE output, UINT bits) +{ + DWORD width = size->cx, height = size->cy; static const char magic[2] = "BM"; struct { @@ -113,7 +118,7 @@ static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE .biHeader = { .biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1, - .biBitCount = 32, .biCompression = BI_RGB, .biSizeImage = width * height * 4, + .biBitCount = bits, .biCompression = BI_RGB, .biSizeImage = width * height * (bits / 8), }, }; DWORD written; @@ -130,20 +135,25 @@ static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE ok(written == length, "written %lu bytes\n", written); } +static void dump_rgb32(const BYTE *data, DWORD length, const SIZE *size, HANDLE output) +{ + return dump_rgb(data, length, size, output, 32); +} + #define check_rgb32_data(a, b, c, d) check_rgb32_data_(__LINE__, a, b, c, d) -static void check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect) +static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect) { + SIZE size = {rect->right, rect->bottom}; WCHAR output_path[MAX_PATH]; const BYTE *expect_data; HRSRC resource; HANDLE output; - DWORD diff; GetTempPathW(ARRAY_SIZE(output_path), output_path); lstrcatW(output_path, filename); output = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError()); - dump_rgb32(data, length, rect, output); + dump_rgb32(data, length, &size, output); trace("created %s\n", debugstr_w(output_path)); CloseHandle(output); @@ -151,8 +161,7 @@ static void check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); - diff = compare_rgb32(data, &length, rect, expect_data); - ok_(__FILE__, line)(diff <= 3 /* small difference in wine */, "Unexpected %lu%% diff\n", diff); + return compare_rgb32(data, &length, &size, rect, expect_data); } static void init_functions(void) @@ -1356,7 +1365,8 @@ static void test_TransferVideoFrame(void) ok(!!map_desc.pData, "got pData %p\n", map_desc.pData); ok(map_desc.DepthPitch == 16384, "got DepthPitch %u\n", map_desc.DepthPitch); ok(map_desc.RowPitch == desc.Width * 4, "got RowPitch %u\n", map_desc.RowPitch); - check_rgb32_data(L"rgb32frame.bmp", map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect); + res = check_rgb32_data(L"rgb32frame.bmp", map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect); + ok(res == 0, "Unexpected %lu%% diff\n", res); ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0); ID3D11DeviceContext_Release(context); From 72e113d558e0586a0fd778d3822424a4994e5614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 Apr 2024 16:45:37 +0200 Subject: [PATCH 146/301] winegstreamer/video_processor: Allow clearing input / output types. (cherry picked from commit c91211f315e8f3a42b2c626355eb99e9f22263f2) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_processor.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 3075bf997d2..cce077ae63b 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -347,6 +347,22 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + if (!type) + { + if (impl->input_type) + { + IMFMediaType_Release(impl->input_type); + impl->input_type = NULL; + } + if (impl->wg_transform) + { + wg_transform_destroy(impl->wg_transform); + impl->wg_transform = 0; + } + + return S_OK; + } + if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || !IsEqualGUID(&major, &MFMediaType_Video)) return E_INVALIDARG; @@ -390,6 +406,22 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + if (!type) + { + if (impl->output_type) + { + IMFMediaType_Release(impl->output_type); + impl->output_type = NULL; + } + if (impl->wg_transform) + { + wg_transform_destroy(impl->wg_transform); + impl->wg_transform = 0; + } + + return S_OK; + } + if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || !IsEqualGUID(&major, &MFMediaType_Video)) return E_INVALIDARG; From be714c57de16bb6e27e65851a4395de95cd63e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 Apr 2024 10:21:18 +0200 Subject: [PATCH 147/301] mf/tests: Move the video processor input bitmap names to the test list. (cherry picked from commit b51b6efb9618a1a7e76676e8155b5e2f371ea079) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 120 +++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 5d2c01a7e73..d9a4498608d 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7484,84 +7484,89 @@ static void test_video_processor(void) const struct transform_desc { const struct attribute_desc *input_type_desc; + const WCHAR *input_bitmap; const struct attribute_desc *output_type_desc; const struct sample_desc *output_sample_desc; - const WCHAR *result_bitmap; + const WCHAR *output_bitmap; ULONG delta; BOOL broken; } video_processor_tests[] = { { - .input_type_desc = nv12_default_stride, .output_type_desc = rgb32_default_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 2, /* Windows returns 0, Wine needs 2 */ + .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", + .output_type_desc = rgb32_default_stride, .output_bitmap = L"rgb32frame-flip.bmp", + .output_sample_desc = &rgb32_sample_desc, .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { - .input_type_desc = nv12_default_stride, .output_type_desc = rgb32_negative_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 2, /* Windows returns 0, Wine needs 2 */ + .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", + .output_type_desc = rgb32_negative_stride, .output_bitmap = L"rgb32frame-flip.bmp", + .output_sample_desc = &rgb32_sample_desc, .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { - .input_type_desc = nv12_default_stride, .output_type_desc = rgb32_positive_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp", - .delta = 6, + .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", + .output_type_desc = rgb32_positive_stride, .output_bitmap = L"rgb32frame.bmp", + .output_sample_desc = &rgb32_sample_desc, .delta = 6, }, { - .input_type_desc = rgb32_default_stride, .output_type_desc = nv12_default_stride, - .output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame-flip.bmp", - .delta = 2, /* Windows returns 0, Wine needs 2 */ + .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", + .output_sample_desc = &nv12_sample_desc, .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { - .input_type_desc = rgb32_negative_stride, .output_type_desc = nv12_default_stride, - .output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame-flip.bmp", - .delta = 2, /* Windows returns 0, Wine needs 2 */ + .input_type_desc = rgb32_negative_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", + .output_sample_desc = &nv12_sample_desc, .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { - .input_type_desc = rgb32_positive_stride, .output_type_desc = nv12_default_stride, - .output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame.bmp", - .delta = 2, /* Windows returns 1, Wine needs 2 */ + .input_type_desc = rgb32_positive_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame.bmp", + .output_sample_desc = &nv12_sample_desc, .delta = 2, /* Windows returns 1, Wine needs 2 */ }, { - .input_type_desc = rgb32_negative_stride, .output_type_desc = rgb32_negative_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp", + .input_type_desc = rgb32_negative_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_negative_stride, .output_bitmap = L"rgb32frame.bmp", + .output_sample_desc = &rgb32_sample_desc, }, { - .input_type_desc = rgb32_negative_stride, .output_type_desc = rgb32_positive_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 3, /* Windows returns 3 */ + .input_type_desc = rgb32_negative_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_positive_stride, .output_bitmap = L"rgb32frame-flip.bmp", + .output_sample_desc = &rgb32_sample_desc, .delta = 3, /* Windows returns 3 */ }, { - .input_type_desc = rgb32_positive_stride, .output_type_desc = rgb32_negative_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 3, /* Windows returns 3 */ + .input_type_desc = rgb32_positive_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_negative_stride, .output_bitmap = L"rgb32frame-flip.bmp", + .output_sample_desc = &rgb32_sample_desc, .delta = 3, /* Windows returns 3 */ }, { - .input_type_desc = rgb32_positive_stride, .output_type_desc = rgb32_positive_stride, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp", + .input_type_desc = rgb32_positive_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_positive_stride, .output_bitmap = L"rgb32frame.bmp", + .output_sample_desc = &rgb32_sample_desc, }, { - .input_type_desc = rgb32_with_aperture, .output_type_desc = rgb32_with_aperture, - .output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp", - .broken = TRUE /* old Windows version incorrectly rescale */ + .input_type_desc = rgb32_with_aperture, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_with_aperture, .output_bitmap = L"rgb32frame.bmp", + .output_sample_desc = &rgb32_sample_desc, .broken = TRUE /* old Windows version incorrectly rescale */ }, { - .input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_default_stride, - .output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame.bmp", + .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb555_default_stride, .output_bitmap = L"rgb555frame.bmp", + .output_sample_desc = &rgb555_sample_desc, }, { - .input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_negative_stride, - .output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame.bmp", + .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb555_negative_stride, .output_bitmap = L"rgb555frame.bmp", + .output_sample_desc = &rgb555_sample_desc, }, { - .input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_positive_stride, - .output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame-flip.bmp", - .delta = 3, /* Windows returns 0, Wine needs 3 */ + .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp", + .output_sample_desc = &rgb555_sample_desc, .delta = 3, /* Windows returns 0, Wine needs 3 */ }, { - .input_type_desc = rgb555_default_stride, .output_type_desc = rgb555_positive_stride, - .output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame-flip.bmp", - .delta = 4, /* Windows returns 0, Wine needs 4 */ + .input_type_desc = rgb555_default_stride, .input_bitmap = L"rgb555frame.bmp", + .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp", + .output_sample_desc = &rgb555_sample_desc, .delta = 4, /* Windows returns 0, Wine needs 4 */ }, }; @@ -7909,38 +7914,33 @@ static void test_video_processor(void) { input_info.cbSize = actual_width * actual_height * 3 / 2; check_mft_get_input_stream_info(transform, S_OK, &input_info); - - load_resource(L"nv12frame.bmp", &input_data, &input_data_len); - /* skip BMP header and RGB data from the dump */ - length = *(DWORD *)(input_data + 2); - input_data_len = input_data_len - length; - ok(input_data_len == 13824, "got length %lu\n", input_data_len); - input_data = input_data + length; } else if (test->input_type_desc == rgb555_default_stride) { input_info.cbSize = actual_width * actual_height * 2; check_mft_get_input_stream_info(transform, S_OK, &input_info); - - load_resource(L"rgb555frame.bmp", &input_data, &input_data_len); - /* skip BMP header and RGB data from the dump */ - length = *(DWORD *)(input_data + 2 + 2 * sizeof(DWORD)); - input_data_len -= length; - ok(input_data_len == 18432, "got length %lu\n", input_data_len); - input_data += length; } else { input_info.cbSize = actual_width * actual_height * 4; check_mft_get_input_stream_info(transform, S_OK, &input_info); + } - load_resource(L"rgb32frame.bmp", &input_data, &input_data_len); + load_resource(test->input_bitmap, &input_data, &input_data_len); + if (test->input_type_desc == nv12_default_stride) + { /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(input_data + 2); + input_data_len = input_data_len - length; + } + else + { + /* skip BMP header */ length = *(DWORD *)(input_data + 2 + 2 * sizeof(DWORD)); input_data_len -= length; - ok(input_data_len == 36864, "got length %lu\n", input_data_len); - input_data += length; } + ok(input_data_len == input_info.cbSize, "got length %lu\n", input_data_len); + input_data += length; input_sample = create_sample(input_data, input_data_len); hr = IMFSample_SetSampleTime(input_sample, 0); @@ -7976,7 +7976,7 @@ static void test_video_processor(void) ref = IMFSample_Release(output_sample); ok(ref == 1, "Release returned %ld\n", ref); - ret = check_mf_sample_collection(output_samples, test->output_sample_desc, test->result_bitmap); + ret = check_mf_sample_collection(output_samples, test->output_sample_desc, test->output_bitmap); ok(ret <= test->delta || broken(test->broken), "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); From d76a36dd8c9d259823c5dcf345f9ba41e438dcce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 Apr 2024 10:32:39 +0200 Subject: [PATCH 148/301] mf/tests: Add more video processor tests with aperture changes. (cherry picked from commit acfa237cfe8acb5f22cda2679fff74c9d9ec1073) CW-Bug-Id: #20833 --- dlls/mf/tests/resource.rc | 4 ++ dlls/mf/tests/rgb32frame-crop.bmp | Bin 0 -> 27606 bytes dlls/mf/tests/transform.c | 93 +++++++++++++++++++++++++++--- 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 dlls/mf/tests/rgb32frame-crop.bmp diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index ab1fb7ecbb0..357a083bc66 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -105,6 +105,10 @@ rgb32frame.bmp RCDATA rgb32frame.bmp /* @makedep: rgb32frame-flip.bmp */ rgb32frame-flip.bmp RCDATA rgb32frame-flip.bmp +/* Generated from running the tests on Windows */ +/* @makedep: rgb32frame-crop.bmp */ +rgb32frame-crop.bmp RCDATA rgb32frame-crop.bmp + /* Generated from running the tests on Windows */ /* @makedep: rgb32frame-grabber.bmp */ rgb32frame-grabber.bmp RCDATA rgb32frame-grabber.bmp diff --git a/dlls/mf/tests/rgb32frame-crop.bmp b/dlls/mf/tests/rgb32frame-crop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..34a28ad44732f38d4165bdc00de313db7c2f390a GIT binary patch literal 27606 zcmeI&!3}~y5J1tP6OUG40p7hByRa#%vK-cdFbyys_V7q%2_Yn#pLc<9e|+DuAGchu zInSI|&JvegBRVeNs(e|lW=y~b$300Rs#zyJdbFu(u< z3^2ez&%iQb7!4R;fB^;=V1NMz7+`<_1{mlW$iD%G(SQL47+`<_1{h#~0R|XgfPtQY v-qY&q#{dHiFu(u<3^2d|0}L?0z-GXqfC36Apnw7jD4>7>3Mim}0{sF%iRi;| literal 0 HcmV?d00001 diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index d9a4498608d..300a22094fb 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7357,6 +7357,15 @@ static void test_video_processor(void) ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), {0}, }; + const struct attribute_desc rgb32_with_aperture_positive_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + {0}, + }; const struct attribute_desc nv12_default_stride[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), @@ -7419,17 +7428,19 @@ static void test_video_processor(void) }; const struct attribute_desc nv12_with_aperture[] = { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), - ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &actual_aperture, 16), {0}, }; const struct attribute_desc rgb32_no_aperture[] = { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), - ATTR_RATIO(MF_MT_FRAME_SIZE, 82, 84), + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, 82, 84, .required = TRUE), {0}, }; const MFT_OUTPUT_STREAM_INFO initial_output_info = {0}; @@ -7455,6 +7466,19 @@ static void test_video_processor(void) .buffer_count = 1, .buffers = &rgb32_buffer_desc, }; + const struct buffer_desc rgb32_crop_buffer_desc = + { + .length = actual_aperture.Area.cx * actual_aperture.Area.cy * 4, + .compare = compare_rgb32, .compare_rect = {.right = actual_aperture.Area.cx, .bottom = actual_aperture.Area.cy}, + .dump = dump_rgb32, .size = actual_aperture.Area, + }; + const struct sample_desc rgb32_crop_sample_desc = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 10000000, + .buffer_count = 1, .buffers = &rgb32_crop_buffer_desc, + }; + const struct buffer_desc rgb555_buffer_desc = { .length = actual_width * actual_height * 2, @@ -7568,6 +7592,26 @@ static void test_video_processor(void) .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp", .output_sample_desc = &rgb555_sample_desc, .delta = 4, /* Windows returns 0, Wine needs 4 */ }, + { + .input_type_desc = nv12_with_aperture, .input_bitmap = L"nv12frame.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_sample_desc = &rgb32_crop_sample_desc, + }, + { + .input_type_desc = rgb32_no_aperture, .input_bitmap = L"rgb32frame-crop.bmp", + .output_type_desc = rgb32_with_aperture, .output_bitmap = L"rgb32frame-flip.bmp", + .output_sample_desc = &rgb32_sample_desc, + }, + { + .input_type_desc = rgb32_with_aperture, .input_bitmap = L"rgb32frame-flip.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_sample_desc = &rgb32_crop_sample_desc, + }, + { + .input_type_desc = rgb32_with_aperture_positive_stride, .input_bitmap = L"rgb32frame.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_sample_desc = &rgb32_crop_sample_desc, .delta = 3, /* Windows returns 3 */ + }, }; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; @@ -7890,6 +7934,23 @@ static void test_video_processor(void) check_mft_set_input_type(transform, test->input_type_desc); check_mft_get_input_current_type(transform, test->input_type_desc); + if (i >= 15) + { + IMFMediaType *media_type; + HRESULT hr; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr); + init_media_type(media_type, test->output_type_desc, -1); + hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); + todo_wine + ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); + IMFMediaType_Release(media_type); + + if (hr != S_OK) + goto skip_test; + } + check_mft_set_output_type_required(transform, test->output_type_desc); check_mft_set_output_type(transform, test->output_type_desc, S_OK); check_mft_get_output_current_type(transform, test->output_type_desc); @@ -7904,13 +7965,18 @@ static void test_video_processor(void) output_info.cbSize = actual_width * actual_height * 2; check_mft_get_output_stream_info(transform, S_OK, &output_info); } + else if (test->output_sample_desc == &rgb32_crop_sample_desc) + { + output_info.cbSize = actual_aperture.Area.cx * actual_aperture.Area.cy * 4; + check_mft_get_output_stream_info(transform, S_OK, &output_info); + } else { output_info.cbSize = actual_width * actual_height * 4; check_mft_get_output_stream_info(transform, S_OK, &output_info); } - if (test->input_type_desc == nv12_default_stride) + if (test->input_type_desc == nv12_default_stride || test->input_type_desc == nv12_with_aperture) { input_info.cbSize = actual_width * actual_height * 3 / 2; check_mft_get_input_stream_info(transform, S_OK, &input_info); @@ -7920,6 +7986,11 @@ static void test_video_processor(void) input_info.cbSize = actual_width * actual_height * 2; check_mft_get_input_stream_info(transform, S_OK, &input_info); } + else if (test->input_type_desc == rgb32_no_aperture) + { + input_info.cbSize = 82 * 84 * 4; + check_mft_get_input_stream_info(transform, S_OK, &input_info); + } else { input_info.cbSize = actual_width * actual_height * 4; @@ -7927,7 +7998,7 @@ static void test_video_processor(void) } load_resource(test->input_bitmap, &input_data, &input_data_len); - if (test->input_type_desc == nv12_default_stride) + if (test->input_type_desc == nv12_default_stride || test->input_type_desc == nv12_with_aperture) { /* skip BMP header and RGB data from the dump */ length = *(DWORD *)(input_data + 2); @@ -7991,6 +8062,12 @@ static void test_video_processor(void) ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); winetest_pop_context(); + +skip_test: + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, NULL, 0); + ok(hr == S_OK, "got %#lx\n", hr); } ret = IMFTransform_Release(transform); From 535052e605f23f613b20b1d2a82a3fed91f1e34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 11:19:31 +0200 Subject: [PATCH 149/301] mf/session: Introduce new (allocate|release)_output_samples helpers. (cherry picked from commit 8ad97c1c0f6646f9ec7ad6f6f5e329263a8df0c9) CW-Bug-Id: #20833 --- dlls/mf/session.c | 69 ++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 8619835ddc3..9d3fbc8ae17 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3128,45 +3128,59 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return hr; } -static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node) +static HRESULT allocate_output_samples(const struct media_session *session, struct topo_node *node, + MFT_OUTPUT_DATA_BUFFER *buffers) { - MFT_OUTPUT_STREAM_INFO stream_info; - MFT_OUTPUT_DATA_BUFFER *buffers; - HRESULT hr = E_UNEXPECTED; - DWORD status = 0; - unsigned int i; - - if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers)))) - return E_OUTOFMEMORY; + HRESULT hr; + UINT i; for (i = 0; i < node->u.transform.output_count; ++i) { + MFT_OUTPUT_STREAM_INFO stream_info = {0}; + buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i); - buffers[i].pSample = NULL; - buffers[i].dwStatus = 0; - buffers[i].pEvents = NULL; - memset(&stream_info, 0, sizeof(stream_info)); if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info))) - break; - - if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))) - { - if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample))) - break; - } + return hr; + if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) + && FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample))) + return hr; } - if (SUCCEEDED(hr)) - hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + return S_OK; +} + +static void release_output_samples(struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) +{ + UINT i; - /* Collect returned samples for all streams. */ for (i = 0; i < node->u.transform.output_count; ++i) { - struct transform_stream *stream = &node->u.transform.outputs[i]; - + if (buffers[i].pSample) + IMFSample_Release(buffers[i].pSample); if (buffers[i].pEvents) IMFCollection_Release(buffers[i].pEvents); + } +} + +static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node) +{ + MFT_OUTPUT_DATA_BUFFER *buffers; + DWORD status; + HRESULT hr; + UINT i; + + if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers)))) + return E_OUTOFMEMORY; + if (FAILED(hr = allocate_output_samples(session, node, buffers))) + goto done; + + status = 0; + hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + + for (i = 0; i < node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &node->u.transform.outputs[i]; if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) { @@ -3175,11 +3189,10 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) WARN("Failed to queue output sample, hr %#lx\n", hr); } - - if (buffers[i].pSample) - IMFSample_Release(buffers[i].pSample); } +done: + release_output_samples(node, buffers); free(buffers); return hr; From cb5654410dc6c53b2e34a6441f9b42425454a4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 12:04:21 +0200 Subject: [PATCH 150/301] mf/session: Get session topo_node from their IMFTopologyNode directly. (cherry picked from commit 657449e12f0bfc1711037fba14eb66b0273910a1) CW-Bug-Id: #20833 --- dlls/mf/session.c | 52 +++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 9d3fbc8ae17..3e616f1b24f 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -855,14 +855,18 @@ static void session_clear_presentation(struct media_session *session) } } -static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id) +static struct topo_node *session_get_topo_node(const struct media_session *session, IMFTopologyNode *node) { - struct topo_node *node; + struct topo_node *topo_node; + TOPOID id; - LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) + if (FAILED(IMFTopologyNode_GetTopoNodeID(node, &id))) + return NULL; + + LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) { - if (node->node_id == id) - return node; + if (topo_node->node_id == id) + return topo_node; } return NULL; @@ -3092,7 +3096,6 @@ static HRESULT transform_get_external_output_sample(const struct media_session * struct topo_node *topo_node; unsigned int buffer_size; DWORD downstream_input; - TOPOID node_id; HRESULT hr; if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input))) @@ -3101,11 +3104,9 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return MF_E_UNEXPECTED; } - IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id); + topo_node = session_get_topo_node(session, downstream_node); IMFTopologyNode_Release(downstream_node); - topo_node = session_get_node_by_id(session, node_id); - if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator) { hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample); @@ -3322,19 +3323,14 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop IMFSample *sample) { struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; - TOPOID node_id; HRESULT hr; if (session->quality_manager) IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample); - IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); - - topo_node = session_get_node_by_id(session, node_id); + topo_node = session_get_topo_node(session, node); - switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_OUTPUT_NODE: if (topo_node->u.sink.requests) @@ -3359,7 +3355,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop transform_node_deliver_samples(session, topo_node); break; case MF_TOPOLOGY_TEE_NODE: - FIXME("Unhandled downstream node type %d.\n", node_type); + FIXME("Unhandled downstream node type %d.\n", topo_node->type); break; default: ; @@ -3369,22 +3365,17 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) { struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; - TOPOID node_id; - IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); + topo_node = session_get_topo_node(session, node); - topo_node = session_get_node_by_id(session, node_id); - - switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_TRANSFORM_NODE: transform_node_pull_samples(session, topo_node); transform_node_deliver_samples(session, topo_node); break; default: - FIXME("Unexpected node type %u.\n", node_type); + FIXME("Unexpected node type %u.\n", topo_node->type); } } @@ -3393,18 +3384,13 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { IMFTopologyNode *down_node; struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; HRESULT hr = S_OK; IMFSample *sample; - TOPOID node_id; DWORD input; - IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); + topo_node = session_get_topo_node(session, node); - topo_node = session_get_node_by_id(session, node_id); - - switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_SOURCESTREAM_NODE: if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL))) @@ -3440,7 +3426,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I break; } case MF_TOPOLOGY_TEE_NODE: - FIXME("Unhandled upstream node type %d.\n", node_type); + FIXME("Unhandled upstream node type %d.\n", topo_node->type); default: hr = E_UNEXPECTED; } From 62dae2615de814e539c91333bd1d2a5af2f6c514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 12:07:02 +0200 Subject: [PATCH 151/301] mf/session: Introduce new session_get_topo_node_output helper. (cherry picked from commit 48839ece47a57e99e4a8823dd4b9d65653f06e77) CW-Bug-Id: #20833 --- dlls/mf/session.c | 73 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 3e616f1b24f..971317d4718 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -872,6 +872,21 @@ static struct topo_node *session_get_topo_node(const struct media_session *sessi return NULL; } +static struct topo_node *session_get_topo_node_output(const struct media_session *session, + const struct topo_node *up_node, DWORD output, DWORD *input) +{ + struct topo_node *down_node = NULL; + IMFTopologyNode *node; + + if (SUCCEEDED(IMFTopologyNode_GetOutput(up_node->node, output, &node, input))) + { + down_node = session_get_topo_node(session, node); + IMFTopologyNode_Release(node); + } + + return down_node; +} + static void session_command_complete(struct media_session *session) { struct session_op *op; @@ -3089,31 +3104,27 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre } static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform, - unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) + DWORD output, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) { - IMFTopologyNode *downstream_node; IMFMediaBuffer *buffer = NULL; struct topo_node *topo_node; unsigned int buffer_size; - DWORD downstream_input; + DWORD input; HRESULT hr; - if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input))) + if (!(topo_node = session_get_topo_node_output(session, transform, output, &input))) { - WARN("Failed to get connected node for output %u.\n", output_index); + WARN("Failed to node %p/%lu output.\n", transform, output); return MF_E_UNEXPECTED; } - topo_node = session_get_topo_node(session, downstream_node); - IMFTopologyNode_Release(downstream_node); - if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator) { hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample); } else { - buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size); + buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output].min_buffer_size); hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer); if (SUCCEEDED(hr)) @@ -3249,13 +3260,14 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s return hr; } -static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, +static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample); static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { - IMFTopologyNode *up_node = topo_node->node, *down_node; + IMFTopologyNode *up_node = topo_node->node; BOOL drained = transform_node_is_drained(topo_node); + struct topo_node *down_node; DWORD output, input; IMFSample *sample; HRESULT hr = S_OK; @@ -3265,9 +3277,9 @@ static void transform_node_deliver_samples(struct media_session *session, struct { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; - if (FAILED(hr = IMFTopologyNode_GetOutput(up_node, output, &down_node, &input))) + if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { - WARN("Failed to node %p/%lu output, hr %#lx.\n", up_node, output, hr); + WARN("Failed to node %p/%lu output\n", topo_node, output); continue; } @@ -3292,8 +3304,6 @@ static void transform_node_deliver_samples(struct media_session *session, struct session_deliver_sample_to_node(session, down_node, input, NULL); stream->requests--; } - - IMFTopologyNode_Release(down_node); } if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && transform_node_has_requests(topo_node)) @@ -3305,7 +3315,7 @@ static void transform_node_deliver_samples(struct media_session *session, struct if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) { - session_deliver_sample_to_node(session, topo_node->node, input, sample); + session_deliver_sample_to_node(session, topo_node, input, sample); IMFSample_Release(sample); } else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) @@ -3319,16 +3329,13 @@ static void transform_node_deliver_samples(struct media_session *session, struct } } -static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, +static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample) { - struct topo_node *topo_node; HRESULT hr; if (session->quality_manager) - IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample); - - topo_node = session_get_topo_node(session, node); + IMFQualityManager_NotifyProcessInput(session->quality_manager, topo_node->node, input, sample); switch (topo_node->type) { @@ -3364,9 +3371,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) { - struct topo_node *topo_node; - - topo_node = session_get_topo_node(session, node); + struct topo_node *topo_node = session_get_topo_node(session, node); switch (topo_node->type) { @@ -3382,8 +3387,7 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) { - IMFTopologyNode *down_node; - struct topo_node *topo_node; + struct topo_node *topo_node, *down_node; HRESULT hr = S_OK; IMFSample *sample; DWORD input; @@ -3400,9 +3404,9 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; - if (FAILED(hr = IMFTopologyNode_GetOutput(node, output, &down_node, &input))) + if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { - WARN("Failed to node %p/%lu output, hr %#lx.\n", node, output, hr); + WARN("Failed to node %p/%lu output\n", topo_node, output); break; } @@ -3421,8 +3425,6 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I stream->requests++; transform_node_deliver_samples(session, topo_node); } - - IMFTopologyNode_Release(down_node); break; } case MF_TOPOLOGY_TEE_NODE: @@ -3468,9 +3470,7 @@ static void session_request_sample(struct media_session *session, IMFStreamSink static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value) { struct topo_node *source_node = NULL, *node; - IMFTopologyNode *downstream_node; - DWORD downstream_input; - HRESULT hr; + DWORD input; if (value && (value->vt != VT_UNKNOWN || !value->punkVal)) { @@ -3493,14 +3493,13 @@ static void session_deliver_sample(struct media_session *session, IMFMediaStream if (!value) source_node->flags |= TOPO_NODE_END_OF_STREAM; - if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input))) + if (!(node = session_get_topo_node_output(session, source_node, 0, &input))) { - WARN("Failed to get downstream node connection, hr %#lx.\n", hr); + WARN("Failed to node %p/%u output.\n", source_node, 0); return; } - session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL); - IMFTopologyNode_Release(downstream_node); + session_deliver_sample_to_node(session, node, input, value ? (IMFSample *)value->punkVal : NULL); } static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink) From 3635888ce7b71ac03558b8c001e1390e34635adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 12:34:41 +0200 Subject: [PATCH 152/301] mf/session: Introduce new session_get_topo_node_input helper. (cherry picked from commit 37b3e1ee6b151506182fe35a98ca720414f0361e) CW-Bug-Id: #20833 --- dlls/mf/session.c | 71 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 971317d4718..7fb5a10abb9 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -872,6 +872,21 @@ static struct topo_node *session_get_topo_node(const struct media_session *sessi return NULL; } +static struct topo_node *session_get_topo_node_input(const struct media_session *session, + const struct topo_node *down_node, DWORD input, DWORD *output) +{ + struct topo_node *up_node = NULL; + IMFTopologyNode *node; + + if (SUCCEEDED(IMFTopologyNode_GetInput(down_node->node, input, &node, output))) + { + up_node = session_get_topo_node(session, node); + IMFTopologyNode_Release(node); + } + + return up_node; +} + static struct topo_node *session_get_topo_node_output(const struct media_session *session, const struct topo_node *up_node, DWORD output, DWORD *input) { @@ -1640,7 +1655,7 @@ static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNoti return 1; } -static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output); +static HRESULT session_request_sample_from_node(struct media_session *session, struct topo_node *topo_node, DWORD output); static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface) { @@ -2582,7 +2597,7 @@ static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback * return E_NOTIMPL; } -static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node); +static void session_deliver_pending_samples(struct media_session *session, struct topo_node *topo_node); static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { @@ -2697,20 +2712,18 @@ static HRESULT WINAPI session_sa_ready_callback_GetParameters(IMFAsyncCallback * static HRESULT WINAPI session_sa_ready_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { IMFVideoSampleAllocatorNotify *notify = (IMFVideoSampleAllocatorNotify *)IMFAsyncResult_GetStateNoAddRef(result); - struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(notify); + struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(notify), *up_node; struct media_session *session = impl_from_sa_ready_callback_IMFAsyncCallback(iface); - IMFTopologyNode *upstream_node; - DWORD upstream_output; + DWORD output; EnterCriticalSection(&session->cs); if (topo_node->u.sink.requests) { - if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output))) - { - session_deliver_pending_samples(session, upstream_node); - IMFTopologyNode_Release(upstream_node); - } + if (!(up_node = session_get_topo_node_input(session, topo_node, 0, &output))) + WARN("Failed to node %p/%u input\n", topo_node, 0); + else + session_deliver_pending_samples(session, up_node); } LeaveCriticalSection(&session->cs); @@ -3265,9 +3278,8 @@ static void session_deliver_sample_to_node(struct media_session *session, struct static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { - IMFTopologyNode *up_node = topo_node->node; BOOL drained = transform_node_is_drained(topo_node); - struct topo_node *down_node; + struct topo_node *up_node, *down_node; DWORD output, input; IMFSample *sample; HRESULT hr = S_OK; @@ -3318,14 +3330,10 @@ static void transform_node_deliver_samples(struct media_session *session, struct session_deliver_sample_to_node(session, topo_node, input, sample); IMFSample_Release(sample); } - else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) - WARN("Failed to get node %p/%lu input, hr %#lx\n", topo_node->node, input, hr); - else - { - if (FAILED(hr = session_request_sample_from_node(session, up_node, output))) - WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr); - IMFTopologyNode_Release(up_node); - } + else if (!(up_node = session_get_topo_node_input(session, topo_node, input, &output))) + WARN("Failed to node %p/%lu input\n", topo_node, input); + else if (FAILED(hr = session_request_sample_from_node(session, up_node, output))) + WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr); } } @@ -3369,10 +3377,8 @@ static void session_deliver_sample_to_node(struct media_session *session, struct } } -static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) +static void session_deliver_pending_samples(struct media_session *session, struct topo_node *topo_node) { - struct topo_node *topo_node = session_get_topo_node(session, node); - switch (topo_node->type) { case MF_TOPOLOGY_TRANSFORM_NODE: @@ -3385,15 +3391,13 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo } -static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) +static HRESULT session_request_sample_from_node(struct media_session *session, struct topo_node *topo_node, DWORD output) { - struct topo_node *topo_node, *down_node; + struct topo_node *down_node; HRESULT hr = S_OK; IMFSample *sample; DWORD input; - topo_node = session_get_topo_node(session, node); - switch (topo_node->type) { case MF_TOPOLOGY_SOURCESTREAM_NODE: @@ -3438,10 +3442,8 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream) { - struct topo_node *sink_node = NULL, *node; - IMFTopologyNode *upstream_node; - DWORD upstream_output; - HRESULT hr; + struct topo_node *sink_node = NULL, *node, *up_node; + DWORD output; LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) { @@ -3455,16 +3457,15 @@ static void session_request_sample(struct media_session *session, IMFStreamSink if (!sink_node) return; - if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output))) + if (!(up_node = session_get_topo_node_input(session, sink_node, 0, &output))) { - WARN("Failed to get upstream node connection, hr %#lx.\n", hr); + WARN("Failed to node %p/%u input\n", sink_node, 0); return; } sink_node->u.sink.requests++; - if (FAILED(session_request_sample_from_node(session, upstream_node, upstream_output))) + if (FAILED(session_request_sample_from_node(session, up_node, output))) sink_node->u.sink.requests--; - IMFTopologyNode_Release(upstream_node); } static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value) From 8f96596cbecf78571d4c6fb0ea28e6c1739a72f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 12:23:51 +0200 Subject: [PATCH 153/301] mf/session: Wrap samples in IMFMediaEvent list instead of IMFSample list. (cherry picked from commit 2c95d9a224cb20b31c0f70d2de24ad8ff33ad79b) CW-Bug-Id: #20833 --- dlls/mf/session.c | 96 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 7fb5a10abb9..fc44f7333f3 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -144,10 +144,10 @@ struct media_sink BOOL finalized; }; -struct sample +struct event_entry { struct list entry; - IMFSample *sample; + IMFMediaEvent *event; }; struct transform_stream @@ -676,39 +676,43 @@ static void session_set_caps(struct media_session *session, DWORD caps) static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample) { - struct sample *entry; + PROPVARIANT value = {.vt = VT_UNKNOWN, .punkVal = (IUnknown *)sample}; + struct event_entry *entry; + HRESULT hr; if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; - - entry->sample = sample; - IMFSample_AddRef(entry->sample); + if (FAILED(hr = MFCreateMediaEvent(MEMediaSample, &GUID_NULL, S_OK, &value, &entry->event))) + { + free(entry); + return hr; + } list_add_tail(&stream->samples, &entry->entry); return S_OK; } -static HRESULT transform_stream_pop_sample(struct transform_stream *stream, IMFSample **sample) +static HRESULT transform_stream_pop_event(struct transform_stream *stream, IMFMediaEvent **event) { - struct sample *entry; + struct event_entry *entry; struct list *ptr; if (!(ptr = list_head(&stream->samples))) return MF_E_TRANSFORM_NEED_MORE_INPUT; - entry = LIST_ENTRY(ptr, struct sample, entry); + entry = LIST_ENTRY(ptr, struct event_entry, entry); list_remove(&entry->entry); - *sample = entry->sample; + *event = entry->event; free(entry); return S_OK; } -static void transform_stream_drop_samples(struct transform_stream *stream) +static void transform_stream_drop_events(struct transform_stream *stream) { - IMFSample *sample; + IMFMediaEvent *event; - while (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) - IMFSample_Release(sample); + while (SUCCEEDED(transform_stream_pop_event(stream, &event))) + IMFMediaEvent_Release(event); } static void release_topo_node(struct topo_node *node) @@ -723,9 +727,9 @@ static void release_topo_node(struct topo_node *node) break; case MF_TOPOLOGY_TRANSFORM_NODE: for (i = 0; i < node->u.transform.input_count; ++i) - transform_stream_drop_samples(&node->u.transform.inputs[i]); + transform_stream_drop_events(&node->u.transform.inputs[i]); for (i = 0; i < node->u.transform.output_count; ++i) - transform_stream_drop_samples(&node->u.transform.outputs[i]); + transform_stream_drop_events(&node->u.transform.outputs[i]); free(node->u.transform.inputs); free(node->u.transform.outputs); free(node->u.transform.input_map); @@ -3276,12 +3280,40 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample); +static HRESULT transform_stream_handle_event(struct media_session *session, struct transform_stream *stream, + struct topo_node *topo_node, unsigned int input, IMFMediaEvent *event) +{ + MediaEventType type; + PROPVARIANT value; + HRESULT hr; + + if (FAILED(hr = IMFMediaEvent_GetType(event, &type))) + return hr; + PropVariantInit(&value); + + switch (type) + { + case MEMediaSample: + if (SUCCEEDED(hr = IMFMediaEvent_GetValue(event, &value))) + session_deliver_sample_to_node(session, topo_node, input, (IMFSample *)value.punkVal); + break; + + default: + ERR("Unexpected event type %lu\n", type); + hr = E_NOTIMPL; + break; + } + + PropVariantClear(&value); + return hr; +} + static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { BOOL drained = transform_node_is_drained(topo_node); struct topo_node *up_node, *down_node; + IMFMediaEvent *event; DWORD output, input; - IMFSample *sample; HRESULT hr = S_OK; /* Push down all available output. */ @@ -3297,18 +3329,22 @@ static void transform_node_deliver_samples(struct media_session *session, struct while (stream->requests) { - if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + MediaEventType type; + + if (FAILED(hr = transform_stream_pop_event(stream, &event))) { /* try getting more samples by calling IMFTransform_ProcessOutput */ if (FAILED(hr = transform_node_pull_samples(session, topo_node))) break; - if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + if (FAILED(hr = transform_stream_pop_event(stream, &event))) break; } - session_deliver_sample_to_node(session, down_node, input, sample); - stream->requests--; - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, down_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + else if (SUCCEEDED(IMFMediaEvent_GetType(event, &type)) && type == MEMediaSample) + stream->requests--; + IMFMediaEvent_Release(event); } while (stream->requests && drained) @@ -3325,10 +3361,11 @@ static void transform_node_deliver_samples(struct media_session *session, struct input = topo_node->u.transform.next_input++ % topo_node->u.transform.input_count; stream = &topo_node->u.transform.inputs[input]; - if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + if (SUCCEEDED(transform_stream_pop_event(stream, &event))) { - session_deliver_sample_to_node(session, topo_node, input, sample); - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, topo_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + IMFMediaEvent_Release(event); } else if (!(up_node = session_get_topo_node_input(session, topo_node, input, &output))) WARN("Failed to node %p/%lu input\n", topo_node, input); @@ -3395,7 +3432,6 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s { struct topo_node *down_node; HRESULT hr = S_OK; - IMFSample *sample; DWORD input; switch (topo_node->type) @@ -3407,6 +3443,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s case MF_TOPOLOGY_TRANSFORM_NODE: { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; + IMFMediaEvent *event; if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { @@ -3414,10 +3451,11 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s break; } - if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + if (SUCCEEDED(transform_stream_pop_event(stream, &event))) { - session_deliver_sample_to_node(session, down_node, input, sample); - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, down_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + IMFMediaEvent_Release(event); } else if (transform_node_has_requests(topo_node)) { From 10639578007589daa5a84ba1687fc4cc513fea2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 16:57:55 +0200 Subject: [PATCH 154/301] mf/session: Handle transform format changes and update downstream media types. (cherry picked from commit a27b95511be1cb6076b4a91027d14dd139ba3744) CW-Bug-Id: #20833 --- dlls/mf/session.c | 242 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index fc44f7333f3..c57a2861938 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -692,6 +692,43 @@ static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMF return S_OK; } +static HRESULT transform_stream_push_format_change(struct transform_stream *stream, IMFMediaType *media_type) +{ + PROPVARIANT value = {.vt = VT_UNKNOWN, .punkVal = (IUnknown *)media_type}; + struct event_entry *entry; + HRESULT hr; + + if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + if (FAILED(hr = MFCreateMediaEvent(MEStreamFormatChanged, &GUID_NULL, S_OK, &value, &entry->event))) + { + free(entry); + return hr; + } + + list_add_tail(&stream->samples, &entry->entry); + return S_OK; +} + +static HRESULT transform_stream_push_events(struct transform_stream *stream, IMFCollection *events) +{ + struct event_entry *entry; + IMFMediaEvent *event; + + while (SUCCEEDED(IMFCollection_RemoveElement(events, 0, (IUnknown **)&event))) + { + if (!(entry = calloc(1, sizeof(*entry)))) + { + IMFMediaEvent_Release(event); + return E_OUTOFMEMORY; + } + entry->event = event; + list_add_tail(&stream->samples, &entry->entry); + } + + return S_OK; +} + static HRESULT transform_stream_pop_event(struct transform_stream *stream, IMFMediaEvent **event) { struct event_entry *entry; @@ -3157,6 +3194,125 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return hr; } +/* update the transform output type while keeping subtype which matches the old output type */ +static HRESULT transform_stream_update_output_type(struct topo_node *node, struct transform_stream *stream, + UINT id, IMFMediaType *old_output_type, IMFMediaType **new_output_type) +{ + GUID subtype, desired; + UINT i = 0; + HRESULT hr; + + TRACE("node %p, stream %p, id %u, old_output_type %p, new_output_type %p\n", + node, stream, id, old_output_type, new_output_type); + + IMFMediaType_GetGUID(old_output_type, &MF_MT_SUBTYPE, &desired); + + /* find an available output type matching the desired subtype */ + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(node->object.transform, id, + i++, new_output_type))) + { + IMFMediaType_GetGUID(*new_output_type, &MF_MT_SUBTYPE, &subtype); + if (IsEqualGUID(&subtype, &desired)) + { + if (FAILED(hr = IMFTransform_SetOutputType(node->object.transform, id, *new_output_type, 0))) + { + IMFMediaType_Release(*new_output_type); + break; + } + return S_OK; + } + IMFMediaType_Release(*new_output_type); + } + + *new_output_type = NULL; + return hr; +} + +static HRESULT transform_node_format_changed(struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) +{ + HRESULT hr = S_OK; + unsigned int i; + + TRACE("node %p, buffers %p\n", node, buffers); + + for (i = 0; SUCCEEDED(hr) && i < node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &node->u.transform.outputs[i]; + IMFMediaType *old_output_type, *new_output_type; + UINT id = buffers[i].dwStreamID; + + if (!(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE)) + continue; + + if (SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(node->object.transform, id, &old_output_type))) + { + if (SUCCEEDED(hr = transform_stream_update_output_type(node, stream, id, old_output_type, + &new_output_type))) + { + if (buffers[i].pEvents || SUCCEEDED(hr = MFCreateCollection(&buffers[i].pEvents))) + { + if (FAILED(hr = transform_stream_push_format_change(stream, new_output_type))) + WARN("Failed to queue format change event, hr %#lx\n", hr); + } + IMFMediaType_Release(new_output_type); + } + IMFMediaType_Release(old_output_type); + } + } + + return hr; +} + +static HRESULT transform_stream_update_input_type(struct topo_node *node, UINT input, IMFMediaType *media_type) +{ + IMFMediaType **old_output_types; + IMFMediaType *new_output_type; + IMFMediaTypeHandler *handler; + UINT output; + HRESULT hr; + + TRACE("node %p, input %u, media_type %p\n", node, input, media_type); + + if (!(old_output_types = calloc(node->u.transform.output_count, sizeof(*old_output_types)))) + return E_OUTOFMEMORY; + + for (output = 0; output < node->u.transform.output_count; ++output) + { + UINT id = transform_node_get_stream_id(node, TRUE, output); + if (FAILED(hr = IMFTransform_GetOutputCurrentType(node->object.transform, id, + &old_output_types[output]))) + goto done; + } + + if (SUCCEEDED(hr = topology_node_get_type_handler(node->node, input, FALSE, &handler))) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) + WARN("Failed to change note %p input %u media type\n", node->node, input); + IMFMediaTypeHandler_Release(handler); + } + + for (output = 0; SUCCEEDED(hr) && output < node->u.transform.output_count; ++output) + { + struct transform_stream *stream = &node->u.transform.outputs[output]; + UINT id = transform_node_get_stream_id(node, TRUE, output); + + if (SUCCEEDED(hr = transform_stream_update_output_type(node, stream, id, + old_output_types[output], &new_output_type))) + { + if (FAILED(hr = transform_stream_push_format_change(stream, new_output_type))) + WARN("Failed to queue format change event, hr %#lx\n", hr); + IMFMediaType_Release(new_output_type); + } + } + +done: + for (output = 0; output < node->u.transform.output_count; ++output) + if (old_output_types[output]) + IMFMediaType_Release(old_output_types[output]); + free(old_output_types); + return hr; +} + static HRESULT allocate_output_samples(const struct media_session *session, struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) { @@ -3206,12 +3362,28 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, status = 0; hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = transform_node_format_changed(node, buffers))) + { + release_output_samples(node, buffers); + + memset(buffers, 0, node->u.transform.output_count * sizeof(*buffers)); + if (FAILED(hr = allocate_output_samples(session, node, buffers))) + goto done; + hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + } + + /* Collect returned samples for all streams. */ for (i = 0; i < node->u.transform.output_count; ++i) { struct transform_stream *stream = &node->u.transform.outputs[i]; - if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) + if (buffers[i].pEvents && FAILED(hr = transform_stream_push_events(stream, buffers[i].pEvents))) + WARN("Failed to push transform events, hr %#lx\n", hr); + if (buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) + continue; + + if (SUCCEEDED(hr)) { if (session->quality_manager) IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample); @@ -3279,6 +3451,69 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample); +static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node); + +static HRESULT transform_node_handle_format_change(struct media_session *session, struct topo_node *topo_node, + UINT input, IMFMediaType *media_type) +{ + struct transform_stream *stream = &topo_node->u.transform.inputs[input]; + UINT id = transform_node_get_stream_id(topo_node, FALSE, input); + IMFTransform *transform = topo_node->object.transform; + UINT32 support_dynamic_format_change = 0; + IMFAttributes *attributes; + HRESULT hr; + + TRACE("session %p, topo_node %p, input %u, media_type %p\n", session, topo_node, input, media_type); + + if (SUCCEEDED(IMFTransform_GetAttributes(transform, &attributes))) + { + if (FAILED(IMFAttributes_GetUINT32(attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &support_dynamic_format_change))) + support_dynamic_format_change = 0; + IMFAttributes_Release(attributes); + } + + if (!support_dynamic_format_change) + { + if (SUCCEEDED(hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, id))) + { + while (SUCCEEDED(hr = transform_node_pull_samples(session, topo_node))) + transform_node_deliver_samples(session, topo_node); + } + + if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) + { + /* transform isn't fully drained, put the event in the stream input queue to try again later */ + if (FAILED(transform_stream_push_format_change(stream, media_type))) + WARN("Failed to queue input format change event\n"); + return hr; + } + } + + return transform_stream_update_input_type(topo_node, input, media_type); +} + +static HRESULT session_handle_format_change(struct media_session *session, struct topo_node *topo_node, + UINT input, IMFMediaType *media_type) +{ + HRESULT hr; + + switch (topo_node->type) + { + case MF_TOPOLOGY_OUTPUT_NODE: + if (!topo_node->u.sink.allocator) + return S_OK; + if (SUCCEEDED(hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(topo_node->u.sink.allocator))) + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 4, media_type); + return hr; + + case MF_TOPOLOGY_TRANSFORM_NODE: + return transform_node_handle_format_change(session, topo_node, input, media_type); + + default: + FIXME("Unhandled downstream node type %d.\n", topo_node->type); + return E_NOTIMPL; + } +} static HRESULT transform_stream_handle_event(struct media_session *session, struct transform_stream *stream, struct topo_node *topo_node, unsigned int input, IMFMediaEvent *event) @@ -3298,6 +3533,11 @@ static HRESULT transform_stream_handle_event(struct media_session *session, stru session_deliver_sample_to_node(session, topo_node, input, (IMFSample *)value.punkVal); break; + case MEStreamFormatChanged: + if (SUCCEEDED(hr = IMFMediaEvent_GetValue(event, &value))) + hr = session_handle_format_change(session, topo_node, input, (IMFMediaType *)value.punkVal); + break; + default: ERR("Unexpected event type %lu\n", type); hr = E_NOTIMPL; From 42f5449b7add8fa78e9172e87104c3cfb130af07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 23:03:31 +0100 Subject: [PATCH 155/301] winegstreamer: Introduce a new wg_transform_create_mf helper. (cherry picked from commit c1158337ab95462118aef966204597d908d30e59) CW-Bug-Id: #20833 --- dlls/winegstreamer/aac_decoder.c | 18 ++++-------------- dlls/winegstreamer/color_convert.c | 18 ++++-------------- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/main.c | 18 ++++++++++++++++++ dlls/winegstreamer/resampler.c | 18 ++++-------------- dlls/winegstreamer/video_decoder.c | 22 ++++------------------ dlls/winegstreamer/video_processor.c | 18 ++++-------------- 7 files changed, 40 insertions(+), 74 deletions(-) diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 5844de33ceb..8e5d76f516a 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -73,25 +73,15 @@ static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct aac_decoder *decoder) { - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; if (decoder->wg_transform) + { wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(decoder->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - return E_FAIL; + decoder->wg_transform = 0; + } - return S_OK; + return wg_transform_create_mf(decoder->input_type, decoder->output_type, &attrs, &decoder->wg_transform); } static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 41e5bcf3b60..b5a1261b669 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -97,25 +97,15 @@ static inline struct color_convert *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct color_convert *impl) { - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) + { wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - - mf_media_type_to_wg_format(impl->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(impl->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - return E_FAIL; + impl->wg_transform = 0; + } - return S_OK; + return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); } static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 223c9398f0c..803a7a2366f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -120,6 +120,8 @@ void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select); wg_transform_t wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format, const struct wg_transform_attrs *attrs); +HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, + const struct wg_transform_attrs *attrs, wg_transform_t *transform); HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 99f968c226b..2f4f452c648 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -31,6 +31,7 @@ #include "dmoreg.h" #include "gst_guids.h" #include "wmcodecdsp.h" +#include "mferror.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); WINE_DECLARE_DEBUG_CHANNEL(mfplat); @@ -549,6 +550,23 @@ wg_transform_t wg_transform_create(const struct wg_format *input_format, return params.transform; } +HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, + const struct wg_transform_attrs *attrs, wg_transform_t *transform) +{ + struct wg_format input_format, output_format; + + mf_media_type_to_wg_format(input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + mf_media_type_to_wg_format(output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) + return E_FAIL; + return S_OK; +} + HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_type, const AM_MEDIA_TYPE *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform) { diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index b5b62d58800..12da0d35c8e 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -56,25 +56,15 @@ struct resampler static HRESULT try_create_wg_transform(struct resampler *impl) { - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) + { wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - - mf_media_type_to_wg_format(impl->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(impl->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - return E_FAIL; + impl->wg_transform = 0; + } - return S_OK; + return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); } static inline struct resampler *impl_from_IUnknown(IUnknown *iface) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index f730839ef57..dfc55f3cdc7 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -245,21 +245,13 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) * transform to be able to queue its input buffers. We need to use a buffer list * to match its expectations. */ - struct wg_format input_format; - struct wg_format output_format; UINT32 low_latency; if (decoder->wg_transform) + { wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(decoder->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; + decoder->wg_transform = 0; + } if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) decoder->wg_transform_attrs.low_latency = !!low_latency; @@ -270,13 +262,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) decoder->wg_transform_attrs.low_latency = FALSE; } - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &decoder->wg_transform_attrs))) - { - ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); - return E_FAIL; - } - - return S_OK; + return wg_transform_create_mf(decoder->input_type, decoder->output_type, &decoder->wg_transform_attrs, &decoder->wg_transform); } static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index cce077ae63b..6f0e5bdae11 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -87,25 +87,15 @@ struct video_processor static HRESULT try_create_wg_transform(struct video_processor *impl) { - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) + { wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - - mf_media_type_to_wg_format(impl->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - mf_media_type_to_wg_format(impl->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) - return E_FAIL; + impl->wg_transform = 0; + } - return S_OK; + return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); } static struct video_processor *impl_from_IMFTransform(IMFTransform *iface) From ffb76224eb1ad18651d09a745e6670e2354b32c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 23:03:31 +0100 Subject: [PATCH 156/301] winegstreamer: Introduce a new check_audio_transform_support helper. (cherry picked from commit cc82780c22db31fed4da8b84e85c01652a995490) CW-Bug-Id: #20833 --- dlls/winegstreamer/aac_decoder.c | 27 +++--------- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/main.c | 26 +++++++++++ dlls/winegstreamer/mfplat.c | 3 +- dlls/winegstreamer/quartz_transform.c | 63 +++++++-------------------- dlls/winegstreamer/resampler.c | 29 +++--------- 6 files changed, 59 insertions(+), 91 deletions(-) diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 8e5d76f516a..0d012fd710a 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -36,8 +36,10 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); static WAVEFORMATEXTENSIBLE const aac_decoder_output_types[] = { - {.Format = {.wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 48000, .nChannels = 2}}, - {.Format = {.wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 48000, .nChannels = 2}}, + {.Format = {.wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 48000, .nChannels = 2, + .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)}}, + {.Format = {.wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 48000, .nChannels = 2, + .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)}}, }; static const UINT32 default_channel_mask[7] = @@ -575,31 +577,16 @@ static HEAACWAVEINFO aac_decoder_input_types[] = HRESULT aac_decoder_create(REFIID riid, void **ret) { - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_F32LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, - }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4}; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct aac_decoder *decoder; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (FAILED(hr = check_audio_transform_support(&aac_decoder_input_types[0].wfx, &aac_decoder_output_types[0].Format))) { - ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); - return E_FAIL; + ERR_(winediag)("GStreamer doesn't support AAC decoding, please install appropriate plugins\n"); + return hr; } - wg_transform_destroy(transform); if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 803a7a2366f..066f0cef8b2 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -132,6 +132,8 @@ HRESULT wg_transform_flush(wg_transform_t transform); void wg_transform_notify_qos(wg_transform_t transform, bool underflow, double proportion, int64_t diff, uint64_t timestamp); +HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMATEX *output); + HRESULT wg_muxer_create(const char *format, wg_muxer_t *muxer); void wg_muxer_destroy(wg_muxer_t muxer); HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2f4f452c648..b287de514f6 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -32,6 +32,7 @@ #include "gst_guids.h" #include "wmcodecdsp.h" #include "mferror.h" +#include "mfapi.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); WINE_DECLARE_DEBUG_CHANNEL(mfplat); @@ -827,6 +828,31 @@ HRESULT wg_muxer_finalize(wg_muxer_t muxer) return S_OK; } +HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMATEX *output) +{ + IMFMediaType *input_type, *output_type; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; + HRESULT hr; + + if (FAILED(hr = MFCreateMediaType(&input_type))) + return hr; + if (FAILED(hr = MFCreateMediaType(&output_type))) + { + IMFMediaType_Release(input_type); + return hr; + } + + if (SUCCEEDED(hr = MFInitMediaTypeFromWaveFormatEx(input_type, input, sizeof(*input) + input->cbSize)) + && SUCCEEDED(hr = MFInitMediaTypeFromWaveFormatEx(output_type, output, sizeof(*output) + output->cbSize)) + && SUCCEEDED(hr = wg_transform_create_mf(input_type, output_type, &attrs, &transform))) + wg_transform_destroy(transform); + + IMFMediaType_Release(output_type); + IMFMediaType_Release(input_type); + return hr; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) unsigned int wg_format_get_stride(const struct wg_format *format) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index ce696b3fb4b..65b2e0eb7c7 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -24,7 +24,6 @@ #include "ks.h" #include "ksmedia.h" #include "wmcodecdsp.h" -#include "initguid.h" #include "d3d9types.h" #include "mfapi.h" #include "mmreg.h" @@ -33,6 +32,8 @@ #include "wine/debug.h" #include "wine/list.h" +#include "initguid.h" + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); DEFINE_GUID(DMOVideoFormat_RGB32,D3DFMT_X8R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index b85b24f4278..31150a71298 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -737,39 +737,24 @@ static const struct transform_ops mpeg_audio_codec_transform_ops = HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format output_format = + static const WAVEFORMATEX output_format = { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_S16LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, + .wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 44100, .nChannels = 1, }; - static const struct wg_format input_format = + static const MPEG1WAVEFORMAT input_format = { - .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio = - { - .layer = 2, - .channels = 1, - .rate = 44100, - }, + .wfx = {.wFormatTag = WAVE_FORMAT_MPEG, .nSamplesPerSec = 44100, .nChannels = 1, + .cbSize = sizeof(input_format) - sizeof(WAVEFORMATEX)}, + .fwHeadLayer = 2, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct transform *object; HRESULT hr; - transform = wg_transform_create(&input_format, &output_format, &attrs); - if (!transform) + if (FAILED(hr = check_audio_transform_support(&input_format.wfx, &output_format))) { ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); hr = transform_create(outer, &CLSID_CMpegAudioCodec, &mpeg_audio_codec_transform_ops, &object); if (FAILED(hr)) @@ -1015,39 +1000,23 @@ static const struct transform_ops mpeg_layer3_decoder_transform_ops = HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format output_format = + static const WAVEFORMATEX output_format = { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_S16LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, + .wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 44100, .nChannels = 1, }; - static const struct wg_format input_format = + static const MPEGLAYER3WAVEFORMAT input_format = { - .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1, - .u.audio = - { - .layer = 3, - .channels = 1, - .rate = 44100, - }, + .wfx = {.wFormatTag = WAVE_FORMAT_MPEGLAYER3, .nSamplesPerSec = 44100, .nChannels = 1, + .cbSize = sizeof(input_format) - sizeof(WAVEFORMATEX)}, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct transform *object; HRESULT hr; - transform = wg_transform_create(&input_format, &output_format, &attrs); - if (!transform) + if (FAILED(hr = check_audio_transform_support(&input_format.wfx, &output_format))) { - ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); - return E_FAIL; + ERR_(winediag)("GStreamer doesn't support MP3 audio decoding, please install appropriate plugins.\n"); + return hr; } - wg_transform_destroy(transform); hr = transform_create(outer, &CLSID_mpeg_layer3_decoder, &mpeg_layer3_decoder_transform_ops, &object); if (FAILED(hr)) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 12da0d35c8e..8df7eb32649 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -908,41 +908,24 @@ static const IWMResamplerPropsVtbl resampler_props_vtbl = HRESULT resampler_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format input_format = + static const WAVEFORMATEX output_format = { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_S16LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, + .wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 44100, .nChannels = 1, }; - static const struct wg_format output_format = + static const WAVEFORMATEX input_format = { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_F32LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, + .wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 44100, .nChannels = 1, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct resampler *impl; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (FAILED(hr = check_audio_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support audio resampling, please install appropriate plugins.\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; From 19a71ba7daf11402d932a126893a862110e2ab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 17:51:49 +0200 Subject: [PATCH 157/301] winegstreamer: Introduce a new check_video_transform_support helper. (cherry picked from commit 067d4f047247b39a5866c1d7b22b5f16b5187d5b) CW-Bug-Id: #20833 --- dlls/winegstreamer/color_convert.c | 31 +++++++++------------------- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 25 ++++++++++++++++++++++ dlls/winegstreamer/video_decoder.c | 25 ++++++++++------------ dlls/winegstreamer/video_processor.c | 31 +++++++++------------------- 5 files changed, 57 insertions(+), 56 deletions(-) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index b5a1261b669..949b85943d0 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -907,39 +907,28 @@ static const IPropertyStoreVtbl property_store_vtbl = HRESULT color_convert_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format input_format = + const MFVIDEOFORMAT input_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_I420, }; - static const struct wg_format output_format = + const MFVIDEOFORMAT output_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_NV12, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct color_convert *impl; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 066f0cef8b2..ca4b1e279ca 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -133,6 +133,7 @@ void wg_transform_notify_qos(wg_transform_t transform, bool underflow, double proportion, int64_t diff, uint64_t timestamp); HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMATEX *output); +HRESULT check_video_transform_support(const MFVIDEOFORMAT *input, const MFVIDEOFORMAT *output); HRESULT wg_muxer_create(const char *format, wg_muxer_t *muxer); void wg_muxer_destroy(wg_muxer_t muxer); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index b287de514f6..6e49ca0e16f 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -853,6 +853,31 @@ HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMA return hr; } +HRESULT check_video_transform_support(const MFVIDEOFORMAT *input, const MFVIDEOFORMAT *output) +{ + IMFMediaType *input_type, *output_type; + struct wg_transform_attrs attrs = {0}; + wg_transform_t transform; + HRESULT hr; + + if (FAILED(hr = MFCreateMediaType(&input_type))) + return hr; + if (FAILED(hr = MFCreateMediaType(&output_type))) + { + IMFMediaType_Release(input_type); + return hr; + } + + if (SUCCEEDED(hr = MFInitMediaTypeFromMFVideoFormat(input_type, input, input->dwSize)) + && SUCCEEDED(hr = MFInitMediaTypeFromMFVideoFormat(output_type, output, output->dwSize)) + && SUCCEEDED(hr = wg_transform_create_mf(input_type, output_type, &attrs, &transform))) + wg_transform_destroy(transform); + + IMFMediaType_Release(output_type); + IMFMediaType_Release(input_type); + return hr; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) unsigned int wg_format_get_stride(const struct wg_format *format) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index dfc55f3cdc7..f6f2640efb3 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1546,30 +1546,27 @@ static const GUID *const h264_decoder_input_types[] = HRESULT h264_decoder_create(REFIID riid, void **out) { - static const struct wg_format output_format = + const MFVIDEOFORMAT output_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_I420, + }; + const MFVIDEOFORMAT input_format = + { + .dwSize = sizeof(MFVIDEOFORMAT), + .guidFormat = MFVideoFormat_H264, }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; - struct wg_transform_attrs attrs = {0}; struct video_decoder *decoder; - wg_transform_t transform; HRESULT hr; TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 6f0e5bdae11..5b93bf08396 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -605,39 +605,28 @@ static const IMFTransformVtbl video_processor_vtbl = HRESULT video_processor_create(REFIID riid, void **ret) { - static const struct wg_format input_format = + const MFVIDEOFORMAT input_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_I420, - .width = 1920, - .height = 1080, - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_I420, }; - static const struct wg_format output_format = + const MFVIDEOFORMAT output_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_NV12, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct video_processor *impl; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; From e33b7c784630ee6d7381f60e37ce1156f106a102 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 10 May 2024 10:44:07 +0700 Subject: [PATCH 158/301] winegstreamer: Recognize MFAudioFormat_MPEG and MFAudioFormat_MP3. Fixes: cc82780c22db31fed4da8b84e85c01652a995490 (cherry picked from commit 08e13d197965d4978167f0dd541d32a8cec2bbf1) CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 61 ++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 65b2e0eb7c7..65019b09c94 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -655,6 +655,61 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *sub FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); } +static void mf_media_type_to_wg_format_audio_mpeg(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +{ + MPEG1WAVEFORMAT wfx = {0}; + UINT32 codec_data_size; + UINT32 rate, channels; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) + { + FIXME("Sample rate is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) + { + FIXME("Channel count is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, (UINT8 *)(&wfx.wfx + 1), + sizeof(wfx) - sizeof(WAVEFORMATEX), &codec_data_size))) + { + FIXME("Codec data is not set.\n"); + return; + } + if (codec_data_size < sizeof(wfx) - sizeof(WAVEFORMATEX)) + { + FIXME("Codec data is incomplete.\n"); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; + format->u.audio.channels = channels; + format->u.audio.rate = rate; + format->u.audio.layer = wfx.fwHeadLayer; +} + +static void mf_media_type_to_wg_format_audio_mpeg_layer3(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +{ + UINT32 rate, channels; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) + { + FIXME("Sample rate is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) + { + FIXME("Channel count is not set.\n"); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG1; + format->u.audio.channels = channels; + format->u.audio.rate = rate; + format->u.audio.layer = 3; +} + static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { BYTE buffer[sizeof(HEAACWAVEFORMAT) + 64]; @@ -959,7 +1014,11 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) if (IsEqualGUID(&major_type, &MFMediaType_Audio)) { - if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || + if (IsEqualGUID(&subtype, &MFAudioFormat_MPEG)) + mf_media_type_to_wg_format_audio_mpeg(type, &subtype, format); + else if (IsEqualGUID(&subtype, &MFAudioFormat_MP3)) + mf_media_type_to_wg_format_audio_mpeg_layer3(type, &subtype, format); + else if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) From e721c95d946ad675867836fb0126e985e4869c6b Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 8 May 2024 11:15:23 +0800 Subject: [PATCH 159/301] winegstreamer/video_decoder: Make output_plane_align specific to h264. If we set output align to wmv decoder, it will fail at copy_video_buffer(). The output size will larger than the sample we provided due to alignment. (cherry-picked from commit 08478473b720e02a403a15b44462b15ebda0e40b) CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index f6f2640efb3..f128e6dd025 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1516,7 +1516,6 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) goto failed; - decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.input_queue_length = 15; *out = decoder; @@ -1585,6 +1584,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; + decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.allow_size_change = TRUE; TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); From c5f6d12e80a716805cc4ec2015296c93451046eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 15:13:53 +0100 Subject: [PATCH 160/301] Revert "mfreadwrite/reader: Consider the transform output attributes for creating shared samples." This reverts commit e8a7e632ec99d43efdee524b7a668378b0ae5f76. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 1461d7acd7b..3bcd55f53eb 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2121,33 +2121,20 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea } static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader, - struct media_stream *stream, IMFAttributes **attributes) + IMFAttributes **attributes) { - UINT32 reader_shared = 0, reader_shared_without_mutex = 0; - UINT32 output_shared = 0, output_shared_without_mutex = 0; + UINT32 shared = 0, shared_without_mutex = 0; HRESULT hr; if (FAILED(hr = MFCreateAttributes(attributes, 1))) return hr; - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &reader_shared); - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &reader_shared_without_mutex); + IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared); + IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex); - if (stream->decoder.transform) - { - IMFAttributes *output_attributes; - - if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(stream->decoder.transform, 0, &output_attributes))) - { - IMFAttributes_GetUINT32(output_attributes, &MF_SA_D3D11_SHARED, &output_shared); - IMFAttributes_GetUINT32(output_attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &output_shared_without_mutex); - IMFAttributes_Release(output_attributes); - } - } - - if (reader_shared_without_mutex || output_shared_without_mutex) + if (shared_without_mutex) hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE); - else if (reader_shared || output_shared) + else if (shared) hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE); return hr; @@ -2183,7 +2170,7 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; } - if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, stream, &attributes))) + if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes))) WARN("Failed to create allocator attributes, hr %#lx.\n", hr); if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, From 2d41e6c2a13798421a22ee1d931bba335e0b0a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 15:14:02 +0100 Subject: [PATCH 161/301] Revert "mfreadwrite/reader: Setup the sample allocator in ReadSample." This reverts commit cf53249fabdda6c9f46e47bfdc4507cce76a7723. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 3bcd55f53eb..7ff167cc72a 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1677,8 +1677,6 @@ static HRESULT source_reader_flush(struct source_reader *reader, unsigned int in return hr; } -static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index); - static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); @@ -1708,15 +1706,7 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb { stream = &reader->streams[stream_index]; - if (!stream->allocator) - { - hr = source_reader_setup_sample_allocator(reader, stream_index); - - if (FAILED(hr)) - WARN("Failed to setup the sample allocator, hr %#lx.\n", hr); - } - - if (SUCCEEDED(hr) && !(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, + if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, &stream_index, &stream_flags, ×tamp, &sample))) { stream->requests++; @@ -2374,12 +2364,8 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D hr = source_reader_create_decoder_for_stream(reader, index, type); else if (hr == S_OK) hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); - - if (reader->streams[index].allocator) - { - IMFVideoSampleAllocatorEx_Release(reader->streams[index].allocator); - reader->streams[index].allocator = NULL; - } + if (SUCCEEDED(hr)) + hr = source_reader_setup_sample_allocator(reader, index); LeaveCriticalSection(&reader->cs); @@ -2478,15 +2464,7 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind stream = &reader->streams[stream_index]; - if (!stream->allocator) - { - hr = source_reader_setup_sample_allocator(reader, stream_index); - - if (FAILED(hr)) - WARN("Failed to setup the sample allocator, hr %#lx.\n", hr); - } - - if (SUCCEEDED(hr) && !source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, + if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, timestamp, sample)) { while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS) From 986198526aa96ba2d38936f0dc40b13a7b33ca1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 15:14:11 +0100 Subject: [PATCH 162/301] Revert "HACK: mfreadwrite/reader: Add a passthrough transform." This reverts commit 88a8e364173463110a2d8073637eb0cbe0aa6594. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 487 -------------------------------------- 1 file changed, 487 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 7ff167cc72a..8b729b80455 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -242,461 +242,6 @@ static ULONG source_reader_release(struct source_reader *reader) return refcount; } -struct passthrough_transform -{ - IMFTransform IMFTransform_iface; - LONG refcount; - IMFMediaType *type; - IMFAttributes *attributes; - IMFAttributes *input_attributes; - IMFAttributes *output_attributes; - IMFSample *sample; -}; - -static inline struct passthrough_transform *impl_from_IMFTransform(IMFTransform *iface) -{ - return CONTAINING_RECORD(iface, struct passthrough_transform, IMFTransform_iface); -} - -static HRESULT WINAPI passthrough_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **out) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IMFTransform)) - { - *out = &transform->IMFTransform_iface; - } - else - { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); - *out = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef(iface); - return S_OK; -} - -static ULONG WINAPI passthrough_transform_AddRef(IMFTransform *iface) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&transform->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI passthrough_transform_Release(IMFTransform *iface) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&transform->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - if (transform->type) - IMFMediaType_Release(transform->type); - IMFAttributes_Release(transform->attributes); - IMFAttributes_Release(transform->input_attributes); - IMFAttributes_Release(transform->output_attributes); - if (transform->sample) - IMFSample_Release(transform->sample); - } - - return refcount; -} -static HRESULT WINAPI passthrough_transform_GetStreamLimits(IMFTransform *iface, - DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) -{ - TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); - - *input_minimum = 1; - *input_maximum = 1; - *output_minimum = 1; - *output_maximum = 1; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -{ - TRACE("%p, %p, %p.\n", iface, inputs, outputs); - - *inputs = 1; - *outputs = 1; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetStreamIDs(IMFTransform *iface, - DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) -{ - TRACE("%p, %ld, %p, %ld, %p.\n", iface, input_size, inputs, output_size, outputs); - - if (input_size < 1 || output_size < 1) - return MF_E_BUFFERTOOSMALL; - - inputs[0] = 0; - outputs[0] = 0; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -{ - TRACE("%p, %ld, %p.\n", iface, id, info); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - info->hnsMaxLatency = 0; - info->dwFlags = MFT_INPUT_STREAM_PROCESSES_IN_PLACE; - info->cbSize = 0; - info->cbMaxLookahead = 0; - info->cbAlignment = 0; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -{ - TRACE("%p, %ld, %p.\n", iface, id, info); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - info->dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; - info->cbSize = 0; - info->cbAlignment = 0; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %p.\n", iface, attributes); - - IMFAttributes_AddRef(transform->attributes); - - *attributes = transform->attributes; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p.\n", iface, id, attributes); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - IMFAttributes_AddRef(transform->input_attributes); - - *attributes = transform->input_attributes; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p.\n", iface, id, attributes); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - IMFAttributes_AddRef(transform->output_attributes); - - *attributes = transform->output_attributes; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_DeleteInputStream(IMFTransform *iface, DWORD id) -{ - TRACE("%p, %ld.\n", iface, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -{ - TRACE("%p, %ld, %p.\n", iface, streams, ids); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) -{ - TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (index != 0) - return MF_E_NO_MORE_TYPES; - - if (!transform->type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *type = transform->type; - IMFMediaType_AddRef(*type); - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (!(flags & MFT_SET_TYPE_TEST_ONLY)) - { - if (transform->type) - IMFMediaType_Release(transform->type); - transform->type = type; - IMFMediaType_AddRef(type); - } - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - DWORD cmp_flags; - HRESULT hr; - - TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (!transform->type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - hr = IMFMediaType_IsEqual(transform->type, type, &cmp_flags); - if (FAILED(hr)) - return hr; - - if (!(cmp_flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) - return MF_E_INVALIDMEDIATYPE; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p.\n", iface, id, type); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (!transform->type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *type = transform->type; - IMFMediaType_AddRef(*type); - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p.\n", iface, id, type); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (!transform->type) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *type = transform->type; - IMFMediaType_AddRef(*type); - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p.\n", iface, id, flags); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - *flags = transform->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %p.\n", iface, flags); - - *flags = transform->sample ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0; - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -{ - FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -{ - FIXME("%p, %ld, %p.\n", iface, id, event); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -{ - FIXME("%p, %u, %Iu.\n", iface, message, param); - - return E_NOTIMPL; -} - -static HRESULT WINAPI passthrough_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - - TRACE("%p, %ld, %p, %ld.\n", iface, id, sample, flags); - - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - - if (transform->sample) - return MF_E_NOTACCEPTING; - - transform->sample = sample; - IMFSample_AddRef(sample); - - return S_OK; -} - -static HRESULT WINAPI passthrough_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -{ - struct passthrough_transform *transform = impl_from_IMFTransform(iface); - unsigned int i; - - TRACE("%p, %ld, %ld, %p, %p.\n", iface, flags, count, samples, status); - - if (!transform->sample) - return MF_E_TRANSFORM_NEED_MORE_INPUT; - - if (samples[0].dwStreamID != 0) - return MF_E_INVALIDSTREAMNUMBER; - - samples[0].pSample = transform->sample; - transform->sample = NULL; - - for (i = 1; i < count; ++i) - samples[i].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; - - *status = 0; - - return S_OK; -} - -static const IMFTransformVtbl passthrough_transform_vtbl = { - passthrough_transform_QueryInterface, - passthrough_transform_AddRef, - passthrough_transform_Release, - passthrough_transform_GetStreamLimits, - passthrough_transform_GetStreamCount, - passthrough_transform_GetStreamIDs, - passthrough_transform_GetInputStreamInfo, - passthrough_transform_GetOutputStreamInfo, - passthrough_transform_GetAttributes, - passthrough_transform_GetInputStreamAttributes, - passthrough_transform_GetOutputStreamAttributes, - passthrough_transform_DeleteInputStream, - passthrough_transform_AddInputStreams, - passthrough_transform_GetInputAvailableType, - passthrough_transform_GetOutputAvailableType, - passthrough_transform_SetInputType, - passthrough_transform_SetOutputType, - passthrough_transform_GetInputCurrentType, - passthrough_transform_GetOutputCurrentType, - passthrough_transform_GetInputStatus, - passthrough_transform_GetOutputStatus, - passthrough_transform_SetOutputBounds, - passthrough_transform_ProcessEvent, - passthrough_transform_ProcessMessage, - passthrough_transform_ProcessInput, - passthrough_transform_ProcessOutput, -}; - -static HRESULT create_passthrough_transform(IMFTransform **transform) -{ - struct passthrough_transform *obj; - HRESULT hr; - - if (!(obj = calloc(1, sizeof(*obj)))) - return E_OUTOFMEMORY; - - obj->IMFTransform_iface.lpVtbl = &passthrough_transform_vtbl; - obj->refcount = 1; - - hr = MFCreateAttributes(&obj->attributes, 0); - if (SUCCEEDED(hr)) - hr = MFCreateAttributes(&obj->input_attributes, 0); - if (SUCCEEDED(hr)) - hr = MFCreateAttributes(&obj->output_attributes, 0); - - if (SUCCEEDED(hr)) - { - *transform = &obj->IMFTransform_iface; - } - else - { - if (obj->attributes) - IMFAttributes_Release(obj->attributes); - if (obj->input_attributes) - IMFAttributes_Release(obj->input_attributes); - if (obj->output_attributes) - IMFAttributes_Release(obj->output_attributes); - free(obj); - } - - return hr; -} - static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -2244,36 +1789,6 @@ static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWO return MF_E_TOPO_CODEC_NOT_FOUND; } -static HRESULT source_reader_add_passthrough_transform(struct source_reader *reader, DWORD index, IMFMediaType *type) -{ - IMFTransform *transform; - HRESULT hr; - - if (FAILED(hr = create_passthrough_transform(&transform))) - return hr; - - if (FAILED(hr = IMFTransform_SetInputType(transform, 0, type, 0))) - { - WARN("Failed to set decoder input type, hr %#lx.\n", hr); - IMFTransform_Release(transform); - return hr; - } - - if (FAILED(hr = IMFTransform_SetOutputType(transform, 0, type, 0))) - { - WARN("Failed to set decoder input type, hr %#lx.\n", hr); - IMFTransform_Release(transform); - return hr; - } - - if (reader->streams[index].decoder.transform) - IMFTransform_Release(reader->streams[index].decoder.transform); - reader->streams[index].decoder.transform = transform; - reader->streams[index].decoder.min_buffer_size = 0; - - return S_OK; -} - static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -2362,8 +1877,6 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D hr = source_reader_set_compatible_media_type(reader, index, type); if (hr == S_FALSE) hr = source_reader_create_decoder_for_stream(reader, index, type); - else if (hr == S_OK) - hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); if (SUCCEEDED(hr)) hr = source_reader_setup_sample_allocator(reader, index); From d78239bf0e6607e11bc04cfaa3ab6c52bac9880f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 May 2024 13:07:48 +0200 Subject: [PATCH 163/301] Revert "mfplat: Add MFVideoFormat_ABGR32 format information." This reverts commit ff469294ac7c11a9c8f34fcba13a447c454ca329. CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index fa69ed3b9c0..dd0b29fac32 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -39,7 +39,6 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB1, D3DFMT_A1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB4, MAKEFOURCC('4','P','x','x')); -DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB1555, D3DFMT_A1R5G5B5); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB4444, D3DFMT_A4R4G4B4); /* SDK MFVideoFormat_A2R10G10B10 uses D3DFMT_A2B10G10R10, let's name it the other way */ @@ -2714,7 +2713,6 @@ static struct uncompressed_video_format video_formats[] = { &MFVideoFormat_RGB32, 32, 3, 1, 0, BI_RGB }, { &MFVideoFormat_RGB565, 16, 3, 1, 0, BI_BITFIELDS }, { &MFVideoFormat_RGB555, 16, 3, 1, 0, BI_RGB }, - { &MFVideoFormat_ABGR32, 32, 3, 1, 0, BI_RGB }, { &MFVideoFormat_A2R10G10B10, 32, 3, 1, 0, -1 }, { &MFVideoFormat_A2B10G10R10, 32, 3, 1, 0, -1 }, { &MFVideoFormat_RGB8, 8, 3, 1, 0, BI_RGB }, @@ -3664,8 +3662,6 @@ DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format) return DXGI_FORMAT_P8; case D3DFMT_A8P8: return DXGI_FORMAT_A8P8; - case D3DFMT_A8B8G8R8: - return DXGI_FORMAT_R8G8B8A8_UNORM; default: return DXGI_FORMAT_UNKNOWN; } From b026e7863b34f3693686354a2e3befe184032bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 May 2024 12:54:58 +0200 Subject: [PATCH 164/301] Revert "winegstreamer/wg_format: Add WG_VIDEO_FORMAT_RGBA format." This reverts commit ff8e86819dccc78e0633955d165c4250d6d16914. CW-Bug-Id: #20833 --- dlls/winegstreamer/main.c | 1 - dlls/winegstreamer/mfplat.c | 2 -- dlls/winegstreamer/quartz_parser.c | 8 -------- dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/wg_format.c | 3 --- 5 files changed, 15 deletions(-) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6e49ca0e16f..349b46a192f 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -924,7 +924,6 @@ bool wg_video_format_is_rgb(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: case WG_VIDEO_FORMAT_BGR: - case WG_VIDEO_FORMAT_RGBA: case WG_VIDEO_FORMAT_RGB15: case WG_VIDEO_FORMAT_RGB16: return true; diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 65019b09c94..755f95d7b4c 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -41,7 +41,6 @@ DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20 DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); -DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); @@ -451,7 +450,6 @@ video_formats[] = {&MFVideoFormat_ARGB32, WG_VIDEO_FORMAT_BGRA}, {&MFVideoFormat_RGB32, WG_VIDEO_FORMAT_BGRx}, {&MFVideoFormat_RGB24, WG_VIDEO_FORMAT_BGR}, - {&MFVideoFormat_ABGR32, WG_VIDEO_FORMAT_RGBA}, {&MFVideoFormat_RGB555, WG_VIDEO_FORMAT_RGB15}, {&MFVideoFormat_RGB565, WG_VIDEO_FORMAT_RGB16}, {&MFVideoFormat_AYUV, WG_VIDEO_FORMAT_AYUV}, diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 7b8d7c87cce..20e2929c5a9 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -29,8 +29,6 @@ #include "dvdmedia.h" #include "mmreg.h" #include "ks.h" -#include "mfapi.h" -#include "d3d9types.h" #include "wmcodecdsp.h" #include "initguid.h" #include "ksmedia.h" @@ -41,7 +39,6 @@ static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; -extern const GUID MFVideoFormat_ABGR32; struct parser { @@ -351,7 +348,6 @@ static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format { case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: - case WG_VIDEO_FORMAT_RGBA: case WG_VIDEO_FORMAT_AYUV: return width * height * 4; @@ -480,7 +476,6 @@ static const GUID *wg_video_format_get_mediasubtype(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return &MEDIASUBTYPE_ARGB32; case WG_VIDEO_FORMAT_BGRx: return &MEDIASUBTYPE_RGB32; case WG_VIDEO_FORMAT_BGR: return &MEDIASUBTYPE_RGB24; - case WG_VIDEO_FORMAT_RGBA: return &MFVideoFormat_ABGR32; case WG_VIDEO_FORMAT_RGB15: return &MEDIASUBTYPE_RGB555; case WG_VIDEO_FORMAT_RGB16: return &MEDIASUBTYPE_RGB565; case WG_VIDEO_FORMAT_AYUV: return &MEDIASUBTYPE_AYUV; @@ -509,7 +504,6 @@ static DWORD wg_video_format_get_compression(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return BI_RGB; case WG_VIDEO_FORMAT_BGRx: return BI_RGB; case WG_VIDEO_FORMAT_BGR: return BI_RGB; - case WG_VIDEO_FORMAT_RGBA: return BI_RGB; case WG_VIDEO_FORMAT_RGB15: return BI_RGB; case WG_VIDEO_FORMAT_RGB16: return BI_BITFIELDS; case WG_VIDEO_FORMAT_AYUV: return mmioFOURCC('A','Y','U','V'); @@ -533,7 +527,6 @@ static WORD wg_video_format_get_depth(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return 32; case WG_VIDEO_FORMAT_BGRx: return 32; case WG_VIDEO_FORMAT_BGR: return 24; - case WG_VIDEO_FORMAT_RGBA: return 32; case WG_VIDEO_FORMAT_RGB15: return 16; case WG_VIDEO_FORMAT_RGB16: return 16; case WG_VIDEO_FORMAT_AYUV: return 32; @@ -932,7 +925,6 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo {&MEDIASUBTYPE_ARGB32, WG_VIDEO_FORMAT_BGRA}, {&MEDIASUBTYPE_RGB32, WG_VIDEO_FORMAT_BGRx}, {&MEDIASUBTYPE_RGB24, WG_VIDEO_FORMAT_BGR}, - {&MFVideoFormat_ABGR32, WG_VIDEO_FORMAT_RGBA}, {&MEDIASUBTYPE_RGB555, WG_VIDEO_FORMAT_RGB15}, {&MEDIASUBTYPE_RGB565, WG_VIDEO_FORMAT_RGB16}, {&MEDIASUBTYPE_AYUV, WG_VIDEO_FORMAT_AYUV}, diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 8d5fe404d8f..cb9b74a1080 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -66,7 +66,6 @@ enum wg_video_format WG_VIDEO_FORMAT_BGRA, WG_VIDEO_FORMAT_BGRx, WG_VIDEO_FORMAT_BGR, - WG_VIDEO_FORMAT_RGBA, WG_VIDEO_FORMAT_RGB15, WG_VIDEO_FORMAT_RGB16, diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 12f3a2c0ecf..6f433e305b1 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -141,8 +141,6 @@ static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) return WG_VIDEO_FORMAT_BGRx; case GST_VIDEO_FORMAT_BGR: return WG_VIDEO_FORMAT_BGR; - case GST_VIDEO_FORMAT_RGBA: - return WG_VIDEO_FORMAT_RGBA; case GST_VIDEO_FORMAT_RGB15: return WG_VIDEO_FORMAT_RGB15; case GST_VIDEO_FORMAT_RGB16: @@ -570,7 +568,6 @@ static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; - case WG_VIDEO_FORMAT_RGBA: return GST_VIDEO_FORMAT_RGBA; case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; From f640ecd71331ebfbba4a821a503fd6ae3023c445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:40:46 +0200 Subject: [PATCH 165/301] Revert "HACK: winegstreamer: Detect h264 use and create a tag file." This reverts commit ebdcf6a3cbc65bb0f2dde9f610acd34b2835f3a3. CW-Bug-Id: #20833 --- dlls/winegstreamer/unix_private.h | 35 ------------------------------- dlls/winegstreamer/wg_parser.c | 15 ------------- dlls/winegstreamer/wg_transform.c | 4 ---- 3 files changed, 54 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 48def4245ec..87ab6a92e29 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -26,11 +26,6 @@ #include #include -#include -#include -#include -#include - /* unixlib.c */ GST_DEBUG_CATEGORY_EXTERN(wine); @@ -118,34 +113,4 @@ extern bool media_converter_init(void); extern bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, struct wg_format *codec_format); -static inline void touch_h264_used_tag(void) -{ - const char *e; - - GST_LOG("h264 is used"); - - if ((e = getenv("STEAM_COMPAT_TRANSCODED_MEDIA_PATH"))) - { - char buffer[PATH_MAX]; - int fd; - - snprintf(buffer, sizeof(buffer), "%s/h264-used", e); - - fd = open(buffer, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd == -1) - { - GST_WARNING("Failed to open/create \"%s/h264-used\"", e); - return; - } - - futimens(fd, NULL); - - close(fd); - } - else - { - GST_WARNING("STEAM_COMPAT_TRANSCODED_MEDIA_PATH not set, cannot create h264-used file"); - } -} - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index bff82d38b4a..c93609bac1a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -529,19 +529,6 @@ static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCap return !format_is_compressed(&format); } -gboolean caps_detect_h264(GstCapsFeatures *features, GstStructure *structure, gpointer user_data) -{ - const char *cap_name = gst_structure_get_name(structure); - - if (!strcmp(cap_name, "video/x-h264")) - { - touch_h264_used_tag(); - return FALSE; - } - - return TRUE; -} - static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user) { @@ -551,8 +538,6 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GST_INFO("Using \"%s\".", name); - gst_caps_foreach(caps, caps_detect_h264, NULL); - if (parser->error) return GST_AUTOPLUG_SELECT_SKIP; if (strstr(name, "Player protection")) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 4c57a084bd1..8a6500412e2 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -398,10 +398,6 @@ NTSTATUS wg_transform_create(void *args) const gchar *media_type; GstEvent *event; - /* to detect h264_decoder_create() */ - if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264) - touch_h264_used_tag(); - if (!(transform = calloc(1, sizeof(*transform)))) return STATUS_NO_MEMORY; if (!(transform->container = gst_bin_new("wg_transform"))) From f0ad7162b8a4d2b0c6c05a88b8e8518bee80a4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:41:11 +0200 Subject: [PATCH 166/301] Revert "HACK: winegstreamer/wg_transform: Check if the decoder accepted our caps." This reverts commit 3546d68111a9513e83bc613c2b77ff979556f7d6. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 8a6500412e2..7174d867dce 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -572,20 +572,6 @@ NTSTATUS wg_transform_create(void *args) || !push_event(transform->my_src, event)) goto out; - /* Check that the caps event have been accepted */ - if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264) - { - GstPad *peer; - if (!(peer = gst_pad_get_peer(transform->my_src))) - goto out; - else if (!gst_pad_has_current_caps(peer)) - { - gst_object_unref(peer); - goto out; - } - gst_object_unref(peer); - } - /* We need to use GST_FORMAT_TIME here because it's the only format * some elements such avdec_wmav2 correctly support. */ gst_segment_init(&transform->segment, GST_FORMAT_TIME); From 2e2371e627b5a76c0847fb9ee18bf2a681245e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:45:02 +0200 Subject: [PATCH 167/301] Revert "HACK: winegstreamer: Don't add unnecessary and slow? videoflip for some games." This reverts commit 047a3280e61e1be25f33c3010e288438f84de628. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 7174d867dce..2e03d5c1a78 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -512,7 +512,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO: { const char *sgi; - if ((sgi = getenv("SteamGameId")) && ((!strcmp(sgi, "2009100")) || (!strcmp(sgi, "2555360")))) + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) { if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) From f2af56306f7cd20bd7acb7f22d8faa03608c57ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jun 2024 17:45:07 +0200 Subject: [PATCH 168/301] Revert "HACK: winegstreamer/wg_transform: Don't add unnecessary and slow? videoflip for some games." This reverts commit 0a4a996f75bd31e9366a8a5975e71501d5b794bf. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 2e03d5c1a78..e645fd0f006 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -510,19 +510,6 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: - { - const char *sgi; - if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) - { - if (!(element = create_element("videoconvert", "base")) - || !append_element(transform->container, element, &first, &last)) - goto out; - gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); - /* HACK: skip slow?? videoflip for some games */ - break; - } - } - if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; From b0d7033fe6bc1d864b75a6a5876abc7593f0d09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 21:16:06 +0100 Subject: [PATCH 169/301] mfreadwrite/reader: Introduce source_reader_queue_sample helper. (cherry picked from commit cbb343567ac155d581bf484e66238ec1e411c79d) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8b729b80455..fbe08af2445 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -463,6 +463,17 @@ static HRESULT source_reader_queue_response(struct source_reader *reader, struct return S_OK; } +static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream, + IMFSample *sample) +{ + LONGLONG timestamp = 0; + + if (FAILED(IMFSample_GetSampleTime(sample, ×tamp))) + WARN("Sample time wasn't set.\n"); + + return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample); +} + static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream) { HRESULT hr = S_OK; @@ -650,7 +661,6 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s MFT_OUTPUT_DATA_BUFFER out_buffer; unsigned int buffer_size; IMFMediaBuffer *buffer; - LONGLONG timestamp; DWORD status; HRESULT hr; @@ -688,11 +698,7 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s break; } - timestamp = 0; - if (FAILED(IMFSample_GetSampleTime(out_buffer.pSample, ×tamp))) - WARN("Sample time wasn't set.\n"); - - source_reader_queue_response(reader, stream, S_OK /* FIXME */, 0, timestamp, out_buffer.pSample); + source_reader_queue_sample(reader, stream, out_buffer.pSample); if (out_buffer.pSample) IMFSample_Release(out_buffer.pSample); if (out_buffer.pEvents) @@ -705,17 +711,10 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream, IMFSample *sample) { - LONGLONG timestamp; HRESULT hr; if (!stream->decoder.transform) - { - timestamp = 0; - if (FAILED(IMFSample_GetSampleTime(sample, ×tamp))) - WARN("Sample time wasn't set.\n"); - - return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample); - } + return source_reader_queue_sample(reader, stream, sample); /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ From de00a1fe36a9d04e6cb0d61859c1560f9f467b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 22:07:59 +0100 Subject: [PATCH 170/301] mfreadwrite/reader: Pass the transform to source_reader_pull_stream_samples. (cherry picked from commit dd6e8198e0af73449e5ed9550e4f9053cf40c985) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index fbe08af2445..71a2021fc82 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -71,7 +71,7 @@ enum media_stream_flags STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */ }; -struct stream_transform +struct transform_entry { IMFTransform *transform; unsigned int min_buffer_size; @@ -81,7 +81,7 @@ struct media_stream { IMFMediaStream *stream; IMFMediaType *current; - struct stream_transform decoder; + struct transform_entry decoder; IMFVideoSampleAllocatorEx *allocator; DWORD id; unsigned int index; @@ -655,7 +655,8 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); } -static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream) +static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry) { MFT_OUTPUT_STREAM_INFO stream_info = { 0 }; MFT_OUTPUT_DATA_BUFFER out_buffer; @@ -664,7 +665,7 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s DWORD status; HRESULT hr; - if (FAILED(hr = IMFTransform_GetOutputStreamInfo(stream->decoder.transform, 0, &stream_info))) + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) { WARN("Failed to get output stream info, hr %#lx.\n", hr); return hr; @@ -679,7 +680,7 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s if (FAILED(hr = MFCreateSample(&out_buffer.pSample))) break; - buffer_size = max(stream_info.cbSize, stream->decoder.min_buffer_size); + buffer_size = max(stream_info.cbSize, entry->min_buffer_size); if (FAILED(hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info.cbAlignment, &buffer))) { @@ -691,7 +692,7 @@ static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, s IMFMediaBuffer_Release(buffer); } - if (FAILED(hr = IMFTransform_ProcessOutput(stream->decoder.transform, 0, 1, &out_buffer, &status))) + if (FAILED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) { if (out_buffer.pSample) IMFSample_Release(out_buffer.pSample); @@ -718,7 +719,7 @@ static HRESULT source_reader_process_sample(struct source_reader *reader, struct /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ - hr = source_reader_pull_stream_samples(reader, stream); + hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder.transform, 0, sample, 0))) @@ -727,7 +728,7 @@ static HRESULT source_reader_process_sample(struct source_reader *reader, struct return hr; } - if ((hr = source_reader_pull_stream_samples(reader, stream)) == MF_E_TRANSFORM_NEED_MORE_INPUT) + if ((hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder)) == MF_E_TRANSFORM_NEED_MORE_INPUT) return S_OK; } else @@ -821,7 +822,7 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re if (stream->decoder.transform && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder.transform, MFT_MESSAGE_COMMAND_DRAIN, 0))) { - if ((hr = source_reader_pull_stream_samples(reader, stream)) != MF_E_TRANSFORM_NEED_MORE_INPUT) + if ((hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder)) != MF_E_TRANSFORM_NEED_MORE_INPUT) WARN("Failed to pull pending samples, hr %#lx.\n", hr); } From 2897ba60bb625d60be6df92a5c71ce57d8ed99c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 22:16:10 +0100 Subject: [PATCH 171/301] mfreadwrite/reader: Introduce a new source_reader_allocate_stream_sample helper. (cherry picked from commit 8946e6df7edbcc8b6e2adfb9cce8c337a1daa697) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 71a2021fc82..8722dc371f2 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -655,42 +655,47 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); } +static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) +{ + IMFMediaBuffer *buffer; + IMFSample *sample; + HRESULT hr; + + *out = NULL; + if (FAILED(hr = MFCreateSample(&sample))) + return hr; + if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer))) + { + if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer))) + { + *out = sample; + IMFSample_AddRef(sample); + } + IMFMediaBuffer_Release(buffer); + } + + IMFSample_Release(sample); + return hr; +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { MFT_OUTPUT_STREAM_INFO stream_info = { 0 }; - MFT_OUTPUT_DATA_BUFFER out_buffer; - unsigned int buffer_size; - IMFMediaBuffer *buffer; DWORD status; HRESULT hr; if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) - { - WARN("Failed to get output stream info, hr %#lx.\n", hr); return hr; - } + stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); for (;;) { - memset(&out_buffer, 0, sizeof(out_buffer)); - - if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))) - { - if (FAILED(hr = MFCreateSample(&out_buffer.pSample))) - break; + MFT_OUTPUT_DATA_BUFFER out_buffer = {0}; - buffer_size = max(stream_info.cbSize, entry->min_buffer_size); - - if (FAILED(hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info.cbAlignment, &buffer))) - { - IMFSample_Release(out_buffer.pSample); - break; - } - - IMFSample_AddBuffer(out_buffer.pSample, buffer); - IMFMediaBuffer_Release(buffer); - } + if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) + && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) + break; if (FAILED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) { From 6a6477e704702b253a3abbc3652cc2951c1ca7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 22:04:55 +0100 Subject: [PATCH 172/301] mfreadwrite/reader: Introduce new source_reader_(drain|flush)_transform_samples helpers. (cherry picked from commit c20fc715e219dbf09ea971d577456d516367c8a6) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 40 ++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8722dc371f2..8f9ef55be63 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -714,6 +714,31 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader return hr; } +static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry) +{ + HRESULT hr; + + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0))) + WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr); + if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry)) + && hr != MF_E_TRANSFORM_NEED_MORE_INPUT) + WARN("Failed to pull pending samples, hr %#lx.\n", hr); + + return S_OK; +} + +static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry) +{ + HRESULT hr; + + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0))) + WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr); + + return S_OK; +} + static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream, IMFSample *sample) { @@ -824,11 +849,10 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re stream->state = STREAM_STATE_EOS; stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED; - if (stream->decoder.transform && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder.transform, - MFT_MESSAGE_COMMAND_DRAIN, 0))) + if (stream->decoder.transform) { - if ((hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder)) != MF_E_TRANSFORM_NEED_MORE_INPUT) - WARN("Failed to pull pending samples, hr %#lx.\n", hr); + if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, &stream->decoder))) + WARN("Failed to drain pending samples, hr %#lx.\n", hr); } while (stream->requests) @@ -1187,10 +1211,16 @@ static void source_reader_release_responses(struct source_reader *reader, struct static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index) { struct media_stream *stream = &reader->streams[stream_index]; + HRESULT hr; source_reader_release_responses(reader, stream); + if (stream->decoder.transform) - IMFTransform_ProcessMessage(stream->decoder.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + { + if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, &stream->decoder))) + WARN("Failed to drain pending samples, hr %#lx.\n", hr); + } + stream->requests = 0; } From 210dd730205e054b6b44c5f4c626e7ab26e80e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 22:16:29 +0100 Subject: [PATCH 173/301] mfreadwrite/reader: Repeat pushing / pulling samples while it succeeds. (cherry picked from commit 75fa35ad7fa2e1acaff0f2724bfe08a6242ecc60) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 51 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8f9ef55be63..5e970f2be0c 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -678,6 +678,26 @@ static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info return hr; } +static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry); +static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry, IMFSample *sample) +{ + HRESULT hr; + + do + { + if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry)) + && hr != MF_E_TRANSFORM_NEED_MORE_INPUT) + return hr; + if (SUCCEEDED(hr = IMFTransform_ProcessInput(entry->transform, 0, sample, 0))) + return source_reader_pull_transform_samples(reader, stream, entry); + } + while (hr == MF_E_NOTACCEPTING); + + return hr; +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { @@ -689,7 +709,7 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader return hr; stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); - for (;;) + while (SUCCEEDED(hr)) { MFT_OUTPUT_DATA_BUFFER out_buffer = {0}; @@ -697,14 +717,9 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) break; - if (FAILED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) - { - if (out_buffer.pSample) - IMFSample_Release(out_buffer.pSample); - break; - } + if (SUCCEEDED(hr = IMFTransform_ProcessOutput(stream->decoder.transform, 0, 1, &out_buffer, &status))) + hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); - source_reader_queue_sample(reader, stream, out_buffer.pSample); if (out_buffer.pSample) IMFSample_Release(out_buffer.pSample); if (out_buffer.pEvents) @@ -748,19 +763,9 @@ static HRESULT source_reader_process_sample(struct source_reader *reader, struct return source_reader_queue_sample(reader, stream, sample); /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ - - hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder); - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) - { - if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder.transform, 0, sample, 0))) - { - WARN("Transform failed to process input, hr %#lx.\n", hr); - return hr; - } - - if ((hr = source_reader_pull_transform_samples(reader, stream, &stream->decoder)) == MF_E_TRANSFORM_NEED_MORE_INPUT) - return S_OK; - } + if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, &stream->decoder, sample)) + || hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK; else WARN("Transform failed to process output, hr %#lx.\n", hr); @@ -797,12 +802,8 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader, if (id == reader->streams[i].id) { /* FIXME: propagate processing errors? */ - reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED; hr = source_reader_process_sample(reader, &reader->streams[i], sample); - if (reader->streams[i].requests) - source_reader_request_sample(reader, &reader->streams[i]); - break; } } From 9fd67c9e8a2762e76f5110480b3c0ecd51d9013e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Jan 2024 22:01:14 +0100 Subject: [PATCH 174/301] mfreadwrite/reader: Split source_reader_create_decoder_for_stream helper. (cherry picked from commit 7325dd4a5a36c9907897e951d98ccbc3d8dc0467) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 61 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 5e970f2be0c..7a35517f4d8 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1825,56 +1825,53 @@ static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWO return MF_E_TOPO_CODEC_NOT_FOUND; } -static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) +static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, + IMFMediaType *input_type, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; - CLSID *clsids, mft_clsid, category; - unsigned int i = 0, count; - IMFMediaType *input_type; + GUID *classes, category; HRESULT hr; + UINT count; - /* TODO: should we check if the source type is compressed? */ - - if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))) + if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) + return hr; + if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype))) return hr; if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video)) - { category = MFT_CATEGORY_VIDEO_DECODER; - } else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) - { category = MFT_CATEGORY_AUDIO_DECODER; - } else - { - WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType)); return MF_E_TOPO_CODEC_NOT_FOUND; + + count = 0; + if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) + { + if (!count) + return MF_E_TOPO_CODEC_NOT_FOUND; + /* TODO: Should we iterate over all of them? */ + hr = source_reader_configure_decoder(reader, index, &classes[0], input_type, output_type); + CoTaskMemFree(classes); } - if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype))) - return hr; + return hr; +} - in_type.guidMajorType = out_type.guidMajorType; +static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) +{ + IMFMediaType *input_type; + unsigned int i = 0; + HRESULT hr; - while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK) + while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { - if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) + if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) { - count = 0; - if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count) - { - mft_clsid = clsids[0]; - CoTaskMemFree(clsids); - - /* TODO: Should we iterate over all of them? */ - if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type))) - { - IMFMediaType_Release(input_type); - return S_OK; - } - - } + IMFMediaType_Release(input_type); + return S_OK; } IMFMediaType_Release(input_type); From b12f7cf215bb2abd3efd7096652015e35b413ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 1 Mar 2024 14:57:24 +0100 Subject: [PATCH 175/301] mf/topology_loader: Only propagate some media type attributes. (cherry picked from commit ba3799527c64070418bf1500522b80040c9e702c) CW-Bug-Id: #20833 --- dlls/mf/topology_loader.c | 60 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index ad442a10cba..447fbfa04dd 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -215,26 +215,50 @@ static HRESULT topology_node_list_branches(IMFTopologyNode *node, struct list *b return hr; } -static HRESULT topology_branch_fill_media_type(IMFMediaType *up_type, IMFMediaType *down_type) +static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) { - HRESULT hr = S_OK; PROPVARIANT value; - UINT32 count; - GUID key; - if (FAILED(hr = IMFMediaType_GetCount(up_type, &count))) - return hr; + PropVariantInit(&value); + if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL)) + && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value))) + *hr = IMFMediaType_SetItem(dst, attr, &value); + PropVariantClear(&value); +} - while (count--) - { - PropVariantInit(&value); - hr = IMFMediaType_GetItemByIndex(up_type, count, &key, &value); - if (SUCCEEDED(hr) && FAILED(IMFMediaType_GetItem(down_type, &key, NULL))) - hr = IMFMediaType_SetItem(down_type, &key, &value); - PropVariantClear(&value); - if (FAILED(hr)) - return hr; - } +/* update a media type with additional attributes reported by upstream element */ +/* also present in mfreadwrite/reader.c pipeline */ +static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +{ + 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); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); + + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr); + 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); + + /* 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); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr); return hr; } @@ -310,7 +334,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); if (down_type) { - if (SUCCEEDED(topology_branch_fill_media_type(up_type, down_type)) + if (SUCCEEDED(update_media_type_from_upstream(down_type, up_type)) && SUCCEEDED(IMFTransform_SetOutputType(transform, 0, down_type, 0))) method = MF_CONNECT_DIRECT; } @@ -319,7 +343,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC if (SUCCEEDED(hr) && method != MF_CONNECT_DIRECT && SUCCEEDED(IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) { - if (SUCCEEDED(topology_branch_fill_media_type(up_type, media_type))) + if (SUCCEEDED(update_media_type_from_upstream(media_type, up_type))) IMFTransform_SetOutputType(transform, 0, media_type, 0); IMFMediaType_Release(media_type); } From 1f50c3329c99c95eec662d9b3831ad678d596522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 28 Feb 2024 16:16:57 +0100 Subject: [PATCH 176/301] mfreadwrite/reader: Call SetOutputType directly on the decoder transform. (cherry picked from commit 48cb5297e783e5525b1ec87c971150800720f235) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 170 ++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 72 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 7a35517f4d8..916d955b7f1 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -678,6 +678,54 @@ static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info return hr; } +static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) +{ + PROPVARIANT value; + + PropVariantInit(&value); + if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL)) + && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value))) + *hr = IMFMediaType_SetItem(dst, attr, &value); + PropVariantClear(&value); +} + +/* 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) +{ + 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); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); + + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr); + 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); + + /* 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); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr); + + return hr; +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry); static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream, @@ -1756,82 +1804,16 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; } -static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid, - IMFMediaType *input_type, IMFMediaType *output_type) -{ - IMFMediaTypeHandler *type_handler; - unsigned int block_alignment = 0; - IMFTransform *transform = NULL; - IMFMediaType *type = NULL; - GUID major = { 0 }; - DWORD flags; - HRESULT hr; - int i = 0; - - if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) - { - WARN("Failed to create transform object, hr %#lx.\n", hr); - return hr; - } - - if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))) - { - WARN("Failed to set decoder input type, hr %#lx.\n", hr); - IMFTransform_Release(transform); - return hr; - } - - /* Find the relevant output type. */ - while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK) - { - flags = 0; - - if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags))) - { - if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES) - { - if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0))) - { - if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) - { - IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type); - IMFMediaTypeHandler_Release(type_handler); - } - - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current))) - WARN("Failed to copy attributes, hr %#lx.\n", hr); - if (SUCCEEDED(IMFMediaType_GetMajorType(type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)) - IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment); - IMFMediaType_Release(type); - - if (reader->streams[index].decoder.transform) - IMFTransform_Release(reader->streams[index].decoder.transform); - - reader->streams[index].decoder.transform = transform; - reader->streams[index].decoder.min_buffer_size = block_alignment; - - return S_OK; - } - } - } - - IMFMediaType_Release(type); - } - - WARN("Failed to find suitable decoder output type.\n"); - - IMFTransform_Release(transform); - - return MF_E_TOPO_CODEC_NOT_FOUND; -} - static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, IMFMediaType *input_type, IMFMediaType *output_type) { + struct media_stream *stream = &reader->streams[index]; + struct transform_entry *entry = &stream->decoder; MFT_REGISTER_TYPE_INFO in_type, out_type; GUID *classes, category; + IMFTransform *transform; + UINT i, count; HRESULT hr; - UINT count; if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType)) || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) @@ -1847,13 +1829,39 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR else return MF_E_TOPO_CODEC_NOT_FOUND; + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) + IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, + &entry->min_buffer_size); + count = 0; if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) { if (!count) return MF_E_TOPO_CODEC_NOT_FOUND; - /* TODO: Should we iterate over all of them? */ - hr = source_reader_configure_decoder(reader, index, &classes[0], input_type, output_type); + + for (i = 0; i < count; i++) + { + IMFMediaType *media_type; + + if (FAILED(hr = CoCreateInstance(&classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) + break; + 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))) + hr = IMFTransform_SetOutputType(transform, 0, output_type, 0); + IMFMediaType_Release(media_type); + + if (SUCCEEDED(hr)) + { + entry->transform = transform; + return S_OK; + } + } + + IMFTransform_Release(transform); + } + CoTaskMemFree(classes); } @@ -1862,6 +1870,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { + struct media_stream *stream = &reader->streams[index]; IMFMediaType *input_type; unsigned int i = 0; HRESULT hr; @@ -1870,6 +1879,23 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea { if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) { + IMFMediaTypeHandler *type_handler; + + if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type))) + WARN("Failed to set current input media type, hr %#lx\n", hr); + IMFMediaTypeHandler_Release(type_handler); + } + + if (FAILED(hr = IMFTransform_GetOutputCurrentType(stream->decoder.transform, 0, &output_type))) + WARN("Failed to get decoder output media type, hr %#lx\n", hr); + else + { + IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current); + IMFMediaType_Release(output_type); + } + IMFMediaType_Release(input_type); return S_OK; } From cb94e31c22cc5fd395135c514d7dbfc13a1ddfc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Jan 2024 22:33:19 +0100 Subject: [PATCH 177/301] mfreadwrite/reader: Keep the stream transforms in a list. (cherry picked from commit d6c9ac94d2fc92d86639e74699ef470b1d8a9861) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 133 +++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 30 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 916d955b7f1..8915beae220 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -73,6 +73,7 @@ enum media_stream_flags struct transform_entry { + struct list entry; IMFTransform *transform; unsigned int min_buffer_size; }; @@ -81,7 +82,7 @@ struct media_stream { IMFMediaStream *stream; IMFMediaType *current; - struct transform_entry decoder; + struct list transforms; IMFVideoSampleAllocatorEx *allocator; DWORD id; unsigned int index; @@ -202,6 +203,30 @@ static ULONG source_reader_addref(struct source_reader *reader) return InterlockedIncrement(&reader->refcount); } +static void transform_entry_destroy(struct transform_entry *entry) +{ + IMFTransform_Release(entry->transform); + free(entry); +} + +static void media_stream_destroy(struct media_stream *stream) +{ + struct transform_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) + { + list_remove(&entry->entry); + transform_entry_destroy(entry); + } + + if (stream->stream) + IMFMediaStream_Release(stream->stream); + if (stream->current) + IMFMediaType_Release(stream->current); + if (stream->allocator) + IMFVideoSampleAllocatorEx_Release(stream->allocator); +} + static ULONG source_reader_release(struct source_reader *reader) { ULONG refcount = InterlockedDecrement(&reader->refcount); @@ -222,15 +247,7 @@ static ULONG source_reader_release(struct source_reader *reader) for (i = 0; i < reader->stream_count; ++i) { struct media_stream *stream = &reader->streams[i]; - - if (stream->stream) - IMFMediaStream_Release(stream->stream); - if (stream->current) - IMFMediaType_Release(stream->current); - if (stream->decoder.transform) - IMFTransform_Release(stream->decoder.transform); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); + media_stream_destroy(stream); } source_reader_release_responses(reader, NULL); free(reader->streams); @@ -749,10 +766,15 @@ static HRESULT source_reader_push_transform_samples(struct source_reader *reader static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { - MFT_OUTPUT_STREAM_INFO stream_info = { 0 }; + MFT_OUTPUT_STREAM_INFO stream_info = {0}; + struct transform_entry *next = NULL; + struct list *ptr; DWORD status; HRESULT hr; + if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) return hr; stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); @@ -765,8 +787,13 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) break; - if (SUCCEEDED(hr = IMFTransform_ProcessOutput(stream->decoder.transform, 0, 1, &out_buffer, &status))) - hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); + if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) + { + if (next) + hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample); + else + hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); + } if (out_buffer.pSample) IMFSample_Release(out_buffer.pSample); @@ -780,38 +807,51 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { + struct transform_entry *next = NULL; + struct list *ptr; HRESULT hr; + if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0))) WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr); if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry)) && hr != MF_E_TRANSFORM_NEED_MORE_INPUT) WARN("Failed to pull pending samples, hr %#lx.\n", hr); - return S_OK; + return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK; } static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { + struct transform_entry *next = NULL; + struct list *ptr; HRESULT hr; + if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0))) WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr); - return S_OK; + return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK; } static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream, IMFSample *sample) { + struct transform_entry *entry; + struct list *ptr; HRESULT hr; - if (!stream->decoder.transform) + if (!(ptr = list_head(&stream->transforms))) return source_reader_queue_sample(reader, stream, sample); + entry = LIST_ENTRY(ptr, struct transform_entry, entry); /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ - if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, &stream->decoder, sample)) + if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample)) || hr == MF_E_TRANSFORM_NEED_MORE_INPUT) hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK; else @@ -895,12 +935,16 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re switch (event_type) { case MEEndOfStream: + { + struct list *ptr; + stream->state = STREAM_STATE_EOS; stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED; - if (stream->decoder.transform) + if ((ptr = list_head(&stream->transforms))) { - if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, &stream->decoder))) + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry))) WARN("Failed to drain pending samples, hr %#lx.\n", hr); } @@ -908,6 +952,7 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL); break; + } case MEStreamSeeked: case MEStreamStarted: stream->state = STREAM_STATE_READY; @@ -1260,13 +1305,15 @@ static void source_reader_release_responses(struct source_reader *reader, struct static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index) { struct media_stream *stream = &reader->streams[stream_index]; + struct list *ptr; HRESULT hr; source_reader_release_responses(reader, stream); - if (stream->decoder.transform) + if ((ptr = list_head(&stream->transforms))) { - if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, &stream->decoder))) + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry))) WARN("Failed to drain pending samples, hr %#lx.\n", hr); } @@ -1701,6 +1748,8 @@ static HRESULT source_reader_get_source_type_handler(struct source_reader *reade static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type) { + struct media_stream *stream = &reader->streams[index]; + struct transform_entry *entry, *next; IMFMediaTypeHandler *type_handler; IMFMediaType *native_type; BOOL type_set = FALSE; @@ -1708,7 +1757,7 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea DWORD flags; HRESULT hr; - if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags))) + if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags))) return hr; if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES)) @@ -1718,6 +1767,12 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA) return S_OK; + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) + { + list_remove(&entry->entry); + transform_entry_destroy(entry); + } + if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler))) return hr; @@ -1728,7 +1783,7 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags) { if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type)))) - IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current); + IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current); } IMFMediaType_Release(native_type); @@ -1804,12 +1859,11 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; } -static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, - IMFMediaType *input_type, IMFMediaType *output_type) +static HRESULT source_reader_create_transform(struct source_reader *reader, + IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out) { - struct media_stream *stream = &reader->streams[index]; - struct transform_entry *entry = &stream->decoder; MFT_REGISTER_TYPE_INFO in_type, out_type; + struct transform_entry *entry; GUID *classes, category; IMFTransform *transform; UINT i, count; @@ -1829,6 +1883,9 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR else return MF_E_TOPO_CODEC_NOT_FOUND; + if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size); @@ -1855,6 +1912,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR if (SUCCEEDED(hr)) { entry->transform = transform; + *out = entry; return S_OK; } } @@ -1865,6 +1923,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR CoTaskMemFree(classes); } + free(entry); return hr; } @@ -1877,10 +1936,14 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { - if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) + struct transform_entry *entry; + + if (SUCCEEDED(hr = source_reader_create_transform(reader, input_type, output_type, &entry))) { IMFMediaTypeHandler *type_handler; + list_add_tail(&stream->transforms, &entry->entry); + if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) { if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type))) @@ -1888,7 +1951,7 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea IMFMediaTypeHandler_Release(type_handler); } - if (FAILED(hr = IMFTransform_GetOutputCurrentType(stream->decoder.transform, 0, &output_type))) + if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) WARN("Failed to get decoder output media type, hr %#lx\n", hr); else { @@ -2192,6 +2255,7 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D REFIID riid, void **object) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + struct media_stream *stream = &reader->streams[index]; IUnknown *obj = NULL; HRESULT hr = S_OK; @@ -2214,7 +2278,14 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D hr = MF_E_INVALIDSTREAMNUMBER; else { - obj = (IUnknown *)reader->streams[index].decoder.transform; + struct list *ptr; + + if ((ptr = list_tail(&stream->transforms))) + { + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + obj = (IUnknown *)entry->transform; + } + if (!obj) hr = E_NOINTERFACE; } break; @@ -2437,6 +2508,8 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri IMFMediaType *src_type; BOOL selected; + list_init(&object->streams[i].transforms); + if (FAILED(hr = MFCreateMediaType(&object->streams[i].current))) break; From f5a6ec58a5e50b4516f88cec6e21f8f8910b2e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 28 Feb 2024 16:17:47 +0100 Subject: [PATCH 178/301] mfreadwrite/reader: Create and append a converter transform. This enables advanced color conversion in all cases, and thus allows NV12 -> RGB32 conversion even when MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING is not set. This should be harmless and makes the code simpler as we can simply append a VideoProcessor transform in all cases. The tests todos is tweaked to reflect cases where a single processor is used, which outputs slightly different attributes to when it is connected to an upstream decoder. Ultimately we could try to match native here, but it shouldn't matter too much in the meantime. (cherry picked from commit ea4b9bafb2f18ae0805c166e49bbb03641fc066c) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 95 +++++++++++++++++++++++++-------- dlls/mfreadwrite/tests/mfplat.c | 65 +++++++++++++--------- 2 files changed, 114 insertions(+), 46 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8915beae220..eb9c6866133 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -76,6 +76,7 @@ struct transform_entry struct list entry; IMFTransform *transform; unsigned int min_buffer_size; + GUID category; }; struct media_stream @@ -84,6 +85,7 @@ struct media_stream IMFMediaType *current; struct list transforms; IMFVideoSampleAllocatorEx *allocator; + IMFTransform *transform_service; DWORD id; unsigned int index; enum media_stream_state state; @@ -1767,6 +1769,11 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA) return S_OK; + if (stream->transform_service) + { + IMFTransform_Release(stream->transform_service); + stream->transform_service = NULL; + } LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) { list_remove(&entry->entry); @@ -1859,7 +1866,23 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; } -static HRESULT source_reader_create_transform(struct source_reader *reader, +static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced) +{ + UINT32 value; + + *advanced = FALSE; + if (!reader->attributes) + return FALSE; + + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value))) + *advanced = value; + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value))) + return value || *advanced; + + return *advanced; +} + +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) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -1877,21 +1900,23 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, return hr; if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video)) - category = MFT_CATEGORY_VIDEO_DECODER; + category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR; else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) - category = MFT_CATEGORY_AUDIO_DECODER; + category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT; else return MF_E_TOPO_CODEC_NOT_FOUND; if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + list_init(&entry->entry); + entry->category = category; if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size); count = 0; - if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) + if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count))) { if (!count) return MF_E_TOPO_CODEC_NOT_FOUND; @@ -1905,9 +1930,19 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, 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))) - hr = IMFTransform_SetOutputType(transform, 0, output_type, 0); - IMFMediaType_Release(media_type); + if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && allow_processor + && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) + { + 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 = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter))) + list_add_tail(&entry->entry, &converter->entry); + + IMFMediaType_Release(media_type); + } if (SUCCEEDED(hr)) { @@ -1929,20 +1964,46 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { + BOOL enable_advanced, allow_processor; struct media_stream *stream = &reader->streams[index]; IMFMediaType *input_type; unsigned int i = 0; HRESULT hr; + allow_processor = source_reader_allow_video_processor(reader, &enable_advanced); + while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { struct transform_entry *entry; - if (SUCCEEDED(hr = source_reader_create_transform(reader, input_type, output_type, &entry))) + /* first, try to append a single processor, then try again with a decoder and a processor */ + if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry))) + || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry))) { + struct list *ptr = list_head(&entry->entry); + struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry; IMFMediaTypeHandler *type_handler; - list_add_tail(&stream->transforms, &entry->entry); + if (enable_advanced) + { + /* when advanced video processing is enabled, converters are exposed as stream transform service */ + stream->transform_service = service->transform; + IMFTransform_AddRef(stream->transform_service); + } + else + { + /* when advanced video processing is disabled, only decoders are exposed as stream transform service */ + if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER) + || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER)) + { + stream->transform_service = entry->transform; + IMFTransform_AddRef(stream->transform_service); + } + } + + /* move any additional transforms that have been created */ + list_move_head(&stream->transforms, &entry->entry); + list_add_head(&stream->transforms, &entry->entry); if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) { @@ -1951,7 +2012,7 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea IMFMediaTypeHandler_Release(type_handler); } - if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) + if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type))) WARN("Failed to get decoder output media type, hr %#lx\n", hr); else { @@ -2276,18 +2337,8 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D if (index >= reader->stream_count) hr = MF_E_INVALIDSTREAMNUMBER; - else - { - struct list *ptr; - - if ((ptr = list_tail(&stream->transforms))) - { - struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); - obj = (IUnknown *)entry->transform; - } - - if (!obj) hr = E_NOINTERFACE; - } + else if (!(obj = (IUnknown *)stream->transform_service)) + hr = E_NOINTERFACE; break; } diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 2095d2f054d..54b550dfe43 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -909,7 +909,7 @@ static void test_source_reader(const char *filename, bool video) hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReader_SetCurrentMediaType(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, mediatype); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(mediatype); if (hr == S_OK) @@ -922,7 +922,7 @@ static void test_source_reader(const char *filename, bool video) ok(IsEqualGUID(&subtype, &MFVideoFormat_RGB32), "Got subtype %s.\n", debugstr_guid(&subtype)); hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_DEFAULT_STRIDE, &stride); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); todo_wine ok(stride == 160 * 4, "Got stride %u.\n", stride); IMFMediaType_Release(mediatype); @@ -1687,7 +1687,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc nv12_expect_advanced_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), @@ -1721,7 +1721,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc yuy2_expect_advanced_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), @@ -1738,7 +1738,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc rgb32_expect_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 384, .todo = TRUE), @@ -1746,15 +1746,24 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_SAMPLE_SIZE, 36864, .todo = TRUE), {0}, }; - static const struct attribute_desc rgb32_expect_advanced_desc[] = + static const struct attribute_desc rgb32_expect_advanced_desc_todo1[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), 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), }; + static const struct attribute_desc rgb32_expect_advanced_desc_todo2[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + 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), + }; IMFStreamDescriptor *video_stream; IMFSourceReaderEx *reader_ex; IMFAttributes *attributes; @@ -1840,16 +1849,21 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, nv12_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else + { + todo_wine_if(enable_processing) /* Wine enables advanced video processing in all cases */ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + } IMFMediaType_Release(media_type); hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) check_media_type(media_type, nv12_expect_advanced_desc, -1); - else + else if (!enable_processing) + check_media_type(media_type, rgb32_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ check_media_type(media_type, rgb32_stream_type_desc, -1); IMFMediaType_Release(media_type); @@ -1858,7 +1872,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -1912,7 +1926,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, rgb32_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_processing || enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); @@ -1920,7 +1934,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) - check_media_type(media_type, rgb32_expect_advanced_desc, -1); + check_media_type(media_type, rgb32_expect_advanced_desc_todo1, -1); else if (enable_processing) check_media_type(media_type, rgb32_expect_desc, -1); else @@ -1932,7 +1946,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -1954,19 +1968,22 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, yuy2_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else + { + todo_wine_if(enable_processing) /* Wine enables advanced video processing in all cases */ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + } IMFMediaType_Release(media_type); hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) check_media_type(media_type, yuy2_expect_advanced_desc, -1); - else if (enable_processing) - check_media_type(media_type, rgb32_expect_desc, -1); - else + else if (!enable_processing) check_media_type(media_type, nv12_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ + check_media_type(media_type, rgb32_expect_desc, -1); IMFMediaType_Release(media_type); /* convert transform is only exposed with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ @@ -1974,7 +1991,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2058,7 +2075,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, rgb32_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_processing || enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); @@ -2066,11 +2083,11 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) - check_media_type(media_type, rgb32_expect_advanced_desc, -1); - else if (enable_processing) - check_media_type(media_type, rgb32_expect_desc, -1); - else + check_media_type(media_type, rgb32_expect_advanced_desc_todo2, -1); + else if (!enable_processing) check_media_type(media_type, h264_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ + check_media_type(media_type, rgb32_expect_desc, -1); IMFMediaType_Release(media_type); /* the exposed transform is the H264 decoder or the converter with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ @@ -2078,7 +2095,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_processing && !enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); From 8dbe15582aeb912721dc0cff72ffe7fb336f99b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 22:28:08 +0100 Subject: [PATCH 179/301] mfreadwrite/reader: Implement IMFSourceReaderEx_GetTransformForStream. (cherry picked from commit 440edde5e1c674bf851e3681a6a20b39d422dac2) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 50 +++++++++++++++++++++++++++++++-- dlls/mfreadwrite/tests/mfplat.c | 20 ++++++------- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index eb9c6866133..59d0f337fb4 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -77,6 +77,7 @@ struct transform_entry IMFTransform *transform; unsigned int min_buffer_size; GUID category; + BOOL hidden; }; struct media_stream @@ -1998,6 +1999,15 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea { stream->transform_service = entry->transform; IMFTransform_AddRef(stream->transform_service); + + /* converters are hidden from the stream transforms */ + if (service != entry) + service->hidden = TRUE; + } + else + { + /* converters are hidden from the stream transforms */ + entry->hidden = TRUE; } } @@ -2443,12 +2453,48 @@ static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx return E_NOTIMPL; } +static struct transform_entry *get_transform_at_index(struct media_stream *stream, UINT index) +{ + struct transform_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &stream->transforms, struct transform_entry, entry) + if (!entry->hidden && !index--) + return entry; + + return NULL; +} + static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index, DWORD transform_index, GUID *category, IMFTransform **transform) { - FIXME("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + struct transform_entry *entry; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + + EnterCriticalSection(&reader->cs); + + if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM) + stream_index = reader->first_video_stream_index; + else if (stream_index == MF_SOURCE_READER_FIRST_AUDIO_STREAM) + stream_index = reader->first_audio_stream_index; + + if (stream_index >= reader->stream_count) + hr = MF_E_INVALIDSTREAMNUMBER; + else if (!(entry = get_transform_at_index(&reader->streams[stream_index], transform_index))) + hr = MF_E_INVALIDINDEX; + else + { + *category = entry->category; + *transform = entry->transform; + IMFTransform_AddRef(*transform); + hr = S_OK; + } + + LeaveCriticalSection(&reader->cs); + + return hr; } static const IMFSourceReaderExVtbl srcreader_vtbl = diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 54b550dfe43..5f282743e29 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2011,9 +2011,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); if (!enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2030,7 +2030,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad } hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex); IMFSourceReader_Release(reader); @@ -2123,9 +2123,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); if (!enable_processing && !enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2144,9 +2144,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad /* the video processor can be accessed at index 1 with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); if (!enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2163,7 +2163,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad } hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 2, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex); /* H264 -> NV12 conversion */ @@ -2212,7 +2212,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2242,7 +2242,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad } hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex); skip_tests: From adb81eecd6413d92b9d8d62ab92a1dd0c6811cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 18:19:11 +0100 Subject: [PATCH 180/301] mfreadwrite/reader: Adjust min_buffer_size to be 1s of audio data. (cherry picked from commit bf800b5e76b808ee0b50be3349a6d5a037c77e36) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 59d0f337fb4..772b94f9e2e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1912,9 +1912,14 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL list_init(&entry->entry); entry->category = category; - if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) - IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, - &entry->min_buffer_size); + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio) + && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size))) + { + UINT32 bytes_per_second; + + if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) + entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second); + } count = 0; if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count))) From 0c7be2fbb9fad7474c9149686dfb480303d7efab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Jan 2024 15:08:51 +0100 Subject: [PATCH 181/301] mfreadwrite/reader: Handle MF_E_TRANSFORM_STREAM_CHANGE results. (cherry picked from commit 14743b0ffb0ce2e788801b27364790c5ac55d7f9) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 772b94f9e2e..fc96c44ba4e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -76,6 +76,7 @@ struct transform_entry struct list entry; IMFTransform *transform; unsigned int min_buffer_size; + UINT32 pending_flags; GUID category; BOOL hidden; }; @@ -484,14 +485,14 @@ static HRESULT source_reader_queue_response(struct source_reader *reader, struct } static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream, - IMFSample *sample) + UINT flags, IMFSample *sample) { LONGLONG timestamp = 0; if (FAILED(IMFSample_GetSampleTime(sample, ×tamp))) WARN("Sample time wasn't set.\n"); - return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample); + return source_reader_queue_response(reader, stream, S_OK, flags, timestamp, sample); } static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream) @@ -785,6 +786,7 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader while (SUCCEEDED(hr)) { MFT_OUTPUT_DATA_BUFFER out_buffer = {0}; + IMFMediaType *output_type, *media_type; if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) @@ -792,10 +794,46 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) { - if (next) + if ((entry->pending_flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) + && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) + { + if (!next) + hr = IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current); + else if (SUCCEEDED(hr = IMFTransform_SetInputType(next->transform, 0, output_type, 0))) + { + /* check if transform output type is still valid or if we need to reset it as well */ + if (FAILED(hr = IMFTransform_GetOutputCurrentType(next->transform, 0, &media_type)) + && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(next->transform, 0, 0, &output_type))) + { + next->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED; + hr = IMFTransform_SetOutputType(entry->transform, 0, media_type, 0); + IMFMediaType_Release(media_type); + } + } + IMFMediaType_Release(output_type); + } + + if (FAILED(hr)) + source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL); + else if (next) hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample); else - hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); + hr = source_reader_queue_sample(reader, stream, entry->pending_flags, out_buffer.pSample); + + entry->pending_flags = 0; + } + + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(entry->transform, 0, 0, &output_type))) + { + hr = IMFTransform_SetOutputType(entry->transform, 0, output_type, 0); + IMFMediaType_Release(output_type); + + if (SUCCEEDED(hr)) + { + hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info); + stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); + entry->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED; + } } if (out_buffer.pSample) @@ -850,7 +888,7 @@ static HRESULT source_reader_process_sample(struct source_reader *reader, struct HRESULT hr; if (!(ptr = list_head(&stream->transforms))) - return source_reader_queue_sample(reader, stream, sample); + return source_reader_queue_sample(reader, stream, 0, sample); entry = LIST_ENTRY(ptr, struct transform_entry, entry); /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ From d4d6b764e9d782b8cc26c831e6d5b4b2124c8507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Mar 2024 14:55:31 +0100 Subject: [PATCH 182/301] mfreadwrite/reader: Use MFTEnumEx to enumerate stream transforms. (cherry picked from commit 17fd8c8e11eabae136be25879b8748fed57b85fc) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index fc96c44ba4e..d31238c7266 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1926,7 +1926,8 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL { MFT_REGISTER_TYPE_INFO in_type, out_type; struct transform_entry *entry; - GUID *classes, category; + IMFActivate **activates; + GUID category; IMFTransform *transform; UINT i, count; HRESULT hr; @@ -1960,7 +1961,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL } count = 0; - if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count))) + if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count))) { if (!count) return MF_E_TOPO_CODEC_NOT_FOUND; @@ -1969,8 +1970,8 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL { IMFMediaType *media_type; - if (FAILED(hr = CoCreateInstance(&classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) - break; + if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) + continue; if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { @@ -1992,17 +1993,20 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL { entry->transform = transform; *out = entry; - return S_OK; + break; } } IMFTransform_Release(transform); } - CoTaskMemFree(classes); + for (i = 0; i < count; ++i) + IMFActivate_Release(activates[i]); + CoTaskMemFree(activates); } - free(entry); + if (FAILED(hr)) + free(entry); return hr; } From ebbd3c2b572a0f3d50bdc72f9cedde2896739713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Mar 2024 14:58:49 +0100 Subject: [PATCH 183/301] mfreadwrite/reader: Make the GetTransformForStream category parameter optional. (cherry picked from commit b5f7ce42638156769d16a114aa173825cb068be2) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index d31238c7266..e55b1fe5823 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2520,6 +2520,9 @@ static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + if (!transform) + return E_POINTER; + EnterCriticalSection(&reader->cs); if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM) @@ -2533,7 +2536,8 @@ static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, hr = MF_E_INVALIDINDEX; else { - *category = entry->category; + if (category) + *category = entry->category; *transform = entry->transform; IMFTransform_AddRef(*transform); hr = S_OK; From a19fdedb0fbff149d60d94e10381c5ed3ff01928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Mar 2024 19:40:04 +0100 Subject: [PATCH 184/301] mfreadwrite/tests: Test the source reader stream change events. (cherry picked from commit ed5031ebd8315cadf13b58d2250e0f882c8c8e88) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/mfplat.c | 524 ++++++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 5f282743e29..8dd5528b37e 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -39,11 +39,14 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "mferror.h" #include "mfreadwrite.h" #include "propvarutil.h" +#include "initguid.h" #include "d3d9.h" #include "dxva2api.h" #include "wine/test.h" +DEFINE_MEDIATYPE_GUID(MFVideoFormat_TEST,MAKEFOURCC('T','E','S','T')); + struct attribute_desc { const GUID *key; @@ -2255,6 +2258,526 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad winetest_pop_context(); } +struct test_decoder +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFMediaType *input_type; + IMFMediaType *output_type; + + MFVIDEOFORMAT output_format; + HRESULT next_output; +}; + +static struct test_decoder *test_decoder_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct test_decoder, IMFTransform_iface); +} + +static HRESULT WINAPI test_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + { + IMFTransform_AddRef(&decoder->IMFTransform_iface); + *out = &decoder->IMFTransform_iface; + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_decoder_AddRef(IMFTransform *iface) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + return refcount; +} + +static ULONG WINAPI test_decoder_Release(IMFTransform *iface) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + if (!refcount) + { + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + free(decoder); + } + + return refcount; +} + +static HRESULT WINAPI test_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + *inputs = *outputs = 1; + return S_OK; +} + +static HRESULT WINAPI test_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + UINT64 frame_size; + GUID subtype; + + if (!decoder->output_type || FAILED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) + frame_size = (UINT64)96 << 32 | 96; + if (!decoder->output_type || FAILED(IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + subtype = MFVideoFormat_YUY2; + + memset(info, 0, sizeof(*info)); + return MFCalculateImageSize(&MFVideoFormat_RGB32, (UINT32)frame_size, frame_size >> 32, (UINT32 *)&info->cbSize); +} + +static HRESULT WINAPI test_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static void test_decoder_set_output_format(IMFTransform *iface, const MFVIDEOFORMAT *output_format) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + decoder->output_format = *output_format; +} + +static HRESULT WINAPI test_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + const GUID subtypes[] = + { + MFVideoFormat_NV12, + MFVideoFormat_YUY2, + }; + MFVIDEOFORMAT format = + { + .dwSize = sizeof(format), + .videoInfo = + { + .dwWidth = 96, + .dwHeight = 96, + }, + }; + HRESULT hr; + + *type = NULL; + if (index >= ARRAY_SIZE(subtypes)) + return MF_E_NO_MORE_TYPES; + + if (decoder->output_format.dwSize) + format = decoder->output_format; + format.guidFormat = subtypes[index]; + + hr = MFCreateMediaType(type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitMediaTypeFromMFVideoFormat(*type, &format, sizeof(format)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + return hr; +} + +static HRESULT WINAPI test_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if ((decoder->input_type = type)) + IMFMediaType_AddRef(decoder->input_type); + return S_OK; +} + +static HRESULT WINAPI test_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + if ((decoder->output_type = type)) + IMFMediaType_AddRef(decoder->output_type); + return S_OK; +} + +static HRESULT WINAPI test_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + if (!(*type = decoder->input_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + if (!(*type = decoder->output_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + switch (message) + { + case MFT_MESSAGE_COMMAND_FLUSH: + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + case MFT_MESSAGE_NOTIFY_END_STREAMING: + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + return S_OK; + + default: + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; + } +} + +static HRESULT WINAPI test_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + return S_OK; +} + +static void test_decoder_set_next_output(IMFTransform *iface, HRESULT hr) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + decoder->next_output = hr; +} + +static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *data, DWORD *status) +{ + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + + if (decoder->next_output == MF_E_TRANSFORM_STREAM_CHANGE) + { + data[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + decoder->next_output = S_OK; + return MF_E_TRANSFORM_STREAM_CHANGE; + } + + if (decoder->next_output == S_OK) + { + decoder->next_output = MF_E_TRANSFORM_NEED_MORE_INPUT; + return S_OK; + } + + return decoder->next_output; +} + +static const IMFTransformVtbl test_decoder_vtbl = +{ + test_decoder_QueryInterface, + test_decoder_AddRef, + test_decoder_Release, + test_decoder_GetStreamLimits, + test_decoder_GetStreamCount, + test_decoder_GetStreamIDs, + test_decoder_GetInputStreamInfo, + test_decoder_GetOutputStreamInfo, + test_decoder_GetAttributes, + test_decoder_GetInputStreamAttributes, + test_decoder_GetOutputStreamAttributes, + test_decoder_DeleteInputStream, + test_decoder_AddInputStreams, + test_decoder_GetInputAvailableType, + test_decoder_GetOutputAvailableType, + test_decoder_SetInputType, + test_decoder_SetOutputType, + test_decoder_GetInputCurrentType, + test_decoder_GetOutputCurrentType, + test_decoder_GetInputStatus, + test_decoder_GetOutputStatus, + test_decoder_SetOutputBounds, + test_decoder_ProcessEvent, + test_decoder_ProcessMessage, + test_decoder_ProcessInput, + test_decoder_ProcessOutput, +}; + +static HRESULT WINAPI test_mft_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IClassFactory) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_mft_factory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI test_mft_factory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI test_mft_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj) +{ + struct test_decoder *decoder; + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; + decoder->IMFTransform_iface.lpVtbl = &test_decoder_vtbl; + decoder->refcount = 1; + + *obj = &decoder->IMFTransform_iface; + return S_OK; +} + +static HRESULT WINAPI test_mft_factory_LockServer(IClassFactory *iface, BOOL fLock) +{ + return S_OK; +} + +static const IClassFactoryVtbl test_mft_factory_vtbl = +{ + test_mft_factory_QueryInterface, + test_mft_factory_AddRef, + test_mft_factory_Release, + test_mft_factory_CreateInstance, + test_mft_factory_LockServer, +}; + +static void test_source_reader_transform_stream_change(void) +{ + static const struct attribute_desc test_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_TEST), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + {0}, + }; + static const struct attribute_desc yuy2_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), + {0}, + }; + static const struct attribute_desc yuy2_expect_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96 * 2, .todo = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 96 * 96 * 2, .todo = TRUE), + {0}, + }; + static const struct attribute_desc yuy2_expect_new_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, 128, 128), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 128 * 2, .todo_value = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 128 * 128 * 2, .todo_value = TRUE), + {0}, + }; + const MFT_REGISTER_TYPE_INFO output_info[] = + { + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + }; + const MFT_REGISTER_TYPE_INFO input_info[] = + { + {MFMediaType_Video, MFVideoFormat_TEST}, + }; + MFVIDEOFORMAT output_format = {.dwSize = sizeof(output_format)}; + IClassFactory factory = {.lpVtbl = &test_mft_factory_vtbl}; + IMFStreamDescriptor *video_stream; + IMFSourceReaderEx *reader_ex; + IMFTransform *test_decoder; + IMFMediaType *media_type; + IMFSourceReader *reader; + IMFMediaSource *source; + LONGLONG timestamp; + DWORD index, flags; + IMFSample *sample; + GUID category; + HRESULT hr; + + + hr = MFTRegisterLocal(&factory, &MFT_CATEGORY_VIDEO_DECODER, L"Test Decoder", 0, + ARRAY_SIZE(input_info), input_info, ARRAY_SIZE(output_info), output_info); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* test source reader with a custom source */ + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, test_stream_type_desc, -1); + hr = MFCreateStreamDescriptor(0, 1, &media_type, &video_stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + source = create_test_source(&video_stream, 1); + ok(!!source, "Failed to create test source.\n"); + IMFStreamDescriptor_Release(video_stream); + + hr = MFCreateSourceReaderFromMediaSource(source, NULL, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaSource_Release(source); + + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + + hr = IMFSourceReader_GetNativeMediaType(reader, 0, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, yuy2_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, yuy2_expect_desc, -1); + IMFMediaType_Release(media_type); + + + + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(test_decoder->lpVtbl == &test_decoder_vtbl, "got unexpected transform\n"); + IMFSourceReaderEx_Release(reader_ex); + + fail_request_sample = FALSE; + + test_decoder_set_next_output(test_decoder, MF_E_TRANSFORM_STREAM_CHANGE); + + output_format.videoInfo.dwHeight = 128; + output_format.videoInfo.dwWidth = 128; + test_decoder_set_output_format(test_decoder, &output_format); + + sample = (void *)0xdeadbeef; + index = flags = timestamp = 0xdeadbeef; + hr = IMFSourceReader_ReadSample(reader, 0, 0, &index, &flags, ×tamp, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "got %lu.\n", index); + ok(flags == MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED, "got %lu.\n", flags); + ok(timestamp == 0, "got %I64d.\n", timestamp); + ok(sample != (void *)0xdeadbeef, "got %p.\n", sample); + IMFSample_Release(sample); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, yuy2_expect_new_desc, -1); + IMFMediaType_Release(media_type); + + fail_request_sample = TRUE; + + IMFTransform_Release(test_decoder); + + IMFSourceReader_Release(reader); + + hr = MFTUnregisterLocal(&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + START_TEST(mfplat) { HRESULT hr; @@ -2272,6 +2795,7 @@ START_TEST(mfplat) test_source_reader_transforms(FALSE, FALSE); test_source_reader_transforms(TRUE, FALSE); test_source_reader_transforms(FALSE, TRUE); + test_source_reader_transform_stream_change(); test_reader_d3d9(); test_sink_writer_create(); test_sink_writer_mp4(); From de1d2d3525a0fd2321074336b1b257295ac47b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Mar 2024 15:00:51 +0100 Subject: [PATCH 185/301] mfreadwrite/tests: Test the D3D awareness of source reader transforms. (cherry picked from commit 5cd5e7b8c6c07179c2a698ef175c20cfd9ea4087) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/Makefile.in | 2 +- dlls/mfreadwrite/tests/mfplat.c | 387 ++++++++++++++++++++++++++++- 2 files changed, 387 insertions(+), 2 deletions(-) diff --git a/dlls/mfreadwrite/tests/Makefile.in b/dlls/mfreadwrite/tests/Makefile.in index cada1bf22ff..3bdab217148 100644 --- a/dlls/mfreadwrite/tests/Makefile.in +++ b/dlls/mfreadwrite/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfreadwrite.dll -IMPORTS = ole32 user32 d3d9 dxva2 mfplat mfreadwrite mfuuid propsys +IMPORTS = ole32 user32 d3d9 dxva2 mfplat mf mfreadwrite mfuuid propsys SOURCES = \ mfplat.c \ diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 8dd5528b37e..fb52046eefc 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -42,11 +42,42 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "initguid.h" #include "d3d9.h" #include "dxva2api.h" +#include "evr.h" #include "wine/test.h" DEFINE_MEDIATYPE_GUID(MFVideoFormat_TEST,MAKEFOURCC('T','E','S','T')); +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + +#define check_service_interface(a, b, c, d) check_service_interface_(__LINE__, a, b, c, d) +static void check_service_interface_(unsigned int line, void *iface_ptr, REFGUID service, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = MFGetService(iface, service, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + struct attribute_desc { const GUID *key; @@ -2258,11 +2289,17 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad winetest_pop_context(); } +static BOOL test_decoder_d3d_aware; +static BOOL test_decoder_got_d3d_manager; +static BOOL test_decoder_allocate_samples; +static IDirect3DDeviceManager9 *expect_d3d_manager; + struct test_decoder { IMFTransform IMFTransform_iface; LONG refcount; + IMFAttributes *attributes; IMFMediaType *input_type; IMFMediaType *output_type; @@ -2352,12 +2389,18 @@ static HRESULT WINAPI test_decoder_GetOutputStreamInfo(IMFTransform *iface, DWOR subtype = MFVideoFormat_YUY2; memset(info, 0, sizeof(*info)); + if (test_decoder_allocate_samples) + info->dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; return MFCalculateImageSize(&MFVideoFormat_RGB32, (UINT32)frame_size, frame_size >> 32, (UINT32 *)&info->cbSize); } static HRESULT WINAPI test_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { - return E_NOTIMPL; + struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + if (!(*attributes = decoder->attributes)) + return E_NOTIMPL; + IMFAttributes_AddRef(*attributes); + return S_OK; } static HRESULT WINAPI test_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) @@ -2507,6 +2550,22 @@ static HRESULT WINAPI test_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA case MFT_MESSAGE_NOTIFY_START_OF_STREAM: return S_OK; + case MFT_MESSAGE_SET_D3D_MANAGER: + ok(test_decoder_d3d_aware, "Unexpected call.\n"); + if (param) + { + IDirect3DDeviceManager9 *manager; + HRESULT hr; + + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == expect_d3d_manager, "got manager %p\n", manager); + IDirect3DDeviceManager9_Release(manager); + + test_decoder_got_d3d_manager = TRUE; + } + return test_decoder_d3d_aware ? S_OK : E_NOTIMPL; + default: ok(0, "Unexpected call.\n"); return E_NOTIMPL; @@ -2528,6 +2587,38 @@ static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flag MFT_OUTPUT_DATA_BUFFER *data, DWORD *status) { struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + IMFMediaBuffer *buffer; + IUnknown *unknown; + HRESULT hr; + + if (test_decoder_allocate_samples) + { + ok(!data->pSample, "Unexpected sample\n"); + + hr = MFCreateSample(&data->pSample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaBufferFromMediaType(decoder->output_type, 0, 0, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr != S_OK) + { + hr = MFCreateMemoryBuffer(96 * 96 * 4, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + hr = IMFSample_AddBuffer(data->pSample, buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + } + + ok(!!data->pSample, "Missing sample\n"); + + hr = IMFSample_GetBufferByIndex(data->pSample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + todo_wine check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + hr = MFGetService((IUnknown *)buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)&unknown); + todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); if (decoder->next_output == MF_E_TRANSFORM_STREAM_CHANGE) { @@ -2539,6 +2630,8 @@ static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flag if (decoder->next_output == S_OK) { decoder->next_output = MF_E_TRANSFORM_NEED_MORE_INPUT; + hr = IMFSample_SetSampleTime(data->pSample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); return S_OK; } @@ -2602,12 +2695,21 @@ static ULONG WINAPI test_mft_factory_Release(IClassFactory *iface) static HRESULT WINAPI test_mft_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj) { struct test_decoder *decoder; + HRESULT hr; if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; decoder->IMFTransform_iface.lpVtbl = &test_decoder_vtbl; decoder->refcount = 1; + if (test_decoder_d3d_aware) + { + hr = MFCreateAttributes(&decoder->attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + *obj = &decoder->IMFTransform_iface; return S_OK; } @@ -2778,6 +2880,288 @@ static void test_source_reader_transform_stream_change(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } +static void test_source_reader_transforms_d3d(void) +{ + static const struct attribute_desc test_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_TEST), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + {0}, + }; + static const struct attribute_desc rgb32_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + {0}, + }; + static const struct attribute_desc rgb32_expect_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + 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), + {0}, + }; + const MFT_REGISTER_TYPE_INFO output_info[] = + { + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + }; + const MFT_REGISTER_TYPE_INFO input_info[] = + { + {MFMediaType_Video, MFVideoFormat_TEST}, + }; + IClassFactory factory = {.lpVtbl = &test_mft_factory_vtbl}; + IMFTransform *test_decoder, *video_processor; + IDirect3DDeviceManager9 *d3d9_manager; + IMFStreamDescriptor *video_stream; + IDirect3DDevice9 *d3d9_device; + IMFSourceReaderEx *reader_ex; + IMFAttributes *attributes; + IMFMediaType *media_type; + IMFSourceReader *reader; + IMFMediaBuffer *buffer; + IMFMediaSource *source; + LONGLONG timestamp; + DWORD index, flags; + IMFSample *sample; + IDirect3D9 *d3d9; + UINT32 value; + HWND window; + UINT token; + HRESULT hr; + + d3d9 = Direct3DCreate9(D3D_SDK_VERSION); + if (!d3d9) + { + skip("Failed to create a D3D9 object, skipping tests.\n"); + return; + } + + window = create_window(); + if (!(d3d9_device = create_d3d9_device(d3d9, window))) + { + skip("Failed to create a D3D9 device, skipping tests.\n"); + goto done; + } + + test_decoder_d3d_aware = TRUE; + + hr = MFTRegisterLocal(&factory, &MFT_CATEGORY_VIDEO_DECODER, L"Test Decoder", 0, + ARRAY_SIZE(input_info), input_info, ARRAY_SIZE(output_info), output_info); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = DXVA2CreateDirect3DDeviceManager9(&token, &d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + expect_d3d_manager = d3d9_manager; + + + /* test d3d aware decoder that doesn't allocate buffers */ + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, test_stream_type_desc, -1); + hr = MFCreateStreamDescriptor(0, 1, &media_type, &video_stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + source = create_test_source(&video_stream, 1); + ok(!!source, "Failed to create test source.\n"); + IMFStreamDescriptor_Release(video_stream); + + hr = MFCreateSourceReaderFromMediaSource(source, attributes, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFMediaSource_Release(source); + + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSourceReader_GetNativeMediaType(reader, 0, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + ok(!test_decoder_got_d3d_manager, "d3d manager received\n"); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, rgb32_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, rgb32_expect_desc, -1); + IMFMediaType_Release(media_type); + + + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* video processor transform is not D3D aware */ + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* FIXME: Wine skips the video processor as the test decoder accepts the output type directly */ + if (hr == S_OK) + { + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFTransform_Release(video_processor); + } + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(test_decoder->lpVtbl == &test_decoder_vtbl, "got unexpected transform\n"); + hr = IMFTransform_GetAttributes(test_decoder, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 1, "got %u\n", value); + IMFAttributes_Release(attributes); + + IMFSourceReaderEx_Release(reader_ex); + + fail_request_sample = FALSE; + test_decoder_set_next_output(test_decoder, S_OK); + + sample = (void *)0xdeadbeef; + index = flags = timestamp = 0xdeadbeef; + hr = IMFSourceReader_ReadSample(reader, 0, 0, &index, &flags, ×tamp, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "got %lu.\n", index); + ok(flags == 0, "got %lu.\n", flags); + ok(timestamp == 0, "got %I64d.\n", timestamp); + ok(sample != (void *)0xdeadbeef, "got %p.\n", sample); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + check_service_interface(buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, TRUE); + IMFMediaBuffer_Release(buffer); + + IMFSample_Release(sample); + + fail_request_sample = TRUE; + + IMFTransform_Release(test_decoder); + IMFSourceReader_Release(reader); + + + /* test d3d aware decoder that allocates buffers */ + + test_decoder_allocate_samples = TRUE; + + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, test_stream_type_desc, -1); + hr = MFCreateStreamDescriptor(0, 1, &media_type, &video_stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + source = create_test_source(&video_stream, 1); + ok(!!source, "Failed to create test source.\n"); + IMFStreamDescriptor_Release(video_stream); + + hr = MFCreateSourceReaderFromMediaSource(source, attributes, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFMediaSource_Release(source); + + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, rgb32_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + + + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(test_decoder->lpVtbl == &test_decoder_vtbl, "got unexpected transform\n"); + IMFSourceReaderEx_Release(reader_ex); + + fail_request_sample = FALSE; + test_decoder_set_next_output(test_decoder, S_OK); + + sample = (void *)0xdeadbeef; + index = flags = timestamp = 0xdeadbeef; + hr = IMFSourceReader_ReadSample(reader, 0, 0, &index, &flags, ×tamp, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "got %lu.\n", index); + ok(flags == 0, "got %lu.\n", flags); + ok(timestamp == 0, "got %I64d.\n", timestamp); + ok(sample != (void *)0xdeadbeef, "got %p.\n", sample); + + /* the buffer we received is a D3D buffer nonetheless */ + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + check_service_interface(buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, TRUE); + IMFMediaBuffer_Release(buffer); + + IMFSample_Release(sample); + + fail_request_sample = TRUE; + + IMFTransform_Release(test_decoder); + IMFSourceReader_Release(reader); + + test_decoder_allocate_samples = FALSE; + + + hr = MFTUnregisterLocal(&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DDeviceManager9_Release(d3d9_manager); + IDirect3DDevice9_Release(d3d9_device); + +done: + IDirect3D9_Release(d3d9); + DestroyWindow(window); + + test_decoder_d3d_aware = FALSE; +} + START_TEST(mfplat) { HRESULT hr; @@ -2796,6 +3180,7 @@ START_TEST(mfplat) test_source_reader_transforms(TRUE, FALSE); test_source_reader_transforms(FALSE, TRUE); test_source_reader_transform_stream_change(); + test_source_reader_transforms_d3d(); test_reader_d3d9(); test_sink_writer_create(); test_sink_writer_mp4(); From 65a30067a0fcac3d7950660cdfb065c6131da6f3 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 11 Mar 2024 20:51:09 +0800 Subject: [PATCH 186/301] mfreadwrite: Fix a memory leak (Coverity). (cherry picked from commit e21244f7a3ecc6458ea426172a8096341b626e43) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index e55b1fe5823..99e1cbc21ab 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1964,7 +1964,10 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count))) { if (!count) + { + free(entry); return MF_E_TOPO_CODEC_NOT_FOUND; + } for (i = 0; i < count; i++) { From 5326f8a224dea7096345156c5d7946cd2cb426ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Mar 2024 11:02:24 +0100 Subject: [PATCH 187/301] mfreadwrite/reader: Avoid accessing an invalid stream index. Fixes d6c9ac94d2fc92d86639e74699ef470b1d8a9861. (cherry picked from commit e3510c6bdb85273fb186d97377b5cb46644c36c0) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 99e1cbc21ab..dd5d8259f45 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2376,7 +2376,6 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D REFIID riid, void **object) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); - struct media_stream *stream = &reader->streams[index]; IUnknown *obj = NULL; HRESULT hr = S_OK; @@ -2397,7 +2396,7 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D if (index >= reader->stream_count) hr = MF_E_INVALIDSTREAMNUMBER; - else if (!(obj = (IUnknown *)stream->transform_service)) + else if (!(obj = (IUnknown *)reader->streams[index].transform_service)) hr = E_NOINTERFACE; break; } From 299a05234e4e585da4effa16828acfea0c4c6c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Mar 2024 12:13:22 +0100 Subject: [PATCH 188/301] mfreadwrite/reader: Keep the output subtypes when propagating media types. (cherry picked from commit a7564b0f8b8d9068b3efed5e7c53486fa3ffc327) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 76 ++++++++++++++++++++++++--------- dlls/mfreadwrite/tests/mfplat.c | 6 +-- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index dd5d8259f45..97b9093eb99 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -767,6 +767,53 @@ static HRESULT source_reader_push_transform_samples(struct source_reader *reader return hr; } +/* update the transform output type while keeping subtype which matches the old output type */ +static HRESULT transform_entry_update_output_type(struct transform_entry *entry, IMFMediaType *old_output_type) +{ + IMFMediaType *new_output_type; + GUID subtype, desired; + UINT i = 0; + HRESULT hr; + + IMFMediaType_GetGUID(old_output_type, &MF_MT_SUBTYPE, &desired); + + /* find an available output type matching the desired subtype */ + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(entry->transform, 0, i++, &new_output_type))) + { + IMFMediaType_GetGUID(new_output_type, &MF_MT_SUBTYPE, &subtype); + if (IsEqualGUID(&subtype, &desired) && SUCCEEDED(hr = IMFTransform_SetOutputType(entry->transform, 0, new_output_type, 0))) + { + entry->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED; + IMFMediaType_Release(new_output_type); + return S_OK; + } + IMFMediaType_Release(new_output_type); + } + + return hr; +} + +/* update the transform input type while keeping an output type which matches the current output subtype */ +static HRESULT transform_entry_update_input_type(struct transform_entry *entry, IMFMediaType *input_type) +{ + IMFMediaType *old_output_type, *new_output_type; + HRESULT hr; + + if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &old_output_type))) + return hr; + if (FAILED(hr = IMFTransform_SetInputType(entry->transform, 0, input_type, 0))) + return hr; + + /* check if transform output type is still valid or if we need to update it as well */ + if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &new_output_type))) + hr = transform_entry_update_output_type(entry, old_output_type); + else + IMFMediaType_Release(new_output_type); + + IMFMediaType_Release(old_output_type); + return hr; +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { @@ -786,7 +833,7 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader while (SUCCEEDED(hr)) { MFT_OUTPUT_DATA_BUFFER out_buffer = {0}; - IMFMediaType *output_type, *media_type; + IMFMediaType *media_type; if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) @@ -794,23 +841,15 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) { + /* propagate upstream type to the transform input type */ if ((entry->pending_flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) - && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) + && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &media_type))) { if (!next) - hr = IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current); - else if (SUCCEEDED(hr = IMFTransform_SetInputType(next->transform, 0, output_type, 0))) - { - /* check if transform output type is still valid or if we need to reset it as well */ - if (FAILED(hr = IMFTransform_GetOutputCurrentType(next->transform, 0, &media_type)) - && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(next->transform, 0, 0, &output_type))) - { - next->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED; - hr = IMFTransform_SetOutputType(entry->transform, 0, media_type, 0); - IMFMediaType_Release(media_type); - } - } - IMFMediaType_Release(output_type); + hr = IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)stream->current); + else + hr = transform_entry_update_input_type(next, media_type); + IMFMediaType_Release(media_type); } if (FAILED(hr)) @@ -823,16 +862,15 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader entry->pending_flags = 0; } - if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(entry->transform, 0, 0, &output_type))) + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &media_type))) { - hr = IMFTransform_SetOutputType(entry->transform, 0, output_type, 0); - IMFMediaType_Release(output_type); + hr = transform_entry_update_output_type(entry, media_type); + IMFMediaType_Release(media_type); if (SUCCEEDED(hr)) { hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info); stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); - entry->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED; } } diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index fb52046eefc..46b31d95f2c 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2757,12 +2757,12 @@ static void test_source_reader_transform_stream_change(void) static const struct attribute_desc yuy2_expect_new_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), ATTR_RATIO(MF_MT_FRAME_SIZE, 128, 128), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 128 * 2, .todo_value = TRUE), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 128 * 128 * 2, .todo_value = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 128 * 2), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 128 * 128 * 2), {0}, }; const MFT_REGISTER_TYPE_INFO output_info[] = From b8f39ca578285211389887eef5aaa959b9107b35 Mon Sep 17 00:00:00 2001 From: Danyil Blyschak Date: Thu, 18 Apr 2024 10:33:18 -0500 Subject: [PATCH 189/301] mfreadwrite: Store result of object activation in stream transform. In source_reader_create_transform(), store the result of IMFActivate_ActivateObject() so that in the event of failure, resources are freed and an appropriate HRESULT is returned. Previously, if every object's activation failed, the last part of the function was not aware of this. (cherry picked from commit f97e12de40295719e9b6eeed1d10007d8d01293c) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 97b9093eb99..6d72bf558f0 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2011,7 +2011,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL { IMFMediaType *media_type; - if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) + if (FAILED(hr = IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) continue; if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) From 4961529afe97a7b00b675f4d9d6b015e78252552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 13:09:25 +0200 Subject: [PATCH 190/301] mfreadwrite/tests: Do not accept MFVideoFormat_RGB32 in the test transform. (cherry picked from commit 7b47833b28ccc365efd677853fa96fcfc4e94697) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/mfplat.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 46b31d95f2c..feaa2e5d57d 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2488,6 +2488,13 @@ static HRESULT WINAPI test_decoder_SetInputType(IMFTransform *iface, DWORD id, I static HRESULT WINAPI test_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct test_decoder *decoder = test_decoder_from_IMFTransform(iface); + GUID subtype; + HRESULT hr; + + if (type && SUCCEEDED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)) + && IsEqualGUID(&subtype, &MFVideoFormat_RGB32)) + return MF_E_INVALIDMEDIATYPE; + if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; if (decoder->output_type) @@ -2900,7 +2907,7 @@ static void test_source_reader_transforms_d3d(void) ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), {0}, @@ -3019,18 +3026,14 @@ static void test_source_reader_transforms_d3d(void) /* video processor transform is not D3D aware */ hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* FIXME: Wine skips the video processor as the test decoder accepts the output type directly */ - if (hr == S_OK) - { - ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); - hr = IMFTransform_GetAttributes(video_processor, &attributes); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); - ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - IMFAttributes_Release(attributes); - IMFTransform_Release(video_processor); - } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFTransform_Release(video_processor); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From 1e3ffbd0a39878c55456e8c478a24bcb98b5bc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 13:29:03 +0200 Subject: [PATCH 191/301] mfreadwrite/tests: Avoid using MFCreateMediaBufferFromMediaType. It's not available on Win7. (cherry picked from commit c908181eefe542a85a062c439c57071a512c8a88) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/mfplat.c | 54 ++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index feaa2e5d57d..798bbba9717 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2604,28 +2604,25 @@ static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flag hr = MFCreateSample(&data->pSample); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = MFCreateMediaBufferFromMediaType(decoder->output_type, 0, 0, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr != S_OK) - { - hr = MFCreateMemoryBuffer(96 * 96 * 4, &buffer); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } + hr = MFCreateMemoryBuffer(96 * 96 * 4, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSample_AddBuffer(data->pSample, buffer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaBuffer_Release(buffer); } + else + { + ok(!!data->pSample, "Missing sample\n"); - ok(!!data->pSample, "Missing sample\n"); - - hr = IMFSample_GetBufferByIndex(data->pSample, 0, &buffer); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine check_interface(buffer, &IID_IMF2DBuffer2, TRUE); - todo_wine check_interface(buffer, &IID_IMFGetService, TRUE); - check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); - hr = MFGetService((IUnknown *)buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)&unknown); - todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); - IMFMediaBuffer_Release(buffer); + hr = IMFSample_GetBufferByIndex(data->pSample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + todo_wine check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + hr = MFGetService((IUnknown *)buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)&unknown); + todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + } if (decoder->next_output == MF_E_TRANSFORM_STREAM_CHANGE) { @@ -2817,6 +2814,16 @@ static void test_source_reader_transform_stream_change(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaSource_Release(source); + /* skip tests on Win7 which misses IMFSourceReaderEx */ + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win7 */, "Unexpected hr %#lx.\n", hr); + if (broken(hr == E_NOINTERFACE)) + { + win_skip("missing IMFSourceReaderEx interface, skipping tests on Win7\n"); + goto skip_tests; + } + IMFSourceReaderEx_Release(reader_ex); + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2881,6 +2888,7 @@ static void test_source_reader_transform_stream_change(void) IMFTransform_Release(test_decoder); +skip_tests: IMFSourceReader_Release(reader); hr = MFTUnregisterLocal(&factory); @@ -2993,6 +3001,17 @@ static void test_source_reader_transforms_d3d(void) IMFAttributes_Release(attributes); IMFMediaSource_Release(source); + /* skip tests on Win7 which misses IMFSourceReaderEx */ + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win7 */, "Unexpected hr %#lx.\n", hr); + if (broken(hr == E_NOINTERFACE)) + { + win_skip("missing IMFSourceReaderEx interface, skipping tests on Win7\n"); + IMFSourceReader_Release(reader); + goto skip_tests; + } + IMFSourceReaderEx_Release(reader_ex); + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3152,6 +3171,7 @@ static void test_source_reader_transforms_d3d(void) test_decoder_allocate_samples = FALSE; +skip_tests: hr = MFTUnregisterLocal(&factory); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From e8f6d4eedb6487369b2f26808d08b7850f3658ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 Apr 2024 18:04:18 +0200 Subject: [PATCH 192/301] mfreadwrite/tests: Shutdown the test stream event queues on source shutdown. (cherry picked from commit 8514ddb2001b1fa2485ae1617b8b174cbb625b9e) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/mfplat.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 798bbba9717..d06354ceee5 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -554,9 +554,15 @@ static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface) { struct test_source *source = impl_from_IMFMediaSource(iface); HRESULT hr; + UINT i; hr = IMFMediaEventQueue_Shutdown(source->event_queue); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < source->stream_count; ++i) + { + hr = IMFMediaEventQueue_Shutdown(source->streams[i]->event_queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } return S_OK; } From e8f1a507b6ea493150f0f518cedd6ee4e0ed7fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 Apr 2024 16:20:53 +0200 Subject: [PATCH 193/301] mfreadwrite/reader: Avoid leaking the stream transform service MFT. (cherry picked from commit 7bb1b147ce2c83156a468e323dc03a151c1b1ff1) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 6d72bf558f0..8e2fa4dbe7d 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -223,6 +223,8 @@ static void media_stream_destroy(struct media_stream *stream) transform_entry_destroy(entry); } + if (stream->transform_service) + IMFTransform_Release(stream->transform_service); if (stream->stream) IMFMediaStream_Release(stream->stream); if (stream->current) From 04277b6bacbab9d3f161b0910dedf0ae18ff60e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 Apr 2024 09:59:47 +0200 Subject: [PATCH 194/301] mfreadwrite/tests: Add some source reader D3D11 awareness tests. (cherry picked from commit 54ff5bdf85f2b635acc1e055db6b11c6e0d5bd0a) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/Makefile.in | 2 +- dlls/mfreadwrite/tests/mfplat.c | 342 +++++++++++++++++++++++++++-- 2 files changed, 324 insertions(+), 20 deletions(-) diff --git a/dlls/mfreadwrite/tests/Makefile.in b/dlls/mfreadwrite/tests/Makefile.in index 3bdab217148..c6262c01009 100644 --- a/dlls/mfreadwrite/tests/Makefile.in +++ b/dlls/mfreadwrite/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfreadwrite.dll -IMPORTS = ole32 user32 d3d9 dxva2 mfplat mf mfreadwrite mfuuid propsys +IMPORTS = ole32 user32 d3d11 d3d9 dxva2 mfplat mf mfreadwrite mfuuid propsys SOURCES = \ mfplat.c \ diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index d06354ceee5..536a3dc4a41 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -42,6 +42,7 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "initguid.h" #include "d3d9.h" #include "dxva2api.h" +#include "d3d11_4.h" #include "evr.h" #include "wine/test.h" @@ -199,6 +200,7 @@ static IDirect3DDevice9 *create_d3d9_device(IDirect3D9 *d3d9, HWND focus_window) } static HRESULT (WINAPI *pMFCreateMFByteStreamOnStream)(IStream *stream, IMFByteStream **bytestream); +static HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager); static void init_functions(void) { @@ -206,6 +208,7 @@ static void init_functions(void) #define X(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return; X(MFCreateMFByteStreamOnStream); + X(MFCreateDXGIDeviceManager); #undef X } @@ -2296,9 +2299,11 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad } static BOOL test_decoder_d3d_aware; +static BOOL test_decoder_d3d11_aware; static BOOL test_decoder_got_d3d_manager; static BOOL test_decoder_allocate_samples; -static IDirect3DDeviceManager9 *expect_d3d_manager; +static IDirect3DDeviceManager9 *expect_d3d9_manager; +static IMFDXGIDeviceManager *expect_dxgi_manager; struct test_decoder { @@ -2564,20 +2569,35 @@ static HRESULT WINAPI test_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA return S_OK; case MFT_MESSAGE_SET_D3D_MANAGER: - ok(test_decoder_d3d_aware, "Unexpected call.\n"); - if (param) + ok(test_decoder_d3d_aware || test_decoder_d3d11_aware, "Unexpected call.\n"); + if (!param) + return S_OK; + + if (test_decoder_d3d_aware) { IDirect3DDeviceManager9 *manager; HRESULT hr; hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&manager); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(manager == expect_d3d_manager, "got manager %p\n", manager); + ok(manager == expect_d3d9_manager, "got manager %p\n", manager); IDirect3DDeviceManager9_Release(manager); test_decoder_got_d3d_manager = TRUE; } - return test_decoder_d3d_aware ? S_OK : E_NOTIMPL; + if (test_decoder_d3d11_aware) + { + IMFDXGIDeviceManager *manager; + HRESULT hr; + + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IMFDXGIDeviceManager, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == expect_dxgi_manager, "got manager %p\n", manager); + IMFDXGIDeviceManager_Release(manager); + + test_decoder_got_d3d_manager = TRUE; + } + return S_OK; default: ok(0, "Unexpected call.\n"); @@ -2712,13 +2732,21 @@ static HRESULT WINAPI test_mft_factory_CreateInstance(IClassFactory *iface, IUnk decoder->IMFTransform_iface.lpVtbl = &test_decoder_vtbl; decoder->refcount = 1; - if (test_decoder_d3d_aware) + if (test_decoder_d3d_aware || test_decoder_d3d11_aware) { hr = MFCreateAttributes(&decoder->attributes, 1); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + if (test_decoder_d3d_aware) + { hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, 1); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } + if (test_decoder_d3d11_aware) + { + hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } *obj = &decoder->IMFTransform_iface; return S_OK; @@ -2901,7 +2929,7 @@ static void test_source_reader_transform_stream_change(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } -static void test_source_reader_transforms_d3d(void) +static void test_source_reader_transforms_d3d9(void) { static const struct attribute_desc test_stream_type_desc[] = { @@ -2966,8 +2994,11 @@ static void test_source_reader_transforms_d3d(void) if (!(d3d9_device = create_d3d9_device(d3d9, window))) { skip("Failed to create a D3D9 device, skipping tests.\n"); - goto done; + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; } + IDirect3D9_Release(d3d9); test_decoder_d3d_aware = TRUE; @@ -2984,9 +3015,11 @@ static void test_source_reader_transforms_d3d(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDevice9_Release(d3d9_device); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)d3d9_manager); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - expect_d3d_manager = d3d9_manager; + expect_d3d9_manager = d3d9_manager; /* test d3d aware decoder that doesn't allocate buffers */ @@ -3016,7 +3049,6 @@ static void test_source_reader_transforms_d3d(void) IMFSourceReader_Release(reader); goto skip_tests; } - IMFSourceReaderEx_Release(reader_ex); hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3046,10 +3078,8 @@ static void test_source_reader_transforms_d3d(void) IMFMediaType_Release(media_type); - hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* video processor transform is not D3D9 aware on more recent Windows */ - /* video processor transform is not D3D aware */ hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); @@ -3057,6 +3087,19 @@ static void test_source_reader_transforms_d3d(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 1, "got %u.\n", value); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); IMFAttributes_Release(attributes); IMFTransform_Release(video_processor); @@ -3070,7 +3113,6 @@ static void test_source_reader_transforms_d3d(void) ok(value == 1, "got %u\n", value); IMFAttributes_Release(attributes); - IMFSourceReaderEx_Release(reader_ex); fail_request_sample = FALSE; test_decoder_set_next_output(test_decoder, S_OK); @@ -3096,7 +3138,33 @@ static void test_source_reader_transforms_d3d(void) fail_request_sample = TRUE; + + /* video processor output stream attributes are left empty in D3D9 mode */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 6, "got %u.\n", value); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + IMFTransform_Release(test_decoder); + IMFSourceReaderEx_Release(reader_ex); IMFSourceReader_Release(reader); @@ -3182,13 +3250,248 @@ static void test_source_reader_transforms_d3d(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IDirect3DDeviceManager9_Release(d3d9_manager); - IDirect3DDevice9_Release(d3d9_device); - -done: - IDirect3D9_Release(d3d9); DestroyWindow(window); + test_decoder_got_d3d_manager = FALSE; test_decoder_d3d_aware = FALSE; + expect_d3d9_manager = NULL; +} + +static void test_source_reader_transforms_d3d11(void) +{ + static const struct attribute_desc test_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_TEST), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + {0}, + }; + static const struct attribute_desc rgb32_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + {0}, + }; + static const struct attribute_desc rgb32_expect_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + {0}, + }; + const MFT_REGISTER_TYPE_INFO output_info[] = + { + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + }; + const MFT_REGISTER_TYPE_INFO input_info[] = + { + {MFMediaType_Video, MFVideoFormat_TEST}, + }; + IClassFactory factory = {.lpVtbl = &test_mft_factory_vtbl}; + IMFTransform *test_decoder, *video_processor; + IMFStreamDescriptor *video_stream; + ID3D11Multithread *multithread; + IMFDXGIDeviceManager *manager; + IMFSourceReaderEx *reader_ex; + IMFAttributes *attributes; + IMFMediaType *media_type; + IMFSourceReader *reader; + IMFMediaBuffer *buffer; + IMFMediaSource *source; + UINT32 value, token; + ID3D11Device *d3d11; + LONGLONG timestamp; + DWORD index, flags; + IMFSample *sample; + HRESULT hr; + + if (!pMFCreateDXGIDeviceManager) + { + win_skip("MFCreateDXGIDeviceManager() is not available, skipping tests.\n"); + return; + } + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + return; + } + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + + test_decoder_d3d11_aware = TRUE; + + hr = MFTRegisterLocal(&factory, &MFT_CATEGORY_VIDEO_DECODER, L"Test Decoder", 0, + ARRAY_SIZE(input_info), input_info, ARRAY_SIZE(output_info), output_info); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + expect_dxgi_manager = manager; + + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, test_stream_type_desc, -1); + hr = MFCreateStreamDescriptor(0, 1, &media_type, &video_stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + source = create_test_source(&video_stream, 1); + ok(!!source, "Failed to create test source.\n"); + IMFStreamDescriptor_Release(video_stream); + + hr = MFCreateSourceReaderFromMediaSource(source, attributes, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFMediaSource_Release(source); + + /* skip tests on Win7 which misses IMFSourceReaderEx */ + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win7 */, "Unexpected hr %#lx.\n", hr); + if (broken(hr == E_NOINTERFACE)) + { + win_skip("missing IMFSourceReaderEx interface, skipping tests on Win7\n"); + IMFSourceReader_Release(reader); + goto skip_tests; + } + + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSourceReader_GetNativeMediaType(reader, 0, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + ok(!test_decoder_got_d3d_manager, "d3d manager received\n"); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, rgb32_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, rgb32_expect_desc, -1); + IMFMediaType_Release(media_type); + + + /* video processor output stream attributes are still empty */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(test_decoder->lpVtbl == &test_decoder_vtbl, "got unexpected transform\n"); + + fail_request_sample = FALSE; + test_decoder_set_next_output(test_decoder, S_OK); + + sample = (void *)0xdeadbeef; + index = flags = timestamp = 0xdeadbeef; + hr = IMFSourceReader_ReadSample(reader, 0, 0, &index, &flags, ×tamp, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "got %lu.\n", index); + ok(flags == 0, "got %lu.\n", flags); + ok(timestamp == 0, "got %I64d.\n", timestamp); + ok(sample != (void *)0xdeadbeef, "got %p.\n", sample); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, FALSE); + check_interface(buffer, &IID_IMFDXGIBuffer, TRUE); + IMFMediaBuffer_Release(buffer); + + IMFSample_Release(sample); + + fail_request_sample = TRUE; + + + /* video processor output stream attributes are now set with some defaults */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 6, "got %u.\n", value); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 1024, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + + IMFSourceReaderEx_Release(reader_ex); + IMFSourceReader_Release(reader); + IMFTransform_Release(test_decoder); + + +skip_tests: + hr = MFTUnregisterLocal(&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFDXGIDeviceManager_Release(manager); + + test_decoder_got_d3d_manager = FALSE; + test_decoder_d3d11_aware = FALSE; + expect_dxgi_manager = NULL; } START_TEST(mfplat) @@ -3209,7 +3512,8 @@ START_TEST(mfplat) test_source_reader_transforms(TRUE, FALSE); test_source_reader_transforms(FALSE, TRUE); test_source_reader_transform_stream_change(); - test_source_reader_transforms_d3d(); + test_source_reader_transforms_d3d9(); + test_source_reader_transforms_d3d11(); test_reader_d3d9(); test_sink_writer_create(); test_sink_writer_mp4(); From 71a11611035e3fe560b294a8a2a27677bf46ef3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 10 Apr 2024 09:28:45 +0200 Subject: [PATCH 195/301] mf/tests: Test video processor D3D11 awareness. (cherry picked from commit c4fb3900bcd84287b4eabe2426f6824d478665d2) CW-Bug-Id: #20833 --- dlls/mf/tests/mf.c | 2 + dlls/mf/tests/mf_test.h | 1 + dlls/mf/tests/transform.c | 309 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1d7e7f4c909..9382d8cae35 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -80,6 +80,7 @@ extern GUID DMOVideoFormat_RGB32; HRESULT (WINAPI *pMFCreateSampleCopierMFT)(IMFTransform **copier); HRESULT (WINAPI *pMFGetTopoNodeCurrentType)(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager); +HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **obj); BOOL has_video_processor; static BOOL is_vista(void) @@ -6899,6 +6900,7 @@ void init_functions(void) mod = GetModuleHandleA("mfplat.dll"); X(MFCreateDXGIDeviceManager); + X(MFCreateVideoSampleAllocatorEx); #undef X hr = CoInitialize(NULL); diff --git a/dlls/mf/tests/mf_test.h b/dlls/mf/tests/mf_test.h index 324815e3e8b..b3247ba00cc 100644 --- a/dlls/mf/tests/mf_test.h +++ b/dlls/mf/tests/mf_test.h @@ -33,6 +33,7 @@ extern HRESULT (WINAPI *pMFCreateSampleCopierMFT)(IMFTransform **copier); extern HRESULT (WINAPI *pMFGetTopoNodeCurrentType)(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); extern HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager); +extern HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **obj); extern BOOL has_video_processor; void init_functions(void); diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 300a22094fb..8bb51cc790c 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7343,6 +7343,7 @@ static void test_video_processor(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MFT_SUPPORT_3DVIDEO, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D11_AWARE, 1, .todo = TRUE), /* ATTR_UINT32(MF_SA_D3D_AWARE, 1), only on W7 */ {0}, }; @@ -8785,6 +8786,8 @@ static void test_h264_with_dxgi_manager(void) IMFDXGIDeviceManager_Release(manager); if (transform) IMFTransform_Release(transform); + + MFShutdown(); CoUninitialize(); } @@ -8981,6 +8984,310 @@ static void test_iv50_decoder(void) IMFCollection_Release(collection); } +static void test_video_processor_with_dxgi_manager(void) +{ + static const unsigned int set_width = 82, set_height = 84, aligned_width = 96, aligned_height = 96; + const struct attribute_desc output_sample_attributes[] = + { + {0}, + }; + const struct buffer_desc output_buffer_desc_rgb32 = + { + .length = aligned_width * aligned_height * 4, + .compare = compare_rgb32, .compare_rect = {.right = set_width, .bottom = set_height}, + .dump = dump_rgb32, .size = {.cx = aligned_width, .cy = aligned_height}, + }; + const struct sample_desc output_sample_desc_rgb32 = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 0, + .buffer_count = 1, .buffers = &output_buffer_desc_rgb32, + }; + + IMFVideoSampleAllocator *allocator = NULL; + IMFDXGIDeviceManager *manager = NULL; + IMFTrackedSample *tracked_sample; + IMFTransform *transform = NULL; + ID3D11Multithread *multithread; + MFT_OUTPUT_DATA_BUFFER output; + IMFCollection *output_samples; + MFT_OUTPUT_STREAM_INFO info; + IMFDXGIBuffer *dxgi_buffer; + const BYTE *nv12frame_data; + D3D11_TEXTURE2D_DESC desc; + ULONG nv12frame_data_len; + IMFSample *input_sample; + IMFMediaBuffer *buffer; + IMFAttributes *attribs; + ID3D11Texture2D *tex2d; + IMF2DBuffer2 *buffer2d; + ID3D11Device *d3d11; + IMFMediaType *type; + DWORD status, val; + ULONG i, length; + UINT32 value; + BYTE *data; + HRESULT hr; + UINT token; + DWORD ret; + + if (!pMFCreateDXGIDeviceManager || !pMFCreateVideoSampleAllocatorEx) + { + win_skip("MFCreateDXGIDeviceManager / MFCreateVideoSampleAllocatorEx are not available, skipping tests.\n"); + return; + } + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + return; + } + + hr = MFStartup(MF_VERSION, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocator, (void **)&allocator); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFVideoSampleAllocator_SetDirectXManager(allocator, (IUnknown *)manager); + ok(hr == S_OK, "got %#lx\n", hr); + + if (FAILED(hr = CoCreateInstance(&CLSID_VideoProcessorMFT, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)transform); + todo_wine ok(hr == E_NOINTERFACE, "got %#lx\n", hr); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got %#lx\n", hr); + if (hr == E_NOINTERFACE) + { + win_skip("No hardware video decoding support.\n"); + goto failed; + } + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + if (broken(!(info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)) /* w8 / w1064v1507 */) + { + win_skip("missing video processor sample allocator support.\n"); + goto failed; + } + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_NV12); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 4, type); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_Release(type); + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_Release(type); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + + /* native wants a dxgi buffer on input */ + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &input_sample); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_GetBufferByIndex(input_sample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + memcpy(data, nv12frame_data, nv12frame_data_len); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaBuffer_Release(buffer); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + todo_wine ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + if (!output.pSample) goto skip_tests; + + hr = IMFTransform_GetAttributes(transform, &attribs); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFAttributes_GetUINT32(attribs, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attribs); + + hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &attribs); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFAttributes_GetCount(attribs, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attribs); + + + hr = IMFSample_QueryInterface(output.pSample, &IID_IMFTrackedSample, (void **)&tracked_sample); + ok(hr == S_OK, "got %#lx\n", hr); + IMFTrackedSample_Release(tracked_sample); + + hr = IMFSample_GetBufferCount(output.pSample, &val); + ok(hr == S_OK, "got %#lx\n", hr); + ok(val == 1, "got %lu.\n", val); + hr = IMFSample_GetBufferByIndex(output.pSample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&buffer2d); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&tex2d); + ok(hr == S_OK, "got %#lx\n", hr); + memset(&desc, 0xcc, sizeof(desc)); + ID3D11Texture2D_GetDesc(tex2d, &desc); + ok(desc.Format == DXGI_FORMAT_B8G8R8X8_UNORM, "got %#x.\n", desc.Format); + ok(!desc.Usage, "got %u.\n", desc.Usage); + ok(desc.BindFlags == (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), "got %#x.\n", desc.BindFlags); + ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags); + ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags); + ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels); + ok(desc.Width == aligned_width, "got %u.\n", desc.Width); + ok(desc.Height == aligned_height, "got %u.\n", desc.Height); + + ID3D11Texture2D_Release(tex2d); + IMFDXGIBuffer_Release(dxgi_buffer); + IMF2DBuffer2_Release(buffer2d); + IMFMediaBuffer_Release(buffer); + + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); + ok(ret <= 5, "got %lu%% diff\n", ret); + + for (i = 0; i < 9; i++) + { + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + } + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "got %#lx\n", hr); + + IMFCollection_Release(output_samples); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + IMFSample_Release(output.pSample); + +skip_tests: + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + memset(&info, 0xcc, sizeof(info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + + hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(allocator); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + + IMFSample_Release(input_sample); + +failed: + if (allocator) + IMFVideoSampleAllocator_Release(allocator); + if (manager) + IMFDXGIDeviceManager_Release(manager); + if (transform) + IMFTransform_Release(transform); + + MFShutdown(); + CoUninitialize(); +} + START_TEST(transform) { init_functions(); @@ -9010,4 +9317,6 @@ START_TEST(transform) test_h264_with_dxgi_manager(); test_h264_decoder_concat_streams(); + + test_video_processor_with_dxgi_manager(); } From e914c55c979fb1d9575dd6e54e4b21d617383c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 21:57:49 +0200 Subject: [PATCH 196/301] winegstreamer/video_processor: Implement D3D awareness. (cherry picked from commit cf3134a841bf2c6a54e3d005c9cc5d05547e84c5) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 24 +++--- dlls/mfreadwrite/tests/mfplat.c | 6 +- dlls/winegstreamer/video_processor.c | 120 ++++++++++++++++++++++++--- 3 files changed, 127 insertions(+), 23 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 8bb51cc790c..ff74674f0ca 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7343,7 +7343,7 @@ static void test_video_processor(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MFT_SUPPORT_3DVIDEO, 1, .todo = TRUE), - ATTR_UINT32(MF_SA_D3D11_AWARE, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D11_AWARE, 1), /* ATTR_UINT32(MF_SA_D3D_AWARE, 1), only on W7 */ {0}, }; @@ -8062,9 +8062,10 @@ static void test_video_processor(void) } ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); - winetest_pop_context(); skip_test: + winetest_pop_context(); + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); ok(hr == S_OK, "got %#lx\n", hr); hr = IMFTransform_SetOutputType(transform, 0, NULL, 0); @@ -9089,7 +9090,7 @@ static void test_video_processor_with_dxgi_manager(void) win_skip("missing video processor sample allocator support.\n"); goto failed; } - todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); hr = MFCreateMediaType(&type); ok(hr == S_OK, "got %#lx\n", hr); @@ -9120,7 +9121,7 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr); load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ @@ -9152,18 +9153,17 @@ static void test_video_processor_with_dxgi_manager(void) hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); - todo_wine ok(!!output.pSample, "got no sample\n"); + ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); - if (!output.pSample) goto skip_tests; hr = IMFTransform_GetAttributes(transform, &attribs); ok(hr == S_OK, "got %#lx\n", hr); @@ -9220,6 +9220,7 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample); ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); + todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 5, "got %lu%% diff\n", ret); for (i = 0; i < 9; i++) @@ -9254,14 +9255,17 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + /* FIXME: Wine sample release happens entirely asynchronously */ + flaky_wine_if(hr == MF_E_SAMPLEALLOCATOR_EMPTY) ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); + flaky_wine_if(hr == MF_E_SAMPLEALLOCATOR_EMPTY) ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); - IMFSample_Release(output.pSample); + if (output.pSample) + IMFSample_Release(output.pSample); -skip_tests: hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0); ok(hr == S_OK, "got %#lx\n", hr); diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 536a3dc4a41..1b86b18d878 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3086,11 +3086,11 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFTransform_GetAttributes(video_processor, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); + todo_wine /* Wine exposes MF_SA_D3D_AWARE on the video processor, as Win7 */ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 1, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 1, "got %u.\n", value); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); IMFAttributes_Release(attributes); diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 5b93bf08396..0fedfb8451e 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -83,6 +83,9 @@ struct video_processor wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; + + IUnknown *device_manager; + IMFVideoSampleAllocatorEx *allocator; }; static HRESULT try_create_wg_transform(struct video_processor *impl) @@ -98,6 +101,46 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); } +static HRESULT video_processor_init_allocator(struct video_processor *processor) +{ + IMFVideoSampleAllocatorEx *allocator; + UINT32 count; + HRESULT hr; + + if (processor->allocator) + return S_OK; + + if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&allocator))) + return hr; + if (FAILED(IMFAttributes_GetUINT32(processor->attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &count))) + count = 2; + if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(allocator, processor->device_manager)) + || FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocator, count, max(count + 2, 10), + processor->output_attributes, processor->output_type))) + { + IMFVideoSampleAllocatorEx_Release(allocator); + return hr; + } + + processor->allocator = allocator; + return S_OK; +} + +static HRESULT video_processor_uninit_allocator(struct video_processor *processor) +{ + HRESULT hr; + + if (!processor->allocator) + return S_OK; + + if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(processor->allocator))) + hr = IMFVideoSampleAllocatorEx_SetDirectXManager(processor->allocator, NULL); + IMFVideoSampleAllocatorEx_Release(processor->allocator); + processor->allocator = NULL; + + return hr; +} + static struct video_processor *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_processor, IMFTransform_iface); @@ -141,6 +184,9 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface) if (!refcount) { + video_processor_uninit_allocator(impl); + if (impl->device_manager) + IUnknown_Release(impl->device_manager); if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); if (impl->input_type) @@ -213,7 +259,7 @@ static HRESULT WINAPI video_processor_GetAttributes(IMFTransform *iface, IMFAttr { struct video_processor *impl = impl_from_IMFTransform(iface); - FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); + TRACE("iface %p, attributes %p\n", iface, attributes); if (!attributes) return E_POINTER; @@ -232,7 +278,7 @@ static HRESULT WINAPI video_processor_GetOutputStreamAttributes(IMFTransform *if { struct video_processor *impl = impl_from_IMFTransform(iface); - FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes); + TRACE("iface %p, id %#lx, attributes %p\n", iface, id, attributes); if (!attributes) return E_POINTER; @@ -428,6 +474,9 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; + if (FAILED(hr = video_processor_uninit_allocator(impl))) + return hr; + if (impl->output_type) IMFMediaType_Release(impl->output_type); IMFMediaType_AddRef((impl->output_type = type)); @@ -528,8 +577,33 @@ static HRESULT WINAPI video_processor_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); - return S_OK; + struct video_processor *processor = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); + + switch (message) + { + case MFT_MESSAGE_SET_D3D_MANAGER: + if (FAILED(hr = video_processor_uninit_allocator(processor))) + return hr; + + if (processor->device_manager) + { + processor->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + IUnknown_Release(processor->device_manager); + } + if ((processor->device_manager = (IUnknown *)param)) + { + IUnknown_AddRef(processor->device_manager); + processor->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + } + return S_OK; + + default: + FIXME("Ignoring message %#x.\n", message); + return S_OK; + } } static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) @@ -549,6 +623,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f { struct video_processor *impl = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; + IMFSample *output_sample; HRESULT hr; TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -560,16 +635,36 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f return MF_E_TRANSFORM_TYPE_NOT_SET; samples->dwStatus = 0; - if (!samples->pSample) - return E_INVALIDARG; - if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) return hr; - if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) - wg_sample_queue_flush(impl->wg_sample_queue, false); + if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + if (FAILED(hr = video_processor_init_allocator(impl))) + return hr; + if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(impl->allocator, &output_sample))) + return hr; + } + else + { + if (!(output_sample = samples->pSample)) + return E_INVALIDARG; + IMFSample_AddRef(output_sample); + } + + if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, + NULL, &samples->dwStatus))) + goto done; + wg_sample_queue_flush(impl->wg_sample_queue, false); + if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + samples->pSample = output_sample; + IMFSample_AddRef(output_sample); + } + +done: + IMFSample_Release(output_sample); return hr; } @@ -633,6 +728,11 @@ HRESULT video_processor_create(REFIID riid, void **ret) if (FAILED(hr = MFCreateAttributes(&impl->attributes, 0))) goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(impl->attributes, &MF_SA_D3D11_AWARE, TRUE))) + goto failed; + /* native only has MF_SA_D3D_AWARE on Win7, but it is useful to have in mfreadwrite */ + if (FAILED(hr = IMFAttributes_SetUINT32(impl->attributes, &MF_SA_D3D_AWARE, TRUE))) + goto failed; if (FAILED(hr = MFCreateAttributes(&impl->output_attributes, 0))) goto failed; if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue))) From 9004f865d2679187812c4a0ddf99597966c85867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 Apr 2024 12:37:03 +0200 Subject: [PATCH 197/301] mfreadwrite/reader: Pass the device manager to the stream transforms. (cherry picked from commit 11c47925f0aa397cab117215f6c4563102b373b1) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 59 +++++++++++++++++++++++++++++++++ dlls/mfreadwrite/tests/mfplat.c | 17 +++++----- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8e2fa4dbe7d..0e90240e95e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -79,6 +79,7 @@ struct transform_entry UINT32 pending_flags; GUID category; BOOL hidden; + BOOL attributes_initialized; }; struct media_stream @@ -816,6 +817,35 @@ static HRESULT transform_entry_update_input_type(struct transform_entry *entry, return hr; } +static void transform_entry_initialize_attributes(struct source_reader *reader, struct transform_entry *entry) +{ + IMFAttributes *attributes; + + if (SUCCEEDED(IMFTransform_GetAttributes(entry->transform, &attributes))) + { + if (FAILED(IMFAttributes_GetItem(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, NULL))) + IMFAttributes_SetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, 6); + + IMFAttributes_Release(attributes); + } + + if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(entry->transform, 0, &attributes))) + { + UINT32 shared, shared_without_mutex, bind_flags; + + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED, shared); + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, shared_without_mutex); + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_D3D11_BIND_FLAGS, &bind_flags))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, bind_flags); + else if ((reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER) && FAILED(IMFAttributes_GetItem(attributes, &MF_SA_D3D11_BINDFLAGS, NULL))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, 1024); + + IMFAttributes_Release(attributes); + } +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { @@ -828,6 +858,12 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader if ((ptr = list_next(&stream->transforms, &entry->entry))) next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (!entry->attributes_initialized) + { + transform_entry_initialize_attributes(reader, entry); + entry->attributes_initialized = TRUE; + } + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) return hr; stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); @@ -2011,10 +2047,33 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL for (i = 0; i < count; i++) { + IMFAttributes *attributes; IMFMediaType *media_type; if (FAILED(hr = IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) continue; + + if (!reader->device_manager || FAILED(IMFTransform_GetAttributes(transform, &attributes))) + entry->attributes_initialized = TRUE; + else + { + UINT32 d3d_aware = FALSE; + + if (reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER) + { + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &d3d_aware)) && d3d_aware) + IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager); + } + else if (reader->flags & SOURCE_READER_D3D9_DEVICE_MANAGER) + { + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware)) && d3d_aware) + IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager); + } + + entry->attributes_initialized = !d3d_aware; + IMFAttributes_Release(attributes); + } + if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 1b86b18d878..d7e143428c6 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3070,7 +3070,7 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); - todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3147,10 +3147,9 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFTransform_GetAttributes(video_processor, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 6, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 6, "got %u.\n", value); IMFAttributes_Release(attributes); hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); @@ -3204,7 +3203,7 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); - todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); @@ -3463,16 +3462,16 @@ static void test_source_reader_transforms_d3d11(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 6, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 6, "got %u.\n", value); IMFAttributes_Release(attributes); hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 1024, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 1024, "got %u.\n", value); IMFAttributes_Release(attributes); IMFTransform_Release(video_processor); From 68b833f46f03dfc3e316cfeecaf0d4c888d5ac12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Nov 2023 00:45:19 +0100 Subject: [PATCH 198/301] mfplat: Add MFVideoFormat_ABGR32 format information. (cherry picked from commit 47884f6fbae0f886c9998a76ee53b7ecea510e59) CW-Bug-Id: #20833 --- dlls/mfplat/mediatype.c | 4 ++++ dlls/mfplat/tests/mfplat.c | 30 +++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index dd0b29fac32..3944d64849e 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -39,6 +39,7 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB1, D3DFMT_A1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB4, MAKEFOURCC('4','P','x','x')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB1555, D3DFMT_A1R5G5B5); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB4444, D3DFMT_A4R4G4B4); /* SDK MFVideoFormat_A2R10G10B10 uses D3DFMT_A2B10G10R10, let's name it the other way */ @@ -2713,6 +2714,7 @@ static struct uncompressed_video_format video_formats[] = { &MFVideoFormat_RGB32, 32, 3, 1, 0, BI_RGB }, { &MFVideoFormat_RGB565, 16, 3, 1, 0, BI_BITFIELDS }, { &MFVideoFormat_RGB555, 16, 3, 1, 0, BI_RGB }, + { &MFVideoFormat_ABGR32, 32, 3, 1, 0, BI_RGB }, { &MFVideoFormat_A2R10G10B10, 32, 3, 1, 0, -1 }, { &MFVideoFormat_A2B10G10R10, 32, 3, 1, 0, -1 }, { &MFVideoFormat_RGB8, 8, 3, 1, 0, BI_RGB }, @@ -3632,6 +3634,8 @@ DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format) return DXGI_FORMAT_B8G8R8A8_UNORM; case D3DFMT_X8R8G8B8: return DXGI_FORMAT_B8G8R8X8_UNORM; + case D3DFMT_A8B8G8R8: + return DXGI_FORMAT_R8G8B8A8_UNORM; case MAKEFOURCC('A','Y','U','V'): return DXGI_FORMAT_AYUV; case MAKEFOURCC('Y','4','1','0'): diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 19edbe41e8a..bbd9b17ba1e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -67,9 +67,11 @@ DEFINE_GUID(DUMMY_GUID3, 0x12345678,0x1234,0x1234,0x23,0x23,0x23,0x23,0x23,0x23, extern const CLSID CLSID_FileSchemePlugin; DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Base,0); +DEFINE_GUID(MEDIASUBTYPE_ABGR32,D3DFMT_A8B8G8R8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB1, D3DFMT_A1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB4, MAKEFOURCC('4','P','x','x')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB1555, D3DFMT_A1R5G5B5); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB4444, D3DFMT_A4R4G4B4); /* SDK MFVideoFormat_A2R10G10B10 uses D3DFMT_A2B10G10R10, let's name it the other way */ @@ -4737,6 +4739,9 @@ image_size_tests[] = { &MFVideoFormat_ARGB32, 3, 5, 60, 0, 320, 60, 64 }, { &MFVideoFormat_ARGB32, 1, 1, 4, 0, 64, 4, 64 }, { &MFVideoFormat_ARGB32, 320, 240, 307200, 0, 307200, 307200, 1280 }, + { &MFVideoFormat_ABGR32, 3, 5, 60, 0, 320, 60, 64 }, + { &MFVideoFormat_ABGR32, 1, 1, 4, 0, 64, 4, 64 }, + { &MFVideoFormat_ABGR32, 320, 240, 307200, 0, 307200, 307200, 1280 }, { &MFVideoFormat_A2R10G10B10, 3, 5, 60, 0, 320, 60, 64 }, { &MFVideoFormat_A2R10G10B10, 1, 1, 4, 0, 64, 4, 64 }, { &MFVideoFormat_A2R10G10B10, 320, 240, 307200, 0, 307200, 307200, 1280 }, @@ -4899,12 +4904,16 @@ static void test_MFCalculateImageSize(void) /* Those are supported since Win10. */ BOOL is_broken = IsEqualGUID(ptr->subtype, &MFVideoFormat_A16B16G16R16F) || - IsEqualGUID(ptr->subtype, &MFVideoFormat_A2R10G10B10); + IsEqualGUID(ptr->subtype, &MFVideoFormat_A2R10G10B10) || + IsEqualGUID(ptr->subtype, &MFVideoFormat_ABGR32); hr = MFCalculateImageSize(ptr->subtype, ptr->width, ptr->height, &size); - ok(hr == S_OK || (is_broken && hr == E_INVALIDARG), "%u: failed to calculate image size, hr %#lx.\n", i, hr); - ok(size == ptr->size, "%u: unexpected image size %u, expected %u. Size %u x %u, format %s.\n", i, size, ptr->size, - ptr->width, ptr->height, wine_dbgstr_an((char *)&ptr->subtype->Data1, 4)); + ok(hr == S_OK || broken(is_broken && hr == E_INVALIDARG), "%u: failed to calculate image size, hr %#lx.\n", i, hr); + if (hr == S_OK) + { + ok(size == ptr->size, "%u: unexpected image size %u, expected %u. Size %u x %u, format %s.\n", i, size, ptr->size, + ptr->width, ptr->height, wine_dbgstr_an((char *)&ptr->subtype->Data1, 4)); + } } } @@ -6208,6 +6217,8 @@ static void test_MFGetStrideForBitmapInfoHeader(void) { &MFVideoFormat_RGB32, 1, -4 }, { &MFVideoFormat_ARGB32, 3, -12 }, { &MFVideoFormat_ARGB32, 1, -4 }, + { &MFVideoFormat_ABGR32, 3, -12 }, + { &MFVideoFormat_ABGR32, 1, -4 }, { &MFVideoFormat_A2R10G10B10, 3, -12 }, { &MFVideoFormat_A2R10G10B10, 1, -4 }, { &MFVideoFormat_A2B10G10R10, 3, -12 }, @@ -9252,6 +9263,7 @@ static void test_MFMapDXGIFormatToDX9Format(void) { DXGI_FORMAT dxgi_format; DWORD d3d9_format; + BOOL broken; } formats_map[] = { @@ -9284,6 +9296,7 @@ static void test_MFMapDXGIFormatToDX9Format(void) { DXGI_FORMAT_B8G8R8X8_UNORM, D3DFMT_X8R8G8B8 }, { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, D3DFMT_A8R8G8B8 }, { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, D3DFMT_X8R8G8B8 }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3DFMT_A8B8G8R8, .broken = TRUE /* <= w1064v1507 */ }, { DXGI_FORMAT_AYUV, MAKEFOURCC('A','Y','U','V') }, { DXGI_FORMAT_Y410, MAKEFOURCC('Y','4','1','0') }, { DXGI_FORMAT_Y416, MAKEFOURCC('Y','4','1','6') }, @@ -9312,7 +9325,8 @@ static void test_MFMapDXGIFormatToDX9Format(void) for (i = 0; i < ARRAY_SIZE(formats_map); ++i) { format = pMFMapDXGIFormatToDX9Format(formats_map[i].dxgi_format); - ok(format == formats_map[i].d3d9_format, "Unexpected d3d9 format %#lx, dxgi format %#x.\n", format, formats_map[i].dxgi_format); + ok(format == formats_map[i].d3d9_format || broken(formats_map[i].broken && format == 0), + "Unexpected d3d9 format %#lx, dxgi format %#x.\n", format, formats_map[i].dxgi_format); } } @@ -9322,6 +9336,7 @@ static void test_MFMapDX9FormatToDXGIFormat(void) { DXGI_FORMAT dxgi_format; DWORD d3d9_format; + BOOL broken; } formats_map[] = { @@ -9349,6 +9364,7 @@ static void test_MFMapDX9FormatToDXGIFormat(void) { DXGI_FORMAT_BC3_UNORM, D3DFMT_DXT4 }, { DXGI_FORMAT_B8G8R8A8_UNORM, D3DFMT_A8R8G8B8 }, { DXGI_FORMAT_B8G8R8X8_UNORM, D3DFMT_X8R8G8B8 }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3DFMT_A8B8G8R8, .broken = TRUE }, { DXGI_FORMAT_AYUV, MAKEFOURCC('A','Y','U','V') }, { DXGI_FORMAT_Y410, MAKEFOURCC('Y','4','1','0') }, { DXGI_FORMAT_Y416, MAKEFOURCC('Y','4','1','6') }, @@ -9377,8 +9393,8 @@ static void test_MFMapDX9FormatToDXGIFormat(void) for (i = 0; i < ARRAY_SIZE(formats_map); ++i) { format = pMFMapDX9FormatToDXGIFormat(formats_map[i].d3d9_format); - ok(format == formats_map[i].dxgi_format, "Unexpected DXGI format %#x, d3d9 format %#lx.\n", - format, formats_map[i].d3d9_format); + ok(format == formats_map[i].dxgi_format || broken(formats_map[i].broken && format == 0), + "Unexpected DXGI format %#x, d3d9 format %#lx.\n", format, formats_map[i].d3d9_format); } } From a616add964ea213d29c3fd7de44e33666953197e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 Apr 2024 10:31:53 +0200 Subject: [PATCH 199/301] mf/tests: Add video processor tests with MFVideoFormat_ABGR32 format. (cherry picked from commit 1c1f03a8b84064a770e0d1d7f371bd93aae62b8b) CW-Bug-Id: #20833 --- dlls/mf/tests/abgr32frame-crop.bmp | Bin 0 -> 27606 bytes dlls/mf/tests/resource.rc | 8 + dlls/mf/tests/rgb32frame-crop-flip.bmp | Bin 0 -> 27606 bytes dlls/mf/tests/rgb32frame-crop.bmp | Bin 27606 -> 27606 bytes dlls/mf/tests/transform.c | 372 +++++++++++++++++++++++-- 5 files changed, 350 insertions(+), 30 deletions(-) create mode 100644 dlls/mf/tests/abgr32frame-crop.bmp create mode 100644 dlls/mf/tests/rgb32frame-crop-flip.bmp diff --git a/dlls/mf/tests/abgr32frame-crop.bmp b/dlls/mf/tests/abgr32frame-crop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2e18f395cbb220cf761a891835669e8fd05a8082 GIT binary patch literal 27606 zcmeIwF-ikb6o%2UkTlLHq_MPg1r|zB>@_0p!cEy57Z4P66)r#s3ge6f#rFCL*}<)b zoPqDcW4fPne(`o&t-hmj4@=jjo6=TwP;OP-t^cnc>(jPv$Oa5BzyJdbFu(u<3^2gJ z<{DTo=b`)ti^U|A-=O{43E6-F1{h#~0R|XgfB^=EXyEzpGL+xo`29YV-=OZgkPR4M zfB^;=V1NMz7+_$C2F5>6q5KA;kF!vIgSu}*Hei4O1{h#~0R|XgfPo{sEA~Q{(^u literal 0 HcmV?d00001 diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 357a083bc66..6c9a6601c24 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -109,6 +109,14 @@ rgb32frame-flip.bmp RCDATA rgb32frame-flip.bmp /* @makedep: rgb32frame-crop.bmp */ rgb32frame-crop.bmp RCDATA rgb32frame-crop.bmp +/* Generated from running the tests on Windows */ +/* @makedep: rgb32frame-crop-flip.bmp */ +rgb32frame-crop-flip.bmp RCDATA rgb32frame-crop-flip.bmp + +/* Generated from running the tests on Windows */ +/* @makedep: abgr32frame-crop.bmp */ +abgr32frame-crop.bmp RCDATA abgr32frame-crop.bmp + /* Generated from running the tests on Windows */ /* @makedep: rgb32frame-grabber.bmp */ rgb32frame-grabber.bmp RCDATA rgb32frame-grabber.bmp diff --git a/dlls/mf/tests/rgb32frame-crop-flip.bmp b/dlls/mf/tests/rgb32frame-crop-flip.bmp new file mode 100644 index 0000000000000000000000000000000000000000..34a28ad44732f38d4165bdc00de313db7c2f390a GIT binary patch literal 27606 zcmeI&!3}~y5J1tP6OUG40p7hByRa#%vK-cdFbyys_V7q%2_Yn#pLc<9e|+DuAGchu zInSI|&JvegBRVeNs(e|lW=y~b$300Rs#zyJdbFu(u< z3^2ez&%iQb7!4R;fB^;=V1NMz7+`<_1{mlW$iD%G(SQL47+`<_1{h#~0R|XgfPtQY v-qY&q#{dHiFu(u<3^2d|0}L?0z-GXqfC36Apnw7jD4>7>3Mim}0{sF%iRi;| literal 0 HcmV?d00001 diff --git a/dlls/mf/tests/rgb32frame-crop.bmp b/dlls/mf/tests/rgb32frame-crop.bmp index 34a28ad44732f38d4165bdc00de313db7c2f390a..310824a5e1061b8ec9a122b3a3638d3844a291bb 100644 GIT binary patch literal 27606 zcmeI4y-EX75Jo40?_uc^SXkPp5g)>hl|L__rJaQ!B4{TB?8Qo~Ed;^JR2H_0m6hXc zHunkUE2cPsZ!aO-%W(G0z3dj*8Gjtu^0O7!&B$(KFEX-?xSHLqeqVlBUHs3TBpJLV z=W`DR2jQscML5E-(w>5k_=t}h2jB?DN)A-2g>y#J8*r3yJen_@AMp_%H4eZLj+Gp!R14>frZ;+ylkbis8O&~9dAe4-U6@|M z5sq~nz(>u!fFm3g`y5g!#Esn)sOKY&GB`J~kIBjQEI;6+CP;^gd4ZCnU+>ar@rg;*|%< zFTM4~`m-;0VV`dkQ|{BR*;zfFm3$IZ&w<&KXT_1jj>LkR*c#`*e%`AUOsn z_60+MM{vw}*!mcbaBMDA81WGwD|pyyz(;&+E>sxt5g#jf*lOr~?5rb61{Zc3V#hxe tkQ9TNjZ^dCKR5_SO)tU`j+OQle8fk5)Hnb~I976?QZ1Y_n%?L+{sU%+=K=r# literal 27606 zcmeI&!3}~y5J1tP6OUG40p7hByRa#%vK-cdFbyys_V7q%2_Yn#pLc<9e|+DuAGchu zInSI|&JvegBRVeNs(e|lW=y~b$300Rs#zyJdbFu(u< z3^2ez&%iQb7!4R;fB^;=V1NMz7+`<_1{mlW$iD%G(SQL47+`<_1{h#~0R|XgfPtQY v-qY&q#{dHiFu(u<3^2d|0}L?0z-GXqfC36Apnw7jD4>7>3Mim}0{sF%iRi;| diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index ff74674f0ca..bd5c52f8243 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -55,10 +55,10 @@ DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0 DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(MFAudioFormat_RAW_AAC1,WAVE_FORMAT_RAW_AAC1,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(MFVideoFormat_ABGR32,0x00000020,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(MFVideoFormat_P208,0x38303250,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(MFVideoFormat_VC1S,0x53314356,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); DEFINE_GUID(MFVideoFormat_WMV_Unknown,0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_P208,MAKEFOURCC('P','2','0','8')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_GUID(mft_output_sample_incomplete,0xffffff,0xffff,0xffff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff); @@ -773,20 +773,23 @@ static void check_mft_set_output_type_required_(int line, IMFTransform *transfor ok_(__FILE__, line)(!ref, "Release returned %lu\n", ref); } -static void check_mft_set_output_type(IMFTransform *transform, const struct attribute_desc *attributes, - HRESULT expect_hr) +#define check_mft_set_output_type(a, b, c) check_mft_set_output_type_(__LINE__, a, b, c, FALSE, FALSE) +static void check_mft_set_output_type_(int line, IMFTransform *transform, const struct attribute_desc *attributes, + HRESULT expect_hr, BOOL todo_test, BOOL todo) { IMFMediaType *media_type; HRESULT hr; hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr); + ok_(__FILE__, line)(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr); init_media_type(media_type, attributes, -1); hr = IMFTransform_SetOutputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); - ok(hr == expect_hr, "SetOutputType returned %#lx.\n", hr); + todo_wine_if(todo_test) + ok_(__FILE__, line)(hr == expect_hr, "SetOutputType returned %#lx.\n", hr); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); - ok(hr == expect_hr, "SetOutputType returned %#lx.\n", hr); + todo_wine_if(todo) + ok_(__FILE__, line)(hr == expect_hr, "SetOutputType returned %#lx.\n", hr); IMFMediaType_Release(media_type); } @@ -934,6 +937,32 @@ DWORD compare_i420(const BYTE *data, DWORD *length, const SIZE *size, const RECT return diff * 100 / 256 / data_size; } +static DWORD compare_abgr32(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect) +{ + DWORD x, y, data_size, diff = 0, width = size->cx, height = size->cy; + + /* skip BMP header from the dump */ + data_size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + data_size; + expect = expect + data_size; + + for (y = 0; y < height; y++, data += width * 4, expect += width * 4) + { + if (y < rect->top || y >= rect->bottom) continue; + for (x = 0; x < width; x++) + { + if (x < rect->left || x >= rect->right) continue; + diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]); + diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]); + diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]); + diff += abs((int)expect[4 * x + 3] - (int)data[4 * x + 3]); + } + } + + data_size = (rect->right - rect->left) * (rect->bottom - rect->top) * 4; + return diff * 100 / 256 / data_size; +} + static DWORD compare_rgb(const BYTE *data, DWORD *length, const SIZE *size, const RECT *rect, const BYTE *expect, UINT bits) { DWORD x, y, step = bits / 8, data_size, diff = 0, width = size->cx, height = size->cy; @@ -7595,22 +7624,22 @@ static void test_video_processor(void) }, { .input_type_desc = nv12_with_aperture, .input_bitmap = L"nv12frame.bmp", - .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop-flip.bmp", .output_sample_desc = &rgb32_crop_sample_desc, }, { - .input_type_desc = rgb32_no_aperture, .input_bitmap = L"rgb32frame-crop.bmp", + .input_type_desc = rgb32_no_aperture, .input_bitmap = L"rgb32frame-crop-flip.bmp", .output_type_desc = rgb32_with_aperture, .output_bitmap = L"rgb32frame-flip.bmp", .output_sample_desc = &rgb32_sample_desc, }, { .input_type_desc = rgb32_with_aperture, .input_bitmap = L"rgb32frame-flip.bmp", - .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop-flip.bmp", .output_sample_desc = &rgb32_crop_sample_desc, }, { .input_type_desc = rgb32_with_aperture_positive_stride, .input_bitmap = L"rgb32frame.bmp", - .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop.bmp", + .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop-flip.bmp", .output_sample_desc = &rgb32_crop_sample_desc, .delta = 3, /* Windows returns 3 */ }, }; @@ -7925,6 +7954,22 @@ static void test_video_processor(void) } ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); + /* MFVideoFormat_ABGR32 isn't supported by the video processor in non-D3D mode */ + check_mft_set_input_type(transform, nv12_default_stride); + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_ABGR32); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); + ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx\n", hr); + IMFMediaType_Release(media_type); + + /* MFVideoFormat_RGB32 output format works */ + + check_mft_set_output_type(transform, rgb32_default_stride, S_OK); + check_mft_get_output_current_type(transform, rgb32_default_stride); + for (i = 0; i < ARRAY_SIZE(video_processor_tests); i++) { const struct transform_desc *test = video_processor_tests + i; @@ -8597,6 +8642,17 @@ static void test_h264_with_dxgi_manager(void) ok(hr == S_OK, "got %#lx\n", hr); IMFMediaType_Release(type); + /* MFVideoFormat_ABGR32 output isn't supported by the D3D11-enabled decoder */ + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_ABGR32); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, type, 0); + ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx\n", hr); + IMFMediaType_Release(type); + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); ok(hr == S_OK, "got %#lx\n", hr); hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); @@ -8985,6 +9041,32 @@ static void test_iv50_decoder(void) IMFCollection_Release(collection); } +static IMFSample *create_d3d_sample(IMFVideoSampleAllocator *allocator, const void *data, ULONG size) +{ + IMFMediaBuffer *media_buffer; + IMFSample *sample; + BYTE *buffer; + HRESULT hr; + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_GetBufferByIndex(sample, 0, &media_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + if (!data) memset(buffer, 0xcd, size); + else memcpy(buffer, data, size); + hr = IMFMediaBuffer_Unlock(media_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaBuffer_Release(media_buffer); + + return sample; +} + static void test_video_processor_with_dxgi_manager(void) { static const unsigned int set_width = 82, set_height = 84, aligned_width = 96, aligned_height = 96; @@ -9005,6 +9087,76 @@ static void test_video_processor_with_dxgi_manager(void) .buffer_count = 1, .buffers = &output_buffer_desc_rgb32, }; + const struct buffer_desc output_buffer_desc_rgb32_crop = + { + .length = set_width * set_height * 4, + .compare = compare_rgb32, .compare_rect = {.right = set_width, .bottom = set_height}, + .dump = dump_rgb32, .size = {.cx = set_width, .cy = set_height}, + }; + const struct sample_desc output_sample_desc_rgb32_crop = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 0, + .buffer_count = 1, .buffers = &output_buffer_desc_rgb32_crop, + }; + + const struct buffer_desc output_buffer_desc_abgr32_crop = + { + .length = set_width * set_height * 4, + .compare = compare_abgr32, .compare_rect = {.right = set_width, .bottom = set_height}, + .dump = dump_rgb32, .size = {.cx = set_width, .cy = set_height}, + }; + const struct sample_desc output_sample_desc_abgr32_crop = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 0, + .buffer_count = 1, .buffers = &output_buffer_desc_abgr32_crop, + }; + + const GUID expect_available_outputs[] = + { + MFVideoFormat_ARGB32, + MFVideoFormat_ABGR32, + MFVideoFormat_A2R10G10B10, + MFVideoFormat_A16B16G16R16F, + MFVideoFormat_NV12, + MFVideoFormat_P010, + MFVideoFormat_YUY2, + MFVideoFormat_L8, + MFVideoFormat_L16, + MFVideoFormat_D16, + }; + static const media_type_desc expect_available_common = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + }; + + static const MFVideoArea aperture = {.Area={set_width, set_height}}; + const struct attribute_desc nv12_with_aperture[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), + ATTR_RATIO(MF_MT_FRAME_SIZE, aligned_width, aligned_height), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &aperture, 16), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &aperture, 16), + ATTR_BLOB(MF_MT_PAN_SCAN_APERTURE, &aperture, 16), + {0}, + }; + const struct attribute_desc rgb32_no_aperture[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, set_width, set_height), + {0}, + }; + const struct attribute_desc abgr32_no_aperture[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_ABGR32), + ATTR_RATIO(MF_MT_FRAME_SIZE, set_width, set_height), + {0}, + }; + IMFVideoSampleAllocator *allocator = NULL; IMFDXGIDeviceManager *manager = NULL; IMFTrackedSample *tracked_sample; @@ -9025,9 +9177,8 @@ static void test_video_processor_with_dxgi_manager(void) ID3D11Device *d3d11; IMFMediaType *type; DWORD status, val; - ULONG i, length; + ULONG i, j, length; UINT32 value; - BYTE *data; HRESULT hr; UINT token; DWORD ret; @@ -9106,6 +9257,45 @@ static void test_video_processor_with_dxgi_manager(void) ok(hr == S_OK, "got %#lx\n", hr); IMFMediaType_Release(type); + j = i = 0; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &type))) + { + GUID guid; + winetest_push_context("out %lu", i); + ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr); + check_media_type(type, expect_available_common, -1); + + hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "GetGUID returned %#lx\n", hr); + + for (; j < ARRAY_SIZE(expect_available_outputs); j++) + if (IsEqualGUID(&expect_available_outputs[j], &guid)) + break; + todo_wine_if(i >= 2) + ok(j < ARRAY_SIZE(expect_available_outputs), "got subtype %s\n", debugstr_guid(&guid)); + + ret = IMFMediaType_Release(type); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + } + ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr); + + + /* MFVideoFormat_ABGR32 is supported by the D3D11-enabled video processor */ + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_ABGR32); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, type, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_Release(type); + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); ok(hr == S_OK, "got %#lx\n", hr); hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); @@ -9130,23 +9320,8 @@ static void test_video_processor_with_dxgi_manager(void) nv12frame_data = nv12frame_data + length; ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); - /* native wants a dxgi buffer on input */ - - hr = IMFVideoSampleAllocator_AllocateSample(allocator, &input_sample); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IMFSample_SetSampleTime(input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IMFSample_SetSampleDuration(input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IMFSample_GetBufferByIndex(input_sample, 0, &buffer); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); - ok(hr == S_OK, "got %#lx\n", hr); - memcpy(data, nv12frame_data, nv12frame_data_len); - hr = IMFMediaBuffer_Unlock(buffer); - ok(hr == S_OK, "got %#lx\n", hr); - IMFMediaBuffer_Release(buffer); + input_sample = create_d3d_sample(allocator, nv12frame_data, nv12frame_data_len); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == S_OK, "got %#lx\n", hr); @@ -9266,6 +9441,143 @@ static void test_video_processor_with_dxgi_manager(void) if (output.pSample) IMFSample_Release(output.pSample); + + /* check RGB32 output aperture cropping with D3D buffers */ + + check_mft_set_input_type(transform, nv12_with_aperture); + check_mft_set_output_type_(__LINE__, transform, rgb32_no_aperture, S_OK, FALSE, TRUE); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_d3d_sample(allocator, nv12frame_data, nv12frame_data_len); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + todo_wine ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + if (!output.pSample) goto skip_rgb32; + + hr = IMFSample_GetBufferByIndex(output.pSample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&tex2d); + ok(hr == S_OK, "got %#lx\n", hr); + memset(&desc, 0xcc, sizeof(desc)); + ID3D11Texture2D_GetDesc(tex2d, &desc); + ok(desc.Format == DXGI_FORMAT_B8G8R8X8_UNORM, "got %#x.\n", desc.Format); + ok(!desc.Usage, "got %u.\n", desc.Usage); + ok(desc.BindFlags == (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), "got %#x.\n", desc.BindFlags); + ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags); + ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags); + ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels); + ok(desc.Width == set_width, "got %u.\n", desc.Width); + ok(desc.Height == set_height, "got %u.\n", desc.Height); + + ID3D11Texture2D_Release(tex2d); + IMFDXGIBuffer_Release(dxgi_buffer); + IMFMediaBuffer_Release(buffer); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32_crop, L"rgb32frame-crop.bmp"); + todo_wine /* FIXME: video process vertically flips the frame... */ + ok(ret <= 5, "got %lu%% diff\n", ret); + + IMFCollection_Release(output_samples); + + +skip_rgb32: + /* check ABGR32 output with D3D buffers */ + + check_mft_set_input_type(transform, nv12_with_aperture); + check_mft_set_output_type_(__LINE__, transform, abgr32_no_aperture, S_OK, TRUE, TRUE); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_d3d_sample(allocator, nv12frame_data, nv12frame_data_len); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + todo_wine ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + if (!output.pSample) goto skip_abgr32; + + hr = IMFSample_GetBufferByIndex(output.pSample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&tex2d); + ok(hr == S_OK, "got %#lx\n", hr); + memset(&desc, 0xcc, sizeof(desc)); + ID3D11Texture2D_GetDesc(tex2d, &desc); + ok(desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "got %#x.\n", desc.Format); + ok(!desc.Usage, "got %u.\n", desc.Usage); + ok(desc.BindFlags == D3D11_BIND_RENDER_TARGET, "got %#x.\n", desc.BindFlags); + ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags); + ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags); + ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels); + ok(desc.Width == set_width, "got %u.\n", desc.Width); + ok(desc.Height == set_height, "got %u.\n", desc.Height); + + ID3D11Texture2D_Release(tex2d); + IMFDXGIBuffer_Release(dxgi_buffer); + IMFMediaBuffer_Release(buffer); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_abgr32_crop, L"abgr32frame-crop.bmp"); + todo_wine /* FIXME: video process vertically flips the frame... */ + ok(ret <= 8 /* NVIDIA needs 5, AMD needs 8 */, "got %lu%% diff\n", ret); + + IMFCollection_Release(output_samples); + + +skip_abgr32: hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0); ok(hr == S_OK, "got %#lx\n", hr); From 3cd95109067b9831ca5ed4bf0d135e00d4bd3c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 Apr 2024 19:06:10 +0200 Subject: [PATCH 200/301] mfreadwrite/tests: Add tests with MFVideoFormat_ABGR32 output format. (cherry picked from commit cc57b05d47506fc1d69f47616a1d8e699a862e15) CW-Bug-Id: #20833 --- dlls/mfreadwrite/tests/mfplat.c | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index d7e143428c6..442037d086d 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -48,6 +48,7 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "wine/test.h" DEFINE_MEDIATYPE_GUID(MFVideoFormat_TEST,MAKEFOURCC('T','E','S','T')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) @@ -2503,7 +2504,8 @@ static HRESULT WINAPI test_decoder_SetOutputType(IMFTransform *iface, DWORD id, HRESULT hr; if (type && SUCCEEDED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)) - && IsEqualGUID(&subtype, &MFVideoFormat_RGB32)) + && (IsEqualGUID(&subtype, &MFVideoFormat_RGB32) + || IsEqualGUID(&subtype, &MFVideoFormat_ABGR32))) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) @@ -3101,6 +3103,12 @@ static void test_source_reader_transforms_d3d9(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(value == 0, "got %u.\n", value); IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputCurrentType(video_processor, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, rgb32_expect_desc, -1); + IMFMediaType_Release(media_type); + IMFTransform_Release(video_processor); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); @@ -3281,6 +3289,22 @@ static void test_source_reader_transforms_d3d11(void) ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), {0}, }; + static const struct attribute_desc abgr32_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_ABGR32), + {0}, + }; + static const struct attribute_desc abgr32_expect_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_ABGR32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + {0}, + }; const MFT_REGISTER_TYPE_INFO output_info[] = { {MFMediaType_Video, MFVideoFormat_NV12}, @@ -3389,6 +3413,21 @@ static void test_source_reader_transforms_d3d11(void) IMFMediaType_Release(media_type); ok(!test_decoder_got_d3d_manager, "d3d manager received\n"); + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, abgr32_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + todo_wine ok(hr == S_OK || broken(hr == MF_E_INVALIDMEDIATYPE) /* needs a GPU */, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + if (hr == S_OK) + { + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, abgr32_expect_desc, -1); + IMFMediaType_Release(media_type); + } + hr = MFCreateMediaType(&media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); init_media_type(media_type, rgb32_stream_type_desc, -1); From 15c4166fe992baf2c5bcb2659ee587f544045b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 May 2024 17:12:17 +0200 Subject: [PATCH 201/301] winegstreamer: Support MFVideoFormat_ABGR32 output in the video processor. (cherry picked from commit f131faaa5acea8e245a63fdd2ea9cb0fb1d8240f) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 14 +++++++------- dlls/winegstreamer/main.c | 2 ++ dlls/winegstreamer/mfplat.c | 2 ++ dlls/winegstreamer/quartz_parser.c | 6 ++++++ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/video_processor.c | 3 +++ dlls/winegstreamer/wg_format.c | 3 +++ 7 files changed, 24 insertions(+), 7 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index bd5c52f8243..673711ae9ab 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -773,9 +773,9 @@ static void check_mft_set_output_type_required_(int line, IMFTransform *transfor ok_(__FILE__, line)(!ref, "Release returned %lu\n", ref); } -#define check_mft_set_output_type(a, b, c) check_mft_set_output_type_(__LINE__, a, b, c, FALSE, FALSE) +#define check_mft_set_output_type(a, b, c) check_mft_set_output_type_(__LINE__, a, b, c, FALSE) static void check_mft_set_output_type_(int line, IMFTransform *transform, const struct attribute_desc *attributes, - HRESULT expect_hr, BOOL todo_test, BOOL todo) + HRESULT expect_hr, BOOL todo) { IMFMediaType *media_type; HRESULT hr; @@ -785,7 +785,6 @@ static void check_mft_set_output_type_(int line, IMFTransform *transform, const init_media_type(media_type, attributes, -1); hr = IMFTransform_SetOutputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); - todo_wine_if(todo_test) ok_(__FILE__, line)(hr == expect_hr, "SetOutputType returned %#lx.\n", hr); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); todo_wine_if(todo) @@ -7942,6 +7941,7 @@ static void test_video_processor(void) for (; k < ARRAY_SIZE(expect_available_outputs); k++) if (IsEqualGUID(&expect_available_outputs[k], &guid)) break; + todo_wine_if(IsEqualGUID(&guid, &MFVideoFormat_ABGR32)) /* enumerated on purpose on Wine */ ok(k < ARRAY_SIZE(expect_available_outputs), "got subtype %s\n", debugstr_guid(&guid)); ret = IMFMediaType_Release(media_type); @@ -7962,7 +7962,7 @@ static void test_video_processor(void) hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_ABGR32); ok(hr == S_OK, "got %#lx\n", hr); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); - ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx\n", hr); + todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx\n", hr); IMFMediaType_Release(media_type); /* MFVideoFormat_RGB32 output format works */ @@ -9292,7 +9292,7 @@ static void test_video_processor_with_dxgi_manager(void) hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); ok(hr == S_OK, "got %#lx\n", hr); hr = IMFTransform_SetOutputType(transform, 0, type, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); IMFMediaType_Release(type); @@ -9445,7 +9445,7 @@ static void test_video_processor_with_dxgi_manager(void) /* check RGB32 output aperture cropping with D3D buffers */ check_mft_set_input_type(transform, nv12_with_aperture); - check_mft_set_output_type_(__LINE__, transform, rgb32_no_aperture, S_OK, FALSE, TRUE); + check_mft_set_output_type_(__LINE__, transform, rgb32_no_aperture, S_OK, TRUE); load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ @@ -9513,7 +9513,7 @@ static void test_video_processor_with_dxgi_manager(void) /* check ABGR32 output with D3D buffers */ check_mft_set_input_type(transform, nv12_with_aperture); - check_mft_set_output_type_(__LINE__, transform, abgr32_no_aperture, S_OK, TRUE, TRUE); + check_mft_set_output_type_(__LINE__, transform, abgr32_no_aperture, S_OK, TRUE); load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 349b46a192f..b8d4aea416b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -891,6 +891,7 @@ unsigned int wg_format_get_stride(const struct wg_format *format) case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_RGBA: return width * 4; case WG_VIDEO_FORMAT_BGR: @@ -926,6 +927,7 @@ bool wg_video_format_is_rgb(enum wg_video_format format) case WG_VIDEO_FORMAT_BGR: case WG_VIDEO_FORMAT_RGB15: case WG_VIDEO_FORMAT_RGB16: + case WG_VIDEO_FORMAT_RGBA: return true; default: diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 755f95d7b4c..ca26cc881e7 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -44,6 +44,7 @@ DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); extern GUID MEDIASUBTYPE_VC1S; @@ -452,6 +453,7 @@ video_formats[] = {&MFVideoFormat_RGB24, WG_VIDEO_FORMAT_BGR}, {&MFVideoFormat_RGB555, WG_VIDEO_FORMAT_RGB15}, {&MFVideoFormat_RGB565, WG_VIDEO_FORMAT_RGB16}, + {&MFVideoFormat_ABGR32, WG_VIDEO_FORMAT_RGBA}, {&MFVideoFormat_AYUV, WG_VIDEO_FORMAT_AYUV}, {&MFVideoFormat_I420, WG_VIDEO_FORMAT_I420}, {&MFVideoFormat_IYUV, WG_VIDEO_FORMAT_I420}, diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 20e2929c5a9..c22f4188785 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -27,6 +27,7 @@ #include #include "dvdmedia.h" +#include "d3d9types.h" #include "mmreg.h" #include "ks.h" #include "wmcodecdsp.h" @@ -39,6 +40,7 @@ static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; +DEFINE_GUID(MEDIASUBTYPE_ABGR32,D3DFMT_A8B8G8R8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); struct parser { @@ -349,6 +351,7 @@ static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: case WG_VIDEO_FORMAT_AYUV: + case WG_VIDEO_FORMAT_RGBA: return width * height * 4; case WG_VIDEO_FORMAT_BGR: @@ -478,6 +481,7 @@ static const GUID *wg_video_format_get_mediasubtype(enum wg_video_format format) case WG_VIDEO_FORMAT_BGR: return &MEDIASUBTYPE_RGB24; case WG_VIDEO_FORMAT_RGB15: return &MEDIASUBTYPE_RGB555; case WG_VIDEO_FORMAT_RGB16: return &MEDIASUBTYPE_RGB565; + case WG_VIDEO_FORMAT_RGBA: return &MEDIASUBTYPE_ABGR32; case WG_VIDEO_FORMAT_AYUV: return &MEDIASUBTYPE_AYUV; case WG_VIDEO_FORMAT_I420: return &MEDIASUBTYPE_I420; case WG_VIDEO_FORMAT_NV12: return &MEDIASUBTYPE_NV12; @@ -506,6 +510,7 @@ static DWORD wg_video_format_get_compression(enum wg_video_format format) case WG_VIDEO_FORMAT_BGR: return BI_RGB; case WG_VIDEO_FORMAT_RGB15: return BI_RGB; case WG_VIDEO_FORMAT_RGB16: return BI_BITFIELDS; + case WG_VIDEO_FORMAT_RGBA: return BI_RGB; case WG_VIDEO_FORMAT_AYUV: return mmioFOURCC('A','Y','U','V'); case WG_VIDEO_FORMAT_I420: return mmioFOURCC('I','4','2','0'); case WG_VIDEO_FORMAT_NV12: return mmioFOURCC('N','V','1','2'); @@ -529,6 +534,7 @@ static WORD wg_video_format_get_depth(enum wg_video_format format) case WG_VIDEO_FORMAT_BGR: return 24; case WG_VIDEO_FORMAT_RGB15: return 16; case WG_VIDEO_FORMAT_RGB16: return 16; + case WG_VIDEO_FORMAT_RGBA: return 32; case WG_VIDEO_FORMAT_AYUV: return 32; case WG_VIDEO_FORMAT_I420: return 12; case WG_VIDEO_FORMAT_NV12: return 12; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index cb9b74a1080..123d1081851 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -68,6 +68,7 @@ enum wg_video_format WG_VIDEO_FORMAT_BGR, WG_VIDEO_FORMAT_RGB15, WG_VIDEO_FORMAT_RGB16, + WG_VIDEO_FORMAT_RGBA, WG_VIDEO_FORMAT_AYUV, WG_VIDEO_FORMAT_I420, diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 0fedfb8451e..6cc504727a9 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -28,6 +28,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); +extern GUID MFVideoFormat_ABGR32; + static const GUID *const input_types[] = { &MFVideoFormat_IYUV, @@ -66,6 +68,7 @@ static const GUID *const output_types[] = &MFVideoFormat_AYUV, &MFVideoFormat_RGB555, &MFVideoFormat_RGB565, + &MFVideoFormat_ABGR32, }; struct video_processor diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 6f433e305b1..eec0ca0665f 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -145,6 +145,8 @@ static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) return WG_VIDEO_FORMAT_RGB15; case GST_VIDEO_FORMAT_RGB16: return WG_VIDEO_FORMAT_RGB16; + case GST_VIDEO_FORMAT_RGBA: + return WG_VIDEO_FORMAT_RGBA; case GST_VIDEO_FORMAT_AYUV: return WG_VIDEO_FORMAT_AYUV; case GST_VIDEO_FORMAT_I420: @@ -570,6 +572,7 @@ static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; + case WG_VIDEO_FORMAT_RGBA: return GST_VIDEO_FORMAT_RGBA; case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; From f5997985c21a3a2ac97ace76c1f555b4bd62645e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 May 2024 11:19:38 +0200 Subject: [PATCH 202/301] mfreadwrite/reader: Fixup MFVideoFormat_ABGR32 subtype to enumerate the video processor. (cherry picked from commit f0e77b163dad11e47576d71561cf03f09b9187fc) CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 13 +++++++++++++ dlls/mfreadwrite/tests/mfplat.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 0e90240e95e..7c51fbe91cf 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -41,6 +41,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); + struct stream_response { struct list entry; @@ -2036,6 +2038,17 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second); } + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video) && IsEqualGUID(&out_type.guidSubtype, &MFVideoFormat_ABGR32) + && IsEqualGUID(&category, &MFT_CATEGORY_VIDEO_PROCESSOR)) + { + /* The video processor isn't registered for MFVideoFormat_ABGR32, and native even only supports that format when + * D3D-enabled, we still want to instantiate a video processor in such case, so fixup the subtype for MFTEnumEx. + */ + WARN("Fixing up MFVideoFormat_ABGR32 subtype for the video processor\n"); + out_type.guidSubtype = MFVideoFormat_RGB32; + } + + count = 0; if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count))) { diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 442037d086d..b813c6639ce 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3417,7 +3417,7 @@ static void test_source_reader_transforms_d3d11(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); init_media_type(media_type, abgr32_stream_type_desc, -1); hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); - todo_wine ok(hr == S_OK || broken(hr == MF_E_INVALIDMEDIATYPE) /* needs a GPU */, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK || broken(hr == MF_E_INVALIDMEDIATYPE) /* needs a GPU */, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); if (hr == S_OK) From 89d017089e1bcce63ad2230129cde85acf4a7bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Apr 2024 12:01:47 +0200 Subject: [PATCH 203/301] winegstreamer: Use DMO_MEDIA_TYPE in the WMA decoder. (cherry picked from commit d05cd460e4e9a791eb2df093d513873d60512f38) CW-Bug-Id: #20833 --- dlls/winegstreamer/wma_decoder.c | 155 +++++++++++++++---------------- 1 file changed, 76 insertions(+), 79 deletions(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 0f68e2ff0c8..164a7c46e2b 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -25,6 +25,7 @@ #include "mftransform.h" #include "wmcodecdsp.h" #include "mediaerr.h" +#include "dmort.h" #include "wine/debug.h" @@ -53,8 +54,8 @@ struct wma_decoder IUnknown *outer; LONG refcount; - struct wg_format input_format; - struct wg_format output_format; + DMO_MEDIA_TYPE input_type; + DMO_MEDIA_TYPE output_type; DWORD input_buf_size; DWORD output_buf_size; @@ -73,19 +74,13 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) struct wg_transform_attrs attrs = {0}; if (decoder->wg_transform) + { wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + decoder->wg_transform = 0; + } - return S_OK; + return wg_transform_create_quartz(&decoder->input_type, &decoder->output_type, + &attrs, &decoder->wg_transform); } static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) @@ -136,6 +131,9 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) wg_transform_destroy(decoder->wg_transform); wg_sample_queue_destroy(decoder->wg_sample_queue); + + MoFreeMediaType(&decoder->input_type); + MoFreeMediaType(&decoder->output_type); free(decoder); } @@ -202,8 +200,8 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id TRACE("iface %p, id %lu, info %p.\n", iface, id, info); - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL) + || IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -223,8 +221,8 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i TRACE("iface %p, id %lu, info %p.\n", iface, id, info); - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL) + || IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -280,11 +278,12 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR struct wma_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *media_type; const GUID *output_type; + WAVEFORMATEX *wfx; HRESULT hr; TRACE("iface %p, id %lu, index %lu, type %p.\n", iface, id, index, type); - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET; *type = NULL; @@ -316,20 +315,16 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR sample_size))) goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, - decoder->input_format.u.audio.channels))) + wfx = (WAVEFORMATEX *)decoder->input_type.pbFormat; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, wfx->nChannels))) goto done; - - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, - decoder->input_format.u.audio.rate))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, wfx->nSamplesPerSec))) goto done; - block_alignment = sample_size * decoder->input_format.u.audio.channels / 8; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, - block_alignment))) + block_alignment = sample_size * wfx->nChannels / 8; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, - decoder->input_format.u.audio.rate * block_alignment))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, wfx->nSamplesPerSec * block_alignment))) goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) @@ -385,9 +380,13 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - mf_media_type_to_wg_format(type, &decoder->input_format); - decoder->input_buf_size = block_alignment; - decoder->output_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + MoFreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); + MoFreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); + + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, &decoder->input_type))) + decoder->input_buf_size = block_alignment; return hr; } @@ -403,7 +402,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF TRACE("iface %p, id %lu, type %p, flags %#lx.\n", iface, id, type, flags); - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET; if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || @@ -446,10 +445,15 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - decoder->input_format.u.audio.depth = sample_size; + MoFreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); - mf_media_type_to_wg_format(type, &decoder->output_format); - decoder->output_buf_size = 1024 * block_alignment * channel_count; + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, &decoder->output_type))) + { + WAVEFORMATEX *wfx = (WAVEFORMATEX *)decoder->input_type.pbFormat; + wfx->wBitsPerSample = sample_size; + decoder->output_buf_size = 1024 * block_alignment * channel_count; + } if (FAILED(hr = try_create_wg_transform(decoder))) goto failed; @@ -457,7 +461,8 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF return S_OK; failed: - decoder->output_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + MoFreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); return hr; } @@ -667,7 +672,9 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde DMO_MEDIA_TYPE *type) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); - WAVEFORMATEX *wfx; + IMFMediaType *media_type; + UINT32 depth; + HRESULT hr; TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface, index, type_index, type); @@ -675,42 +682,34 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde return DMO_E_INVALIDSTREAMINDEX; if (type_index >= 1) return DMO_E_NO_MORE_ITEMS; - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; if (!type) return S_OK; - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Audio; - type->subtype = MEDIASUBTYPE_PCM; - type->formattype = FORMAT_WaveFormatEx; - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; - - type->cbFormat = sizeof(WAVEFORMATEX); - type->pbFormat = CoTaskMemAlloc(type->cbFormat); - memset(type->pbFormat, 0, type->cbFormat); + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->input_type, &media_type))) + return hr; - wfx = (WAVEFORMATEX *)type->pbFormat; - if (decoder->input_format.u.audio.depth == 32) - wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth)) + && depth == 32) + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float); else - wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = decoder->input_format.u.audio.channels; - wfx->nSamplesPerSec = decoder->input_format.u.audio.rate; - wfx->wBitsPerSample = decoder->input_format.u.audio.depth; - wfx->nAvgBytesPerSec = wfx->nChannels * wfx->nSamplesPerSec * wfx->wBitsPerSample / 8; - wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); - return S_OK; + if (SUCCEEDED(hr)) + hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA); + if (SUCCEEDED(hr)) + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, type); + + IMFMediaType_Release(media_type); + return hr; } static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_format wg_format; unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -722,7 +721,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { if (flags != DMO_SET_TYPEF_CLEAR) return E_INVALIDARG; - memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + MoFreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -744,14 +744,13 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (i == ARRAY_SIZE(wma_decoder_input_types)) return DMO_E_TYPE_NOT_ACCEPTED; - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) - return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_AUDIO_WMA); - if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - decoder->input_format = wg_format; + MoFreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); + MoCopyMediaType(&decoder->input_type, type); + if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -766,8 +765,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { struct wma_decoder *decoder = impl_from_IMediaObject(iface); struct wg_transform_attrs attrs = {0}; - struct wg_format wg_format; unsigned int i; + HRESULT hr; TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); @@ -778,7 +777,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { if (flags != DMO_SET_TYPEF_CLEAR) return E_INVALIDARG; - memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + MoFreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -800,18 +800,14 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (i == ARRAY_SIZE(wma_decoder_output_types)) return DMO_E_TYPE_NOT_ACCEPTED; - - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) - return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_AUDIO); - - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - decoder->output_format = wg_format; + MoFreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); + MoCopyMediaType(&decoder->output_type, type); /* Set up wg_transform. */ if (decoder->wg_transform) @@ -819,8 +815,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = 0; } - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, &decoder->output_type, + &attrs, &decoder->wg_transform))) + return hr; return S_OK; } @@ -855,7 +852,7 @@ static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD return E_POINTER; if (index > 0) return DMO_E_INVALIDSTREAMINDEX; - if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; *size = 8192; From 7148b61d9da08e3ef1857892ae65dcf257d1a709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 May 2024 12:01:08 +0200 Subject: [PATCH 204/301] winegstreamer: Implement WMA DMO Get(Input|Output)CurrentType. (cherry picked from commit 52ae7e7b642195777b62986110f878b437b7d194) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 33 +++++--------------------------- dlls/winegstreamer/wma_decoder.c | 26 +++++++++++++++++++++---- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 673711ae9ab..783276bed4b 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3519,37 +3519,26 @@ static void test_wma_decoder_dmo_input_type(void) hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 0, NULL); - todo_wine ok(hr == DMO_E_TYPE_NOT_SET, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, &type); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 0, &type); - todo_wine ok(hr == DMO_E_TYPE_NOT_SET, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 0, NULL); - todo_wine ok(hr == E_POINTER, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, &type); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 0, &type); - todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr); - if (hr == S_OK) - { - check_dmo_media_type(&type, good_input_type); - MoFreeMediaType(&type); - } + check_dmo_media_type(&type, good_input_type); + MoFreeMediaType(&type); /* Cleanup. */ ret = IMediaObject_Release(dmo); @@ -3721,8 +3710,6 @@ static void test_wma_decoder_dmo_output_type(void) /* Test GetOutputCurrentType. */ hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); - todo_wine - { hr = IMediaObject_GetOutputCurrentType(dmo, 1, NULL); ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, NULL); @@ -3731,12 +3718,9 @@ static void test_wma_decoder_dmo_output_type(void) ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr); - } hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); - todo_wine - { hr = IMediaObject_GetOutputCurrentType(dmo, 1, NULL); ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, NULL); @@ -3745,12 +3729,8 @@ static void test_wma_decoder_dmo_output_type(void) ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); ok(hr == S_OK, "GetOutputCurrentType returned %#lx.\n", hr); - } - if (hr == S_OK) - { - check_dmo_media_type(&type, good_output_type); - MoFreeMediaType(&type); - } + check_dmo_media_type(&type, good_output_type); + MoFreeMediaType(&type); /* Test GetOutputSizeInfo. */ hr = IMediaObject_GetOutputSizeInfo(dmo, 1, NULL, NULL); @@ -3767,20 +3747,17 @@ static void test_wma_decoder_dmo_output_type(void) ok(alignment == 1, "Unexpected alignment %lu.\n", alignment); hr = IMediaObject_GetInputCurrentType(dmo, 0, input_type); - todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); - todo_wine ok(hr == S_OK, "GetOutputCurrentType returned %#lx.\n", hr); init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate * 2, 32); hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); - todo_wine - ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr); + todo_wine ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr); /* Cleanup. */ ret = IMediaObject_Release(dmo); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 164a7c46e2b..e316e99c04b 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -824,14 +824,32 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; + struct wma_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, type %p\n", iface, index, type); + + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + if (!type) + return E_POINTER; + return MoCopyMediaType(type, &decoder->input_type); } static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; + struct wma_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, type %p\n", iface, index, type); + + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + if (!type) + return E_POINTER; + return MoCopyMediaType(type, &decoder->output_type); } static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, From 22b30d8eca41ec713709a0f2eebfb92caec7042a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 14:06:35 +0200 Subject: [PATCH 205/301] winegstreamer: Use a GstCaps for wg_parser current_format. And rename it desired_caps as this is the caps that has been requested, not necessarily the current stream caps. (cherry picked from commit 4f96f2f5546c7cd32623a3a23c9112968f2fbcf0) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index c93609bac1a..8651ed6244e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -120,7 +120,8 @@ struct wg_parser_stream GstPad *my_sink; GstElement *flip, *decodebin; GstSegment segment; - struct wg_format preferred_format, current_format, codec_format; + struct wg_format preferred_format, codec_format; + GstCaps *desired_caps; pthread_cond_t event_cond, event_empty_cond; GstBuffer *buffer; @@ -261,7 +262,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) pthread_mutex_lock(&parser->mutex); - stream->current_format = *format; + stream->desired_caps = wg_format_to_caps(format); stream->enabled = true; pthread_mutex_unlock(&parser->mutex); @@ -284,7 +285,11 @@ static NTSTATUS wg_parser_stream_disable(void *args) pthread_mutex_lock(&parser->mutex); stream->enabled = false; - stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + if (stream->desired_caps) + { + gst_caps_unref(stream->desired_caps); + stream->desired_caps = NULL; + } pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&stream->event_cond); pthread_cond_signal(&stream->event_empty_cond); @@ -835,11 +840,12 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) gst_query_parse_caps(query, &filter); pthread_mutex_lock(&parser->mutex); - caps = wg_format_to_caps(&stream->current_format); - pthread_mutex_unlock(&parser->mutex); - - if (!caps) + if (!stream->desired_caps || !(caps = gst_caps_copy(stream->desired_caps))) + { + pthread_mutex_unlock(&parser->mutex); return FALSE; + } + pthread_mutex_unlock(&parser->mutex); /* Clear some fields that shouldn't prevent us from connecting. */ for (i = 0; i < gst_caps_get_size(caps); ++i) @@ -862,13 +868,13 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) case GST_QUERY_ACCEPT_CAPS: { - struct wg_format format; + struct wg_format format, current_format; gboolean ret = TRUE; GstCaps *caps; pthread_mutex_lock(&parser->mutex); - if (stream->current_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (!stream->desired_caps) { pthread_mutex_unlock(&parser->mutex); gst_query_set_accept_caps_result(query, TRUE); @@ -877,7 +883,8 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) gst_query_parse_accept_caps(query, &caps); wg_format_from_caps(&format, caps); - ret = wg_format_compare(&format, &stream->current_format); + wg_format_from_caps(¤t_format, stream->desired_caps); + ret = wg_format_compare(&format, ¤t_format); pthread_mutex_unlock(&parser->mutex); @@ -911,7 +918,6 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser, char *id stream->parser = parser; stream->number = parser->stream_count; stream->no_more_pads = true; - stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; pthread_cond_init(&stream->event_cond, NULL); pthread_cond_init(&stream->event_empty_cond, NULL); From e95b79009542414363c89f6deacd50ddfb70dcfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 14:11:36 +0200 Subject: [PATCH 206/301] winegstreamer: Use a GstCaps instead of preferred_format. And rename it current_caps as this is the actual current stream caps. (cherry picked from commit 60b2f0848566a8e95f406ae4ddbab1590c70103f) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 8651ed6244e..429677da860 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -120,14 +120,15 @@ struct wg_parser_stream GstPad *my_sink; GstElement *flip, *decodebin; GstSegment segment; - struct wg_format preferred_format, codec_format; + struct wg_format codec_format; + GstCaps *current_caps; GstCaps *desired_caps; pthread_cond_t event_cond, event_empty_cond; GstBuffer *buffer; GstMapInfo map_info; - bool flushing, eos, enabled, has_caps, has_tags, has_buffer, no_more_pads; + bool flushing, eos, enabled, has_tags, has_buffer, no_more_pads; uint64_t duration; gchar *tags[WG_PARSER_TAG_COUNT]; @@ -237,8 +238,13 @@ static NTSTATUS wg_parser_push_data(void *args) static NTSTATUS wg_parser_stream_get_preferred_format(void *args) { const struct wg_parser_stream_get_preferred_format_params *params = args; + struct wg_parser_stream *stream = get_stream(params->stream); + + if (stream->current_caps) + wg_format_from_caps(params->format, stream->current_caps); + else + memset(params->format, 0, sizeof(*params->format)); - *params->format = get_stream(params->stream)->preferred_format; return S_OK; } @@ -247,9 +253,13 @@ static NTSTATUS wg_parser_stream_get_codec_format(void *args) struct wg_parser_stream_get_codec_format_params *params = args; struct wg_parser_stream *stream = get_stream(params->stream); - *params->format = format_is_compressed(&stream->codec_format) ? - stream->codec_format : - stream->preferred_format; + if (format_is_compressed(&stream->codec_format)) + *params->format = stream->codec_format; + else if (stream->current_caps) + wg_format_from_caps(params->format, stream->current_caps); + else + memset(params->format, 0, sizeof(*params->format)); + return S_OK; } @@ -744,8 +754,7 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) gst_event_parse_caps(event, &caps); pthread_mutex_lock(&parser->mutex); - wg_format_from_caps(&stream->preferred_format, caps); - stream->has_caps = true; + stream->current_caps = gst_caps_ref(caps); pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->init_cond); break; @@ -1870,7 +1879,7 @@ static NTSTATUS wg_parser_connect(void *args) gint64 duration; /* If we received a buffer, waiting for tags or caps does not make sense anymore. */ - while ((!stream->has_caps || !stream->has_tags) && !parser->error && !stream->has_buffer) + while ((!stream->current_caps || !stream->has_tags) && !parser->error && !stream->has_buffer) pthread_cond_wait(&parser->init_cond, &parser->mutex); /* GStreamer doesn't actually provide any guarantees about when duration From 97be1c074787be548152c510df9d3c2b7e2514c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 May 2024 17:19:43 +0200 Subject: [PATCH 207/301] winegstreamer: Rename get_preferred_format to get_current_format. (cherry picked from commit 08730dae2ebf96b5ec470642018b702cca11518c) CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 6 +++--- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 16 ++++++++-------- dlls/winegstreamer/unixlib.h | 4 ++-- dlls/winegstreamer/wg_parser.c | 14 +++++++------- dlls/winegstreamer/wm_reader.c | 12 ++++++------ 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index ca4b1e279ca..0c0e20a8566 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -82,7 +82,7 @@ void wg_parser_push_data(wg_parser_t parser, const void *data, uint32_t size); uint32_t wg_parser_get_stream_count(wg_parser_t parser); wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index); -void wg_parser_stream_get_preferred_format(wg_parser_stream_t stream, struct wg_format *format); +void wg_parser_stream_get_current_format(wg_parser_stream_t stream, struct wg_format *format); void wg_parser_stream_get_codec_format(wg_parser_stream_t stream, struct wg_format *format); void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format); void wg_parser_stream_disable(wg_parser_stream_t stream); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index b8d4aea416b..414c45fcebd 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -178,9 +178,9 @@ wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index) return params.stream; } -void wg_parser_stream_get_preferred_format(wg_parser_stream_t stream, struct wg_format *format) +void wg_parser_stream_get_current_format(wg_parser_stream_t stream, struct wg_format *format) { - struct wg_parser_stream_get_preferred_format_params params = + struct wg_parser_stream_get_current_format_params params = { .stream = stream, .format = format, @@ -188,7 +188,7 @@ void wg_parser_stream_get_preferred_format(wg_parser_stream_t stream, struct wg_ TRACE("stream %#I64x, format %p.\n", stream, format); - WINE_UNIX_CALL(unix_wg_parser_stream_get_preferred_format, ¶ms); + WINE_UNIX_CALL(unix_wg_parser_stream_get_current_format, ¶ms); } void wg_parser_stream_get_codec_format(wg_parser_stream_t stream, struct wg_format *format) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 47195172a24..8b06c720200 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1744,7 +1744,7 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc struct media_stream *stream; struct wg_format format; - wg_parser_stream_get_preferred_format(wg_stream, &format); + wg_parser_stream_get_current_format(wg_stream, &format); if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) goto fail; if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, wg_stream, &stream))) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index c22f4188785..0e387353743 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1632,7 +1632,7 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin, WG_VIDEO_FORMAT_RGB15, }; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); memset(mt, 0, sizeof(AM_MEDIA_TYPE)); @@ -2239,7 +2239,7 @@ static HRESULT wave_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE pad_mt; HRESULT hr; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -2254,7 +2254,7 @@ static HRESULT wave_parser_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; @@ -2317,7 +2317,7 @@ static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE pad_mt; HRESULT hr; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -2332,7 +2332,7 @@ static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; @@ -2388,7 +2388,7 @@ static BOOL mpeg_splitter_filter_init_gst(struct parser *filter) for (i = 0; i < stream_count; ++i) { stream = wg_parser_get_stream(parser, i); - wg_parser_stream_get_preferred_format(stream, &fmt); + wg_parser_stream_get_current_format(stream, &fmt); if (fmt.major_type == WG_MAJOR_TYPE_VIDEO_MPEG1) { if (!create_pin(filter, wg_parser_get_stream(parser, i), L"Video")) @@ -2411,7 +2411,7 @@ static HRESULT mpeg_splitter_source_query_accept(struct parser_source *pin, cons AM_MEDIA_TYPE pad_mt; HRESULT hr; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -2426,7 +2426,7 @@ static HRESULT mpeg_splitter_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; - wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_current_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 123d1081851..8a343deaccf 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -238,7 +238,7 @@ struct wg_parser_get_stream_params wg_parser_stream_t stream; }; -struct wg_parser_stream_get_preferred_format_params +struct wg_parser_stream_get_current_format_params { wg_parser_stream_t stream; struct wg_format *format; @@ -477,7 +477,7 @@ enum unix_funcs unix_wg_parser_get_stream_count, unix_wg_parser_get_stream, - unix_wg_parser_stream_get_preferred_format, + unix_wg_parser_stream_get_current_format, unix_wg_parser_stream_get_codec_format, unix_wg_parser_stream_enable, unix_wg_parser_stream_disable, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 429677da860..b696a2a24ea 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -235,9 +235,9 @@ static NTSTATUS wg_parser_push_data(void *args) return S_OK; } -static NTSTATUS wg_parser_stream_get_preferred_format(void *args) +static NTSTATUS wg_parser_stream_get_current_format(void *args) { - const struct wg_parser_stream_get_preferred_format_params *params = args; + const struct wg_parser_stream_get_current_format_params *params = args; struct wg_parser_stream *stream = get_stream(params->stream); if (stream->current_caps) @@ -2232,7 +2232,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_stream_count), X(wg_parser_get_stream), - X(wg_parser_stream_get_preferred_format), + X(wg_parser_stream_get_current_format), X(wg_parser_stream_get_codec_format), X(wg_parser_stream_enable), X(wg_parser_stream_disable), @@ -2319,20 +2319,20 @@ static NTSTATUS wow64_wg_parser_push_data(void *args) { return wg_parser_push_data(¶ms); } -static NTSTATUS wow64_wg_parser_stream_get_preferred_format(void *args) +static NTSTATUS wow64_wg_parser_stream_get_current_format(void *args) { struct { wg_parser_stream_t stream; PTR32 format; } *params32 = args; - struct wg_parser_stream_get_preferred_format_params params = + struct wg_parser_stream_get_current_format_params params = { .stream = params32->stream, .format = ULongToPtr(params32->format), }; - return wg_parser_stream_get_preferred_format(¶ms); + return wg_parser_stream_get_current_format(¶ms); } static NTSTATUS wow64_wg_parser_stream_get_codec_format(void *args) @@ -2677,7 +2677,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X(wg_parser_get_stream_count), X(wg_parser_get_stream), - X64(wg_parser_stream_get_preferred_format), + X64(wg_parser_stream_get_current_format), X64(wg_parser_stream_get_codec_format), X64(wg_parser_stream_enable), X(wg_parser_stream_disable), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 79251f8ebc9..16b5ca3bcd1 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1490,7 +1490,7 @@ static HRESULT init_stream(struct wm_reader *reader) stream->reader = reader; stream->index = i; stream->selection = WMT_ON; - wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format); + wg_parser_stream_get_current_format(stream->wg_stream, &stream->format); if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO) { /* R.U.S.E enumerates available audio types, picks the first one it @@ -1600,7 +1600,7 @@ static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed) stream->wg_stream = wg_parser_get_stream(reader->wg_parser, reader->stream_count - i - 1); stream->reader = reader; - wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_get_current_format(stream->wg_stream, &format); if (stream->selection == WMT_ON) wg_parser_stream_enable(stream->wg_stream, read_compressed ? &format : &stream->format); } @@ -2018,7 +2018,7 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, return E_INVALIDARG; } - wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_get_current_format(stream->wg_stream, &format); switch (format.major_type) { @@ -2079,7 +2079,7 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o return E_INVALIDARG; } - wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_get_current_format(stream->wg_stream, &format); switch (format.major_type) { case WG_MAJOR_TYPE_VIDEO: @@ -2330,7 +2330,7 @@ static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, return E_INVALIDARG; } - wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format); + wg_parser_stream_get_current_format(stream->wg_stream, &pref_format); if (pref_format.major_type != format.major_type) { /* R.U.S.E sets the type of the wrong stream, apparently by accident. */ @@ -2519,7 +2519,7 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface, if (stream->read_compressed) { struct wg_format format; - wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_get_current_format(stream->wg_stream, &format); wg_parser_stream_enable(stream->wg_stream, &format); } else From 3bd03349c312151d600a5b4de59db172a4c35753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 14:18:53 +0200 Subject: [PATCH 208/301] winegstreamer: Use a GstCaps for wg_parser_stream codec format. (cherry picked from commit 2d3910d4cd128062a248706af805c22fe20248c0) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b696a2a24ea..1f3d59b0c58 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -120,7 +120,7 @@ struct wg_parser_stream GstPad *my_sink; GstElement *flip, *decodebin; GstSegment segment; - struct wg_format codec_format; + GstCaps *codec_caps; GstCaps *current_caps; GstCaps *desired_caps; @@ -146,11 +146,17 @@ static struct wg_parser_stream *get_stream(wg_parser_stream_t stream) return (struct wg_parser_stream *)(ULONG_PTR)stream; } -static bool format_is_compressed(struct wg_format *format) +static bool caps_is_compressed(GstCaps *caps) { - return format->major_type != WG_MAJOR_TYPE_UNKNOWN - && format->major_type != WG_MAJOR_TYPE_VIDEO - && format->major_type != WG_MAJOR_TYPE_AUDIO; + struct wg_format format; + + if (!caps) + return false; + wg_format_from_caps(&format, caps); + + return format.major_type != WG_MAJOR_TYPE_UNKNOWN + && format.major_type != WG_MAJOR_TYPE_VIDEO + && format.major_type != WG_MAJOR_TYPE_AUDIO; } static NTSTATUS wg_parser_get_stream_count(void *args) @@ -253,8 +259,8 @@ static NTSTATUS wg_parser_stream_get_codec_format(void *args) struct wg_parser_stream_get_codec_format_params *params = args; struct wg_parser_stream *stream = get_stream(params->stream); - if (format_is_compressed(&stream->codec_format)) - *params->format = stream->codec_format; + if (caps_is_compressed(stream->codec_caps)) + wg_format_from_caps(params->format, stream->codec_caps); else if (stream->current_caps) wg_format_from_caps(params->format, stream->current_caps); else @@ -537,11 +543,7 @@ static bool parser_no_more_pads(struct wg_parser *parser) static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCaps * caps, gpointer user) { - struct wg_format format; - - wg_format_from_caps(&format, caps); - - return !format_is_compressed(&format); + return !caps_is_compressed(caps); } static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, @@ -1167,7 +1169,6 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { struct wg_parser_stream *stream; struct wg_parser *parser = user; - GstCaps *caps; GST_LOG("parser %p, element %p, pad %p.", parser, element, pad); @@ -1176,13 +1177,10 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!(stream = create_stream(parser, gst_pad_get_stream_id(pad)))) return; - - caps = gst_pad_query_caps(pad, NULL); - wg_format_from_caps(&stream->codec_format, caps); - gst_caps_unref(caps); + stream->codec_caps = gst_pad_query_caps(pad, NULL); /* For compressed stream, create an extra decodebin to decode it. */ - if (!parser->output_compressed && format_is_compressed(&stream->codec_format)) + if (!parser->output_compressed && caps_is_compressed(stream->codec_caps)) { if (!stream_decodebin_create(stream)) { From 5d4a01a3f45be66881647cee6da4d9f07e7d674e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 18:09:36 +0200 Subject: [PATCH 209/301] winegstreamer: Allow to clear video decoder input/output types. (cherry picked from commit 6bed7314ca10918d1454bf4602a648a997cd28d7) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 10 ++++++-- dlls/winegstreamer/video_decoder.c | 37 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 783276bed4b..4dec1ce7df6 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5886,6 +5886,7 @@ static void test_wmv_decoder(void) const struct sample_desc *output_sample_desc; const WCHAR *result_bitmap; ULONG delta; + BOOL todo; } transform_tests[] = { @@ -5908,7 +5909,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info, .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", - .delta = 0, + .delta = 0, .todo = TRUE, }, { @@ -5941,7 +5942,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info_rgb, .output_sample_desc = &output_sample_desc_rgb, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 5, + .delta = 5, .todo = TRUE, }, }; @@ -6114,8 +6115,13 @@ static void test_wmv_decoder(void) ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc, transform_tests[j].result_bitmap); + todo_wine_if(transform_tests[j].todo) ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); + + hr = IMFTransform_SetOutputType(transform, 0, NULL, 0); + ok(hr == S_OK, "SetOutputType returned %#lx\n", hr); + winetest_pop_context(); } diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index f128e6dd025..b540c804256 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -552,6 +552,27 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + if (!type) + { + if (decoder->input_type) + { + IMFMediaType_Release(decoder->input_type); + decoder->input_type = NULL; + } + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; + } + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) return E_INVALIDARG; @@ -603,6 +624,22 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + if (!type) + { + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; + } + if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; From 8ec17faa408a9d6f4f53a7064d668f873765ccf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 11:47:43 +0200 Subject: [PATCH 210/301] winegstreamer: Enforce default stride value in the video decoder. (cherry picked from commit 5b8b20c82acf3bebd971c9ee191391e1bd721d9c) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 7 +++-- dlls/winegstreamer/video_decoder.c | 42 ++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 4dec1ce7df6..c5626a918a5 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5909,7 +5909,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info, .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", - .delta = 0, .todo = TRUE, + .delta = 0, }, { @@ -5935,14 +5935,14 @@ static void test_wmv_decoder(void) }, { - /* WMV1 -> RGB (positive stride */ + /* WMV1 -> RGB (positive stride) */ .output_type_desc = output_type_desc_rgb_positive_stride, .expect_output_type_desc = expect_output_type_desc_rgb, .expect_input_info = &expect_input_info_rgb, .expect_output_info = &expect_output_info_rgb, .output_sample_desc = &output_sample_desc_rgb, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 5, .todo = TRUE, + .delta = 5, }, }; @@ -6115,7 +6115,6 @@ static void test_wmv_decoder(void) ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc, transform_tests[j].result_bitmap); - todo_wine_if(transform_tests[j].todo) ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index b540c804256..817693a3417 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -238,7 +238,23 @@ static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); } -static HRESULT try_create_wg_transform(struct video_decoder *decoder) +static HRESULT normalize_stride(IMFMediaType *media_type, IMFMediaType **ret) +{ + DMO_MEDIA_TYPE amt; + HRESULT hr; + + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_VideoInfo, &amt))) + { + VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)amt.pbFormat; + vih->bmiHeader.biHeight = abs(vih->bmiHeader.biHeight); + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, ret); + FreeMediaType(&amt); + } + + return hr; +} + +static HRESULT try_create_wg_transform(struct video_decoder *decoder, IMFMediaType *output_type) { /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput * return values, it calls them in a specific order and expects the decoder @@ -262,7 +278,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) decoder->wg_transform_attrs.low_latency = FALSE; } - return wg_transform_create_mf(decoder->input_type, decoder->output_type, &decoder->wg_transform_attrs, &decoder->wg_transform); + return wg_transform_create_mf(decoder->input_type, output_type, &decoder->wg_transform_attrs, &decoder->wg_transform); } static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, @@ -618,6 +634,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF { struct video_decoder *decoder = impl_from_IMFTransform(iface); UINT64 frame_size, stream_frame_size; + IMFMediaType *output_type; GUID major, subtype; HRESULT hr; ULONG i; @@ -668,25 +685,40 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF IMFMediaType_Release(decoder->output_type); IMFMediaType_AddRef((decoder->output_type = type)); + /* WMV decoder outputs RGB formats with default stride forced to negative, likely a + * result of internal conversion to DMO media type */ + if (!decoder->IMediaObject_iface.lpVtbl) + { + output_type = decoder->output_type; + IMFMediaType_AddRef(output_type); + } + else if (FAILED(hr = normalize_stride(decoder->output_type, &output_type))) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return hr; + } + if (decoder->wg_transform) { struct wg_format output_format; - mf_media_type_to_wg_format(decoder->output_type, &output_format); + mf_media_type_to_wg_format(output_type, &output_format); if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; - return MF_E_INVALIDMEDIATYPE; + hr = MF_E_INVALIDMEDIATYPE; } } - else if (FAILED(hr = try_create_wg_transform(decoder))) + else if (FAILED(hr = try_create_wg_transform(decoder, output_type))) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; } + IMFMediaType_Release(output_type); return hr; } From 2c41f176becba329c69bfaa43993e373d2046f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 11:42:50 +0200 Subject: [PATCH 211/301] winegstreamer: Enforce default stride presence in the video processor. (cherry picked from commit 2fef494765deccb98258d749e876e663081e90e1) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 1 - dlls/winegstreamer/video_processor.c | 40 +++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index c5626a918a5..142251a2382 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -9377,7 +9377,6 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample); ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); - todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 5, "got %lu%% diff\n", ret); for (i = 0; i < 9; i++) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 6cc504727a9..2461140ab21 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -91,9 +91,36 @@ struct video_processor IMFVideoSampleAllocatorEx *allocator; }; +static HRESULT normalize_stride(IMFMediaType *media_type, BOOL bottom_up, IMFMediaType **ret) +{ + MFVIDEOFORMAT *format; + LONG stride; + UINT32 size; + HRESULT hr; + + if (SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) + { + *ret = media_type; + IMFMediaType_AddRef(media_type); + return hr; + } + + if (SUCCEEDED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &format, &size))) + { + if (bottom_up) format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; + hr = MFCreateVideoMediaType(format, (IMFVideoMediaType **)ret); + CoTaskMemFree(format); + } + + return hr; +} + static HRESULT try_create_wg_transform(struct video_processor *impl) { + BOOL bottom_up = !impl->device_manager; /* when not D3D-enabled, the transform outputs bottom up RGB buffers */ + IMFMediaType *input_type, *output_type; struct wg_transform_attrs attrs = {0}; + HRESULT hr; if (impl->wg_transform) { @@ -101,7 +128,18 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) impl->wg_transform = 0; } - return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); + if (FAILED(hr = normalize_stride(impl->input_type, bottom_up, &input_type))) + return hr; + if (FAILED(hr = normalize_stride(impl->output_type, bottom_up, &output_type))) + { + IMFMediaType_Release(input_type); + return hr; + } + hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform); + IMFMediaType_Release(output_type); + IMFMediaType_Release(input_type); + + return hr; } static HRESULT video_processor_init_allocator(struct video_processor *processor) From 30887599c9e175e680a5f71ed01daa58b3daab07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Jun 2024 09:53:16 +0200 Subject: [PATCH 212/301] winegstreamer: Rename allow_size_change to allow_format_change. (cherry picked from commit aaa83820752e5313540e5e7127381b9c81de58dc) CW-Bug-Id: #20833 --- dlls/winegstreamer/unixlib.h | 2 +- dlls/winegstreamer/video_decoder.c | 2 +- dlls/winegstreamer/wg_transform.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 8a343deaccf..82f768c58cc 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -385,7 +385,7 @@ struct wg_transform_attrs { UINT32 output_plane_align; UINT32 input_queue_length; - BOOL allow_size_change; + BOOL allow_format_change; BOOL low_latency; }; diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 817693a3417..e405b6da055 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1654,7 +1654,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) decoder->output_info.cbSize = 1920 * 1088 * 2; decoder->wg_transform_attrs.output_plane_align = 15; - decoder->wg_transform_attrs.allow_size_change = TRUE; + decoder->wg_transform_attrs.allow_format_change = TRUE; TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e645fd0f006..22b3943353f 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -194,7 +194,7 @@ static GstCaps *transform_format_to_caps(struct wg_transform *transform, const s if (format->major_type == WG_MAJOR_TYPE_VIDEO) { - if (transform->attrs.allow_size_change) + if (transform->attrs.allow_format_change) copy.u.video.width = copy.u.video.height = 0; copy.u.video.fps_n = copy.u.video.fps_d = 0; } From 0baaca7819ef6bc4d248e49029dd1813b9dd11ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 14:51:48 +0200 Subject: [PATCH 213/301] winegstreamer: Only report format changes when frontend supports it. (cherry picked from commit a8bdb0a6378884ca20df7878e05dc2f3a9e09107) CW-Bug-Id: #20833 --- dlls/quartz/tests/mpegvideo.c | 9 ++++----- dlls/winegstreamer/wg_transform.c | 6 ++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/dlls/quartz/tests/mpegvideo.c b/dlls/quartz/tests/mpegvideo.c index 08c59e169fb..835bc5bec42 100644 --- a/dlls/quartz/tests/mpegvideo.c +++ b/dlls/quartz/tests/mpegvideo.c @@ -1201,7 +1201,7 @@ static void test_quality_control(IFilterGraph2 *graph, IBaseFilter *filter, testsource->qc = NULL; } -static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BYTE *data, LONG len, BOOL todo) +static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BYTE *data, LONG len) { BYTE *target_data; HRESULT hr; @@ -1216,8 +1216,7 @@ static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BY ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMemInputPin_Receive(input, sample); - todo_wine_if(todo) /* 0xc00d6d61 is MF_E_TRANSFORM_STREAM_CHANGE */ - ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); } static void test_send_video(IMemInputPin *input, IMediaSample *sample) @@ -1248,8 +1247,8 @@ static void test_send_video(IMemInputPin *input, IMediaSample *sample) IPin *pin; /* native won't emit anything until an unknown-sized internal buffer is filled, or EOS is announced */ - test_send_sample(input, sample, empty_mpg_frames, ARRAY_SIZE(empty_mpg_frames), TRUE); - test_send_sample(input, sample, empty_mpg_eos, ARRAY_SIZE(empty_mpg_eos), FALSE); + test_send_sample(input, sample, empty_mpg_frames, ARRAY_SIZE(empty_mpg_frames)); + test_send_sample(input, sample, empty_mpg_eos, ARRAY_SIZE(empty_mpg_eos)); hr = IMemInputPin_QueryInterface(input, &IID_IPin, (void **)&pin); ok(hr == S_OK, "Got hr %#lx.\n", hr); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 22b3943353f..cd5b34e3e13 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -96,7 +96,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst return GST_FLOW_ERROR; } - if (transform->output_caps_changed) + if (transform->output_caps_changed && transform->attrs.allow_format_change) GST_MINI_OBJECT_FLAG_SET(sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED); transform->output_caps_changed = false; @@ -273,9 +273,7 @@ static void transform_sink_event_caps(struct wg_transform *transform, GstEvent * gst_event_parse_caps(event, &caps); - transform->output_caps_changed = transform->output_caps_changed - || !transform_output_caps_is_compatible(transform, caps); - + transform->output_caps_changed = true; gst_caps_unref(transform->output_caps); transform->output_caps = gst_caps_ref(caps); } From e7fdcda0f7e4ddb827bdac051e1ee709943c9fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Jun 2024 10:22:50 +0200 Subject: [PATCH 214/301] winegstreamer: Use a caps to store the desired output format. (cherry picked from commit 3dd3535a2c5ba0970602106a9fe8f4544f412701) CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 85 ++++++++++++++++++------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index cd5b34e3e13..530fb35e238 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -56,10 +56,10 @@ struct wg_transform bool input_is_flipped; GstElement *video_flip; - struct wg_format output_format; GstAtomicQueue *output_queue; GstSample *output_sample; bool output_caps_changed; + GstCaps *desired_caps; GstCaps *output_caps; }; @@ -188,28 +188,53 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, return true; } -static GstCaps *transform_format_to_caps(struct wg_transform *transform, const struct wg_format *format) +static void caps_remove_field(GstCaps *caps, const char *field) { - struct wg_format copy = *format; + guint i; - if (format->major_type == WG_MAJOR_TYPE_VIDEO) + for (i = 0; i < gst_caps_get_size(caps); ++i) { - if (transform->attrs.allow_format_change) - copy.u.video.width = copy.u.video.height = 0; - copy.u.video.fps_n = copy.u.video.fps_d = 0; + GstStructure *structure = gst_caps_get_structure(caps, i); + gst_structure_remove_fields(structure, field, NULL); } +} + +static GstCaps *caps_strip_fields(GstCaps *caps, bool strip_size) +{ + if (stream_type_from_caps(caps) != GST_STREAM_TYPE_VIDEO) + return gst_caps_ref(caps); + + if ((caps = gst_caps_copy(caps))) + { + if (strip_size) + { + caps_remove_field(caps, "width"); + caps_remove_field(caps, "height"); + } - return wg_format_to_caps(©); + /* strip fields which we do not support and could cause pipeline failure or spurious format changes */ + caps_remove_field(caps, "framerate"); + caps_remove_field(caps, "colorimetry"); + caps_remove_field(caps, "chroma-site"); + caps_remove_field(caps, "interlace-mode"); + caps_remove_field(caps, "pixel-aspect-ratio"); + } + + return caps; } static gboolean transform_sink_query_caps(struct wg_transform *transform, GstQuery *query) { GstCaps *caps, *filter, *temp; + bool strip_size = false; GST_LOG("transform %p, %"GST_PTR_FORMAT, transform, query); gst_query_parse_caps(query, &filter); - if (!(caps = transform_format_to_caps(transform, &transform->output_format))) + if (filter && gst_structure_has_field(gst_caps_get_structure(filter, 0), "width")) + strip_size = transform->attrs.allow_format_change; + + if (!(caps = caps_strip_fields(transform->desired_caps, strip_size))) return false; if (filter) @@ -248,23 +273,6 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery return gst_pad_query_default(pad, parent, query); } -static gboolean transform_output_caps_is_compatible(struct wg_transform *transform, GstCaps *caps) -{ - GstCaps *copy = gst_caps_copy(caps); - gboolean ret; - gsize i; - - for (i = 0; i < gst_caps_get_size(copy); ++i) - { - GstStructure *structure = gst_caps_get_structure(copy, i); - gst_structure_remove_fields(structure, "framerate", NULL); - } - - ret = gst_caps_is_always_compatible(transform->output_caps, copy); - gst_caps_unref(copy); - return ret; -} - static void transform_sink_event_caps(struct wg_transform *transform, GstEvent *event) { GstCaps *caps; @@ -274,6 +282,8 @@ static void transform_sink_event_caps(struct wg_transform *transform, GstEvent * gst_event_parse_caps(event, &caps); transform->output_caps_changed = true; + gst_caps_unref(transform->desired_caps); + transform->desired_caps = gst_caps_ref(caps); gst_caps_unref(transform->output_caps); transform->output_caps = gst_caps_ref(caps); } @@ -318,6 +328,7 @@ NTSTATUS wg_transform_destroy(void *args) g_object_unref(transform->my_sink); g_object_unref(transform->my_src); gst_query_unref(transform->drain_query); + gst_caps_unref(transform->desired_caps); gst_caps_unref(transform->output_caps); gst_atomic_queue_unref(transform->output_queue); free(transform); @@ -409,9 +420,8 @@ NTSTATUS wg_transform_create(void *args) if (!(transform->allocator = wg_allocator_create())) goto out; transform->attrs = *params->attrs; - transform->output_format = output_format; - if (!(src_caps = transform_format_to_caps(transform, &input_format))) + if (!(src_caps = wg_format_to_caps(&input_format))) goto out; if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) goto out; @@ -425,8 +435,9 @@ NTSTATUS wg_transform_create(void *args) gst_pad_set_element_private(transform->my_src, transform); gst_pad_set_query_function(transform->my_src, transform_src_query_cb); - if (!(transform->output_caps = transform_format_to_caps(transform, &output_format))) + if (!(transform->output_caps = wg_format_to_caps(&output_format))) goto out; + transform->desired_caps = gst_caps_ref(transform->output_caps); if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, transform->output_caps))) goto out; transform->my_sink = gst_pad_new_from_template(template, "sink"); @@ -577,6 +588,8 @@ NTSTATUS wg_transform_create(void *args) out: if (transform->my_sink) gst_object_unref(transform->my_sink); + if (transform->desired_caps) + gst_caps_unref(transform->desired_caps); if (transform->output_caps) gst_caps_unref(transform->output_caps); if (transform->my_src) @@ -610,23 +623,25 @@ NTSTATUS wg_transform_set_output_format(void *args) struct wg_transform_set_output_format_params *params = args; struct wg_transform *transform = get_transform(params->transform); const struct wg_format *format = params->format; + GstCaps *caps, *stripped; GstSample *sample; - GstCaps *caps; - if (!(caps = transform_format_to_caps(transform, format))) + if (!(caps = wg_format_to_caps(format))) { GST_ERROR("Failed to convert format %p to caps.", format); return STATUS_UNSUCCESSFUL; } - transform->output_format = *format; GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, caps); - if (transform_output_caps_is_compatible(transform, caps)) + stripped = caps_strip_fields(caps, transform->attrs.allow_format_change); + if (gst_caps_is_always_compatible(transform->output_caps, stripped)) { + gst_caps_unref(stripped); gst_caps_unref(caps); return STATUS_SUCCESS; } + gst_caps_unref(stripped); if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) { @@ -634,8 +649,8 @@ NTSTATUS wg_transform_set_output_format(void *args) return STATUS_UNSUCCESSFUL; } - gst_caps_unref(transform->output_caps); - transform->output_caps = caps; + gst_caps_unref(transform->desired_caps); + transform->desired_caps = caps; if (transform->video_flip) { From 3f4184be6983a0176d13203452f037f559b143cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Mar 2024 12:47:06 +0100 Subject: [PATCH 215/301] winegstreamer: Request the new transform output format explicitly. (cherry picked from commit 1e8e0d41b4b55953f5366d072397b07659d46019) CW-Bug-Id: #20833 --- dlls/winegstreamer/aac_decoder.c | 2 +- dlls/winegstreamer/color_convert.c | 2 +- dlls/winegstreamer/gst_private.h | 9 +++- dlls/winegstreamer/main.c | 19 ++++++-- dlls/winegstreamer/resampler.c | 2 +- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 +++- dlls/winegstreamer/video_decoder.c | 12 ++--- dlls/winegstreamer/video_processor.c | 3 +- dlls/winegstreamer/wg_parser.c | 19 +++++++- dlls/winegstreamer/wg_sample.c | 19 +++----- dlls/winegstreamer/wg_transform.c | 66 ++++++++++++++++++---------- dlls/winegstreamer/wma_decoder.c | 2 +- 13 files changed, 107 insertions(+), 57 deletions(-) diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 0d012fd710a..2cf605bc56c 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -521,7 +521,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr; if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(decoder->wg_sample_queue, false); else samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 949b85943d0..4b60628e8ba 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -582,7 +582,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr; if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(impl->wg_sample_queue, false); return hr; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 0c0e20a8566..86d6761ebbc 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -125,6 +125,7 @@ HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_ty HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); +bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); HRESULT wg_transform_drain(wg_transform_t transform); @@ -183,10 +184,16 @@ HRESULT wg_transform_push_quartz(wg_transform_t transform, struct wg_sample *sam HRESULT wg_transform_push_dmo(wg_transform_t transform, IMediaBuffer *media_buffer, DWORD flags, REFERENCE_TIME time_stamp, REFERENCE_TIME time_length, struct wg_sample_queue *queue); HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample, - DWORD sample_size, struct wg_format *format, DWORD *flags); + DWORD sample_size, DWORD *flags); HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *sample); HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER *buffer); +/* These unixlib entry points should not be used directly, they assume samples + * to be queued and zero-copy support, use the helpers below instead. + */ +HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample); +HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample); + HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj); HRESULT gstreamer_byte_stream_handler_2_create(REFIID riid, void **obj); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 414c45fcebd..ad5e945c22d 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -607,18 +607,16 @@ HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sampl return params.result; } -HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample, - struct wg_format *format) +HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample) { struct wg_transform_read_data_params params = { .transform = transform, .sample = sample, - .format = format, }; NTSTATUS status; - TRACE("transform %#I64x, sample %p, format %p.\n", transform, sample, format); + TRACE("transform %#I64x, sample %p.\n", transform, sample); if ((status = WINE_UNIX_CALL(unix_wg_transform_read_data, ¶ms))) return HRESULT_FROM_NT(status); @@ -642,6 +640,19 @@ bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input) return true; } +bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format) +{ + struct wg_transform_get_output_format_params params = + { + .transform = transform, + .format = format, + }; + + TRACE("transform %#I64x, format %p.\n", transform, format); + + return !WINE_UNIX_CALL(unix_wg_transform_get_output_format, ¶ms); +} + bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format) { struct wg_transform_set_output_format_params params = diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 8df7eb32649..c1ce9897ef1 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -541,7 +541,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr; if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(impl->wg_sample_queue, false); return hr; diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 87ab6a92e29..6bee8cf8f9c 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -71,6 +71,7 @@ extern NTSTATUS wg_source_set_stream_flags(void *args); extern NTSTATUS wg_transform_create(void *args); extern NTSTATUS wg_transform_destroy(void *args); +extern NTSTATUS wg_transform_get_output_format(void *args); extern NTSTATUS wg_transform_set_output_format(void *args); extern NTSTATUS wg_transform_push_data(void *args); extern NTSTATUS wg_transform_read_data(void *args); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 82f768c58cc..9eeba8ceff4 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -408,10 +408,15 @@ struct wg_transform_read_data_params { wg_transform_t transform; struct wg_sample *sample; - struct wg_format *format; HRESULT result; }; +struct wg_transform_get_output_format_params +{ + wg_transform_t transform; + struct wg_format *format; +}; + struct wg_transform_set_output_format_params { wg_transform_t transform; @@ -505,6 +510,7 @@ enum unix_funcs unix_wg_transform_create, unix_wg_transform_destroy, + unix_wg_transform_get_output_format, unix_wg_transform_set_output_format, unix_wg_transform_push_data, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index e405b6da055..66c70b6c020 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -862,14 +862,17 @@ static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMF return S_OK; } -static HRESULT handle_stream_type_change(struct video_decoder *decoder, const struct wg_format *format) +static HRESULT handle_stream_type_change(struct video_decoder *decoder) { UINT64 frame_size, frame_rate; + struct wg_format format; HRESULT hr; if (decoder->stream_type) IMFMediaType_Release(decoder->stream_type); - if (!(decoder->stream_type = mf_media_type_from_wg_format(format))) + if (!(wg_transform_get_output_format(decoder->wg_transform, &format))) + return E_FAIL; + if (!(decoder->stream_type = mf_media_type_from_wg_format(&format))) return E_OUTOFMEMORY; if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)) @@ -889,7 +892,6 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct video_decoder *decoder = impl_from_IMFTransform(iface); - struct wg_format wg_format; UINT32 sample_size; LONGLONG duration; IMFSample *sample; @@ -939,7 +941,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, } if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample, - sample_size, &wg_format, &samples->dwStatus))) + sample_size, &samples->dwStatus))) { wg_sample_queue_flush(decoder->wg_sample_queue, false); @@ -958,7 +960,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, { samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - hr = handle_stream_type_change(decoder, &wg_format); + hr = handle_stream_type_change(decoder); } if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 2461140ab21..4afdddcb036 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -693,8 +693,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f IMFSample_AddRef(output_sample); } - if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, - NULL, &samples->dwStatus))) + if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, &samples->dwStatus))) goto done; wg_sample_queue_flush(impl->wg_sample_queue, false); diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 1f3d59b0c58..074a0e9f3ca 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2258,6 +2258,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_create), X(wg_transform_destroy), + X(wg_transform_get_output_format), X(wg_transform_set_output_format), X(wg_transform_push_data), @@ -2525,6 +2526,21 @@ NTSTATUS wow64_wg_transform_create(void *args) return ret; } +NTSTATUS wow64_wg_transform_get_output_format(void *args) +{ + struct + { + wg_transform_t transform; + PTR32 format; + } *params32 = args; + struct wg_transform_get_output_format_params params = + { + .transform = params32->transform, + .format = ULongToPtr(params32->format), + }; + return wg_transform_get_output_format(¶ms); +} + NTSTATUS wow64_wg_transform_set_output_format(void *args) { struct @@ -2566,14 +2582,12 @@ NTSTATUS wow64_wg_transform_read_data(void *args) { wg_transform_t transform; PTR32 sample; - PTR32 format; HRESULT result; } *params32 = args; struct wg_transform_read_data_params params = { .transform = params32->transform, .sample = ULongToPtr(params32->sample), - .format = ULongToPtr(params32->format), }; NTSTATUS ret; @@ -2701,6 +2715,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_transform_create), X(wg_transform_destroy), + X64(wg_transform_get_output_format), X64(wg_transform_set_output_format), X64(wg_transform_push_data), diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index 513907d9d77..00f0187afca 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -305,13 +305,6 @@ void wg_sample_queue_destroy(struct wg_sample_queue *queue) free(queue); } -/* These unixlib entry points should not be used directly, they assume samples - * to be queued and zero-copy support, use the helpers below instead. - */ -HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample); -HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample, - struct wg_format *format); - HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample, struct wg_sample_queue *queue) { @@ -348,23 +341,21 @@ HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample, } HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample, - DWORD sample_size, struct wg_format *format, DWORD *flags) + DWORD sample_size, DWORD *flags) { struct wg_sample *wg_sample; IMFMediaBuffer *buffer; HRESULT hr; - TRACE_(mfplat)("transform %#I64x, sample %p, format %p, flags %p.\n", transform, sample, format, flags); + TRACE_(mfplat)("transform %#I64x, sample %p, flags %p.\n", transform, sample, flags); if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample))) return hr; wg_sample->size = 0; - if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { - if (hr == MF_E_TRANSFORM_STREAM_CHANGE && !format) - FIXME("Unexpected stream format change!\n"); wg_sample_release(wg_sample); return hr; } @@ -432,7 +423,7 @@ HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *wg_ TRACE_(mfplat)("transform %#I64x, wg_sample %p.\n", transform, wg_sample); - if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { if (hr == MF_E_TRANSFORM_STREAM_CHANGE) FIXME("Unexpected stream format change!\n"); @@ -507,7 +498,7 @@ HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER * return hr; wg_sample->size = 0; - if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { if (hr == MF_E_TRANSFORM_STREAM_CHANGE) TRACE_(mfplat)("Stream format changed.\n"); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 530fb35e238..531085c0637 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -618,6 +618,48 @@ NTSTATUS wg_transform_create(void *args) return status; } +NTSTATUS wg_transform_get_output_format(void *args) +{ + struct wg_transform_get_output_format_params *params = args; + struct wg_transform *transform = get_transform(params->transform); + struct wg_format *format = params->format; + GstVideoInfo video_info; + GstCaps *output_caps; + + if (transform->output_sample) + output_caps = gst_sample_get_caps(transform->output_sample); + else + output_caps = transform->output_caps; + + GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps); + + wg_format_from_caps(format, output_caps); + + if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO + && gst_video_info_from_caps(&video_info, output_caps)) + { + gsize plane_align = transform->attrs.output_plane_align; + GstVideoAlignment align = {0}; + + /* set the desired output buffer alignment on the dest video info */ + align_video_info_planes(plane_align, &video_info, &align); + + GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, + align.padding_top, align.padding_right, align.padding_bottom); + + format->u.video.padding.left = align.padding_left; + format->u.video.width += format->u.video.padding.left; + format->u.video.padding.right = align.padding_right; + format->u.video.width += format->u.video.padding.right; + format->u.video.padding.top = align.padding_top; + format->u.video.height += format->u.video.padding.top; + format->u.video.padding.bottom = align.padding_bottom; + format->u.video.height += format->u.video.padding.bottom; + } + + return STATUS_SUCCESS; +} + NTSTATUS wg_transform_set_output_format(void *args) { struct wg_transform_set_output_format_params *params = args; @@ -929,7 +971,6 @@ NTSTATUS wg_transform_read_data(void *args) struct wg_transform *transform = get_transform(params->transform); GstVideoInfo src_video_info, dst_video_info; struct wg_sample *sample = params->sample; - struct wg_format *format = params->format; GstVideoAlignment align = {0}; GstBuffer *output_buffer; GstCaps *output_caps; @@ -963,29 +1004,6 @@ NTSTATUS wg_transform_read_data(void *args) if (GST_MINI_OBJECT_FLAG_IS_SET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED)) { GST_MINI_OBJECT_FLAG_UNSET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED); - - GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps); - - if (format) - { - wg_format_from_caps(format, output_caps); - - if (format->major_type == WG_MAJOR_TYPE_VIDEO) - { - GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, - align.padding_top, align.padding_right, align.padding_bottom); - - format->u.video.padding.left = align.padding_left; - format->u.video.width += format->u.video.padding.left; - format->u.video.padding.right = align.padding_right; - format->u.video.width += format->u.video.padding.right; - format->u.video.padding.top = align.padding_top; - format->u.video.height += format->u.video.padding.top; - format->u.video.padding.bottom = align.padding_bottom; - format->u.video.height += format->u.video.padding.bottom; - } - } - params->result = MF_E_TRANSFORM_STREAM_CHANGE; GST_INFO("Format changed detected, returning no output"); wg_allocator_release_sample(transform->allocator, sample, false); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index e316e99c04b..b34ad6b289a 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -568,7 +568,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr; if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(decoder->wg_sample_queue, false); return hr; From 614a6958c59b0c5f3f47e1649c3c5ebd1cc20539 Mon Sep 17 00:00:00 2001 From: Alfred Agrell Date: Wed, 19 Jun 2024 17:09:42 +0200 Subject: [PATCH 216/301] winegstreamer: Recalculate alignment and bytes per second, instead of copying from input. (cherry picked from commit 1b702aea3c28a71c92feba5817ab34c61c0ad8e4) CW-Bug-Id: #20833 --- dlls/winegstreamer/wma_decoder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index b34ad6b289a..de1bedb1d38 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -672,8 +672,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde DMO_MEDIA_TYPE *type) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); + UINT32 depth, channels, rate; IMFMediaType *media_type; - UINT32 depth; HRESULT hr; TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface, index, type_index, type); @@ -697,6 +697,16 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde else hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + if (SUCCEEDED(hr)) + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels); + if (SUCCEEDED(hr)) + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, depth * channels / 8); + + if (SUCCEEDED(hr)) + hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate); + if (SUCCEEDED(hr)) + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, depth * channels / 8 * rate); + if (SUCCEEDED(hr)) hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA); if (SUCCEEDED(hr)) From c2c7e6cce2885f6832d924c98ff51be40a5cafa6 Mon Sep 17 00:00:00 2001 From: Alfred Agrell Date: Wed, 19 Jun 2024 17:10:48 +0200 Subject: [PATCH 217/301] mf/tests: Clobber the alignment and bytes per second, to test if the DMO fixes it. (cherry picked from commit 1953d1e774d9cd79b7b7ac49159a3aef734cd8c6) CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 142251a2382..06a106ff734 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3585,6 +3585,8 @@ static void test_wma_decoder_dmo_output_type(void) good_output_type = (void *)buffer_good_output; bad_output_type = (void *)buffer_bad_output; init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate, 16); + ((WAVEFORMATEX *)(input_type + 1))->nBlockAlign = 640; + ((WAVEFORMATEX *)(input_type + 1))->nAvgBytesPerSec = 2000; init_dmo_media_type_audio(good_output_type, &MEDIASUBTYPE_PCM, channel_count, rate, bits_per_sample); memset(bad_output_type, 0, sizeof(buffer_bad_output)); From f843fdba936d035e6c14dbca19b5cf8697e7dec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 May 2024 13:07:26 +0200 Subject: [PATCH 218/301] winegstreamer: Translate GstCaps directly to MFVIDEOFORMAT / WAVEFORMATEX in wg_transform. (cherry picked from commit fbceb9e60b3fa4c3009abd4e639c5ab8cc0a75c3) CW-Bug-Id: #20833 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 63 +++- dlls/winegstreamer/unix_private.h | 9 +- dlls/winegstreamer/unixlib.h | 37 ++- dlls/winegstreamer/video_decoder.c | 10 +- dlls/winegstreamer/wg_format.c | 2 +- dlls/winegstreamer/wg_media_type.c | 461 +++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 31 +- dlls/winegstreamer/wg_transform.c | 33 +-- 10 files changed, 597 insertions(+), 52 deletions(-) create mode 100644 dlls/winegstreamer/wg_media_type.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 20bd6ef5fa7..cacebd28e4b 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -23,6 +23,7 @@ SOURCES = \ video_processor.c \ wg_allocator.c \ wg_format.c \ + wg_media_type.c \ wg_muxer.c \ wg_parser.c \ wg_sample.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 86d6761ebbc..6a4f7d28169 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -125,7 +125,7 @@ HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_ty HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); -bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format); +HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **media_type); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); HRESULT wg_transform_drain(wg_transform_t transform); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index ad5e945c22d..e8ba0a3ccfb 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -70,6 +70,41 @@ bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) return TRUE; } +static HRESULT media_type_from_video_format(const MFVIDEOFORMAT *format, IMFMediaType **media_type) +{ + HRESULT hr; + + if (FAILED(hr = MFCreateVideoMediaType(format, (IMFVideoMediaType **)media_type)) || format->dwSize <= sizeof(*format)) + return hr; + + /* fixup MPEG video formats here, so we can consistently use MFVIDEOFORMAT internally */ + if (IsEqualGUID(&format->guidFormat, &MEDIASUBTYPE_MPEG1Payload) + || IsEqualGUID(&format->guidFormat, &MEDIASUBTYPE_MPEG1Packet) + || IsEqualGUID(&format->guidFormat, &MEDIASUBTYPE_MPEG2_VIDEO)) + { + struct mpeg_video_format *mpeg = (struct mpeg_video_format *)format; + IMFMediaType_SetBlob(*media_type, &MF_MT_MPEG_SEQUENCE_HEADER, mpeg->sequence_header, mpeg->sequence_header_count); + IMFMediaType_SetUINT32(*media_type, &MF_MT_MPEG_START_TIME_CODE, mpeg->start_time_code); + IMFMediaType_SetUINT32(*media_type, &MF_MT_MPEG2_PROFILE, mpeg->profile); + IMFMediaType_SetUINT32(*media_type, &MF_MT_MPEG2_LEVEL, mpeg->level); + IMFMediaType_SetUINT32(*media_type, &MF_MT_MPEG2_FLAGS, mpeg->flags); + IMFMediaType_DeleteItem(*media_type, &MF_MT_USER_DATA); + } + + return hr; +} + +static HRESULT wg_media_type_to_mf(const struct wg_media_type *wg_media_type, IMFMediaType **media_type) +{ + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Video)) + return media_type_from_video_format(wg_media_type->u.video, media_type); + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Audio)) + return MFCreateAudioMediaType(wg_media_type->u.audio, (IMFAudioMediaType **)media_type); + + FIXME("Unsupported major type %s\n", debugstr_guid(&wg_media_type->major)); + return E_NOTIMPL; +} + wg_parser_t wg_parser_create(enum wg_parser_type type, bool output_compressed, bool use_opengl) { struct wg_parser_create_params params = @@ -640,17 +675,35 @@ bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input) return true; } -bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format) +HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **media_type) { - struct wg_transform_get_output_format_params params = + struct wg_transform_get_output_type_params params = { .transform = transform, - .format = format, }; + NTSTATUS status; + HRESULT hr; - TRACE("transform %#I64x, format %p.\n", transform, format); + TRACE("transform %#I64x, media_type %p.\n", transform, media_type); - return !WINE_UNIX_CALL(unix_wg_transform_get_output_format, ¶ms); + if ((status = WINE_UNIX_CALL(unix_wg_transform_get_output_type, ¶ms)) + && status == STATUS_BUFFER_TOO_SMALL) + { + if (!(params.media_type.u.format = CoTaskMemAlloc(params.media_type.format_size))) + return ERROR_OUTOFMEMORY; + status = WINE_UNIX_CALL(unix_wg_transform_get_output_type, ¶ms); + } + + if (status) + { + CoTaskMemFree(params.media_type.u.format); + WARN("Failed to get output media type, status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + hr = wg_media_type_to_mf(¶ms.media_type, media_type); + CoTaskMemFree(params.media_type.u.format); + return hr; } bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 6bee8cf8f9c..4bfe7a286d9 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -25,6 +25,7 @@ #include #include +#include /* unixlib.c */ @@ -52,6 +53,7 @@ extern void set_max_threads(GstElement *element); extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps); extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b); extern GstCaps *wg_format_to_caps(const struct wg_format *format); +extern uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info); /* wg_source.c */ @@ -71,7 +73,7 @@ extern NTSTATUS wg_source_set_stream_flags(void *args); extern NTSTATUS wg_transform_create(void *args); extern NTSTATUS wg_transform_destroy(void *args); -extern NTSTATUS wg_transform_get_output_format(void *args); +extern NTSTATUS wg_transform_get_output_type(void *args); extern NTSTATUS wg_transform_set_output_format(void *args); extern NTSTATUS wg_transform_push_data(void *args); extern NTSTATUS wg_transform_read_data(void *args); @@ -80,6 +82,11 @@ extern NTSTATUS wg_transform_drain(void *args); extern NTSTATUS wg_transform_flush(void *args); extern NTSTATUS wg_transform_notify_qos(void *args); +/* wg_media_type.c */ + +extern NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, + UINT32 video_plane_align); + /* wg_muxer.c */ extern NTSTATUS wg_muxer_create(void *args); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9eeba8ceff4..f0d8e2d29ec 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -26,9 +26,40 @@ #include "winternl.h" #include "wtypes.h" #include "mmreg.h" +#include "vfw.h" +#include "dshow.h" +#include "dvdmedia.h" +#include "mfobjects.h" #include "wine/unixlib.h" +/* same as MPEG1VIDEOINFO / MPEG2VIDEOINFO but with MFVIDEOFORMAT */ +struct mpeg_video_format +{ + MFVIDEOFORMAT hdr; + UINT32 start_time_code; + UINT32 profile; + UINT32 level; + UINT32 flags; + UINT32 sequence_header_count; + UINT32 __pad; + BYTE sequence_header[]; +}; + +C_ASSERT(sizeof(struct mpeg_video_format) == offsetof(struct mpeg_video_format, sequence_header[0])); + +struct wg_media_type +{ + GUID major; + UINT32 format_size; + union + { + void *format; + WAVEFORMATEX *audio; + MFVIDEOFORMAT *video; + } u; +}; + typedef UINT32 wg_major_type; enum wg_major_type { @@ -411,10 +442,10 @@ struct wg_transform_read_data_params HRESULT result; }; -struct wg_transform_get_output_format_params +struct wg_transform_get_output_type_params { wg_transform_t transform; - struct wg_format *format; + struct wg_media_type media_type; }; struct wg_transform_set_output_format_params @@ -510,7 +541,7 @@ enum unix_funcs unix_wg_transform_create, unix_wg_transform_destroy, - unix_wg_transform_get_output_format, + unix_wg_transform_get_output_type, unix_wg_transform_set_output_format, unix_wg_transform_push_data, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 66c70b6c020..5ad72752044 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -865,15 +865,15 @@ static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMF static HRESULT handle_stream_type_change(struct video_decoder *decoder) { UINT64 frame_size, frame_rate; - struct wg_format format; HRESULT hr; if (decoder->stream_type) IMFMediaType_Release(decoder->stream_type); - if (!(wg_transform_get_output_format(decoder->wg_transform, &format))) - return E_FAIL; - if (!(decoder->stream_type = mf_media_type_from_wg_format(&format))) - return E_OUTOFMEMORY; + if (FAILED(hr = wg_transform_get_output_type(decoder->wg_transform, &decoder->stream_type))) + { + WARN("Failed to get transform output type, hr %#lx\n", hr); + return hr; + } if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)) && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate))) diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index eec0ca0665f..47571422065 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -96,7 +96,7 @@ static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) return 0; } -static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) +uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) { uint32_t mask = 0, position; unsigned int i; diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c new file mode 100644 index 00000000000..21338e89399 --- /dev/null +++ b/dlls/winegstreamer/wg_media_type.c @@ -0,0 +1,461 @@ +/* + * Copyright 2024 RĂ©mi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "windef.h" +#include "winbase.h" + +#include "initguid.h" +#include "d3d9types.h" +#include "mfapi.h" +#include "wmcodecdsp.h" + +#include "unix_private.h" + +#define WG_GUID_FORMAT "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}" +#define WG_GUID_ARGS(guid) (int)(guid).Data1, (guid).Data2, (guid).Data3, (guid).Data4[0], \ + (guid).Data4[1], (guid).Data4[2], (guid).Data4[3], (guid).Data4[4], \ + (guid).Data4[5], (guid).Data4[6], (guid).Data4[7] + +#define WG_RATIO_FORMAT "%d:%d" +#define WG_RATIO_ARGS(ratio) (int)(ratio).Numerator, (int)(ratio).Denominator + +#define WG_APERTURE_FORMAT "(%d,%d)-(%d,%d)" +#define WG_APERTURE_ARGS(aperture) (int)(aperture).OffsetX.value, (int)(aperture).OffsetY.value, \ + (int)(aperture).Area.cx, (int)(aperture).Area.cy + +static const GUID GUID_NULL; + +DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); +DEFINE_MEDIATYPE_GUID(MFAudioFormat_MSAudio1,WAVE_FORMAT_MSAUDIO1); + +DEFINE_MEDIATYPE_GUID(MFVideoFormat_CVID,MAKEFOURCC('c','v','i','d')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); + +static WORD wave_format_tag_from_gst_audio_format(GstAudioFormat audio_format) +{ + switch (audio_format) + { + case GST_AUDIO_FORMAT_U8: return WAVE_FORMAT_PCM; + case GST_AUDIO_FORMAT_S16LE: return WAVE_FORMAT_PCM; + case GST_AUDIO_FORMAT_S24LE: return WAVE_FORMAT_PCM; + case GST_AUDIO_FORMAT_S32LE: return WAVE_FORMAT_PCM; + case GST_AUDIO_FORMAT_F32LE: return WAVE_FORMAT_IEEE_FLOAT; + case GST_AUDIO_FORMAT_F64LE: return WAVE_FORMAT_IEEE_FLOAT; + default: return WAVE_FORMAT_EXTENSIBLE; + } +} + +static GUID subtype_from_gst_audio_format(GstAudioFormat audio_format) +{ + switch (audio_format) + { + case GST_AUDIO_FORMAT_U8: return MFAudioFormat_PCM; + case GST_AUDIO_FORMAT_S16LE: return MFAudioFormat_PCM; + case GST_AUDIO_FORMAT_S24LE: return MFAudioFormat_PCM; + case GST_AUDIO_FORMAT_S32LE: return MFAudioFormat_PCM; + case GST_AUDIO_FORMAT_F32LE: return MFAudioFormat_Float; + case GST_AUDIO_FORMAT_F64LE: return MFAudioFormat_Float; + default: return GUID_NULL; + } +} + +static void init_wave_format_ex_from_gst_caps(const GstCaps *caps, WORD format_tag, gint depth, + WAVEFORMATEX *format, UINT32 format_size) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint bitrate, channels, rate, block_align; + + memset(format, 0, format_size); + format->cbSize = format_size - sizeof(*format); + format->wFormatTag = format_tag; + format->wBitsPerSample = depth; + + if (gst_structure_get_int(structure, "channels", &channels)) + format->nChannels = channels; + if (gst_structure_get_int(structure, "rate", &rate)) + format->nSamplesPerSec = rate; + if (gst_structure_get_int(structure, "depth", &depth)) + format->wBitsPerSample = depth; + + format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; + + if (gst_structure_get_int(structure, "block_align", &block_align)) + format->nBlockAlign = block_align; + if (gst_structure_get_int(structure, "bitrate", &bitrate)) + format->nAvgBytesPerSec = bitrate / 8; +} + +static GstBuffer *caps_get_buffer(const GstCaps *caps, const char *name, UINT32 *buffer_size) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + const GValue *buffer_value; + + if ((buffer_value = gst_structure_get_value(structure, name))) + { + GstBuffer *buffer = gst_value_get_buffer(buffer_value); + *buffer_size = gst_buffer_get_size(buffer); + return buffer; + } + + *buffer_size = 0; + return NULL; +} + +static NTSTATUS wave_format_extensible_from_gst_caps(const GstCaps *caps, const GUID *subtype, UINT32 depth, + UINT64 channel_mask, WAVEFORMATEXTENSIBLE *format, UINT32 *format_size) +{ + UINT32 capacity = *format_size, codec_data_size; + GstBuffer *codec_data = caps_get_buffer(caps, "codec_data", &codec_data_size); + + *format_size = sizeof(*format) + codec_data_size; + if (*format_size > capacity) + return STATUS_BUFFER_TOO_SMALL; + + init_wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_EXTENSIBLE, depth, &format->Format, *format_size); + format->Samples.wValidBitsPerSample = 0; + format->dwChannelMask = channel_mask; + format->SubFormat = *subtype; + + if (codec_data) + gst_buffer_extract(codec_data, 0, format + 1, codec_data_size); + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample, " + "%u valid bps, channel mask %#x, subtype " WG_GUID_FORMAT ".", + format->Format.wFormatTag, format->Format.nChannels, (int)format->Format.nSamplesPerSec, + (int)format->Format.nAvgBytesPerSec, format->Format.nBlockAlign, format->Format.wBitsPerSample, + format->Samples.wValidBitsPerSample, (int)format->dwChannelMask, WG_GUID_ARGS(format->SubFormat)); + if (format->Format.cbSize) + { + guint extra_size = sizeof(WAVEFORMATEX) + format->Format.cbSize - sizeof(WAVEFORMATEXTENSIBLE); + GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), extra_size); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS wave_format_ex_from_gst_caps(const GstCaps *caps, WORD format_tag, UINT32 depth, + UINT32 wave_format_size, WAVEFORMATEX *format, UINT32 *format_size) +{ + UINT32 capacity = *format_size, codec_data_size; + GstBuffer *codec_data = caps_get_buffer(caps, "codec_data", &codec_data_size); + + *format_size = max(wave_format_size, sizeof(*format) + codec_data_size); + if (*format_size > capacity) + return STATUS_BUFFER_TOO_SMALL; + + init_wave_format_ex_from_gst_caps(caps, format_tag, depth, format, *format_size); + + if (codec_data) + gst_buffer_extract(codec_data, 0, format + 1, codec_data_size); + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample.", + format->wFormatTag, format->nChannels, (int)format->nSamplesPerSec, + (int)format->nAvgBytesPerSec, format->nBlockAlign, format->wBitsPerSample); + if (format->cbSize) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->cbSize); + + return STATUS_SUCCESS; +} + +static NTSTATUS wave_format_from_gst_caps(const GstCaps *caps, void *format, UINT32 *format_size) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + GstAudioFormat audio_format = GST_AUDIO_FORMAT_ENCODED; + WORD format_tag = WAVE_FORMAT_EXTENSIBLE; + gint channels, depth = 0; + const gchar *str_value; + guint64 channel_mask; + + if ((str_value = gst_structure_get_string(structure, "format"))) + { + audio_format = gst_audio_format_from_string(str_value); + format_tag = wave_format_tag_from_gst_audio_format(audio_format); + depth = GST_AUDIO_FORMAT_INFO_DEPTH(gst_audio_format_get_info(audio_format)); + } + + if (!gst_structure_get_int(structure, "channels", &channels)) + channels = 1; + if (!gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL)) + channel_mask = 0; + + if (format_tag == WAVE_FORMAT_EXTENSIBLE || channel_mask != 0) + { + GUID subtype = subtype_from_gst_audio_format(audio_format); + return wave_format_extensible_from_gst_caps(caps, &subtype, depth, channel_mask, format, format_size); + } + + return wave_format_ex_from_gst_caps(caps, format_tag, depth, sizeof(WAVEFORMATEX), format, format_size); +} + +static NTSTATUS mpeg_wave_format_from_gst_caps(const GstCaps *caps, WAVEFORMATEX *format, UINT32 *format_size) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + NTSTATUS status; + gint layer = 0; + + if (gst_structure_get_int(structure, "layer", &layer) && layer == 3) + return wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_MPEGLAYER3, 0, sizeof(MPEGLAYER3WAVEFORMAT), format, format_size); + + if (!(status = wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_MPEG, 0, sizeof(MPEG1WAVEFORMAT), format, format_size))) + { + MPEG1WAVEFORMAT *mpeg = CONTAINING_RECORD(format, MPEG1WAVEFORMAT, wfx); + mpeg->fwHeadLayer = layer; + } + + return status; +} + +static NTSTATUS wma_wave_format_from_gst_caps(const GstCaps *caps, WAVEFORMATEX *format, UINT32 *format_size) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint wmaversion; + + if (!gst_structure_get_int(structure, "wmaversion", &wmaversion)) + { + GST_WARNING("Missing \"wmaversion\" value in %" GST_PTR_FORMAT ".", caps); + return STATUS_INVALID_PARAMETER; + } + + if (wmaversion == 1) + return wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_MSAUDIO1, 0, sizeof(MSAUDIO1WAVEFORMAT), format, format_size); + if (wmaversion == 2) + return wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_WMAUDIO2, 0, sizeof(WMAUDIO2WAVEFORMAT), format, format_size); + if (wmaversion == 3) + return wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_WMAUDIO3, 0, sizeof(WMAUDIO3WAVEFORMAT), format, format_size); + + GST_FIXME("Unsupported wmaversion %u", wmaversion); + return STATUS_NOT_IMPLEMENTED; +} + +static GUID subtype_from_gst_video_format(GstVideoFormat video_format) +{ + switch (video_format) + { + case GST_VIDEO_FORMAT_BGRA: return MFVideoFormat_ARGB32; + case GST_VIDEO_FORMAT_BGRx: return MFVideoFormat_RGB32; + case GST_VIDEO_FORMAT_BGR: return MFVideoFormat_RGB24; + case GST_VIDEO_FORMAT_RGBA: return MFVideoFormat_ABGR32; + case GST_VIDEO_FORMAT_RGB15: return MFVideoFormat_RGB555; + case GST_VIDEO_FORMAT_RGB16: return MFVideoFormat_RGB565; + case GST_VIDEO_FORMAT_AYUV: return MFVideoFormat_AYUV; + case GST_VIDEO_FORMAT_I420: return MFVideoFormat_I420; + case GST_VIDEO_FORMAT_NV12: return MFVideoFormat_NV12; + case GST_VIDEO_FORMAT_UYVY: return MFVideoFormat_UYVY; + case GST_VIDEO_FORMAT_YUY2: return MFVideoFormat_YUY2; + case GST_VIDEO_FORMAT_YV12: return MFVideoFormat_YV12; + case GST_VIDEO_FORMAT_YVYU: return MFVideoFormat_YVYU; + default: return GUID_NULL; + } +} + +static void init_mf_video_format_from_gst_caps(const GstCaps *caps, const GUID *subtype, MFVIDEOFORMAT *format, + UINT32 format_size, UINT32 video_plane_align) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint width = 0, height = 0, num_value, den_value; + const gchar *str_value; + + memset(format, 0, format_size); + format->dwSize = format_size; + + if (subtype) + format->guidFormat = *subtype; + else if ((str_value = gst_structure_get_string(structure, "format"))) + { + GstVideoFormat video_format = gst_video_format_from_string(str_value); + format->guidFormat = subtype_from_gst_video_format(video_format); + } + + if (gst_structure_get_int(structure, "width", &width)) + format->videoInfo.dwWidth = (width + video_plane_align) & ~video_plane_align; + if (gst_structure_get_int(structure, "height", &height)) + format->videoInfo.dwHeight = (height + video_plane_align) & ~video_plane_align; + if (format->videoInfo.dwWidth != width || format->videoInfo.dwHeight != height) + { + format->videoInfo.MinimumDisplayAperture.Area.cx = width; + format->videoInfo.MinimumDisplayAperture.Area.cy = height; + } + format->videoInfo.GeometricAperture = format->videoInfo.MinimumDisplayAperture; + format->videoInfo.PanScanAperture = format->videoInfo.MinimumDisplayAperture; + + if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &num_value, &den_value)) + { + format->videoInfo.PixelAspectRatio.Numerator = num_value; + format->videoInfo.PixelAspectRatio.Denominator = den_value; + } + if (gst_structure_get_fraction(structure, "framerate", &num_value, &den_value)) + { + format->videoInfo.FramesPerSecond.Numerator = num_value; + format->videoInfo.FramesPerSecond.Denominator = den_value; + } +} + +static NTSTATUS video_format_from_gst_caps(const GstCaps *caps, const GUID *subtype, MFVIDEOFORMAT *format, + UINT32 *format_size, UINT32 video_plane_align) +{ + UINT32 capacity = *format_size, codec_data_size; + GstBuffer *codec_data = caps_get_buffer(caps, "codec_data", &codec_data_size); + + *format_size = sizeof(*format) + codec_data_size; + if (*format_size > capacity) + return STATUS_BUFFER_TOO_SMALL; + + init_mf_video_format_from_gst_caps(caps, subtype, format, *format_size, video_plane_align); + + if (codec_data) + gst_buffer_extract(codec_data, 0, format + 1, codec_data_size); + + GST_TRACE("subtype " WG_GUID_FORMAT " %ux%u, FPS " WG_RATIO_FORMAT ", aperture " WG_APERTURE_FORMAT ", " + "PAR " WG_RATIO_FORMAT ", videoFlags %#x.", + WG_GUID_ARGS(format->guidFormat), (int)format->videoInfo.dwWidth, (int)format->videoInfo.dwHeight, + WG_RATIO_ARGS(format->videoInfo.FramesPerSecond), WG_APERTURE_ARGS(format->videoInfo.MinimumDisplayAperture), + WG_RATIO_ARGS(format->videoInfo.PixelAspectRatio), (int)format->videoInfo.VideoFlags ); + if (format->dwSize > sizeof(*format)) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->dwSize - sizeof(*format)); + + return STATUS_SUCCESS; +} + +static NTSTATUS wmv_video_format_from_gst_caps(const GstCaps *caps, MFVIDEOFORMAT *format, + UINT32 *format_size, UINT32 video_plane_align) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gchar format_buffer[5] = {'W','M','V','0',0}; + const gchar *wmv_format_str; + gint wmv_version = 0; + const GUID *subtype; + + if (!(wmv_format_str = gst_structure_get_string(structure, "format"))) + { + if (!gst_structure_get_int(structure, "wmvversion", &wmv_version)) + GST_WARNING("Unable to get WMV format."); + format_buffer[3] += wmv_version; + wmv_format_str = format_buffer; + } + + if (!strcmp(wmv_format_str, "WMV1")) + subtype = &MFVideoFormat_WMV1; + else if (!strcmp(wmv_format_str, "WMV2")) + subtype = &MFVideoFormat_WMV2; + else if (!strcmp(wmv_format_str, "WMV3")) + subtype = &MFVideoFormat_WMV3; + else if (!strcmp(wmv_format_str, "WMVA")) + subtype = &MEDIASUBTYPE_WMVA; + else if (!strcmp(wmv_format_str, "WVC1")) + subtype = &MFVideoFormat_WVC1; + else + { + GST_WARNING("Unknown \"wmvversion\" value."); + return STATUS_INVALID_PARAMETER; + } + + return video_format_from_gst_caps(caps, subtype, format, format_size, video_plane_align); +} + +static NTSTATUS mpeg_video_format_from_gst_caps(const GstCaps *caps, struct mpeg_video_format *format, + UINT32 *format_size, UINT32 video_plane_align) +{ + UINT32 capacity = *format_size, codec_data_size; + GstBuffer *codec_data = caps_get_buffer(caps, "codec_data", &codec_data_size); + + *format_size = sizeof(*format) + codec_data_size; + if (*format_size > capacity) + return STATUS_BUFFER_TOO_SMALL; + + init_mf_video_format_from_gst_caps(caps, &MEDIASUBTYPE_MPEG1Payload, &format->hdr, *format_size, video_plane_align); + + if (codec_data) + { + gst_buffer_extract(codec_data, 0, format->sequence_header, codec_data_size); + format->sequence_header_count = codec_data_size; + } + + GST_TRACE("subtype " WG_GUID_FORMAT " %ux%u, FPS " WG_RATIO_FORMAT ", aperture " WG_APERTURE_FORMAT ", " + "PAR " WG_RATIO_FORMAT ", videoFlags %#x, start_time_code %u, profile %u, level %u, flags %#x.", + WG_GUID_ARGS(format->hdr.guidFormat), (int)format->hdr.videoInfo.dwWidth, (int)format->hdr.videoInfo.dwHeight, + WG_RATIO_ARGS(format->hdr.videoInfo.FramesPerSecond), WG_APERTURE_ARGS(format->hdr.videoInfo.MinimumDisplayAperture), + WG_RATIO_ARGS(format->hdr.videoInfo.PixelAspectRatio), (int)format->hdr.videoInfo.VideoFlags, format->start_time_code, + format->profile, format->level, format->flags ); + if (format->sequence_header_count) GST_MEMDUMP("extra bytes:", format->sequence_header, format->sequence_header_count); + + return STATUS_SUCCESS; +} + +NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UINT32 video_plane_align) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + const char *name = gst_structure_get_name(structure); + gboolean parsed; + + GST_TRACE("caps %"GST_PTR_FORMAT, caps); + + if (g_str_has_prefix(name, "audio/")) + { + media_type->major = MFMediaType_Audio; + + if (!strcmp(name, "audio/x-raw")) + return wave_format_from_gst_caps(caps, media_type->u.audio, &media_type->format_size); + if (!strcmp(name, "audio/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) + return mpeg_wave_format_from_gst_caps(caps, media_type->u.audio, &media_type->format_size); + if (!strcmp(name, "audio/x-wma")) + return wma_wave_format_from_gst_caps(caps, media_type->u.audio, &media_type->format_size); + + GST_FIXME("Unhandled caps %" GST_PTR_FORMAT ".", caps); + return STATUS_UNSUCCESSFUL; + } + else if (g_str_has_prefix(name, "video/")) + { + media_type->major = MFMediaType_Video; + + if (!strcmp(name, "video/x-raw")) + return video_format_from_gst_caps(caps, NULL, media_type->u.video, &media_type->format_size, video_plane_align); + if (!strcmp(name, "video/x-cinepak")) + return video_format_from_gst_caps(caps, &MFVideoFormat_CVID, media_type->u.video, &media_type->format_size, video_plane_align); + if (!strcmp(name, "video/x-wmv")) + return wmv_video_format_from_gst_caps(caps, media_type->u.video, &media_type->format_size, video_plane_align); + if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) + return mpeg_video_format_from_gst_caps(caps, media_type->u.format, &media_type->format_size, video_plane_align); + + GST_FIXME("Unhandled caps %" GST_PTR_FORMAT ".", caps); + return STATUS_UNSUCCESSFUL; + } + else + { + GST_FIXME("Unhandled caps %" GST_PTR_FORMAT ".", caps); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 074a0e9f3ca..36ebb499a25 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2258,7 +2258,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_create), X(wg_transform_destroy), - X(wg_transform_get_output_format), + X(wg_transform_get_output_type), X(wg_transform_set_output_format), X(wg_transform_push_data), @@ -2283,6 +2283,13 @@ C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count); typedef ULONG PTR32; +struct wg_media_type32 +{ + GUID major; + UINT32 format_size; + PTR32 format; +}; + static NTSTATUS wow64_wg_parser_connect(void *args) { struct @@ -2526,19 +2533,29 @@ NTSTATUS wow64_wg_transform_create(void *args) return ret; } -NTSTATUS wow64_wg_transform_get_output_format(void *args) +NTSTATUS wow64_wg_transform_get_output_type(void *args) { struct { wg_transform_t transform; - PTR32 format; + struct wg_media_type32 media_type; } *params32 = args; - struct wg_transform_get_output_format_params params = + struct wg_transform_get_output_type_params params = { .transform = params32->transform, - .format = ULongToPtr(params32->format), + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, }; - return wg_transform_get_output_format(¶ms); + NTSTATUS status; + + status = wg_transform_get_output_type(¶ms); + params32->media_type.major = params.media_type.major; + params32->media_type.format_size = params.media_type.format_size; + return status; } NTSTATUS wow64_wg_transform_set_output_format(void *args) @@ -2715,7 +2732,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_transform_create), X(wg_transform_destroy), - X64(wg_transform_get_output_format), + X64(wg_transform_get_output_type), X64(wg_transform_set_output_format), X64(wg_transform_push_data), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 531085c0637..772b8127944 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -36,6 +36,7 @@ #define WIN32_NO_STATUS #include "winternl.h" #include "mferror.h" +#include "mfapi.h" #include "unix_private.h" @@ -618,12 +619,10 @@ NTSTATUS wg_transform_create(void *args) return status; } -NTSTATUS wg_transform_get_output_format(void *args) +NTSTATUS wg_transform_get_output_type(void *args) { - struct wg_transform_get_output_format_params *params = args; + struct wg_transform_get_output_type_params *params = args; struct wg_transform *transform = get_transform(params->transform); - struct wg_format *format = params->format; - GstVideoInfo video_info; GstCaps *output_caps; if (transform->output_sample) @@ -633,31 +632,7 @@ NTSTATUS wg_transform_get_output_format(void *args) GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps); - wg_format_from_caps(format, output_caps); - - if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO - && gst_video_info_from_caps(&video_info, output_caps)) - { - gsize plane_align = transform->attrs.output_plane_align; - GstVideoAlignment align = {0}; - - /* set the desired output buffer alignment on the dest video info */ - align_video_info_planes(plane_align, &video_info, &align); - - GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, - align.padding_top, align.padding_right, align.padding_bottom); - - format->u.video.padding.left = align.padding_left; - format->u.video.width += format->u.video.padding.left; - format->u.video.padding.right = align.padding_right; - format->u.video.width += format->u.video.padding.right; - format->u.video.padding.top = align.padding_top; - format->u.video.height += format->u.video.padding.top; - format->u.video.padding.bottom = align.padding_bottom; - format->u.video.height += format->u.video.padding.bottom; - } - - return STATUS_SUCCESS; + return caps_to_media_type(output_caps, ¶ms->media_type, transform->attrs.output_plane_align); } NTSTATUS wg_transform_set_output_format(void *args) From 563249786177d98373fbcaf308160f24dc9b2654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 May 2024 18:28:07 +0200 Subject: [PATCH 219/301] winegstreamer: Translate MFVIDEOFORMAT / WAVEFORMATEX directly to GstCaps in wg_transform. (cherry picked from commit 0906f6957a4a7f48f915fe841a6be7ce68c86c94) CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 83 ++++++- dlls/winegstreamer/unix_private.h | 3 +- dlls/winegstreamer/unixlib.h | 6 +- dlls/winegstreamer/video_decoder.c | 20 +- dlls/winegstreamer/wg_media_type.c | 365 +++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 19 +- dlls/winegstreamer/wg_transform.c | 15 +- 8 files changed, 476 insertions(+), 37 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 6a4f7d28169..6a1e6af57ad 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -126,7 +126,7 @@ HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_M const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **media_type); -bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); +HRESULT wg_transform_set_output_type(wg_transform_t transform, IMFMediaType *media_type); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); HRESULT wg_transform_drain(wg_transform_t transform); HRESULT wg_transform_flush(wg_transform_t transform); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index e8ba0a3ccfb..bd23212a66d 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -70,6 +70,66 @@ bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) return TRUE; } +static HRESULT video_format_from_media_type(IMFMediaType *media_type, MFVIDEOFORMAT **format, UINT32 *format_size) +{ + GUID subtype; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, format, format_size))) + return hr; + + /* fixup MPEG video formats here, so we can consistently use MFVIDEOFORMAT internally */ + if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG1Payload) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG1Packet) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG2_VIDEO)) + { + struct mpeg_video_format *mpeg; + UINT32 mpeg_size, len; + + if (FAILED(IMFMediaType_GetBlobSize(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, &len))) + len = 0; + mpeg_size = offsetof(struct mpeg_video_format, sequence_header[len]); + + if ((mpeg = CoTaskMemAlloc(mpeg_size))) + { + memset(mpeg, 0, mpeg_size); + mpeg->hdr = **format; + + IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, mpeg->sequence_header, len, NULL); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, (UINT32 *)&mpeg->start_time_code); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_PROFILE, &mpeg->profile); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_LEVEL, &mpeg->level); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_FLAGS, &mpeg->flags); + + CoTaskMemFree(*format); + *format = &mpeg->hdr; + *format_size = mpeg_size; + } + } + + return hr; +} + +static HRESULT wg_media_type_from_mf(IMFMediaType *media_type, struct wg_media_type *wg_media_type) +{ + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &wg_media_type->major))) + return hr; + + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Video)) + return video_format_from_media_type(media_type, &wg_media_type->u.video, + &wg_media_type->format_size); + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Audio)) + return MFCreateWaveFormatExFromMFMediaType(media_type, &wg_media_type->u.audio, + &wg_media_type->format_size, 0); + + FIXME("Unsupported major type %s\n", debugstr_guid(&wg_media_type->major)); + return E_NOTIMPL; +} + static HRESULT media_type_from_video_format(const MFVIDEOFORMAT *format, IMFMediaType **media_type) { HRESULT hr; @@ -706,17 +766,30 @@ HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **me return hr; } -bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format) +HRESULT wg_transform_set_output_type(wg_transform_t transform, IMFMediaType *media_type) { - struct wg_transform_set_output_format_params params = + struct wg_transform_set_output_type_params params = { .transform = transform, - .format = format, }; + NTSTATUS status; + HRESULT hr; - TRACE("transform %#I64x, format %p.\n", transform, format); + TRACE("transform %#I64x, media_type %p.\n", transform, media_type); - return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); + if (FAILED(hr = wg_media_type_from_mf(media_type, ¶ms.media_type))) + { + WARN("Failed to initialize media type, hr %#lx\n", hr); + return hr; + } + if ((status = WINE_UNIX_CALL(unix_wg_transform_set_output_type, ¶ms))) + { + WARN("Failed to set transform output type, status %#lx\n", status); + hr = HRESULT_FROM_NT(status); + } + + CoTaskMemFree(params.media_type.u.format); + return hr; } HRESULT wg_transform_drain(wg_transform_t transform) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 4bfe7a286d9..e0feef21778 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -74,7 +74,7 @@ extern NTSTATUS wg_source_set_stream_flags(void *args); extern NTSTATUS wg_transform_create(void *args); extern NTSTATUS wg_transform_destroy(void *args); extern NTSTATUS wg_transform_get_output_type(void *args); -extern NTSTATUS wg_transform_set_output_format(void *args); +extern NTSTATUS wg_transform_set_output_type(void *args); extern NTSTATUS wg_transform_push_data(void *args); extern NTSTATUS wg_transform_read_data(void *args); extern NTSTATUS wg_transform_get_status(void *args); @@ -84,6 +84,7 @@ extern NTSTATUS wg_transform_notify_qos(void *args); /* wg_media_type.c */ +extern GstCaps *caps_from_media_type(const struct wg_media_type *media_type); extern NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UINT32 video_plane_align); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index f0d8e2d29ec..a6214efd8a7 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -448,10 +448,10 @@ struct wg_transform_get_output_type_params struct wg_media_type media_type; }; -struct wg_transform_set_output_format_params +struct wg_transform_set_output_type_params { wg_transform_t transform; - const struct wg_format *format; + struct wg_media_type media_type; }; struct wg_transform_get_status_params @@ -542,7 +542,7 @@ enum unix_funcs unix_wg_transform_create, unix_wg_transform_destroy, unix_wg_transform_get_output_type, - unix_wg_transform_set_output_format, + unix_wg_transform_set_output_type, unix_wg_transform_push_data, unix_wg_transform_read_data, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 5ad72752044..d70eed6336b 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -700,25 +700,17 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF } if (decoder->wg_transform) - { - struct wg_format output_format; - mf_media_type_to_wg_format(output_type, &output_format); + hr = wg_transform_set_output_type(decoder->wg_transform, output_type); + else + hr = try_create_wg_transform(decoder, output_type); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - hr = MF_E_INVALIDMEDIATYPE; - } - } - else if (FAILED(hr = try_create_wg_transform(decoder, output_type))) + IMFMediaType_Release(output_type); + + if (FAILED(hr)) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; } - - IMFMediaType_Release(output_type); return hr; } diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 21338e89399..14fc1a9cdf4 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -64,6 +64,371 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); +static void init_caps_codec_data(GstCaps *caps, const void *codec_data, int codec_data_size) +{ + GstBuffer *buffer; + + if (codec_data_size > 0 && (buffer = gst_buffer_new_and_alloc(codec_data_size))) + { + gst_buffer_fill(buffer, 0, codec_data, codec_data_size); + gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + } +} + +static void init_caps_from_wave_format_mpeg1(GstCaps *caps, const MPEG1WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->fwHeadLayer, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_wave_format_mp3(GstCaps *caps, const MPEGLAYER3WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_wave_format_aac(GstCaps *caps, const HEAACWAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, format->pbAudioSpecificConfig, format_size - sizeof(format->wfInfo)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); + + switch (format->wfInfo.wPayloadType) + { + case 0: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); break; + case 1: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); break; + case 2: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adif", NULL); break; + case 3: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "loas", NULL); break; + } + + /* FIXME: Use gst_codec_utils_aac_caps_set_level_and_profile from GStreamer pbutils library */ +} + +static void init_caps_from_wave_format_aac_raw(GstCaps *caps, const WAVEFORMATEX *format, UINT32 format_size) +{ + init_caps_codec_data(caps, format + 1, format->cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); +} + +static void init_caps_from_wave_format_wma1(GstCaps *caps, const MSAUDIO1WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format_wma2(GstCaps *caps, const WMAUDIO2WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 2, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format_wma3(GstCaps *caps, const WMAUDIO3WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format(GstCaps *caps, const GUID *subtype, + const void *format, UINT32 format_size) +{ + if (IsEqualGUID(subtype, &MFAudioFormat_MPEG)) + return init_caps_from_wave_format_mpeg1(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_MP3)) + return init_caps_from_wave_format_mp3(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_AAC)) + return init_caps_from_wave_format_aac(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_RAW_AAC)) + return init_caps_from_wave_format_aac_raw(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_MSAudio1)) + return init_caps_from_wave_format_wma1(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV8)) + return init_caps_from_wave_format_wma2(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV9) + || IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) + return init_caps_from_wave_format_wma3(caps, format, format_size); + + GST_FIXME("Unsupported subtype " WG_GUID_FORMAT, WG_GUID_ARGS(*subtype)); +} + +static GstAudioFormat wave_format_tag_to_gst_audio_format(UINT tag, UINT depth) +{ + switch (tag) + { + case WAVE_FORMAT_PCM: + if (depth == 32) return GST_AUDIO_FORMAT_S32LE; + if (depth == 24) return GST_AUDIO_FORMAT_S24LE; + if (depth == 16) return GST_AUDIO_FORMAT_S16LE; + if (depth == 8) return GST_AUDIO_FORMAT_U8; + break; + + case WAVE_FORMAT_IEEE_FLOAT: + if (depth == 64) return GST_AUDIO_FORMAT_F64LE; + if (depth == 32) return GST_AUDIO_FORMAT_F32LE; + break; + } + + return GST_AUDIO_FORMAT_ENCODED; +} + +static GstCaps *caps_from_wave_format_ex(const WAVEFORMATEX *format, UINT32 format_size, const GUID *subtype, UINT64 channel_mask) +{ + GstAudioFormat audio_format = wave_format_tag_to_gst_audio_format(subtype->Data1, format->wBitsPerSample); + GstCaps *caps; + + if (!(caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gst_audio_format_to_string(audio_format), + "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, format->nSamplesPerSec, + "channels", G_TYPE_INT, format->nChannels, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL))) + return NULL; + + if (audio_format == GST_AUDIO_FORMAT_ENCODED) + init_caps_from_wave_format(caps, subtype, format, format_size); + + return caps; +} + +static WAVEFORMATEX *strip_wave_format_extensible(const WAVEFORMATEXTENSIBLE *format_ext) +{ + UINT32 extra_size = format_ext->Format.cbSize + sizeof(WAVEFORMATEX) - sizeof(WAVEFORMATEXTENSIBLE); + WAVEFORMATEX *format; + + if (!(format = malloc(sizeof(*format) + extra_size))) + return NULL; + + *format = format_ext->Format; + format->cbSize = extra_size; + format->wFormatTag = format_ext->SubFormat.Data1; + memcpy(format + 1, format_ext + 1, extra_size); + return format; +} + +static GstCaps *caps_from_wave_format_extensible(const WAVEFORMATEXTENSIBLE *format, UINT32 format_size) +{ + WAVEFORMATEX *wfx; + GstCaps *caps; + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample, " + "%u valid bps, channel mask %#x, subtype " WG_GUID_FORMAT ".", + format->Format.wFormatTag, format->Format.nChannels, (int)format->Format.nSamplesPerSec, + (int)format->Format.nAvgBytesPerSec, format->Format.nBlockAlign, format->Format.wBitsPerSample, + format->Samples.wValidBitsPerSample, (int)format->dwChannelMask, WG_GUID_ARGS(format->SubFormat)); + if (format->Format.cbSize) + { + guint extra_size = sizeof(WAVEFORMATEX) + format->Format.cbSize - sizeof(WAVEFORMATEXTENSIBLE); + GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), extra_size); + } + + if (!(wfx = strip_wave_format_extensible(format))) + return NULL; + + caps = caps_from_wave_format_ex(wfx, format_size + sizeof(*wfx) - sizeof(*format), + &format->SubFormat, format->dwChannelMask); + free(wfx); + return caps; +} + +static GstCaps *caps_from_wave_format(const void *format, UINT32 format_size) +{ + const WAVEFORMATEX *wfx = format; + GUID subtype = MFAudioFormat_Base; + UINT channel_mask; + + if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + return caps_from_wave_format_extensible(format, format_size); + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample.", + wfx->wFormatTag, wfx->nChannels, (int)wfx->nSamplesPerSec, + (int)wfx->nAvgBytesPerSec, wfx->nBlockAlign, wfx->wBitsPerSample); + if (wfx->cbSize) GST_MEMDUMP("extra bytes:", (guint8 *)(wfx + 1), wfx->cbSize); + + subtype.Data1 = wfx->wFormatTag; + channel_mask = gst_audio_channel_get_fallback_mask(wfx->nChannels); + return caps_from_wave_format_ex(format, format_size, &subtype, channel_mask); +} + +static void init_caps_from_video_cinepak(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-cinepak"); +} + +static void init_caps_from_video_h264(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-h264"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); + gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); +} + +static void init_caps_from_video_wmv(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size, + int wmv_version, const char *wmv_format) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, wmv_version, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, wmv_format, NULL); +} + +static void init_caps_from_video_indeo(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-indeo"); + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, 5, NULL); +} + +static void init_caps_from_video_mpeg(GstCaps *caps, const struct mpeg_video_format *format, UINT format_size) +{ + init_caps_codec_data(caps, format->sequence_header, format->sequence_header_count); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_video_subtype(GstCaps *caps, const GUID *subtype, const void *format, UINT format_size) +{ + if (IsEqualGUID(subtype, &MFVideoFormat_CVID)) + return init_caps_from_video_cinepak(caps, format, format_size); + if (IsEqualGUID(subtype, &MFVideoFormat_H264)) + return init_caps_from_video_h264(caps, format, format_size); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) + return init_caps_from_video_wmv(caps, format, format_size, 1, "WMV1"); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) + return init_caps_from_video_wmv(caps, format, format_size, 2, "WMV2"); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WMV3"); + if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WMVA"); + if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WVC1"); + if (IsEqualGUID(subtype, &MFVideoFormat_IV50)) + return init_caps_from_video_indeo(caps, format, format_size); + if (IsEqualGUID(subtype, &MEDIASUBTYPE_MPEG1Payload)) + return init_caps_from_video_mpeg(caps, format, format_size); + + GST_FIXME("Unsupported subtype " WG_GUID_FORMAT, WG_GUID_ARGS(*subtype)); +} + +static GstVideoFormat subtype_to_gst_video_format(const GUID *subtype) +{ + GUID base = *subtype; + base.Data1 = 0; + + if (IsEqualGUID(&base, &MFVideoFormat_Base)) + { + switch (subtype->Data1) + { + case D3DFMT_A8R8G8B8: return GST_VIDEO_FORMAT_BGRA; + case D3DFMT_X8R8G8B8: return GST_VIDEO_FORMAT_BGRx; + case D3DFMT_R8G8B8: return GST_VIDEO_FORMAT_BGR; + case D3DFMT_A8B8G8R8: return GST_VIDEO_FORMAT_RGBA; + case D3DFMT_X1R5G5B5: return GST_VIDEO_FORMAT_RGB15; + case D3DFMT_R5G6B5: return GST_VIDEO_FORMAT_RGB16; + case MAKEFOURCC('A','Y','U','V'): return GST_VIDEO_FORMAT_AYUV; + case MAKEFOURCC('I','4','2','0'): return GST_VIDEO_FORMAT_I420; + case MAKEFOURCC('N','V','1','2'): return GST_VIDEO_FORMAT_NV12; + case MAKEFOURCC('U','Y','V','Y'): return GST_VIDEO_FORMAT_UYVY; + case MAKEFOURCC('Y','U','Y','2'): return GST_VIDEO_FORMAT_YUY2; + case MAKEFOURCC('Y','V','1','2'): return GST_VIDEO_FORMAT_YV12; + case MAKEFOURCC('Y','V','Y','U'): return GST_VIDEO_FORMAT_YVYU; + } + } + + return GST_VIDEO_FORMAT_ENCODED; +} + +static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 format_size) +{ + GstVideoFormat video_format = subtype_to_gst_video_format(&format->guidFormat); + GstCaps *caps; + + GST_TRACE("subtype " WG_GUID_FORMAT " %ux%u, FPS " WG_RATIO_FORMAT ", aperture " WG_APERTURE_FORMAT ", " + "PAR " WG_RATIO_FORMAT ", videoFlags %#x.", + WG_GUID_ARGS(format->guidFormat), (int)format->videoInfo.dwWidth, (int)format->videoInfo.dwHeight, + WG_RATIO_ARGS(format->videoInfo.FramesPerSecond), WG_APERTURE_ARGS(format->videoInfo.MinimumDisplayAperture), + WG_RATIO_ARGS(format->videoInfo.PixelAspectRatio), (int)format->videoInfo.VideoFlags ); + if (format->dwSize > sizeof(*format)) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->dwSize - sizeof(*format)); + + if (!(caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, gst_video_format_to_string(video_format), NULL))) + return NULL; + + if (format->videoInfo.dwWidth) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->videoInfo.dwWidth, NULL); + if (format->videoInfo.dwHeight) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->videoInfo.dwHeight, NULL); + + if (format->videoInfo.PixelAspectRatio.Denominator) + gst_caps_set_simple(caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, + format->videoInfo.PixelAspectRatio.Numerator, + format->videoInfo.PixelAspectRatio.Denominator, NULL); + if (format->videoInfo.FramesPerSecond.Denominator) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, + format->videoInfo.FramesPerSecond.Numerator, + format->videoInfo.FramesPerSecond.Denominator, NULL); + + if (video_format == GST_VIDEO_FORMAT_ENCODED) + init_caps_from_video_subtype(caps, &format->guidFormat, format, format_size); + + return caps; +} + +GstCaps *caps_from_media_type(const struct wg_media_type *media_type) +{ + GstCaps *caps = NULL; + + if (IsEqualGUID(&media_type->major, &MFMediaType_Video)) + caps = caps_from_video_format(media_type->u.video, media_type->format_size); + else if (IsEqualGUID(&media_type->major, &MFMediaType_Audio)) + caps = caps_from_wave_format(media_type->u.audio, media_type->format_size); + + GST_TRACE("caps %"GST_PTR_FORMAT, caps); + return caps; +} + static WORD wave_format_tag_from_gst_audio_format(GstAudioFormat audio_format) { switch (audio_format) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 36ebb499a25..81826a12f51 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2259,7 +2259,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_create), X(wg_transform_destroy), X(wg_transform_get_output_type), - X(wg_transform_set_output_format), + X(wg_transform_set_output_type), X(wg_transform_push_data), X(wg_transform_read_data), @@ -2558,19 +2558,24 @@ NTSTATUS wow64_wg_transform_get_output_type(void *args) return status; } -NTSTATUS wow64_wg_transform_set_output_format(void *args) +NTSTATUS wow64_wg_transform_set_output_type(void *args) { struct { wg_transform_t transform; - PTR32 format; + struct wg_media_type32 media_type; } *params32 = args; - struct wg_transform_set_output_format_params params = + struct wg_transform_set_output_type_params params = { .transform = params32->transform, - .format = ULongToPtr(params32->format), + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, }; - return wg_transform_set_output_format(¶ms); + return wg_transform_set_output_type(¶ms); } NTSTATUS wow64_wg_transform_push_data(void *args) @@ -2733,7 +2738,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_transform_create), X(wg_transform_destroy), X64(wg_transform_get_output_type), - X64(wg_transform_set_output_format), + X64(wg_transform_set_output_type), X64(wg_transform_push_data), X64(wg_transform_read_data), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 772b8127944..407da3b185b 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -635,17 +635,20 @@ NTSTATUS wg_transform_get_output_type(void *args) return caps_to_media_type(output_caps, ¶ms->media_type, transform->attrs.output_plane_align); } -NTSTATUS wg_transform_set_output_format(void *args) +NTSTATUS wg_transform_set_output_type(void *args) { - struct wg_transform_set_output_format_params *params = args; + struct wg_transform_set_output_type_params *params = args; struct wg_transform *transform = get_transform(params->transform); - const struct wg_format *format = params->format; + MFVideoInfo output_info = {0}; GstCaps *caps, *stripped; GstSample *sample; - if (!(caps = wg_format_to_caps(format))) + if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) + output_info = params->media_type.u.video->videoInfo; + + if (!(caps = caps_from_media_type(¶ms->media_type))) { - GST_ERROR("Failed to convert format %p to caps.", format); + GST_ERROR("Failed to convert media type to caps."); return STATUS_UNSUCCESSFUL; } @@ -672,7 +675,7 @@ NTSTATUS wg_transform_set_output_format(void *args) if (transform->video_flip) { const char *value; - if (transform->input_is_flipped != wg_format_video_is_flipped(format)) + if (transform->input_is_flipped != !!(output_info.VideoFlags & MFVideoFlag_BottomUpLinearRep)) value = "vertical-flip"; else value = "none"; From c604c42770fc700e71dcd17de8481f2280ea0b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 May 2024 11:28:42 +0200 Subject: [PATCH 220/301] winegstreamer: Create transforms from MFVIDEOFORMAT / WAVEFORMATEX. Instead of going through a custom intermediate format. (cherry picked from commit 9192b3b724d90788f7a1682b3f9eedb7bf363e22) CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 - dlls/winegstreamer/main.c | 133 ++++++++++--------- dlls/winegstreamer/quartz_transform.c | 25 ++-- dlls/winegstreamer/unixlib.h | 6 +- dlls/winegstreamer/wg_parser.c | 22 +++- dlls/winegstreamer/wg_transform.c | 178 +++++++++++--------------- 6 files changed, 173 insertions(+), 193 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 6a1e6af57ad..f0067a2b4e9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -118,8 +118,6 @@ char *wg_source_get_stream_tag(wg_source_t source, UINT32 index, wg_parser_tag tag); void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select); -wg_transform_t wg_transform_create(const struct wg_format *input_format, - const struct wg_format *output_format, const struct wg_transform_attrs *attrs); HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform); HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index bd23212a66d..cef0bc0bd0b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -627,55 +627,59 @@ void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select) WINE_UNIX_CALL(unix_wg_source_set_stream_flags, ¶ms); } -wg_transform_t wg_transform_create(const struct wg_format *input_format, - const struct wg_format *output_format, const struct wg_transform_attrs *attrs) +HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, + const struct wg_transform_attrs *attrs, wg_transform_t *transform) { struct wg_transform_create_params params = { - .input_format = input_format, - .output_format = output_format, - .attrs = attrs, + .attrs = *attrs, }; + NTSTATUS status; + HRESULT hr; - TRACE("input_format %p, output_format %p.\n", input_format, output_format); - - if (WINE_UNIX_CALL(unix_wg_transform_create, ¶ms)) - return 0; + TRACE("input_type %p, output_type %p.\n", input_type, output_type); - TRACE("Returning transform %#I64x.\n", params.transform); - return params.transform; -} - -HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, - const struct wg_transform_attrs *attrs, wg_transform_t *transform) -{ - struct wg_format input_format, output_format; + if (FAILED(hr = wg_media_type_from_mf(input_type, ¶ms.input_type))) + return hr; + if (FAILED(hr = wg_media_type_from_mf(output_type, ¶ms.output_type))) + { + CoTaskMemFree(params.input_type.u.format); + return hr; + } - mf_media_type_to_wg_format(input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - mf_media_type_to_wg_format(output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; + if ((status = WINE_UNIX_CALL(unix_wg_transform_create, ¶ms))) + { + WARN("Failed to create transform, status %#lx\n", status); + hr = HRESULT_FROM_NT(status); + } - if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) - return E_FAIL; - return S_OK; + CoTaskMemFree(params.output_type.u.format); + CoTaskMemFree(params.input_type.u.format); + *transform = params.transform; + return hr; } -HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_type, const AM_MEDIA_TYPE *output_type, +HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, const struct wg_transform_attrs *attrs, wg_transform_t *transform) { - struct wg_format input_format, output_format; + IMFMediaType *input_type, *output_type; + HRESULT hr; - if (!amt_to_wg_format(input_type, &input_format)) - return E_FAIL; - if (!amt_to_wg_format(output_type, &output_format)) - return E_FAIL; + TRACE("input_format %p, output_format %p.\n", input_format, output_format); - if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) - return E_FAIL; - return S_OK; + /* through IMFMediaType to normalize representation to MFVIDEOFORMAT / WAVEFORMATEX */ + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void *)input_format, &input_type))) + return 0; + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void *)output_format, &output_type))) + { + IMFMediaType_Release(input_type); + return 0; + } + + hr = wg_transform_create_mf(input_type, output_type, attrs, transform); + IMFMediaType_Release(output_type); + IMFMediaType_Release(input_type); + return hr; } void wg_transform_destroy(wg_transform_t transform) @@ -965,24 +969,22 @@ HRESULT wg_muxer_finalize(wg_muxer_t muxer) return S_OK; } -HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMATEX *output) +static HRESULT check_transform_support(const struct wg_media_type *input, const struct wg_media_type *output) { IMFMediaType *input_type, *output_type; struct wg_transform_attrs attrs = {0}; wg_transform_t transform; HRESULT hr; - if (FAILED(hr = MFCreateMediaType(&input_type))) + if (FAILED(hr = wg_media_type_to_mf(input, &input_type))) return hr; - if (FAILED(hr = MFCreateMediaType(&output_type))) + if (FAILED(hr = wg_media_type_to_mf(output, &output_type))) { IMFMediaType_Release(input_type); return hr; } - if (SUCCEEDED(hr = MFInitMediaTypeFromWaveFormatEx(input_type, input, sizeof(*input) + input->cbSize)) - && SUCCEEDED(hr = MFInitMediaTypeFromWaveFormatEx(output_type, output, sizeof(*output) + output->cbSize)) - && SUCCEEDED(hr = wg_transform_create_mf(input_type, output_type, &attrs, &transform))) + if (SUCCEEDED(hr = wg_transform_create_mf(input_type, output_type, &attrs, &transform))) wg_transform_destroy(transform); IMFMediaType_Release(output_type); @@ -990,29 +992,38 @@ HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMA return hr; } -HRESULT check_video_transform_support(const MFVIDEOFORMAT *input, const MFVIDEOFORMAT *output) +HRESULT check_audio_transform_support(const WAVEFORMATEX *input, const WAVEFORMATEX *output) { - IMFMediaType *input_type, *output_type; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; - HRESULT hr; - - if (FAILED(hr = MFCreateMediaType(&input_type))) - return hr; - if (FAILED(hr = MFCreateMediaType(&output_type))) + const struct wg_media_type input_type = { - IMFMediaType_Release(input_type); - return hr; - } - - if (SUCCEEDED(hr = MFInitMediaTypeFromMFVideoFormat(input_type, input, input->dwSize)) - && SUCCEEDED(hr = MFInitMediaTypeFromMFVideoFormat(output_type, output, output->dwSize)) - && SUCCEEDED(hr = wg_transform_create_mf(input_type, output_type, &attrs, &transform))) - wg_transform_destroy(transform); + .major = MFMediaType_Audio, + .format_size = sizeof(*input) + input->cbSize, + .u.audio = (WAVEFORMATEX *)input, + }; + const struct wg_media_type output_type = + { + .major = MFMediaType_Audio, + .format_size = sizeof(*output) + output->cbSize, + .u.audio = (WAVEFORMATEX *)output, + }; + return check_transform_support(&input_type, &output_type); +} - IMFMediaType_Release(output_type); - IMFMediaType_Release(input_type); - return hr; +HRESULT check_video_transform_support(const MFVIDEOFORMAT *input, const MFVIDEOFORMAT *output) +{ + const struct wg_media_type input_type = + { + .major = MFMediaType_Video, + .format_size = input->dwSize, + .u.video = (MFVIDEOFORMAT *)input, + }; + const struct wg_media_type output_type = + { + .major = MFMediaType_Video, + .format_size = output->dwSize, + .u.video = (MFVIDEOFORMAT *)output, + }; + return check_transform_support(&input_type, &output_type); } #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 31150a71298..ff57ea02ed0 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -874,31 +874,26 @@ static const struct transform_ops mpeg_video_codec_transform_ops = HRESULT mpeg_video_codec_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format output_format = + const MFVIDEOFORMAT output_format = { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = { - .format = WG_VIDEO_FORMAT_I420, - /* size doesn't matter, this one is only used to check if the GStreamer plugin exists */ - }, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MEDIASUBTYPE_NV12, }; - static const struct wg_format input_format = + const MFVIDEOFORMAT input_format = { - .major_type = WG_MAJOR_TYPE_VIDEO_MPEG1, - .u.video = {}, + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MEDIASUBTYPE_MPEG1Payload, }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct transform *object; HRESULT hr; - transform = wg_transform_create(&input_format, &output_format, &attrs); - if (!transform) + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support MPEG-1 video decoding, please install appropriate plugins.\n"); - return E_FAIL; + return hr; } - wg_transform_destroy(transform); hr = transform_create(outer, &CLSID_CMpegVideoCodec, &mpeg_video_codec_transform_ops, &object); if (FAILED(hr)) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index a6214efd8a7..547c3414d21 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -423,9 +423,9 @@ struct wg_transform_attrs struct wg_transform_create_params { wg_transform_t transform; - const struct wg_format *input_format; - const struct wg_format *output_format; - const struct wg_transform_attrs *attrs; + struct wg_media_type input_type; + struct wg_media_type output_type; + struct wg_transform_attrs attrs; }; struct wg_transform_push_data_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 81826a12f51..81e13fba433 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2516,15 +2516,25 @@ NTSTATUS wow64_wg_transform_create(void *args) struct { wg_transform_t transform; - PTR32 input_format; - PTR32 output_format; - PTR32 attrs; + struct wg_media_type32 input_type; + struct wg_media_type32 output_type; + struct wg_transform_attrs attrs; } *params32 = args; struct wg_transform_create_params params = { - .input_format = ULongToPtr(params32->input_format), - .output_format = ULongToPtr(params32->output_format), - .attrs = ULongToPtr(params32->attrs), + .input_type = + { + .major = params32->input_type.major, + .format_size = params32->input_type.format_size, + .u.format = ULongToPtr(params32->input_type.format), + }, + .output_type = + { + .major = params32->output_type.major, + .format_size = params32->output_type.format_size, + .u.format = ULongToPtr(params32->output_type.format), + }, + .attrs = params32->attrs, }; NTSTATUS ret; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 407da3b185b..faef62d1c8b 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -53,9 +53,8 @@ struct wg_transform GstQuery *drain_query; GstAtomicQueue *input_queue; - - bool input_is_flipped; GstElement *video_flip; + MFVideoInfo input_info; GstAtomicQueue *output_queue; GstSample *output_sample; @@ -337,60 +336,32 @@ NTSTATUS wg_transform_destroy(void *args) return STATUS_SUCCESS; } -static bool wg_format_video_is_flipped(const struct wg_format *format) -{ - return format->major_type == WG_MAJOR_TYPE_VIDEO && (format->u.video.height < 0); -} - -static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char *media_type) +static GstCaps *transform_get_parsed_caps(GstCaps *caps, const char *media_type) { + GstStructure *structure = gst_caps_get_structure(caps, 0); GstCaps *parsed_caps; + gint value; if (!(parsed_caps = gst_caps_new_empty_simple(media_type))) return NULL; - switch (format->major_type) + if (gst_structure_get_int(structure, "mpegversion", &value)) { - case WG_MAJOR_TYPE_AUDIO_MPEG1: - gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, - "layer", G_TYPE_INT, format->u.audio.layer, NULL); - break; - case WG_MAJOR_TYPE_AUDIO_MPEG4: + if (value == 4) gst_caps_set_simple(parsed_caps, "framed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 4, NULL); - break; - case WG_MAJOR_TYPE_AUDIO_WMA: - gst_caps_set_simple(parsed_caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); - break; - case WG_MAJOR_TYPE_VIDEO_H264: - gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, NULL); - break; - case WG_MAJOR_TYPE_VIDEO_MPEG1: - gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, 1, NULL); - break; - case WG_MAJOR_TYPE_VIDEO_WMV: - switch (format->u.video.format) - { - case WG_VIDEO_FORMAT_WMV1: - gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 1, NULL); - break; - case WG_VIDEO_FORMAT_WMV2: - gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 2, NULL); - break; - case WG_VIDEO_FORMAT_WMV3: - case WG_VIDEO_FORMAT_WMVA: - case WG_VIDEO_FORMAT_WVC1: - gst_caps_set_simple(parsed_caps, "wmvversion", G_TYPE_INT, 3, NULL); - break; - default: - GST_WARNING("Unknown WMV format %u.", format->u.video.format); - break; - } - break; - case WG_MAJOR_TYPE_AUDIO: - case WG_MAJOR_TYPE_VIDEO: - case WG_MAJOR_TYPE_UNKNOWN: - break; + else + { + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "mpegversion", G_TYPE_INT, value, NULL); + if (gst_structure_get_int(structure, "layer", &value)) + gst_caps_set_simple(parsed_caps, "layer", G_TYPE_INT, value, NULL); + } } + else if (gst_structure_get_int(structure, "wmaversion", &value)) + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "wmaversion", G_TYPE_INT, value, NULL); + else if (gst_structure_get_int(structure, "wmvversion", &value)) + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, "wmvversion", G_TYPE_INT, value, NULL); + else + gst_caps_set_simple(parsed_caps, "parsed", G_TYPE_BOOLEAN, true, NULL); return parsed_caps; } @@ -398,14 +369,13 @@ static GstCaps *transform_get_parsed_caps(struct wg_format *format, const char * NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; - struct wg_format output_format = *params->output_format; - struct wg_format input_format = *params->input_format; GstElement *first = NULL, *last = NULL, *element; GstCaps *sink_caps = NULL, *src_caps = NULL, *parsed_caps = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; + const gchar *input_mime, *output_mime; GstPadTemplate *template = NULL; struct wg_transform *transform; - const gchar *media_type; + MFVideoInfo output_info = {0}; GstEvent *event; if (!(transform = calloc(1, sizeof(*transform)))) @@ -420,9 +390,14 @@ NTSTATUS wg_transform_create(void *args) goto out; if (!(transform->allocator = wg_allocator_create())) goto out; - transform->attrs = *params->attrs; + transform->attrs = params->attrs; - if (!(src_caps = wg_format_to_caps(&input_format))) + if (IsEqualGUID(¶ms->input_type.major, &MFMediaType_Video)) + transform->input_info = params->input_type.u.video->videoInfo; + if (IsEqualGUID(¶ms->output_type.major, &MFMediaType_Video)) + output_info = params->output_type.u.video->videoInfo; + + if (!(src_caps = caps_from_media_type(¶ms->input_type))) goto out; if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) goto out; @@ -436,7 +411,7 @@ NTSTATUS wg_transform_create(void *args) gst_pad_set_element_private(transform->my_src, transform); gst_pad_set_query_function(transform->my_src, transform_src_query_cb); - if (!(transform->output_caps = wg_format_to_caps(&output_format))) + if (!(transform->output_caps = caps_from_media_type(¶ms->output_type))) goto out; transform->desired_caps = gst_caps_ref(transform->output_caps); if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, transform->output_caps))) @@ -453,55 +428,48 @@ NTSTATUS wg_transform_create(void *args) gst_pad_set_query_function(transform->my_sink, transform_sink_query_cb); gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - media_type = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); - if (!(parsed_caps = transform_get_parsed_caps(&input_format, media_type))) + input_mime = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); + if (!(parsed_caps = transform_get_parsed_caps(src_caps, input_mime))) goto out; /* Since we append conversion elements, we don't want to filter decoders * based on the actual output caps now. Matching decoders with the * raw output media type should be enough. */ - media_type = gst_structure_get_name(gst_caps_get_structure(transform->output_caps, 0)); - if (!(sink_caps = gst_caps_new_empty_simple(media_type))) + output_mime = gst_structure_get_name(gst_caps_get_structure(transform->output_caps, 0)); + if (!(sink_caps = gst_caps_new_empty_simple(output_mime))) goto out; - switch (input_format.major_type) + if (strcmp(input_mime, "audio/x-raw") && strcmp(input_mime, "video/x-raw")) { - case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_AUDIO_MPEG1: - case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_VIDEO_CINEPAK: - case WG_MAJOR_TYPE_VIDEO_INDEO: - case WG_MAJOR_TYPE_VIDEO_WMV: - case WG_MAJOR_TYPE_VIDEO_MPEG1: - if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, src_caps, parsed_caps)) - && !append_element(transform->container, element, &first, &last)) - goto out; - else if (!element) - { - gst_caps_unref(parsed_caps); - parsed_caps = gst_caps_ref(src_caps); - } + if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, src_caps, parsed_caps)) + && !append_element(transform->container, element, &first, &last)) + goto out; + else if (!element) + { + gst_caps_unref(parsed_caps); + parsed_caps = gst_caps_ref(src_caps); + } - if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, parsed_caps, sink_caps)) - || !append_element(transform->container, element, &first, &last)) - goto out; - set_max_threads(element); - break; - - case WG_MAJOR_TYPE_AUDIO: - case WG_MAJOR_TYPE_VIDEO: - transform->attrs.input_queue_length = 16; - break; - case WG_MAJOR_TYPE_UNKNOWN: - GST_FIXME("Format %u not implemented!", input_format.major_type); + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, parsed_caps, sink_caps)) + || !append_element(transform->container, element, &first, &last)) goto out; + set_max_threads(element); + } + else + { + transform->attrs.input_queue_length = 16; } - switch (output_format.major_type) + if (g_str_has_prefix(output_mime, "audio/")) { - case WG_MAJOR_TYPE_AUDIO: + if (strcmp(output_mime, "audio/x-raw")) + { + GST_FIXME("output caps %"GST_PTR_FORMAT" not implemented!", transform->output_caps); + goto out; + } + else + { /* The MF audio decoder transforms allow decoding to various formats * as well as resampling the audio at the same time, whereas * GStreamer decoder plugins usually only support decoding to a @@ -517,36 +485,33 @@ NTSTATUS wg_transform_create(void *args) if (!(element = create_element("audioresample", "base")) || !append_element(transform->container, element, &first, &last)) goto out; - break; + } + } - case WG_MAJOR_TYPE_VIDEO: + if (g_str_has_prefix(output_mime, "video/")) + { + if (strcmp(output_mime, "video/x-raw")) + { + GST_FIXME("output caps %"GST_PTR_FORMAT" not implemented!", transform->output_caps); + goto out; + } + else + { if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; if (!(transform->video_flip = create_element("videoflip", "base")) || !append_element(transform->container, transform->video_flip, &first, &last)) goto out; - transform->input_is_flipped = wg_format_video_is_flipped(&input_format); - if (transform->input_is_flipped != wg_format_video_is_flipped(&output_format)) + + if ((transform->input_info.VideoFlags ^ output_info.VideoFlags) & MFVideoFlag_BottomUpLinearRep) gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", "vertical-flip"); if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; /* Let GStreamer choose a default number of threads. */ gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); - break; - - case WG_MAJOR_TYPE_UNKNOWN: - case WG_MAJOR_TYPE_AUDIO_MPEG1: - case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_WMA: - case WG_MAJOR_TYPE_VIDEO_CINEPAK: - case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_INDEO: - case WG_MAJOR_TYPE_VIDEO_WMV: - case WG_MAJOR_TYPE_VIDEO_MPEG1: - GST_FIXME("Format %u not implemented!", output_format.major_type); - goto out; + } } if (!link_src_to_element(transform->my_src, first)) @@ -675,7 +640,8 @@ NTSTATUS wg_transform_set_output_type(void *args) if (transform->video_flip) { const char *value; - if (transform->input_is_flipped != !!(output_info.VideoFlags & MFVideoFlag_BottomUpLinearRep)) + + if ((transform->input_info.VideoFlags ^ output_info.VideoFlags) & MFVideoFlag_BottomUpLinearRep) value = "vertical-flip"; else value = "none"; From 4137f3800c75dfdbde05e7b01e7171a502faa26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Dec 2023 11:49:06 +0100 Subject: [PATCH 221/301] winegstreamer: Register more VIDEO_EFFECT DMO classes. CW-Bug-Id: #20427 CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 33 +++++++++++++++++++++++++++++++++ include/wmcodecdsp.idl | 15 +++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index ca26cc881e7..34815f54d9f 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -411,6 +411,39 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(resampler_types), resampler_types, }, + { + CLSID_CFrameRateConvertDmo, + MFT_CATEGORY_VIDEO_EFFECT, + L"Frame Rate Converter", + MFT_ENUM_FLAG_SYNCMFT, + /* FIXME: check the actual media types */ + ARRAY_SIZE(color_convert_input_types), + color_convert_input_types, + ARRAY_SIZE(color_convert_output_types), + color_convert_output_types, + }, + { + CLSID_CResizerDMO, + MFT_CATEGORY_VIDEO_EFFECT, + L"Resizer MFT", + MFT_ENUM_FLAG_SYNCMFT, + /* FIXME: check the actual media types */ + ARRAY_SIZE(color_convert_input_types), + color_convert_input_types, + ARRAY_SIZE(color_convert_output_types), + color_convert_output_types, + }, + { + CLSID_CColorControlDmo, + MFT_CATEGORY_VIDEO_EFFECT, + L"Color Control", + MFT_ENUM_FLAG_SYNCMFT, + /* FIXME: check the actual media types */ + ARRAY_SIZE(color_convert_input_types), + color_convert_input_types, + ARRAY_SIZE(color_convert_output_types), + color_convert_output_types, + }, { CLSID_CColorConvertDMO, MFT_CATEGORY_VIDEO_EFFECT, diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl index a6f350ea2fc..7e91015f19e 100644 --- a/include/wmcodecdsp.idl +++ b/include/wmcodecdsp.idl @@ -72,6 +72,21 @@ coclass CWMAEncMediaObject {} ] coclass AACMFTEncoder {} +[ + uuid(01f36ce2-0907-4d8b-979d-f151be91c883) +] +coclass CFrameRateConvertDmo {} + +[ + uuid(1ea1ea14-48f4-4054-ad1a-e8aee10ac805) +] +coclass CResizerDMO {} + +[ + uuid(798059f0-89ca-4160-b325-aeb48efe4f9a) +] +coclass CColorControlDmo {} + [ uuid(98230571-0087-4204-b020-3282538e57d3) ] From 88318716cea9ac9bee723514e7b44893209fbb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Dec 2023 11:49:49 +0100 Subject: [PATCH 222/301] HACK: winegstreamer: Register the video processor MFT as a decoder. CW-Bug-Id: #20427 CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 34815f54d9f..5b5502a0487 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -454,6 +454,19 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(color_convert_output_types), color_convert_output_types, }, + { + /* HACK: Register the video processor as a decoder too as + * the media source currently always decodes. + */ + CLSID_VideoProcessorMFT, + MFT_CATEGORY_VIDEO_DECODER, + L"Null Decoder", + MFT_ENUM_FLAG_SYNCMFT, + ARRAY_SIZE(video_processor_input_types), + video_processor_input_types, + ARRAY_SIZE(video_processor_output_types), + video_processor_output_types, + }, }; unsigned int i; From dcad9ad38eb2c7942f396348346814ff0d519620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Nov 2023 14:11:01 +0100 Subject: [PATCH 223/301] HACK: winegstreamer/wmv_decoder: Implement WMVDecMediaObject pass-through DMO. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 31 ------------------------------ 1 file changed, 31 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index d70eed6336b..48ac7e05cb1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1140,7 +1140,6 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { struct video_decoder *decoder = impl_from_IMediaObject(iface); IMFMediaType *media_type; - unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -1166,12 +1165,6 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) return DMO_E_TYPE_NOT_ACCEPTED; - for (i = 0; i < decoder->input_type_count; ++i) - if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->input_types[i]))) - break; - if (i == decoder->input_type_count) - return DMO_E_TYPE_NOT_ACCEPTED; - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void *)type, &media_type))) return DMO_E_TYPE_NOT_ACCEPTED; @@ -1728,35 +1721,11 @@ static const GUID *const wmv_decoder_output_types[] = HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format input_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO_WMV, - .u.video.format = WG_VIDEO_FORMAT_WMV3, - }; - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, - }; - struct wg_transform_attrs attrs = {0}; struct video_decoder *decoder; - wg_transform_t transform; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - if (FAILED(hr = video_decoder_create_with_types(wmv_decoder_input_types, ARRAY_SIZE(wmv_decoder_input_types), wmv_decoder_output_types, ARRAY_SIZE(wmv_decoder_output_types), outer, &decoder))) return hr; From 95e364b947681203636db2a36f4e37ab75aa8ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Nov 2023 18:42:14 +0100 Subject: [PATCH 224/301] HACK: winegstreamer/wma_decoder: Support XMAudio2 input format in WMA decoder. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 CW-Bug-Id: #16839 CW-Bug-Id: #18678 CW-Bug-Id: #19362 Wine-Staging: mfplat-streaming-support CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 11 ++++++++++- dlls/winegstreamer/quartz_parser.c | 14 ++++++++++++-- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_format.c | 18 ++++++++++++++---- dlls/winegstreamer/wma_decoder.c | 3 +++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 5b5502a0487..7c4823b8336 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -42,6 +42,7 @@ DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x2 DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); +DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); @@ -855,6 +856,7 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID { UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; BYTE codec_data[64]; + bool is_xma = false; UINT32 version; if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) @@ -896,6 +898,11 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID version = 3; else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) version = 4; + else if (IsEqualGUID(subtype, &MFAudioFormat_XMAudio2)) + { + version = 2; + is_xma = true; + } else { assert(0); @@ -911,6 +918,7 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID format->u.audio.block_align = block_align; format->u.audio.codec_data_len = codec_data_len; memcpy(format->u.audio.codec_data, codec_data, codec_data_len); + format->u.audio.is_xma = is_xma; } static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_format *format) @@ -1067,7 +1075,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) else if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || - IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) + IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless) || + IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) mf_media_type_to_wg_format_audio_mpeg4(type, &subtype, format); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 0e387353743..5d34ea2b74a 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -41,6 +41,7 @@ static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; DEFINE_GUID(MEDIASUBTYPE_ABGR32,D3DFMT_A8B8G8R8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +static const GUID MEDIASUBTYPE_XMAUDIO2 = {0x0166, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; struct parser { @@ -301,6 +302,11 @@ static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_form subtype = &MEDIASUBTYPE_WMAUDIO2; codec_data_len = WMAUDIO2_WFX_EXTRA_BYTES; fmt_tag = WAVE_FORMAT_WMAUDIO2; + if (format->u.audio.is_xma) + { + subtype = &MEDIASUBTYPE_XMAUDIO2; + fmt_tag = 0x0166; + } break; case 3: subtype = &MEDIASUBTYPE_WMAUDIO3; @@ -870,7 +876,8 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct return true; } -static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format) +static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format, + bool is_xma) { const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; @@ -896,6 +903,7 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format else assert(false); format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio.is_xma = is_xma; format->u.audio.bitrate = audio_format->nAvgBytesPerSec * 8; format->u.audio.rate = audio_format->nSamplesPerSec; format->u.audio.depth = audio_format->wBitsPerSample; @@ -1075,7 +1083,9 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) - return amt_to_wg_format_audio_wma(mt, format); + return amt_to_wg_format_audio_wma(mt, format, false); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_XMAUDIO2)) + return amt_to_wg_format_audio_wma(mt, format, true); return amt_to_wg_format_audio(mt, format); } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 547c3414d21..2f0a7c08666 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -144,6 +144,7 @@ struct wg_format uint32_t payload_type; uint32_t codec_data_len; unsigned char codec_data[64]; + UINT8 is_xma; } audio; /* Valid members for different video formats: diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 47571422065..f08c9e35a2f 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -643,10 +643,20 @@ static GstCaps *wg_format_to_caps_audio_wma(const struct wg_format *format) GstBuffer *buffer; GstCaps *caps; - if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) - return NULL; - if (format->u.audio.version) - gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); + if (format->u.audio.is_xma) + { + if (!(caps = gst_caps_new_empty_simple("audio/x-xma"))) + return NULL; + if (format->u.audio.version) + gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.audio.version, NULL); + } + else + { + if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) + return NULL; + if (format->u.audio.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio.version, NULL); + } if (format->u.audio.bitrate) gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio.bitrate, NULL); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index de1bedb1d38..234596e6389 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -32,12 +32,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(wmadec); WINE_DECLARE_DEBUG_CHANNEL(winediag); +extern const GUID MFAudioFormat_XMAudio2; + static const GUID *const wma_decoder_input_types[] = { &MEDIASUBTYPE_MSAUDIO1, &MFAudioFormat_WMAudioV8, &MFAudioFormat_WMAudioV9, &MFAudioFormat_WMAudio_Lossless, + &MFAudioFormat_XMAudio2, }; static const GUID *const wma_decoder_output_types[] = { From b6ad9211791208e7c5c62c7f66a270d6eaf79445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Aug 2022 10:50:35 +0200 Subject: [PATCH 225/301] HACK: winegstreamer/wma_decoder: Allow WMA decoder DMO to pass-through buffers. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 CW-Bug-Id: #20833 --- dlls/winegstreamer/wma_decoder.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 234596e6389..98587bb224d 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -30,7 +30,6 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wmadec); -WINE_DECLARE_DEBUG_CHANNEL(winediag); extern const GUID MFAudioFormat_XMAudio2; @@ -723,7 +722,6 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index const DMO_MEDIA_TYPE *type, DWORD flags) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); - unsigned int i; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -751,12 +749,6 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) return DMO_E_TYPE_NOT_ACCEPTED; - for (i = 0; i < ARRAY_SIZE(wma_decoder_input_types); ++i) - if (IsEqualGUID(&type->subtype, wma_decoder_input_types[i])) - break; - if (i == ARRAY_SIZE(wma_decoder_input_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; @@ -1065,32 +1057,11 @@ static const IPropertyBagVtbl property_bag_vtbl = HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) { - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_AUDIO, - .u.audio = - { - .format = WG_AUDIO_FORMAT_F32LE, - .channel_mask = 1, - .channels = 1, - .rate = 44100, - }, - }; - static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_WMA}; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; struct wma_decoder *decoder; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; From 56a8cb9e345300883453177ebae20774f6a91b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 4 May 2024 09:57:02 +0200 Subject: [PATCH 226/301] winegstreamer: Translate unknown GstCaps to generic MFVIDEOFORMAT / WAVEFORMATEX. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_media_type.c | 55 +++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 14fc1a9cdf4..71191bb448f 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -56,9 +56,11 @@ static const GUID GUID_NULL; +DEFINE_MEDIATYPE_GUID(MFAudioFormat_GStreamer,MAKEFOURCC('G','S','T','a')); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFAudioFormat_MSAudio1,WAVE_FORMAT_MSAUDIO1); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_GStreamer,MAKEFOURCC('G','S','T','v')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_CVID,MAKEFOURCC('c','v','i','d')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); @@ -210,6 +212,9 @@ static GstCaps *caps_from_wave_format_ex(const WAVEFORMATEX *format, UINT32 form GstAudioFormat audio_format = wave_format_tag_to_gst_audio_format(subtype->Data1, format->wBitsPerSample); GstCaps *caps; + if (IsEqualGUID(subtype, &MFAudioFormat_GStreamer)) + return gst_caps_from_string((char *)(format + 1)); + if (!(caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gst_audio_format_to_string(audio_format), "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, format->nSamplesPerSec, "channels", G_TYPE_INT, format->nChannels, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL))) @@ -393,6 +398,9 @@ static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 forma WG_RATIO_ARGS(format->videoInfo.PixelAspectRatio), (int)format->videoInfo.VideoFlags ); if (format->dwSize > sizeof(*format)) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->dwSize - sizeof(*format)); + if (IsEqualGUID(&format->guidFormat, &MFVideoFormat_GStreamer)) + return gst_caps_from_string((char *)(format + 1)); + if (!(caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, gst_video_format_to_string(video_format), NULL))) return NULL; @@ -625,6 +633,27 @@ static NTSTATUS wma_wave_format_from_gst_caps(const GstCaps *caps, WAVEFORMATEX return STATUS_NOT_IMPLEMENTED; } +static NTSTATUS other_wave_format_from_gst_caps(const GstCaps *caps, WAVEFORMATEXTENSIBLE *format, + UINT32 *format_size) +{ + gchar *str = gst_caps_to_string(caps); + UINT32 capacity = *format_size, codec_data_size = strlen(str) + 1; + + *format_size = sizeof(*format) + codec_data_size; + if (*format_size > capacity) + { + g_free(str); + return STATUS_BUFFER_TOO_SMALL; + } + + init_wave_format_ex_from_gst_caps(caps, WAVE_FORMAT_EXTENSIBLE, 0, &format->Format, *format_size); + format->SubFormat = MFAudioFormat_GStreamer; + memcpy(format + 1, str, codec_data_size); + g_free(str); + + return STATUS_SUCCESS; +} + static GUID subtype_from_gst_video_format(GstVideoFormat video_format) { switch (video_format) @@ -642,6 +671,7 @@ static GUID subtype_from_gst_video_format(GstVideoFormat video_format) case GST_VIDEO_FORMAT_YUY2: return MFVideoFormat_YUY2; case GST_VIDEO_FORMAT_YV12: return MFVideoFormat_YV12; case GST_VIDEO_FORMAT_YVYU: return MFVideoFormat_YVYU; + case GST_VIDEO_FORMAT_ENCODED: return MFVideoFormat_GStreamer; default: return GUID_NULL; } } @@ -778,6 +808,23 @@ static NTSTATUS mpeg_video_format_from_gst_caps(const GstCaps *caps, struct mpeg return STATUS_SUCCESS; } +static NTSTATUS other_video_format_from_gst_caps(const GstCaps *caps, MFVIDEOFORMAT *format, UINT32 *format_size, + UINT32 video_plane_align) +{ + gchar *str = gst_caps_to_string(caps); + GstCaps *copy = gst_caps_copy(caps); + gsize len = strlen(str) + 1; + GstBuffer *buffer; + + if (!(buffer = gst_buffer_new_and_alloc(len))) + return STATUS_NO_MEMORY; + gst_buffer_fill(buffer, 0, str, len); + gst_caps_set_simple(copy, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + + return video_format_from_gst_caps(copy, &MFVideoFormat_GStreamer, format, format_size, video_plane_align); +} + NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UINT32 video_plane_align) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -797,8 +844,8 @@ NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UIN if (!strcmp(name, "audio/x-wma")) return wma_wave_format_from_gst_caps(caps, media_type->u.audio, &media_type->format_size); - GST_FIXME("Unhandled caps %" GST_PTR_FORMAT ".", caps); - return STATUS_UNSUCCESSFUL; + GST_FIXME("Using fallback for unknown audio caps %" GST_PTR_FORMAT ".", caps); + return other_wave_format_from_gst_caps(caps, media_type->u.format, &media_type->format_size); } else if (g_str_has_prefix(name, "video/")) { @@ -813,8 +860,8 @@ NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UIN if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) return mpeg_video_format_from_gst_caps(caps, media_type->u.format, &media_type->format_size, video_plane_align); - GST_FIXME("Unhandled caps %" GST_PTR_FORMAT ".", caps); - return STATUS_UNSUCCESSFUL; + GST_FIXME("Using fallback for unknown video caps %" GST_PTR_FORMAT ".", caps); + return other_video_format_from_gst_caps(caps, media_type->u.video, &media_type->format_size, video_plane_align); } else { From 231f861f0b94d01c01c8aeeafcfccbbaac135cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Jul 2024 09:21:27 +0200 Subject: [PATCH 227/301] winegstreamer: Only use pool and set buffer meta for raw video frames. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index faef62d1c8b..ff85db18cce 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -131,6 +131,7 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, gsize plane_align = transform->attrs.output_plane_align; GstStructure *config, *params; GstVideoAlignment align; + const char *mime_type; gboolean needs_pool; GstBufferPool *pool; GstVideoInfo info; @@ -139,7 +140,9 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, GST_LOG("transform %p, %"GST_PTR_FORMAT, transform, query); gst_query_parse_allocation(query, &caps, &needs_pool); - if (stream_type_from_caps(caps) != GST_STREAM_TYPE_VIDEO || !needs_pool) + + mime_type = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + if (strcmp(mime_type, "video/x-raw") || !needs_pool) return false; if (!gst_video_info_from_caps(&info, caps) @@ -917,6 +920,7 @@ NTSTATUS wg_transform_read_data(void *args) struct wg_sample *sample = params->sample; GstVideoAlignment align = {0}; GstBuffer *output_buffer; + const char *output_mime; GstCaps *output_caps; bool discard_data; NTSTATUS status; @@ -932,8 +936,9 @@ NTSTATUS wg_transform_read_data(void *args) output_buffer = gst_sample_get_buffer(transform->output_sample); output_caps = gst_sample_get_caps(transform->output_sample); + output_mime = gst_structure_get_name(gst_caps_get_structure(output_caps, 0)); - if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO) + if (!strcmp(output_mime, "video/x-raw")) { gsize plane_align = transform->attrs.output_plane_align; @@ -954,7 +959,7 @@ NTSTATUS wg_transform_read_data(void *args) return STATUS_SUCCESS; } - if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO) + if (!strcmp(output_mime, "video/x-raw")) status = read_transform_output_video(sample, output_buffer, &src_video_info, &dst_video_info); else From dc4628ad9ac0b53cd8a5180b06a3f0a51db7d215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Jul 2024 09:21:55 +0200 Subject: [PATCH 228/301] winegstreamer: Use a new wg_video_buffer_pool class to add buffer meta. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 84 +++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index ff85db18cce..03d72c6f0b6 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -82,6 +82,57 @@ static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVi gst_video_info_align(info, align); } +typedef struct +{ + GstVideoBufferPool parent; + GstVideoInfo info; +} WgVideoBufferPool; + +typedef struct +{ + GstVideoBufferPoolClass parent_class; +} WgVideoBufferPoolClass; + +G_DEFINE_TYPE(WgVideoBufferPool, wg_video_buffer_pool, GST_TYPE_VIDEO_BUFFER_POOL); + +static void wg_video_buffer_pool_init(WgVideoBufferPool *pool) +{ +} + +static void wg_video_buffer_pool_class_init(WgVideoBufferPoolClass *klass) +{ +} + +static WgVideoBufferPool *wg_video_buffer_pool_create(GstCaps *caps, gsize plane_align, + GstAllocator *allocator, GstVideoAlignment *align) +{ + WgVideoBufferPool *pool; + GstStructure *config; + + if (!(pool = g_object_new(wg_video_buffer_pool_get_type(), NULL))) + return NULL; + + gst_video_info_from_caps(&pool->info, caps); + align_video_info_planes(plane_align, &pool->info, align); + + if (!(config = gst_buffer_pool_get_config(GST_BUFFER_POOL(pool)))) + GST_ERROR("Failed to get %"GST_PTR_FORMAT" config.", pool); + else + { + gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META); + gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); + gst_buffer_pool_config_set_video_alignment(config, align); + + gst_buffer_pool_config_set_params(config, caps, pool->info.size, 0, 0); + gst_buffer_pool_config_set_allocator(config, allocator, NULL); + if (!gst_buffer_pool_set_config(GST_BUFFER_POOL(pool), config)) + GST_ERROR("Failed to set %"GST_PTR_FORMAT" config.", pool); + } + + GST_INFO("Created %"GST_PTR_FORMAT, pool); + return pool; +} + static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_transform *transform = gst_pad_get_element_private(pad); @@ -128,13 +179,11 @@ static gboolean transform_src_query_cb(GstPad *pad, GstObject *parent, GstQuery static gboolean transform_sink_query_allocation(struct wg_transform *transform, GstQuery *query) { - gsize plane_align = transform->attrs.output_plane_align; - GstStructure *config, *params; + WgVideoBufferPool *pool; GstVideoAlignment align; const char *mime_type; + GstStructure *params; gboolean needs_pool; - GstBufferPool *pool; - GstVideoInfo info; GstCaps *caps; GST_LOG("transform %p, %"GST_PTR_FORMAT, transform, query); @@ -145,12 +194,10 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, if (strcmp(mime_type, "video/x-raw") || !needs_pool) return false; - if (!gst_video_info_from_caps(&info, caps) - || !(pool = gst_video_buffer_pool_new())) + if (!(pool = wg_video_buffer_pool_create(caps, transform->attrs.output_plane_align, + transform->allocator, &align))) return false; - align_video_info_planes(plane_align, &info, &align); - if ((params = gst_structure_new("video-meta", "padding-top", G_TYPE_UINT, align.padding_top, "padding-bottom", G_TYPE_UINT, align.padding_bottom, @@ -162,30 +209,15 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, gst_structure_free(params); } - if (!(config = gst_buffer_pool_get_config(pool))) - GST_ERROR("Failed to get %"GST_PTR_FORMAT" config.", pool); - else - { - gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META); - gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); - gst_buffer_pool_config_set_video_alignment(config, &align); - - gst_buffer_pool_config_set_params(config, caps, - info.size, 0, 0); - gst_buffer_pool_config_set_allocator(config, transform->allocator, NULL); - if (!gst_buffer_pool_set_config(pool, config)) - GST_ERROR("Failed to set %"GST_PTR_FORMAT" config.", pool); - } - /* Prevent pool reconfiguration, we don't want another alignment. */ - if (!gst_buffer_pool_set_active(pool, true)) + if (!gst_buffer_pool_set_active(GST_BUFFER_POOL(pool), true)) GST_ERROR("%"GST_PTR_FORMAT" failed to activate.", pool); - gst_query_add_allocation_pool(query, pool, info.size, 0, 0); + gst_query_add_allocation_pool(query, GST_BUFFER_POOL(pool), pool->info.size, 0, 0); gst_query_add_allocation_param(query, transform->allocator, NULL); GST_INFO("Proposing %"GST_PTR_FORMAT", buffer size %#zx, %"GST_PTR_FORMAT", for %"GST_PTR_FORMAT, - pool, info.size, transform->allocator, query); + pool, pool->info.size, transform->allocator, query); g_object_unref(pool); return true; From faf157ef8eaa94abc004add1c79987ce4c1cce94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 18:20:48 +0100 Subject: [PATCH 229/301] winegstreamer: Keep the input caps on the transform. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 39 ++++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 03d72c6f0b6..6a46011d6a3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -61,6 +61,7 @@ struct wg_transform bool output_caps_changed; GstCaps *desired_caps; GstCaps *output_caps; + GstCaps *input_caps; }; static struct wg_transform *get_transform(wg_transform_t trans) @@ -365,6 +366,7 @@ NTSTATUS wg_transform_destroy(void *args) gst_query_unref(transform->drain_query); gst_caps_unref(transform->desired_caps); gst_caps_unref(transform->output_caps); + gst_caps_unref(transform->input_caps); gst_atomic_queue_unref(transform->output_queue); free(transform); @@ -405,7 +407,7 @@ NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; GstElement *first = NULL, *last = NULL, *element; - GstCaps *sink_caps = NULL, *src_caps = NULL, *parsed_caps = NULL; + GstCaps *sink_caps = NULL, *parsed_caps = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; const gchar *input_mime, *output_mime; GstPadTemplate *template = NULL; @@ -427,27 +429,31 @@ NTSTATUS wg_transform_create(void *args) goto out; transform->attrs = params->attrs; + if (!(transform->input_caps = caps_from_media_type(¶ms->input_type))) + goto out; + GST_INFO("transform %p input caps %"GST_PTR_FORMAT, transform, transform->input_caps); + input_mime = gst_structure_get_name(gst_caps_get_structure(transform->input_caps, 0)); + + if (!(transform->output_caps = caps_from_media_type(¶ms->output_type))) + goto out; + GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, transform->output_caps); + output_mime = gst_structure_get_name(gst_caps_get_structure(transform->output_caps, 0)); + if (IsEqualGUID(¶ms->input_type.major, &MFMediaType_Video)) transform->input_info = params->input_type.u.video->videoInfo; if (IsEqualGUID(¶ms->output_type.major, &MFMediaType_Video)) output_info = params->output_type.u.video->videoInfo; - if (!(src_caps = caps_from_media_type(¶ms->input_type))) - goto out; - if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) + if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, transform->input_caps))) goto out; transform->my_src = gst_pad_new_from_template(template, "src"); g_object_unref(template); if (!transform->my_src) goto out; - GST_INFO("transform %p input caps %"GST_PTR_FORMAT, transform, src_caps); - gst_pad_set_element_private(transform->my_src, transform); gst_pad_set_query_function(transform->my_src, transform_src_query_cb); - if (!(transform->output_caps = caps_from_media_type(¶ms->output_type))) - goto out; transform->desired_caps = gst_caps_ref(transform->output_caps); if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, transform->output_caps))) goto out; @@ -456,34 +462,30 @@ NTSTATUS wg_transform_create(void *args) if (!transform->my_sink) goto out; - GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, transform->output_caps); - gst_pad_set_element_private(transform->my_sink, transform); gst_pad_set_event_function(transform->my_sink, transform_sink_event_cb); gst_pad_set_query_function(transform->my_sink, transform_sink_query_cb); gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - input_mime = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); - if (!(parsed_caps = transform_get_parsed_caps(src_caps, input_mime))) + if (!(parsed_caps = transform_get_parsed_caps(transform->input_caps, input_mime))) goto out; /* Since we append conversion elements, we don't want to filter decoders * based on the actual output caps now. Matching decoders with the * raw output media type should be enough. */ - output_mime = gst_structure_get_name(gst_caps_get_structure(transform->output_caps, 0)); if (!(sink_caps = gst_caps_new_empty_simple(output_mime))) goto out; if (strcmp(input_mime, "audio/x-raw") && strcmp(input_mime, "video/x-raw")) { - if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, src_caps, parsed_caps)) + if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, transform->input_caps, parsed_caps)) && !append_element(transform->container, element, &first, &last)) goto out; else if (!element) { gst_caps_unref(parsed_caps); - parsed_caps = gst_caps_ref(src_caps); + parsed_caps = gst_caps_ref(transform->input_caps); } if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, parsed_caps, sink_caps)) @@ -565,7 +567,7 @@ NTSTATUS wg_transform_create(void *args) if (!(event = gst_event_new_stream_start("stream")) || !push_event(transform->my_src, event)) goto out; - if (!(event = gst_event_new_caps(src_caps)) + if (!(event = gst_event_new_caps(transform->input_caps)) || !push_event(transform->my_src, event)) goto out; @@ -579,7 +581,6 @@ NTSTATUS wg_transform_create(void *args) goto out; gst_caps_unref(parsed_caps); - gst_caps_unref(src_caps); gst_caps_unref(sink_caps); GST_INFO("Created winegstreamer transform %p.", transform); @@ -595,8 +596,8 @@ NTSTATUS wg_transform_create(void *args) gst_caps_unref(transform->output_caps); if (transform->my_src) gst_object_unref(transform->my_src); - if (src_caps) - gst_caps_unref(src_caps); + if (transform->input_caps) + gst_caps_unref(transform->input_caps); if (parsed_caps) gst_caps_unref(parsed_caps); if (sink_caps) From 03a5266a2bc5c2fe679055b09ea51b005c85621f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 18:20:48 +0100 Subject: [PATCH 230/301] winegstreamer: Use video info stride in buffer meta rather than videoflip. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 108 +++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 6a46011d6a3..6c7d09279d8 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -53,8 +53,8 @@ struct wg_transform GstQuery *drain_query; GstAtomicQueue *input_queue; - GstElement *video_flip; MFVideoInfo input_info; + MFVideoInfo output_info; GstAtomicQueue *output_queue; GstSample *output_sample; @@ -69,7 +69,8 @@ static struct wg_transform *get_transform(wg_transform_t trans) return (struct wg_transform *)(ULONG_PTR)trans; } -static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align) +static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, + GstVideoInfo *info, GstVideoAlignment *align) { gst_video_alignment_reset(align); @@ -81,6 +82,15 @@ static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVi align->stride_align[3] = plane_align; gst_video_info_align(info, align); + + if (video_info->VideoFlags & MFVideoFlag_BottomUpLinearRep) + { + for (guint i = 0; i < ARRAY_SIZE(info->offset); ++i) + { + info->offset[i] += (info->height - 1) * info->stride[i]; + info->stride[i] = -info->stride[i]; + } + } } typedef struct @@ -96,16 +106,53 @@ typedef struct G_DEFINE_TYPE(WgVideoBufferPool, wg_video_buffer_pool, GST_TYPE_VIDEO_BUFFER_POOL); +static void buffer_add_video_meta(GstBuffer *buffer, GstVideoInfo *info) +{ + GstVideoMeta *meta; + + if (!(meta = gst_buffer_get_video_meta(buffer))) + meta = gst_buffer_add_video_meta(buffer, GST_VIDEO_FRAME_FLAG_NONE, + info->finfo->format, info->width, info->height); + + if (!meta) + GST_ERROR("Failed to add video meta to buffer %"GST_PTR_FORMAT, buffer); + else + { + memcpy(meta->offset, info->offset, sizeof(info->offset)); + memcpy(meta->stride, info->stride, sizeof(info->stride)); + } +} + +static GstFlowReturn wg_video_buffer_pool_alloc_buffer(GstBufferPool *gst_pool, GstBuffer **buffer, + GstBufferPoolAcquireParams *params) +{ + GstBufferPoolClass *parent_class = GST_BUFFER_POOL_CLASS(wg_video_buffer_pool_parent_class); + WgVideoBufferPool *pool = (WgVideoBufferPool *)gst_pool; + GstFlowReturn ret; + + GST_LOG("%"GST_PTR_FORMAT", buffer %p, params %p", pool, buffer, params); + + if (!(ret = parent_class->alloc_buffer(gst_pool, buffer, params))) + { + buffer_add_video_meta(*buffer, &pool->info); + GST_INFO("%"GST_PTR_FORMAT" allocated buffer %"GST_PTR_FORMAT, pool, *buffer); + } + + return ret; +} + static void wg_video_buffer_pool_init(WgVideoBufferPool *pool) { } static void wg_video_buffer_pool_class_init(WgVideoBufferPoolClass *klass) { + GstBufferPoolClass *pool_class = GST_BUFFER_POOL_CLASS(klass); + pool_class->alloc_buffer = wg_video_buffer_pool_alloc_buffer; } static WgVideoBufferPool *wg_video_buffer_pool_create(GstCaps *caps, gsize plane_align, - GstAllocator *allocator, GstVideoAlignment *align) + GstAllocator *allocator, MFVideoInfo *video_info, GstVideoAlignment *align) { WgVideoBufferPool *pool; GstStructure *config; @@ -114,7 +161,7 @@ static WgVideoBufferPool *wg_video_buffer_pool_create(GstCaps *caps, gsize plane return NULL; gst_video_info_from_caps(&pool->info, caps); - align_video_info_planes(plane_align, &pool->info, align); + align_video_info_planes(video_info, plane_align, &pool->info, align); if (!(config = gst_buffer_pool_get_config(GST_BUFFER_POOL(pool)))) GST_ERROR("Failed to get %"GST_PTR_FORMAT" config.", pool); @@ -196,7 +243,7 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, return false; if (!(pool = wg_video_buffer_pool_create(caps, transform->attrs.output_plane_align, - transform->allocator, &align))) + transform->allocator, &transform->output_info, &align))) return false; if ((params = gst_structure_new("video-meta", @@ -412,7 +459,6 @@ NTSTATUS wg_transform_create(void *args) const gchar *input_mime, *output_mime; GstPadTemplate *template = NULL; struct wg_transform *transform; - MFVideoInfo output_info = {0}; GstEvent *event; if (!(transform = calloc(1, sizeof(*transform)))) @@ -442,7 +488,7 @@ NTSTATUS wg_transform_create(void *args) if (IsEqualGUID(¶ms->input_type.major, &MFMediaType_Video)) transform->input_info = params->input_type.u.video->videoInfo; if (IsEqualGUID(¶ms->output_type.major, &MFMediaType_Video)) - output_info = params->output_type.u.video->videoInfo; + transform->output_info = params->output_type.u.video->videoInfo; if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, transform->input_caps))) goto out; @@ -534,15 +580,6 @@ NTSTATUS wg_transform_create(void *args) } else { - if (!(element = create_element("videoconvert", "base")) - || !append_element(transform->container, element, &first, &last)) - goto out; - if (!(transform->video_flip = create_element("videoflip", "base")) - || !append_element(transform->container, transform->video_flip, &first, &last)) - goto out; - - if ((transform->input_info.VideoFlags ^ output_info.VideoFlags) & MFVideoFlag_BottomUpLinearRep) - gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", "vertical-flip"); if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; @@ -640,19 +677,18 @@ NTSTATUS wg_transform_set_output_type(void *args) { struct wg_transform_set_output_type_params *params = args; struct wg_transform *transform = get_transform(params->transform); - MFVideoInfo output_info = {0}; GstCaps *caps, *stripped; GstSample *sample; - if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) - output_info = params->media_type.u.video->videoInfo; - if (!(caps = caps_from_media_type(¶ms->media_type))) { GST_ERROR("Failed to convert media type to caps."); return STATUS_UNSUCCESSFUL; } + if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) + transform->output_info = params->media_type.u.video->videoInfo; + GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, caps); stripped = caps_strip_fields(caps, transform->attrs.allow_format_change); @@ -673,16 +709,6 @@ NTSTATUS wg_transform_set_output_type(void *args) gst_caps_unref(transform->desired_caps); transform->desired_caps = caps; - if (transform->video_flip) - { - const char *value; - - if ((transform->input_info.VideoFlags ^ output_info.VideoFlags) & MFVideoFlag_BottomUpLinearRep) - value = "vertical-flip"; - else - value = "none"; - gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", value); - } if (!push_event(transform->my_sink, gst_event_new_reconfigure())) { GST_ERROR("Failed to reconfigure transform %p.", transform); @@ -716,6 +742,8 @@ NTSTATUS wg_transform_push_data(void *args) struct wg_transform_push_data_params *params = args; struct wg_transform *transform = get_transform(params->transform); struct wg_sample *sample = params->sample; + const gchar *input_mime; + GstVideoInfo video_info; GstBuffer *buffer; guint length; @@ -739,6 +767,14 @@ NTSTATUS wg_transform_push_data(void *args) GST_INFO("Wrapped %u/%u bytes from sample %p to %"GST_PTR_FORMAT, sample->size, sample->max_size, sample, buffer); } + input_mime = gst_structure_get_name(gst_caps_get_structure(transform->input_caps, 0)); + if (!strcmp(input_mime, "video/x-raw") && gst_video_info_from_caps(&video_info, transform->input_caps)) + { + GstVideoAlignment align; + align_video_info_planes(&transform->input_info, 0, &video_info, &align); + buffer_add_video_meta(buffer, &video_info); + } + if (sample->flags & WG_SAMPLE_FLAG_HAS_PTS) GST_BUFFER_PTS(buffer) = sample->pts * 100; if (sample->flags & WG_SAMPLE_FLAG_HAS_DURATION) @@ -974,13 +1010,21 @@ NTSTATUS wg_transform_read_data(void *args) if (!strcmp(output_mime, "video/x-raw")) { gsize plane_align = transform->attrs.output_plane_align; + GstVideoMeta *meta; if (!gst_video_info_from_caps(&src_video_info, output_caps)) GST_ERROR("Failed to get video info from %"GST_PTR_FORMAT, output_caps); dst_video_info = src_video_info; - /* set the desired output buffer alignment on the dest video info */ - align_video_info_planes(plane_align, &dst_video_info, &align); + /* set the desired output buffer alignment and stride on the dest video info */ + align_video_info_planes(&transform->output_info, plane_align, &dst_video_info, &align); + + /* copy the actual output buffer alignment and stride to the src video info */ + if ((meta = gst_buffer_get_video_meta(output_buffer))) + { + memcpy(src_video_info.offset, meta->offset, sizeof(meta->offset)); + memcpy(src_video_info.stride, meta->stride, sizeof(meta->stride)); + } } if (GST_MINI_OBJECT_FLAG_IS_SET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED)) From 974a73041a6170088ec340b3ab9c7a2ccb5cc7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Jul 2024 09:25:33 +0200 Subject: [PATCH 231/301] winegstreamer: Respect video format padding for input buffers too. CW-Bug-Id: #20833 --- dlls/mf/tests/transform.c | 54 +++++++---------- dlls/winegstreamer/wg_media_type.c | 11 ++++ dlls/winegstreamer/wg_transform.c | 93 ++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 34 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 06a106ff734..3f9541af667 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7608,7 +7608,7 @@ static void test_video_processor(void) { .input_type_desc = nv12_with_aperture, .input_bitmap = L"nv12frame.bmp", .output_type_desc = rgb32_no_aperture, .output_bitmap = L"rgb32frame-crop-flip.bmp", - .output_sample_desc = &rgb32_crop_sample_desc, + .output_sample_desc = &rgb32_crop_sample_desc, .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { .input_type_desc = rgb32_no_aperture, .input_bitmap = L"rgb32frame-crop-flip.bmp", @@ -7964,23 +7964,6 @@ static void test_video_processor(void) check_mft_set_input_type(transform, test->input_type_desc); check_mft_get_input_current_type(transform, test->input_type_desc); - if (i >= 15) - { - IMFMediaType *media_type; - HRESULT hr; - - hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr); - init_media_type(media_type, test->output_type_desc, -1); - hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); - todo_wine - ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); - IMFMediaType_Release(media_type); - - if (hr != S_OK) - goto skip_test; - } - check_mft_set_output_type_required(transform, test->output_type_desc); check_mft_set_output_type(transform, test->output_type_desc, S_OK); check_mft_get_output_current_type(transform, test->output_type_desc); @@ -8092,7 +8075,6 @@ static void test_video_processor(void) ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); -skip_test: winetest_pop_context(); hr = IMFTransform_SetInputType(transform, 0, NULL, 0); @@ -8117,8 +8099,8 @@ static void test_video_processor(void) check_mft_set_output_type(transform, rgb32_no_aperture, S_OK); check_mft_get_output_current_type(transform, rgb32_no_aperture); - check_mft_set_input_type_(__LINE__, transform, nv12_with_aperture, TRUE); - check_mft_get_input_current_type_(__LINE__, transform, nv12_with_aperture, TRUE, FALSE); + check_mft_set_input_type(transform, nv12_with_aperture, S_OK); + check_mft_get_input_current_type(transform, nv12_with_aperture); /* output type is the same as before */ check_mft_get_output_current_type(transform, rgb32_no_aperture); @@ -8783,7 +8765,13 @@ static void test_h264_with_dxgi_manager(void) status = 0; hr = get_next_h264_output_sample(transform, &input_sample, NULL, output, &data, &data_len); + todo_wine_if(hr == MF_E_UNEXPECTED) /* with some llvmpipe versions */ ok(hr == S_OK, "got %#lx\n", hr); + if (hr == MF_E_UNEXPECTED) + { + IMFSample_Release(input_sample); + goto failed; + } ok(sample != output[0].pSample, "got %p.\n", output[0].pSample); sample = output[0].pSample; @@ -9427,8 +9415,8 @@ static void test_video_processor_with_dxgi_manager(void) /* check RGB32 output aperture cropping with D3D buffers */ - check_mft_set_input_type(transform, nv12_with_aperture); - check_mft_set_output_type_(__LINE__, transform, rgb32_no_aperture, S_OK, TRUE); + check_mft_set_input_type(transform, nv12_with_aperture, S_OK); + check_mft_set_output_type(transform, rgb32_no_aperture, S_OK); load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ @@ -9440,7 +9428,7 @@ static void test_video_processor_with_dxgi_manager(void) input_sample = create_d3d_sample(allocator, nv12frame_data, nv12frame_data_len); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); ok(hr == S_OK, "got %#lx\n", hr); @@ -9449,9 +9437,9 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); - todo_wine ok(!!output.pSample, "got no sample\n"); + ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); if (!output.pSample) goto skip_rgb32; @@ -9486,7 +9474,6 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample); ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32_crop, L"rgb32frame-crop.bmp"); - todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 5, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); @@ -9495,8 +9482,8 @@ static void test_video_processor_with_dxgi_manager(void) skip_rgb32: /* check ABGR32 output with D3D buffers */ - check_mft_set_input_type(transform, nv12_with_aperture); - check_mft_set_output_type_(__LINE__, transform, abgr32_no_aperture, S_OK, TRUE); + check_mft_set_input_type(transform, nv12_with_aperture, S_OK); + check_mft_set_output_type(transform, abgr32_no_aperture, S_OK); load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ @@ -9508,7 +9495,7 @@ static void test_video_processor_with_dxgi_manager(void) input_sample = create_d3d_sample(allocator, nv12frame_data, nv12frame_data_len); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); ok(hr == S_OK, "got %#lx\n", hr); @@ -9517,9 +9504,9 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); - todo_wine ok(!!output.pSample, "got no sample\n"); + ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); if (!output.pSample) goto skip_abgr32; @@ -9535,7 +9522,7 @@ static void test_video_processor_with_dxgi_manager(void) ID3D11Texture2D_GetDesc(tex2d, &desc); ok(desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "got %#x.\n", desc.Format); ok(!desc.Usage, "got %u.\n", desc.Usage); - ok(desc.BindFlags == D3D11_BIND_RENDER_TARGET, "got %#x.\n", desc.BindFlags); + todo_wine ok(desc.BindFlags == D3D11_BIND_RENDER_TARGET, "got %#x.\n", desc.BindFlags); ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags); ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags); ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels); @@ -9554,7 +9541,6 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample); ret = check_mf_sample_collection(output_samples, &output_sample_desc_abgr32_crop, L"abgr32frame-crop.bmp"); - todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 8 /* NVIDIA needs 5, AMD needs 8 */, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 71191bb448f..1c142745f0e 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -386,6 +386,11 @@ static GstVideoFormat subtype_to_gst_video_format(const GUID *subtype) return GST_VIDEO_FORMAT_ENCODED; } +static BOOL is_mf_video_area_empty(const MFVideoArea *area) +{ + return !area->OffsetX.value && !area->OffsetY.value && !area->Area.cx && !area->Area.cy; +} + static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 format_size) { GstVideoFormat video_format = subtype_to_gst_video_format(&format->guidFormat); @@ -418,6 +423,12 @@ static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 forma format->videoInfo.FramesPerSecond.Numerator, format->videoInfo.FramesPerSecond.Denominator, NULL); + if (!is_mf_video_area_empty(&format->videoInfo.MinimumDisplayAperture)) + { + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->videoInfo.MinimumDisplayAperture.Area.cx, NULL); + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->videoInfo.MinimumDisplayAperture.Area.cy, NULL); + } + if (video_format == GST_VIDEO_FORMAT_ENCODED) init_caps_from_video_subtype(caps, &format->guidFormat, format, format_size); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 6c7d09279d8..772e2912184 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -69,13 +69,35 @@ static struct wg_transform *get_transform(wg_transform_t trans) return (struct wg_transform *)(ULONG_PTR)trans; } +static BOOL is_mf_video_area_empty(const MFVideoArea *area) +{ + return !area->OffsetX.value && !area->OffsetY.value && !area->Area.cx && !area->Area.cy; +} + static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align) { + const MFVideoArea *aperture = &video_info->MinimumDisplayAperture; + gst_video_alignment_reset(align); align->padding_right = ((plane_align + 1) - (info->width & plane_align)) & plane_align; align->padding_bottom = ((plane_align + 1) - (info->height & plane_align)) & plane_align; + if (!is_mf_video_area_empty(aperture)) + { + align->padding_right = max(align->padding_right, video_info->dwWidth - aperture->OffsetX.value - aperture->Area.cx); + align->padding_bottom = max(align->padding_bottom, video_info->dwHeight - aperture->OffsetY.value - aperture->Area.cy); + align->padding_top = aperture->OffsetX.value; + align->padding_left = aperture->OffsetY.value; + } + + if (video_info->VideoFlags & MFVideoFlag_BottomUpLinearRep) + { + gsize top = align->padding_top; + align->padding_top = align->padding_bottom; + align->padding_bottom = top; + } + align->stride_align[0] = plane_align; align->stride_align[1] = plane_align; align->stride_align[2] = plane_align; @@ -93,6 +115,57 @@ static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, } } +static void init_mf_video_info_rect(const MFVideoInfo *info, RECT *rect) +{ + if (!is_mf_video_area_empty(&info->MinimumDisplayAperture)) + { + rect->left = info->MinimumDisplayAperture.OffsetX.value; + rect->top = info->MinimumDisplayAperture.OffsetY.value; + rect->right = rect->left + info->MinimumDisplayAperture.Area.cx; + rect->bottom = rect->top + info->MinimumDisplayAperture.Area.cy; + } + else + { + rect->left = 0; + rect->top = 0; + rect->right = info->dwWidth; + rect->bottom = info->dwHeight; + } +} + +static inline BOOL intersect_rect(RECT *dst, const RECT *src1, const RECT *src2) +{ + dst->left = max(src1->left, src2->left); + dst->top = max(src1->top, src2->top); + dst->right = min(src1->right, src2->right); + dst->bottom = min(src1->bottom, src2->bottom); + return !IsRectEmpty(dst); +} + +static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info) +{ + RECT rect, input_rect, output_rect; + + init_mf_video_info_rect(input_info, &input_rect); + init_mf_video_info_rect(output_info, &output_rect); + intersect_rect(&rect, &input_rect, &output_rect); + + input_info->MinimumDisplayAperture.OffsetX.value = rect.left; + input_info->MinimumDisplayAperture.OffsetY.value = rect.top; + input_info->MinimumDisplayAperture.Area.cx = rect.right - rect.left; + input_info->MinimumDisplayAperture.Area.cy = rect.bottom - rect.top; + output_info->MinimumDisplayAperture = input_info->MinimumDisplayAperture; +} + +static void set_video_caps_aperture(GstCaps *caps, MFVideoInfo *video_info) +{ + if (!is_mf_video_area_empty(&video_info->MinimumDisplayAperture)) + { + gst_caps_set_simple(caps, "width", G_TYPE_INT, video_info->MinimumDisplayAperture.Area.cx, NULL); + gst_caps_set_simple(caps, "height", G_TYPE_INT, video_info->MinimumDisplayAperture.Area.cy, NULL); + } +} + typedef struct { GstVideoBufferPool parent; @@ -490,6 +563,15 @@ NTSTATUS wg_transform_create(void *args) if (IsEqualGUID(¶ms->output_type.major, &MFMediaType_Video)) transform->output_info = params->output_type.u.video->videoInfo; + /* update the video apertures to make sure GStreamer has a consistent input/output frame size */ + if (!strcmp(input_mime, "video/x-raw") && !strcmp(output_mime, "video/x-raw")) + update_video_aperture(&transform->input_info, &transform->output_info); + + if (IsEqualGUID(¶ms->input_type.major, &MFMediaType_Video)) + set_video_caps_aperture(transform->input_caps, &transform->input_info); + if (IsEqualGUID(¶ms->output_type.major, &MFMediaType_Video)) + set_video_caps_aperture(transform->output_caps, &transform->output_info); + if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, transform->input_caps))) goto out; transform->my_src = gst_pad_new_from_template(template, "src"); @@ -677,6 +759,7 @@ NTSTATUS wg_transform_set_output_type(void *args) { struct wg_transform_set_output_type_params *params = args; struct wg_transform *transform = get_transform(params->transform); + const char *input_mime, *output_mime; GstCaps *caps, *stripped; GstSample *sample; @@ -686,9 +769,19 @@ NTSTATUS wg_transform_set_output_type(void *args) return STATUS_UNSUCCESSFUL; } + input_mime = gst_structure_get_name(gst_caps_get_structure(transform->input_caps, 0)); + output_mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) transform->output_info = params->media_type.u.video->videoInfo; + /* update the video apertures to make sure GStreamer has a consistent input/output frame size */ + if (!strcmp(input_mime, "video/x-raw") && !strcmp(output_mime, "video/x-raw")) + update_video_aperture(&transform->input_info, &transform->output_info); + + if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) + set_video_caps_aperture(caps, &transform->output_info); + GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, caps); stripped = caps_strip_fields(caps, transform->attrs.allow_format_change); From c6efb777b048c31f4e97e0629dd60566652225c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Feb 2022 21:31:55 +0100 Subject: [PATCH 232/301] HACK: winegstreamer/wg_transform: Check if the decoder accepted our caps. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 CW-Bug-Id: #19854 CW-Bug-Id: #20966 CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 772e2912184..12083fbe3c5 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -690,6 +690,20 @@ NTSTATUS wg_transform_create(void *args) || !push_event(transform->my_src, event)) goto out; + /* Check that the caps event have been accepted */ + if (!strcmp(input_mime, "video/x-h264")) + { + GstPad *peer; + if (!(peer = gst_pad_get_peer(transform->my_src))) + goto out; + else if (!gst_pad_has_current_caps(peer)) + { + gst_object_unref(peer); + goto out; + } + gst_object_unref(peer); + } + /* We need to use GST_FORMAT_TIME here because it's the only format * some elements such avdec_wmav2 correctly support. */ gst_segment_init(&transform->segment, GST_FORMAT_TIME); From c8cfa60e89681da5fd274ab4366dc208807217c0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 3 Nov 2022 18:54:06 +0200 Subject: [PATCH 233/301] HACK: winegstreamer: Detect h264 use and create a tag file. CW-Bug-Id: #21473 CW-Bug-Id: #20833 --- dlls/winegstreamer/unix_private.h | 35 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 15 +++++++++++++ dlls/winegstreamer/wg_transform.c | 3 +++ 3 files changed, 53 insertions(+) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index e0feef21778..c0f2df3d786 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -27,6 +27,11 @@ #include #include +#include +#include +#include +#include + /* unixlib.c */ GST_DEBUG_CATEGORY_EXTERN(wine); @@ -122,4 +127,34 @@ extern bool media_converter_init(void); extern bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, struct wg_format *codec_format); +static inline void touch_h264_used_tag(void) +{ + const char *e; + + GST_LOG("h264 is used"); + + if ((e = getenv("STEAM_COMPAT_TRANSCODED_MEDIA_PATH"))) + { + char buffer[PATH_MAX]; + int fd; + + snprintf(buffer, sizeof(buffer), "%s/h264-used", e); + + fd = open(buffer, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) + { + GST_WARNING("Failed to open/create \"%s/h264-used\"", e); + return; + } + + futimens(fd, NULL); + + close(fd); + } + else + { + GST_WARNING("STEAM_COMPAT_TRANSCODED_MEDIA_PATH not set, cannot create h264-used file"); + } +} + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 81e13fba433..4bd604e8a96 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -546,6 +546,19 @@ static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCap return !caps_is_compressed(caps); } +gboolean caps_detect_h264(GstCapsFeatures *features, GstStructure *structure, gpointer user_data) +{ + const char *cap_name = gst_structure_get_name(structure); + + if (!strcmp(cap_name, "video/x-h264")) + { + touch_h264_used_tag(); + return FALSE; + } + + return TRUE; +} + static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user) { @@ -555,6 +568,8 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GST_INFO("Using \"%s\".", name); + gst_caps_foreach(caps, caps_detect_h264, NULL); + if (parser->error) return GST_AUTOPLUG_SELECT_SKIP; if (strstr(name, "Player protection")) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 12083fbe3c5..80d8a1258d8 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -553,6 +553,9 @@ NTSTATUS wg_transform_create(void *args) GST_INFO("transform %p input caps %"GST_PTR_FORMAT, transform, transform->input_caps); input_mime = gst_structure_get_name(gst_caps_get_structure(transform->input_caps, 0)); + if (!strcmp(input_mime, "video/x-h264")) + touch_h264_used_tag(); + if (!(transform->output_caps = caps_from_media_type(¶ms->output_type))) goto out; GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, transform->output_caps); From f4c685784d07c40b63f76435234e787f350b6d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 22:29:41 +0100 Subject: [PATCH 234/301] winegstreamer/new_media_source: Use GST_PTR_FORMAT more consistently. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 61 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 6e000e36e31..5fab3deade8 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -80,7 +80,6 @@ static GstCaps *detect_caps_from_data(const char *url, const void *data, guint s const char *extension = url ? strrchr(url, '.') : NULL; GstTypeFindProbability probability; GstCaps *caps; - gchar *str; if (!(caps = gst_type_find_helper_for_data_with_extension(NULL, data, size, extension ? extension + 1 : NULL, &probability))) @@ -89,14 +88,12 @@ static GstCaps *detect_caps_from_data(const char *url, const void *data, guint s return NULL; } - str = gst_caps_to_string(caps); if (probability > GST_TYPE_FIND_POSSIBLE) - GST_INFO("Detected caps %s with probability %u for url %s, data %p, size %u", - str, probability, url, data, size); + GST_INFO("Detected caps %"GST_PTR_FORMAT" with probability %u for url %s, data %p, size %u", + caps, probability, url, data, size); else - GST_FIXME("Detected caps %s with probability %u for url %s, data %p, size %u", - str, probability, url, data, size); - g_free(str); + GST_FIXME("Detected caps %"GST_PTR_FORMAT" with probability %u for url %s, data %p, size %u", + caps, probability, url, data, size); return caps; } @@ -196,21 +193,17 @@ static NTSTATUS source_get_stream_buffer(struct wg_source *source, guint index, static gboolean src_event_seek(struct wg_source *source, GstEvent *event) { guint32 i, seqnum = gst_event_get_seqnum(event); - GstSeekType cur_type, stop_type; GstSeekFlags flags; GstFormat format; - gint64 cur, stop; - gdouble rate; + gint64 cur; - gst_event_parse_seek(event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, event); + + gst_event_parse_seek(event, NULL, &format, &flags, NULL, &cur, NULL, NULL); gst_event_unref(event); if (format != GST_FORMAT_BYTES) return false; - GST_TRACE("source %p, rate %f, format %s, flags %#x, cur_type %u, cur %#" G_GINT64_MODIFIER "x, " - "stop_type %u, stop %#" G_GINT64_MODIFIER "x.", source, rate, gst_format_get_name(format), - flags, cur_type, cur, stop_type, stop); - if (flags & GST_SEEK_FLAG_FLUSH) { if (!(event = gst_event_new_flush_start())) @@ -261,8 +254,9 @@ static gboolean src_query_duration(struct wg_source *source, GstQuery *query) { GstFormat format; + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, query); + gst_query_parse_duration(query, &format, NULL); - GST_TRACE("source %p, format %s", source, gst_format_get_name(format)); if (format != GST_FORMAT_BYTES) return false; @@ -272,7 +266,8 @@ static gboolean src_query_duration(struct wg_source *source, GstQuery *query) static gboolean src_query_scheduling(struct wg_source *source, GstQuery *query) { - GST_TRACE("source %p", source); + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, query); + gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); return true; @@ -282,8 +277,9 @@ static gboolean src_query_seeking(struct wg_source *source, GstQuery *query) { GstFormat format; + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, query); + gst_query_parse_seeking(query, &format, NULL, NULL, NULL); - GST_TRACE("source %p, format %s", source, gst_format_get_name(format)); if (format != GST_FORMAT_BYTES) return false; @@ -295,8 +291,9 @@ static gboolean src_query_uri(struct wg_source *source, GstQuery *query) { gchar *uri; + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, query); + gst_query_parse_uri(query, &uri); - GST_TRACE("source %p, uri %s", source, uri); gst_query_set_uri(query, source->url); return true; @@ -328,7 +325,7 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu struct wg_source *source = gst_pad_get_element_private(pad); guint index; - GST_TRACE("source %p, pad %p, buffer %p.", source, pad, buffer); + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, buffer); for (index = 0; index < source->stream_count; index++) if (source->streams[index].pad == pad) @@ -346,12 +343,10 @@ static gboolean sink_event_caps(struct wg_source *source, GstPad *pad, GstEvent { GstStream *stream; GstCaps *caps; - gchar *str; + + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); gst_event_parse_caps(event, &caps); - str = gst_caps_to_string(caps); - GST_TRACE("source %p, pad %p, caps %s", source, pad, str); - g_free(str); if ((stream = gst_pad_get_stream(pad))) { @@ -369,8 +364,9 @@ static gboolean sink_event_tag(struct wg_source *source, GstPad *pad, GstEvent * GstTagList *new_tags; GstStream *stream; + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); + gst_event_parse_tag(event, &new_tags); - GST_TRACE("source %p, pad %p, new_tags %p", source, pad, new_tags); if ((stream = gst_pad_get_stream(pad))) { @@ -396,6 +392,8 @@ static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, G gint64 duration; const gchar *id; + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); + gst_event_parse_stream_start(event, &id); gst_event_parse_stream(event, &stream); gst_event_parse_stream_flags(event, &flags); @@ -403,10 +401,10 @@ static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, G group = -1; if (gst_pad_peer_query_duration(pad, GST_FORMAT_TIME, &duration) && GST_CLOCK_TIME_IS_VALID(duration)) + { source->max_duration = max(source->max_duration, duration); - - GST_TRACE("source %p, pad %p, stream %p, id %s, flags %#x, group %d, duration %" GST_TIME_FORMAT, - source, pad, stream, id, flags, group, GST_TIME_ARGS(duration)); + GST_TRACE("source %p, %"GST_PTR_FORMAT", got duration %" GST_TIME_FORMAT, source, pad, GST_TIME_ARGS(duration)); + } gst_event_unref(event); return true; @@ -416,7 +414,7 @@ static gboolean sink_event_eos(struct wg_source *source, GstPad *pad, GstEvent * { guint index; - GST_TRACE("source %p, pad %p, event %p", source, pad, event); + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); for (index = 0; index < source->stream_count; index++) if (source->streams[index].pad == pad) @@ -474,7 +472,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) GstEvent *event; guint index; - GST_TRACE("source %p, element %p, pad %p.", source, element, pad); + GST_TRACE("source %p, %"GST_PTR_FORMAT", %p", source, pad, user); + if ((index = source->stream_count++) >= ARRAY_SIZE(source->streams)) { GST_FIXME("Not enough sink pads, need %u", source->stream_count); @@ -688,7 +687,7 @@ NTSTATUS wg_source_set_position(void *args) GstEvent *event; guint i; - GST_TRACE("source %p", source); + GST_TRACE("source %p, time %"G_GINT64_MODIFIER"d", source, time); if (!(event = gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1)) From 96a42caaebb5c285be62814e7140a74a78b6a539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 22:32:21 +0100 Subject: [PATCH 235/301] winegstreamer/new_media_source: Use push_event more consistently. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 38 ++++++++-------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 5fab3deade8..751c1e8b9d3 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -206,14 +206,9 @@ static gboolean src_event_seek(struct wg_source *source, GstEvent *event) if (flags & GST_SEEK_FLAG_FLUSH) { - if (!(event = gst_event_new_flush_start())) - GST_ERROR("Failed to allocate flush_start event"); - else - { + if ((event = gst_event_new_flush_start())) gst_event_set_seqnum(event, seqnum); - if (!gst_pad_push_event(source->src_pad, event)) - GST_ERROR("Failed to push flush_start event"); - } + push_event(source->src_pad, event); } source->segment.start = cur; @@ -223,14 +218,9 @@ static gboolean src_event_seek(struct wg_source *source, GstEvent *event) if (flags & GST_SEEK_FLAG_FLUSH) { - if (!(event = gst_event_new_flush_stop(true))) - GST_ERROR("Failed to allocate flush_stop event"); - else - { + if ((event = gst_event_new_flush_stop(true))) gst_event_set_seqnum(event, seqnum); - if (!gst_pad_push_event(source->src_pad, event)) - GST_ERROR("Failed to push flush_stop event"); - } + push_event(source->src_pad, event); source->valid_segment = false; } @@ -504,7 +494,6 @@ NTSTATUS wg_source_create(void *args) GstCaps *src_caps, *any_caps; struct wg_source *source; const gchar *media_type; - GstEvent *event; GstPad *peer; guint i; @@ -579,8 +568,7 @@ NTSTATUS wg_source_create(void *args) if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error; - if (!(event = create_stream_start_event("wg_source")) - || !push_event(source->src_pad, event)) + if (!push_event(source->src_pad, create_stream_start_event("wg_source"))) goto error; gst_caps_unref(src_caps); @@ -684,15 +672,12 @@ NTSTATUS wg_source_set_position(void *args) struct wg_source_set_position_params *params = args; struct wg_source *source = get_source(params->source); guint64 time = params->time * 100; - GstEvent *event; guint i; GST_TRACE("source %p, time %"G_GINT64_MODIFIER"d", source, time); - if (!(event = gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1)) - || !gst_pad_push_event(source->streams[0].pad, event)) - GST_WARNING("Failed to seek source %p to %" G_GINT64_MODIFIER "x", source, time); + push_event(source->streams[0].pad, gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1)); for (i = 0; i < source->stream_count; i++) { @@ -715,15 +700,12 @@ NTSTATUS wg_source_push_data(void *args) struct wg_source *source = get_source(params->source); GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buffer; - GstEvent *event; GST_TRACE("source %p, data %p, size %#x", source, params->data, params->size); if (!source->valid_segment) { - if (!(event = gst_event_new_segment(&source->segment)) - || !gst_pad_push_event(source->src_pad, event)) - GST_ERROR("Failed to push new segment event"); + push_event(source->src_pad, gst_event_new_segment(&source->segment)); source->valid_segment = true; } @@ -752,9 +734,7 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_SUCCESS; eos: - if (!(event = gst_event_new_eos()) - || !gst_pad_push_event(source->src_pad, event)) - GST_WARNING("Failed to push EOS event"); + push_event(source->src_pad, gst_event_new_eos()); source->segment.start = source->segment.stop; return STATUS_SUCCESS; From d7aa8e1940a6770389a04e1935111df3c8aaa34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 10:10:16 +0100 Subject: [PATCH 236/301] winegstreamer/new_media_source: Set read offsets on pushed buffers. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 5 +++-- dlls/winegstreamer/new_media_source.c | 25 ++++++++++++++----------- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 8 +++++--- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index f0067a2b4e9..fb504a16da5 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -110,7 +110,7 @@ HRESULT wg_source_get_stream_count(wg_source_t source, uint32_t *stream_count); HRESULT wg_source_get_duration(wg_source_t source, uint64_t *duration); HRESULT wg_source_set_position(wg_source_t source, uint64_t time); HRESULT wg_source_get_position(wg_source_t source, uint64_t *read_offset); -HRESULT wg_source_push_data(wg_source_t source, const void *data, uint32_t size); +HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size); HRESULT wg_source_read_data(wg_source_t source, UINT32 index, IMFSample **out); bool wg_source_get_stream_format(wg_source_t source, UINT32 index, struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index cef0bc0bd0b..d93b2ce5699 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -551,16 +551,17 @@ HRESULT wg_source_set_position(wg_source_t source, uint64_t time) return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_set_position, ¶ms)); } -HRESULT wg_source_push_data(wg_source_t source, const void *data, uint32_t size) +HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size) { struct wg_source_push_data_params params = { .source = source, + .offset = offset, .data = data, .size = size, }; - TRACE("source %#I64x, data %p, size %#x\n", source, data, size); + TRACE("source %#I64x, offset %#I64x, data %p, size %#x\n", source, offset, data, size); return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_push_data, ¶ms)); } diff --git a/dlls/winegstreamer/new_media_source.c b/dlls/winegstreamer/new_media_source.c index efaf6a3e087..bdb026f6e66 100644 --- a/dlls/winegstreamer/new_media_source.c +++ b/dlls/winegstreamer/new_media_source.c @@ -40,6 +40,7 @@ struct object_context WCHAR *url; BYTE *buffer; + UINT64 read_offset; wg_source_t wg_source; WCHAR mime_type[256]; UINT32 stream_count; @@ -774,8 +775,8 @@ static HRESULT media_stream_send_eos(struct media_source *source, struct media_s static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + UINT64 read_offset, position; DWORD id, read_size; - UINT64 read_offset; IMFSample *sample; HRESULT hr; @@ -789,11 +790,14 @@ static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { if (FAILED(hr = wg_source_get_position(source->wg_source, &read_offset))) break; - if (FAILED(hr = IMFByteStream_SetCurrentPosition(source->byte_stream, read_offset))) - WARN("Failed to seek stream to %#I64x, hr %#lx\n", read_offset, hr); + if (FAILED(hr = IMFByteStream_GetCurrentPosition(source->byte_stream, &position))) + WARN("Failed to get current byte stream position, hr %#lx\n", hr); + else if (position != (read_offset = min(read_offset, source->file_size)) + && FAILED(hr = IMFByteStream_SetCurrentPosition(source->byte_stream, read_offset))) + WARN("Failed to set current byte stream position, hr %#lx\n", hr); else if (FAILED(hr = IMFByteStream_Read(source->byte_stream, source->read_buffer, SOURCE_BUFFER_SIZE, &read_size))) WARN("Failed to read %#lx bytes from stream, hr %#lx\n", read_size, hr); - else if (FAILED(hr = wg_source_push_data(source->wg_source, source->read_buffer, read_size))) + else if (FAILED(hr = wg_source_push_data(source->wg_source, read_offset, source->read_buffer, read_size))) WARN("Failed to push %#lx bytes to source, hr %#lx\n", read_size, hr); } @@ -2021,7 +2025,6 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM IUnknown *object, *state = IMFAsyncResult_GetStateNoAddRef(result); struct object_context *context; struct result_entry *entry; - UINT64 read_offset; DWORD size = 0; HRESULT hr; @@ -2033,23 +2036,23 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM else if (!context->wg_source && FAILED(hr = wg_source_create(context->url, context->file_size, context->buffer, size, context->mime_type, &context->wg_source))) WARN("Failed to create wg_source, hr %#lx\n", hr); - else if (FAILED(hr = wg_source_push_data(context->wg_source, context->buffer, size))) + else if (FAILED(hr = wg_source_push_data(context->wg_source, context->read_offset, context->buffer, size))) WARN("Failed to push wg_source data, hr %#lx\n", hr); else if (FAILED(hr = wg_source_get_stream_count(context->wg_source, &context->stream_count))) WARN("Failed to get wg_source status, hr %#lx\n", hr); else if (!context->stream_count) { - QWORD position, offset; - if (FAILED(hr = wg_source_get_position(context->wg_source, &read_offset))) + QWORD position; + if (FAILED(hr = wg_source_get_position(context->wg_source, &context->read_offset))) WARN("Failed to get wg_source position, hr %#lx\n", hr); else if (FAILED(hr = IMFByteStream_GetCurrentPosition(context->stream, &position))) WARN("Failed to get current byte stream position, hr %#lx\n", hr); - else if (position != (offset = min(read_offset, context->file_size)) - && FAILED(hr = IMFByteStream_SetCurrentPosition(context->stream, offset))) + else if (position != (context->read_offset = min(context->read_offset, context->file_size)) + && FAILED(hr = IMFByteStream_SetCurrentPosition(context->stream, context->read_offset))) WARN("Failed to set current byte stream position, hr %#lx\n", hr); else { - UINT32 read_size = min(SOURCE_BUFFER_SIZE, context->file_size - offset); + UINT32 read_size = min(SOURCE_BUFFER_SIZE, context->file_size - context->read_offset); return IMFByteStream_BeginRead(context->stream, context->buffer, read_size, &handler->IMFAsyncCallback_iface, state); } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 2f0a7c08666..28d2f2f7448 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -379,6 +379,7 @@ struct wg_source_set_position_params struct wg_source_push_data_params { wg_source_t source; + UINT64 offset; const void *data; UINT32 size; }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 751c1e8b9d3..4a9a4749530 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -113,7 +113,7 @@ static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) return pad; } -static GstBuffer *create_buffer_from_bytes(const void *data, guint size) +static GstBuffer *create_buffer_from_bytes(UINT64 offset, const void *data, guint size) { GstBuffer *buffer; @@ -123,6 +123,8 @@ static GstBuffer *create_buffer_from_bytes(const void *data, guint size) { gst_buffer_fill(buffer, 0, data, size); gst_buffer_set_size(buffer, size); + GST_BUFFER_OFFSET(buffer) = offset; + GST_BUFFER_OFFSET_END(buffer) = offset + size; } return buffer; @@ -701,7 +703,7 @@ NTSTATUS wg_source_push_data(void *args) GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buffer; - GST_TRACE("source %p, data %p, size %#x", source, params->data, params->size); + GST_TRACE("source %p, offset %#"G_GINT64_MODIFIER"x, data %p, size %#x", source, params->offset, params->data, params->size); if (!source->valid_segment) { @@ -716,7 +718,7 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_SUCCESS; } - if (!(buffer = create_buffer_from_bytes(params->data, params->size))) + if (!(buffer = create_buffer_from_bytes(params->offset, params->data, params->size))) { GST_WARNING("Failed to allocate buffer for data"); return STATUS_UNSUCCESSFUL; From 0d9d6f907a642a5e64495c38c8ad983575a1bec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 11:26:51 +0100 Subject: [PATCH 237/301] winegstreamer/new_media_source: Set EOS segment start before pushing event. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 4a9a4749530..8619d87a6e7 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -736,8 +736,8 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_SUCCESS; eos: - push_event(source->src_pad, gst_event_new_eos()); source->segment.start = source->segment.stop; + push_event(source->src_pad, gst_event_new_eos()); return STATUS_SUCCESS; } From 9561d6ea7569d082d47c6f7aa60d0456e3def8f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 11:44:02 +0100 Subject: [PATCH 238/301] winegstreamer/new_media_source: Push new stream start even after EOS. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 8619d87a6e7..4808e747d03 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -55,6 +55,7 @@ struct wg_source GstPad *src_pad; GstElement *container; GstSegment segment; + bool valid_stream; bool valid_segment; guint64 max_duration; @@ -569,9 +570,6 @@ NTSTATUS wg_source_create(void *args) gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error; - - if (!push_event(source->src_pad, create_stream_start_event("wg_source"))) - goto error; gst_caps_unref(src_caps); params->source = (wg_source_t)(ULONG_PTR)source; @@ -705,6 +703,12 @@ NTSTATUS wg_source_push_data(void *args) GST_TRACE("source %p, offset %#"G_GINT64_MODIFIER"x, data %p, size %#x", source, params->offset, params->data, params->size); + if (!source->valid_stream) + { + push_event(source->src_pad, create_stream_start_event("wg_source")); + source->valid_stream = true; + } + if (!source->valid_segment) { push_event(source->src_pad, gst_event_new_segment(&source->segment)); @@ -738,6 +742,7 @@ NTSTATUS wg_source_push_data(void *args) eos: source->segment.start = source->segment.stop; push_event(source->src_pad, gst_event_new_eos()); + source->valid_stream = false; return STATUS_SUCCESS; } From 2384aa228299b749217130dab793b84da196bd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Mar 2024 22:33:57 +0100 Subject: [PATCH 239/301] winegstreamer/new_media_source: Keep the GstStreams on the wg_source streams. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 144 ++++++++++++++++----------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 4808e747d03..5591e57c533 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -44,6 +44,7 @@ struct source_stream { GstPad *pad; + GstStream *stream; GstAtomicQueue *queue; GstBuffer *buffer; gboolean eos; @@ -68,6 +69,14 @@ static struct wg_source *get_source(wg_source_t source) return (struct wg_source *)(ULONG_PTR)source; } +static struct source_stream *source_stream_from_pad(struct wg_source *source, GstPad *pad) +{ + struct source_stream *stream, *end; + for (stream = source->streams, end = stream + source->stream_count; stream != end; stream++) + if (stream->pad == pad) return stream; + return NULL; +} + static const char *media_type_from_caps(GstCaps *caps) { GstStructure *structure; @@ -133,7 +142,9 @@ static GstBuffer *create_buffer_from_bytes(UINT64 offset, const void *data, guin static GstStream *source_get_stream(struct wg_source *source, guint index) { - return index >= source->stream_count ? NULL : gst_pad_get_stream(source->streams[index].pad); + if (index >= source->stream_count) + return NULL; + return gst_object_ref(source->streams[index].stream); } static GstCaps *source_get_stream_caps(struct wg_source *source, guint index) @@ -168,17 +179,6 @@ static bool source_set_stream_flags(struct wg_source *source, guint index, GstSt return true; } -static GstStreamFlags source_get_stream_flags(struct wg_source *source, guint index) -{ - GstStreamFlags flags; - GstStream *stream; - if (!(stream = source_get_stream(source, index))) - return 0; - flags = gst_stream_get_stream_flags(stream); - gst_object_unref(stream); - return flags; -} - static NTSTATUS source_get_stream_buffer(struct wg_source *source, guint index, GstBuffer **buffer) { GstBuffer **stream_buffer; @@ -316,16 +316,12 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_source *source = gst_pad_get_element_private(pad); - guint index; + struct source_stream *stream = source_stream_from_pad(source, pad); GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, buffer); - for (index = 0; index < source->stream_count; index++) - if (source->streams[index].pad == pad) - break; - - if (source_get_stream_flags(source, index) & GST_STREAM_FLAG_SELECT) - gst_atomic_queue_push(source->streams[index].queue, buffer); + if (gst_stream_get_stream_flags(stream->stream) & GST_STREAM_FLAG_SELECT) + gst_atomic_queue_push(stream->queue, buffer); else gst_buffer_unref(buffer); @@ -334,65 +330,66 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu static gboolean sink_event_caps(struct wg_source *source, GstPad *pad, GstEvent *event) { - GstStream *stream; + struct source_stream *stream = source_stream_from_pad(source, pad); GstCaps *caps; GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); gst_event_parse_caps(event, &caps); - if ((stream = gst_pad_get_stream(pad))) - { - gst_stream_set_caps(stream, gst_caps_copy(caps)); - gst_stream_set_stream_type(stream, stream_type_from_caps(caps)); - gst_object_unref(stream); - } + gst_stream_set_caps(stream->stream, gst_caps_copy(caps)); + gst_stream_set_stream_type(stream->stream, stream_type_from_caps(caps)); gst_event_unref(event); - return !!stream; + return true; } static gboolean sink_event_tag(struct wg_source *source, GstPad *pad, GstEvent *event) { - GstTagList *new_tags; - GstStream *stream; + struct source_stream *stream = source_stream_from_pad(source, pad); + GstTagList *new_tags, *old_tags = gst_stream_get_tags(stream->stream); GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); gst_event_parse_tag(event, &new_tags); - if ((stream = gst_pad_get_stream(pad))) + if ((new_tags = gst_tag_list_merge(old_tags, new_tags, GST_TAG_MERGE_REPLACE))) { - GstTagList *old_tags = gst_stream_get_tags(stream); - if ((new_tags = gst_tag_list_merge(old_tags, new_tags, GST_TAG_MERGE_REPLACE))) - { - gst_stream_set_tags(stream, new_tags); - gst_tag_list_unref(new_tags); - } - if (old_tags) - gst_tag_list_unref(old_tags); - gst_object_unref(stream); + gst_stream_set_tags(stream->stream, new_tags); + gst_tag_list_unref(new_tags); } + if (old_tags) + gst_tag_list_unref(old_tags); gst_event_unref(event); - return stream && new_tags; + return true; } static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, GstEvent *event) { + struct source_stream *stream = source_stream_from_pad(source, pad); + const gchar *new_id, *old_id = gst_stream_get_stream_id(stream->stream); + GstStream *new_stream, *old_stream = stream->stream; guint group, flags; - GstStream *stream; gint64 duration; - const gchar *id; GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); - gst_event_parse_stream_start(event, &id); - gst_event_parse_stream(event, &stream); + gst_event_parse_stream_start(event, &new_id); + gst_event_parse_stream(event, &new_stream); gst_event_parse_stream_flags(event, &flags); if (!gst_event_parse_group_id(event, &group)) group = -1; + if (strcmp(old_id, new_id)) + { + if (!(stream->stream = new_stream)) + stream->stream = gst_stream_new(new_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0); + else + gst_object_ref(stream->stream); + gst_object_unref(old_stream); + } + if (gst_pad_peer_query_duration(pad, GST_FORMAT_TIME, &duration) && GST_CLOCK_TIME_IS_VALID(duration)) { source->max_duration = max(source->max_duration, duration); @@ -405,16 +402,11 @@ static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, G static gboolean sink_event_eos(struct wg_source *source, GstPad *pad, GstEvent *event) { - guint index; + struct source_stream *stream = source_stream_from_pad(source, pad); GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); - for (index = 0; index < source->stream_count; index++) - if (source->streams[index].pad == pad) - break; - - if (index < source->stream_count) - source->streams[index].eos = true; + stream->eos = true; gst_event_unref(event); return true; @@ -444,13 +436,12 @@ static GstEvent *create_stream_start_event(const char *stream_id) GstStream *stream; GstEvent *event; - if (!(stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0))) - return NULL; - gst_stream_set_stream_flags(stream, GST_STREAM_FLAG_SELECT); + stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0); if ((event = gst_event_new_stream_start(stream_id))) { gst_event_set_stream(event, stream); - gst_object_unref(stream); + gst_event_set_stream_flags(event, GST_STREAM_FLAG_SELECT); + gst_event_set_group_id(event, 1); } return event; @@ -459,34 +450,43 @@ static GstEvent *create_stream_start_event(const char *stream_id) static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { struct wg_source *source = user; - char stream_id[256]; - GstFlowReturn ret; - GstPad *sink_pad; - GstEvent *event; - guint index; + struct source_stream *stream; + char stream_id[256], *id; GST_TRACE("source %p, %"GST_PTR_FORMAT", %p", source, pad, user); - if ((index = source->stream_count++) >= ARRAY_SIZE(source->streams)) + stream = source->streams + source->stream_count++; + if (stream >= source->streams + ARRAY_SIZE(source->streams)) { GST_FIXME("Not enough sink pads, need %u", source->stream_count); return; } - sink_pad = source->streams[index].pad; - if (gst_pad_link(pad, sink_pad) < 0 || !gst_pad_set_active(sink_pad, true)) - GST_ERROR("Failed to link new pad to sink pad %p", sink_pad); + if (gst_pad_link(pad, stream->pad) < 0 || !gst_pad_set_active(stream->pad, true)) + GST_ERROR("Failed to link new pad to sink pad %p", stream->pad); - snprintf(stream_id, ARRAY_SIZE(stream_id), "wg_source/%03u", index); - if (!(event = create_stream_start_event(stream_id))) - GST_ERROR("Failed to create stream event for sink pad %p", sink_pad); + if ((stream->stream = gst_pad_get_stream(pad))) + { + GST_TRACE("got pad %"GST_PTR_FORMAT" stream %"GST_PTR_FORMAT, pad, stream->stream); + gst_stream_set_stream_flags(stream->stream, GST_STREAM_FLAG_SELECT); + } else { - if ((ret = gst_pad_store_sticky_event(pad, event)) < 0) - GST_ERROR("Failed to create pad %p stream, ret %d", sink_pad, ret); - if ((ret = gst_pad_store_sticky_event(sink_pad, event)) < 0) - GST_ERROR("Failed to create pad %p stream, ret %d", sink_pad, ret); - gst_event_unref(event); + if (!(id = gst_pad_get_stream_id(pad))) + { + snprintf(stream_id, ARRAY_SIZE(stream_id), "wg_source/%03zu", stream - source->streams); + id = g_strdup(stream_id); + } + + if (!(stream->stream = gst_stream_new(id, NULL, GST_STREAM_TYPE_UNKNOWN, 0))) + GST_ERROR("Failed to create stream event for sink pad %p", stream->pad); + else + { + GST_TRACE("created stream %"GST_PTR_FORMAT" for pad %"GST_PTR_FORMAT, stream->stream, stream->pad); + gst_stream_set_stream_flags(stream->stream, GST_STREAM_FLAG_SELECT); + } + + g_free(id); } } From 470bf131c607e54f2902a0d985b977e82fc385e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Mar 2024 21:09:15 +0100 Subject: [PATCH 240/301] winegstreamer/new_media_source: Use wg_media_type to get wg_source stream types. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 3 +- dlls/winegstreamer/main.c | 31 +++++--- dlls/winegstreamer/new_media_source.c | 101 +++++++++++--------------- dlls/winegstreamer/unix_private.h | 2 +- dlls/winegstreamer/unixlib.h | 6 +- dlls/winegstreamer/wg_parser.c | 31 +++++++- dlls/winegstreamer/wg_source.c | 10 +-- 7 files changed, 104 insertions(+), 80 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index fb504a16da5..2660e908693 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -112,8 +112,7 @@ HRESULT wg_source_set_position(wg_source_t source, uint64_t time); HRESULT wg_source_get_position(wg_source_t source, uint64_t *read_offset); HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size); HRESULT wg_source_read_data(wg_source_t source, UINT32 index, IMFSample **out); -bool wg_source_get_stream_format(wg_source_t source, UINT32 index, - struct wg_format *format); +HRESULT wg_source_get_stream_type(wg_source_t source, UINT32 index, IMFMediaType **media_type); char *wg_source_get_stream_tag(wg_source_t source, UINT32 index, wg_parser_tag tag); void wg_source_set_stream_flags(wg_source_t source, UINT32 index, BOOL select); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index d93b2ce5699..627ce2e266e 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -566,23 +566,36 @@ HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_push_data, ¶ms)); } -bool wg_source_get_stream_format(wg_source_t source, UINT32 index, - struct wg_format *format) +HRESULT wg_source_get_stream_type(wg_source_t source, UINT32 index, IMFMediaType **media_type) { - struct wg_source_get_stream_format_params params = + struct wg_source_get_stream_type_params params = { .source = source, .index = index, }; + NTSTATUS status; + HRESULT hr; - TRACE("source %#I64x, index %u, format %p\n", source, - index, format); + TRACE("source %#I64x, index %u, media_type %p\n", source, index, media_type); - if (WINE_UNIX_CALL(unix_wg_source_get_stream_format, ¶ms)) - return false; + if ((status = WINE_UNIX_CALL(unix_wg_source_get_stream_type, ¶ms)) + && status == STATUS_BUFFER_TOO_SMALL) + { + if (!(params.media_type.u.format = CoTaskMemAlloc(params.media_type.format_size))) + return ERROR_OUTOFMEMORY; + status = WINE_UNIX_CALL(unix_wg_source_get_stream_type, ¶ms); + } - *format = params.format; - return true; + if (status) + { + CoTaskMemFree(params.media_type.u.format); + WARN("Failed to get output media type, status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + hr = wg_media_type_to_mf(¶ms.media_type, media_type); + CoTaskMemFree(params.media_type.u.format); + return hr; } char *wg_source_get_stream_tag(wg_source_t source, UINT32 index, wg_parser_tag tag) diff --git a/dlls/winegstreamer/new_media_source.c b/dlls/winegstreamer/new_media_source.c index bdb026f6e66..662118b6f53 100644 --- a/dlls/winegstreamer/new_media_source.c +++ b/dlls/winegstreamer/new_media_source.c @@ -457,19 +457,6 @@ static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *ifa return IMFMediaSource_Release(&source->IMFMediaSource_iface); } -static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type) -{ - IMFMediaTypeHandler *handler; - HRESULT hr; - - if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) - return hr; - hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type); - IMFMediaTypeHandler_Release(handler); - - return hr; -} - static HRESULT stream_descriptor_get_major_type(IMFStreamDescriptor *descriptor, GUID *major) { IMFMediaTypeHandler *handler; @@ -483,19 +470,6 @@ static HRESULT stream_descriptor_get_major_type(IMFStreamDescriptor *descriptor, return hr; } -static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format) -{ - IMFMediaType *media_type; - HRESULT hr; - - if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type))) - return hr; - mf_media_type_to_wg_format(media_type, format); - IMFMediaType_Release(media_type); - - return hr; -} - static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_source_t source, UINT index, const GUID *attr, enum wg_parser_tag tag) { @@ -522,29 +496,25 @@ static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, return hr; } -static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) +static HRESULT stream_descriptor_create(UINT32 id, IMFMediaType *media_type, IMFStreamDescriptor **out) { IMFStreamDescriptor *descriptor; IMFMediaTypeHandler *handler; - IMFMediaType *type; HRESULT hr; - if (!(type = mf_media_type_from_wg_format(format))) - return MF_E_INVALIDMEDIATYPE; - if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &type, &descriptor))) - goto done; + *out = NULL; + if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &media_type, &descriptor))) + return hr; if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) IMFStreamDescriptor_Release(descriptor); else { - hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); + if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) + *out = descriptor; IMFMediaTypeHandler_Release(handler); } -done: - IMFMediaType_Release(type); - *out = SUCCEEDED(hr) ? descriptor : NULL; return hr; } @@ -603,14 +573,10 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - struct wg_format format; HRESULT hr; TRACE("source %p, stream %p\n", source, stream); - if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) - WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) WARN("Failed to send source stream event, hr %#lx\n", hr); @@ -1553,8 +1519,9 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = static void media_source_init_stream_map(struct media_source *source, UINT stream_count) { - struct wg_format format; + IMFMediaType *media_type; int i, n = 0; + GUID major; if (wcscmp(source->mime_type, L"video/mp4")) { @@ -1568,26 +1535,40 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea for (i = stream_count - 1; i >= 0; i--) { - wg_source_get_stream_format(source->wg_source, i, &format); - if (format.major_type == WG_MAJOR_TYPE_UNKNOWN) continue; - if (format.major_type >= WG_MAJOR_TYPE_VIDEO) continue; - TRACE("mapping stream %u to wg_source stream %u\n", n, i); - source->stream_map[n++] = i; + if (SUCCEEDED(wg_source_get_stream_type(source->wg_source, i, &media_type))) + { + if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) + && IsEqualGUID(&major, &MFMediaType_Video)) + { + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } + } } for (i = stream_count - 1; i >= 0; i--) { - wg_source_get_stream_format(source->wg_source, i, &format); - if (format.major_type == WG_MAJOR_TYPE_UNKNOWN) continue; - if (format.major_type < WG_MAJOR_TYPE_VIDEO) continue; - TRACE("mapping stream %u to wg_source stream %u\n", n, i); - source->stream_map[n++] = i; + if (SUCCEEDED(wg_source_get_stream_type(source->wg_source, i, &media_type))) + { + if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) + && IsEqualGUID(&major, &MFMediaType_Audio)) + { + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } + } } for (i = stream_count - 1; i >= 0; i--) { - wg_source_get_stream_format(source->wg_source, i, &format); - if (format.major_type != WG_MAJOR_TYPE_UNKNOWN) continue; - TRACE("mapping stream %u to wg_source stream %u\n", n, i); - source->stream_map[n++] = i; + if (SUCCEEDED(wg_source_get_stream_type(source->wg_source, i, &media_type))) + { + if (FAILED(IMFMediaType_GetMajorType(media_type, &major)) + || (!IsEqualGUID(&major, &MFMediaType_Audio) + && !IsEqualGUID(&major, &MFMediaType_Audio))) + { + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } + } } } @@ -1703,12 +1684,16 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc { IMFStreamDescriptor *descriptor; struct media_stream *stream; - struct wg_format format; + IMFMediaType *media_type; - if (FAILED(hr = wg_source_get_stream_format(object->wg_source, object->stream_map[i], &format))) + if (FAILED(hr = wg_source_get_stream_type(object->wg_source, object->stream_map[i], &media_type))) goto fail; - if (FAILED(hr = stream_descriptor_create(i + 1, &format, &descriptor))) + if (FAILED(hr = stream_descriptor_create(i + 1, media_type, &descriptor))) + { + IMFMediaType_Release(media_type); goto fail; + } + IMFMediaType_Release(media_type); if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, &stream))) { IMFStreamDescriptor_Release(descriptor); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index c0f2df3d786..24a41e36958 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -70,7 +70,7 @@ extern NTSTATUS wg_source_get_position(void *args); extern NTSTATUS wg_source_set_position(void *args); extern NTSTATUS wg_source_push_data(void *args); extern NTSTATUS wg_source_read_data(void *args); -extern NTSTATUS wg_source_get_stream_format(void *args); +extern NTSTATUS wg_source_get_stream_type(void *args); extern NTSTATUS wg_source_get_stream_tag(void *args); extern NTSTATUS wg_source_set_stream_flags(void *args); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 28d2f2f7448..e039cc35cd6 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -391,11 +391,11 @@ struct wg_source_read_data_params struct wg_sample *sample; }; -struct wg_source_get_stream_format_params +struct wg_source_get_stream_type_params { wg_source_t source; UINT32 index; - struct wg_format format; + struct wg_media_type media_type; }; struct wg_source_get_stream_tag_params @@ -537,7 +537,7 @@ enum unix_funcs unix_wg_source_set_position, unix_wg_source_push_data, unix_wg_source_read_data, - unix_wg_source_get_stream_format, + unix_wg_source_get_stream_type, unix_wg_source_get_stream_tag, unix_wg_source_set_stream_flags, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 4bd604e8a96..65e97153f69 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2267,7 +2267,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_source_set_position), X(wg_source_push_data), X(wg_source_read_data), - X(wg_source_get_stream_format), + X(wg_source_get_stream_type), X(wg_source_get_stream_tag), X(wg_source_set_stream_flags), @@ -2504,6 +2504,33 @@ NTSTATUS wow64_wg_source_read_data(void *args) return wg_source_read_data(¶ms); } +NTSTATUS wow64_wg_source_get_stream_type(void *args) +{ + struct + { + wg_source_t source; + UINT32 index; + struct wg_media_type32 media_type; + } *params32 = args; + struct wg_source_get_stream_type_params params = + { + .source = params32->source, + .index = params32->index, + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, + }; + NTSTATUS status; + + status = wg_source_get_stream_type(¶ms); + params32->media_type.major = params.media_type.major; + params32->media_type.format_size = params.media_type.format_size; + return status; +} + NTSTATUS wow64_wg_source_get_stream_tag(void *args) { struct @@ -2757,7 +2784,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X(wg_source_get_position), X64(wg_source_push_data), X64(wg_source_read_data), - X(wg_source_get_stream_format), + X64(wg_source_get_stream_type), X64(wg_source_get_stream_tag), X64(wg_transform_create), diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 5591e57c533..dd08437ce19 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -806,21 +806,21 @@ NTSTATUS wg_source_read_data(void *args) return status; } -NTSTATUS wg_source_get_stream_format(void *args) +NTSTATUS wg_source_get_stream_type(void *args) { - struct wg_source_get_stream_format_params *params = args; + struct wg_source_get_stream_type_params *params = args; struct wg_source *source = get_source(params->source); guint index = params->index; + NTSTATUS status; GstCaps *caps; GST_TRACE("source %p, index %u", source, index); if (!(caps = source_get_stream_caps(source, index))) return STATUS_UNSUCCESSFUL; - wg_format_from_caps(¶ms->format, caps); - + status = caps_to_media_type(caps, ¶ms->media_type, 0); gst_caps_unref(caps); - return STATUS_SUCCESS; + return status; } static gchar *stream_lang_from_tags(GstTagList *tags, bool is_quicktime) From 18ecf2fa8f314ee67aa894f794bb27a3b17c905b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Mar 2024 15:47:57 +0100 Subject: [PATCH 241/301] winegstreamer/new_media_source: Ignore empty wg_source buffers. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index dd08437ce19..e25b3c1332b 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -320,7 +320,8 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, buffer); - if (gst_stream_get_stream_flags(stream->stream) & GST_STREAM_FLAG_SELECT) + if (gst_stream_get_stream_flags(stream->stream) & GST_STREAM_FLAG_SELECT + && gst_buffer_get_size(buffer) > 0) gst_atomic_queue_push(stream->queue, buffer); else gst_buffer_unref(buffer); From 55dcc19ce892d3318ba1dad649675825720b16fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Mar 2024 16:23:23 +0100 Subject: [PATCH 242/301] winegstreamer/new_media_source: Push stream and segment events directly when needed. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 111 ++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index e25b3c1332b..c5f4ac27c1c 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -55,10 +55,11 @@ struct wg_source gchar *url; GstPad *src_pad; GstElement *container; + GstSegment segment; - bool valid_stream; - bool valid_segment; guint64 max_duration; + GstAtomicQueue *seek_queue; + pthread_t push_thread; guint stream_count; struct source_stream streams[WG_SOURCE_MAX_STREAMS]; @@ -193,11 +194,28 @@ static NTSTATUS source_get_stream_buffer(struct wg_source *source, guint index, return STATUS_SUCCESS; } +static GstEvent *create_stream_start_event(const char *stream_id) +{ + GstStream *stream; + GstEvent *event; + + stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0); + if ((event = gst_event_new_stream_start(stream_id))) + { + gst_event_set_stream(event, stream); + gst_event_set_stream_flags(event, GST_STREAM_FLAG_SELECT); + gst_event_set_group_id(event, 1); + } + + return event; +} + static gboolean src_event_seek(struct wg_source *source, GstEvent *event) { guint32 i, seqnum = gst_event_get_seqnum(event); GstSeekFlags flags; GstFormat format; + gboolean eos; gint64 cur; GST_TRACE("source %p, %"GST_PTR_FORMAT, source, event); @@ -210,23 +228,39 @@ static gboolean src_event_seek(struct wg_source *source, GstEvent *event) if (flags & GST_SEEK_FLAG_FLUSH) { if ((event = gst_event_new_flush_start())) + { gst_event_set_seqnum(event, seqnum); - push_event(source->src_pad, event); + push_event(source->src_pad, event); + } } - source->segment.start = cur; - - for (i = 0; i < ARRAY_SIZE(source->streams); i++) - source->streams[i].eos = false; + if ((eos = cur >= source->segment.stop)) + source->segment.start = source->segment.stop; + else + { + for (i = 0; i < ARRAY_SIZE(source->streams); i++) + source->streams[i].eos = false; + source->segment.start = cur; + } if (flags & GST_SEEK_FLAG_FLUSH) { if ((event = gst_event_new_flush_stop(true))) + { + gst_event_set_seqnum(event, seqnum); + push_event(source->src_pad, event); + } + + if ((event = gst_event_new_segment(&source->segment))) + { gst_event_set_seqnum(event, seqnum); - push_event(source->src_pad, event); - source->valid_segment = false; + push_event(source->src_pad, event); + } } + if (source->segment.start == source->segment.stop) + push_event(source->src_pad, gst_event_new_eos()); + return true; } @@ -432,22 +466,6 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) } } -static GstEvent *create_stream_start_event(const char *stream_id) -{ - GstStream *stream; - GstEvent *event; - - stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0); - if ((event = gst_event_new_stream_start(stream_id))) - { - gst_event_set_stream(event, stream); - gst_event_set_stream_flags(event, GST_STREAM_FLAG_SELECT); - gst_event_set_group_id(event, 1); - } - - return event; -} - static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { struct wg_source *source = user; @@ -573,6 +591,9 @@ NTSTATUS wg_source_create(void *args) goto error; gst_caps_unref(src_caps); + push_event(source->src_pad, create_stream_start_event("wg_source")); + push_event(source->src_pad, gst_event_new_segment(&source->segment)); + params->source = (wg_source_t)(ULONG_PTR)source; GST_INFO("Created winegstreamer source %p.", source); return STATUS_SUCCESS; @@ -704,22 +725,9 @@ NTSTATUS wg_source_push_data(void *args) GST_TRACE("source %p, offset %#"G_GINT64_MODIFIER"x, data %p, size %#x", source, params->offset, params->data, params->size); - if (!source->valid_stream) - { - push_event(source->src_pad, create_stream_start_event("wg_source")); - source->valid_stream = true; - } - - if (!source->valid_segment) - { - push_event(source->src_pad, gst_event_new_segment(&source->segment)); - source->valid_segment = true; - } - if (!params->size) { - if (source->segment.start != source->segment.stop) - goto eos; + push_event(source->src_pad, gst_event_new_eos()); return STATUS_SUCCESS; } @@ -729,23 +737,24 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_UNSUCCESSFUL; } - source->segment.start += params->size; - if ((ret = gst_pad_push(source->src_pad, buffer)) && ret != GST_FLOW_EOS) + if (params->offset > source->segment.start) { - GST_WARNING("Failed to push data buffer, ret %d", ret); - source->segment.start -= params->size; - return STATUS_UNSUCCESSFUL; + source->segment.start = params->offset; + gst_buffer_set_flags(buffer, GST_BUFFER_FLAG_DISCONT); + } + else if (params->offset < source->segment.start) + { + source->segment.start = params->offset; + push_event(source->src_pad, gst_event_new_segment(&source->segment)); } - if (source->segment.start != source->segment.stop) + source->segment.start += params->size; + if (!(ret = gst_pad_push(source->src_pad, buffer)) || ret == GST_FLOW_EOS) return STATUS_SUCCESS; -eos: - source->segment.start = source->segment.stop; - push_event(source->src_pad, gst_event_new_eos()); - source->valid_stream = false; - - return STATUS_SUCCESS; + GST_WARNING("Failed to push data buffer, ret %d", ret); + source->segment.start -= params->size; + return STATUS_UNSUCCESSFUL; } NTSTATUS wg_source_read_data(void *args) From 855f395228f38f363e20f3f91cb8e22fbefb96df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 17:00:12 +0200 Subject: [PATCH 243/301] winegstreamer/new_media_source: Add support for asynchronous wg_source seek events. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 52 ++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index c5f4ac27c1c..4b4a2ab621c 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -210,20 +210,14 @@ static GstEvent *create_stream_start_event(const char *stream_id) return event; } -static gboolean src_event_seek(struct wg_source *source, GstEvent *event) +static void source_handle_seek(struct wg_source *source, GstEvent *event) { guint32 i, seqnum = gst_event_get_seqnum(event); GstSeekFlags flags; - GstFormat format; gboolean eos; gint64 cur; - GST_TRACE("source %p, %"GST_PTR_FORMAT, source, event); - - gst_event_parse_seek(event, NULL, &format, &flags, NULL, &cur, NULL, NULL); - gst_event_unref(event); - if (format != GST_FORMAT_BYTES) - return false; + gst_event_parse_seek(event, NULL, NULL, &flags, NULL, &cur, NULL, NULL); if (flags & GST_SEEK_FLAG_FLUSH) { @@ -260,6 +254,34 @@ static gboolean src_event_seek(struct wg_source *source, GstEvent *event) if (source->segment.start == source->segment.stop) push_event(source->src_pad, gst_event_new_eos()); +} + +static gboolean src_event_seek(struct wg_source *source, GstEvent *event) +{ + GstFormat format; + + GST_TRACE("source %p, %"GST_PTR_FORMAT, source, event); + + gst_event_parse_seek(event, NULL, &format, NULL, NULL, NULL, NULL, NULL); + if (format != GST_FORMAT_BYTES) + { + gst_event_unref(event); + return false; + } + + /* Even in push mode, oggdemux uses a separate thread to request seeks, we have to handle + * these asynchronously from wg_source_get_position. + * On the other hand, other demuxers emit seeks synchronously during gst_pad_push_buffer, + * and expect to see flush events being pushed synchronously as well, we have to handle + * these directly here. + */ + if (source->push_thread != pthread_self()) + gst_atomic_queue_push(source->seek_queue, event); + else + { + source_handle_seek(source, event); + gst_event_unref(event); + } return true; } @@ -547,6 +569,7 @@ NTSTATUS wg_source_create(void *args) gst_pad_set_element_private(source->src_pad, source); gst_pad_set_query_function(source->src_pad, src_query_cb); gst_pad_set_event_function(source->src_pad, src_event_cb); + source->seek_queue = gst_atomic_queue_new(1); for (i = 0; i < ARRAY_SIZE(source->streams); i++) { @@ -627,10 +650,15 @@ NTSTATUS wg_source_create(void *args) NTSTATUS wg_source_destroy(void *args) { struct wg_source *source = get_source(*(wg_source_t *)args); + GstEvent *event; guint i; GST_TRACE("source %p", source); + while ((event = gst_atomic_queue_pop(source->seek_queue))) + gst_event_unref(event); + gst_atomic_queue_unref(source->seek_queue); + gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); for (i = 0; i < ARRAY_SIZE(source->streams); i++) @@ -682,9 +710,16 @@ NTSTATUS wg_source_get_position(void *args) { struct wg_source_get_position_params *params = args; struct wg_source *source = get_source(params->source); + GstEvent *event; GST_TRACE("source %p", source); + while ((event = gst_atomic_queue_pop(source->seek_queue))) + { + source_handle_seek(source, event); + gst_event_unref(event); + } + params->read_offset = source->segment.start; return STATUS_SUCCESS; } @@ -748,6 +783,7 @@ NTSTATUS wg_source_push_data(void *args) push_event(source->src_pad, gst_event_new_segment(&source->segment)); } + source->push_thread = pthread_self(); source->segment.start += params->size; if (!(ret = gst_pad_push(source->src_pad, buffer)) || ret == GST_FLOW_EOS) return STATUS_SUCCESS; From afb91e415b5e5d3e1acd0dc78e2dbbe6980c9102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Nov 2023 11:13:35 +0100 Subject: [PATCH 244/301] winegstreamer: Rename aac_decoder to audio_decoder. CW-Bug-Id: #21953 CW-Bug-Id: #20833 --- dlls/winegstreamer/Makefile.in | 2 +- .../{aac_decoder.c => audio_decoder.c} | 54 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) rename dlls/winegstreamer/{aac_decoder.c => audio_decoder.c} (91%) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index cacebd28e4b..ee1bff4b085 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -7,7 +7,7 @@ UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) SOURCES = \ - aac_decoder.c \ + audio_decoder.c \ color_convert.c \ main.c \ media_sink.c \ diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/audio_decoder.c similarity index 91% rename from dlls/winegstreamer/aac_decoder.c rename to dlls/winegstreamer/audio_decoder.c index 2cf605bc56c..704a3a17e68 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -1,4 +1,4 @@ -/* AAC Decoder Transform +/* Audio Decoder Transform * * Copyright 2022 RĂ©mi Bernon for CodeWeavers * @@ -34,7 +34,7 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); #define NEXT_WAVEFORMATEXTENSIBLE(format) (WAVEFORMATEXTENSIBLE *)((BYTE *)(&(format)->Format + 1) + (format)->Format.cbSize) -static WAVEFORMATEXTENSIBLE const aac_decoder_output_types[] = +static WAVEFORMATEXTENSIBLE const audio_decoder_output_types[] = { {.Format = {.wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 48000, .nChannels = 2, .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)}}, @@ -53,7 +53,7 @@ static const UINT32 default_channel_mask[7] = KSAUDIO_SPEAKER_5POINT1, }; -struct aac_decoder +struct audio_decoder { IMFTransform IMFTransform_iface; LONG refcount; @@ -68,12 +68,12 @@ struct aac_decoder struct wg_sample_queue *wg_sample_queue; }; -static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) +static struct audio_decoder *impl_from_IMFTransform(IMFTransform *iface) { - return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); + return CONTAINING_RECORD(iface, struct audio_decoder, IMFTransform_iface); } -static HRESULT try_create_wg_transform(struct aac_decoder *decoder) +static HRESULT try_create_wg_transform(struct audio_decoder *decoder) { struct wg_transform_attrs attrs = {0}; @@ -88,7 +88,7 @@ static HRESULT try_create_wg_transform(struct aac_decoder *decoder) static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -107,7 +107,7 @@ static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedIncrement(&decoder->refcount); TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); return refcount; @@ -115,7 +115,7 @@ static ULONG WINAPI transform_AddRef(IMFTransform *iface) static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); ULONG refcount = InterlockedDecrement(&decoder->refcount); TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); @@ -220,7 +220,7 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); const WAVEFORMATEXTENSIBLE *format = decoder->input_types; UINT count = decoder->input_type_count; @@ -237,7 +237,7 @@ static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); UINT32 channel_count, sample_rate; WAVEFORMATEXTENSIBLE wfx = {{0}}; IMFMediaType *media_type; @@ -252,7 +252,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET; - wfx = aac_decoder_output_types[index % ARRAY_SIZE(aac_decoder_output_types)]; + wfx = audio_decoder_output_types[index % ARRAY_SIZE(audio_decoder_output_types)]; if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) || !channel_count) @@ -263,15 +263,15 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (channel_count >= ARRAY_SIZE(default_channel_mask)) return MF_E_INVALIDMEDIATYPE; - if (channel_count > 2 && index >= ARRAY_SIZE(aac_decoder_output_types)) + if (channel_count > 2 && index >= ARRAY_SIZE(audio_decoder_output_types)) { /* If there are more than two channels in the input type GetOutputAvailableType additionally lists * types with 2 channels. */ - index -= ARRAY_SIZE(aac_decoder_output_types); + index -= ARRAY_SIZE(audio_decoder_output_types); channel_count = 2; } - if (index >= ARRAY_SIZE(aac_decoder_output_types)) + if (index >= ARRAY_SIZE(audio_decoder_output_types)) return MF_E_NO_MORE_TYPES; wfx.Format.nChannels = channel_count; @@ -314,7 +314,7 @@ static BOOL matches_format(const WAVEFORMATEXTENSIBLE *a, const WAVEFORMATEXTENS static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); UINT32 size, count = decoder->input_type_count; WAVEFORMATEXTENSIBLE *format, wfx; HRESULT hr; @@ -354,7 +354,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); WAVEFORMATEXTENSIBLE *format, wfx; UINT32 size; HRESULT hr; @@ -373,10 +373,10 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF wfx = *format; CoTaskMemFree(format); - for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) - if (matches_format(&aac_decoder_output_types[i], &wfx)) + for (i = 0; i < ARRAY_SIZE(audio_decoder_output_types); ++i) + if (matches_format(&audio_decoder_output_types[i], &wfx)) break; - if (i == ARRAY_SIZE(aac_decoder_output_types)) + if (i == ARRAY_SIZE(audio_decoder_output_types)) return MF_E_INVALIDMEDIATYPE; if (!wfx.Format.wBitsPerSample || !wfx.Format.nChannels || !wfx.Format.nSamplesPerSec) @@ -403,7 +403,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *type; HRESULT hr; @@ -425,7 +425,7 @@ static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD i static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *type; HRESULT hr; @@ -447,7 +447,7 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); bool accepts_input; TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); @@ -488,7 +488,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); @@ -501,7 +501,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); + struct audio_decoder *decoder = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; HRESULT hr; @@ -577,12 +577,12 @@ static HEAACWAVEINFO aac_decoder_input_types[] = HRESULT aac_decoder_create(REFIID riid, void **ret) { - struct aac_decoder *decoder; + struct audio_decoder *decoder; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (FAILED(hr = check_audio_transform_support(&aac_decoder_input_types[0].wfx, &aac_decoder_output_types[0].Format))) + if (FAILED(hr = check_audio_transform_support(&aac_decoder_input_types[0].wfx, &audio_decoder_output_types[0].Format))) { ERR_(winediag)("GStreamer doesn't support AAC decoding, please install appropriate plugins\n"); return hr; From fe2199190d5bd2807cd923294adfe74be1744fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Jul 2023 15:46:13 +0200 Subject: [PATCH 245/301] winegstreamer: Introduce a generic audio decoder transform. CW-Bug-Id: #21953 CW-Bug-Id: #20833 --- dlls/winegstreamer/audio_decoder.c | 38 ++++++++++++++++++++ dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/mfplat.c | 23 ++++++++++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 ++++ 4 files changed, 68 insertions(+) diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/audio_decoder.c index 704a3a17e68..5b86974cab9 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -590,6 +590,9 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->refcount = 1; + decoder->input_types = (WAVEFORMATEXTENSIBLE *)aac_decoder_input_types; decoder->input_type_count = ARRAY_SIZE(aac_decoder_input_types); @@ -599,9 +602,44 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) return hr; } + *ret = &decoder->IMFTransform_iface; + TRACE("Created decoder %p\n", *ret); + return S_OK; +} + +static WAVEFORMATEXTENSIBLE audio_decoder_input_types[] = +{ +#define MAKE_WAVEFORMATEXTENSIBLE(format) \ + {.Format = {.wFormatTag = WAVE_FORMAT_EXTENSIBLE, .nChannels = 6, .nSamplesPerSec = 48000, .nAvgBytesPerSec = 1152000, \ + .nBlockAlign = 24, .wBitsPerSample = 32, .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)}, \ + .SubFormat = {format,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}}} + + MAKE_WAVEFORMATEXTENSIBLE(MAKEFOURCC('G','S','T','a')), + +#undef MAKE_WAVEFORMATEXTENSIBLE +}; + +HRESULT audio_decoder_create(REFIID riid, void **ret) +{ + struct audio_decoder *decoder; + HRESULT hr; + + TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->input_types = audio_decoder_input_types; + decoder->input_type_count = ARRAY_SIZE(audio_decoder_input_types); + + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + { + free(decoder); + return hr; + } + *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2660e908693..1693e284bdf 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -198,6 +198,7 @@ unsigned int wg_format_get_stride(const struct wg_format *format); bool wg_video_format_is_rgb(enum wg_video_format format); +HRESULT audio_decoder_create(REFIID riid, void **ret); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 7c4823b8336..64a297acae8 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -46,6 +46,7 @@ DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); +DEFINE_MEDIATYPE_GUID(MFAudioFormat_GStreamer,MAKEFOURCC('G','S','T','a')); DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); extern GUID MEDIASUBTYPE_VC1S; @@ -128,6 +129,7 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerByteStreamHandler2 = {0x317df619, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; +static const GUID CLSID_GStreamerAudioDecoder = {0x480b1517, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; @@ -138,6 +140,7 @@ static const struct class_object } class_objects[] = { + { &CLSID_GStreamerAudioDecoder, &audio_decoder_create }, { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_GStreamerByteStreamHandler2, &gstreamer_byte_stream_handler_2_create }, @@ -339,6 +342,16 @@ HRESULT mfplat_DllRegisterServer(void) {MFMediaType_Video, MFVideoFormat_NV11}, }; + MFT_REGISTER_TYPE_INFO audio_decoder_input_types[] = + { + {MFMediaType_Audio, MFAudioFormat_GStreamer}, + }; + MFT_REGISTER_TYPE_INFO audio_decoder_output_types[] = + { + {MFMediaType_Audio, MFAudioFormat_Float}, + {MFMediaType_Audio, MFAudioFormat_PCM}, + }; + struct mft { GUID clsid; @@ -468,6 +481,16 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(video_processor_output_types), video_processor_output_types, }, + { + CLSID_GStreamerAudioDecoder, + MFT_CATEGORY_AUDIO_DECODER, + L"Wine Audio Decoder MFT", + MFT_ENUM_FLAG_SYNCMFT, + ARRAY_SIZE(audio_decoder_input_types), + audio_decoder_input_types, + ARRAY_SIZE(audio_decoder_output_types), + audio_decoder_output_types, + }, }; unsigned int i; diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 493e6cff2b0..2ef6d994274 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -89,6 +89,12 @@ coclass GStreamerByteStreamHandler {} ] coclass GStreamerByteStreamHandler2 {} +[ + threading(both), + uuid(480b1517-c8e9-4eae-b006-e6300718d85d) +] +coclass GStreamerAudioDecoder {} + [ threading(both), uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) From 4a6dd89e0080d2ad5babd2c612d46542ecb9f2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 12:14:49 +0100 Subject: [PATCH 246/301] winegstreamer: Expose the generic video decoder transform. CW-Bug-Id: #21953 CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/mfplat.c | 31 ++++++++++++++++++ dlls/winegstreamer/video_decoder.c | 33 ++++++++++++++++++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 ++++ 4 files changed, 71 insertions(+) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 1693e284bdf..a19c62c5afa 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -199,6 +199,7 @@ unsigned int wg_format_get_stride(const struct wg_format *format); bool wg_video_format_is_rgb(enum wg_video_format format); HRESULT audio_decoder_create(REFIID riid, void **ret); +HRESULT video_decoder_create(REFIID riid, void **ret); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 64a297acae8..d81a34a66ba 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -47,6 +47,7 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_GStreamer,MAKEFOURCC('G','S','T','a')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_GStreamer,MAKEFOURCC('G','S','T','v')); DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); extern GUID MEDIASUBTYPE_VC1S; @@ -130,6 +131,7 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerByteStreamHandler2 = {0x317df619, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerAudioDecoder = {0x480b1517, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; +static const GUID CLSID_GStreamerVideoDecoder = {0x480b1518, 0xc8e9, 0x4eae, {0xb0, 0x06, 0xe6, 0x30, 0x07, 0x18, 0xd8, 0x5d}}; static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; @@ -141,6 +143,7 @@ static const struct class_object class_objects[] = { { &CLSID_GStreamerAudioDecoder, &audio_decoder_create }, + { &CLSID_GStreamerVideoDecoder, &video_decoder_create }, { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_GStreamerByteStreamHandler2, &gstreamer_byte_stream_handler_2_create }, @@ -352,6 +355,24 @@ HRESULT mfplat_DllRegisterServer(void) {MFMediaType_Audio, MFAudioFormat_PCM}, }; + MFT_REGISTER_TYPE_INFO video_decoder_input_types[] = + { + {MFMediaType_Video, MFVideoFormat_GStreamer}, + {MFMediaType_Video, MFVideoFormat_IV50}, + }; + MFT_REGISTER_TYPE_INFO video_decoder_output_types[] = + { + {MFMediaType_Video, MFVideoFormat_YV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + {MFMediaType_Video, MFVideoFormat_NV11}, + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_RGB32}, + {MFMediaType_Video, MFVideoFormat_RGB24}, + {MFMediaType_Video, MFVideoFormat_RGB565}, + {MFMediaType_Video, MFVideoFormat_RGB555}, + {MFMediaType_Video, MFVideoFormat_RGB8}, + }; + struct mft { GUID clsid; @@ -491,6 +512,16 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(audio_decoder_output_types), audio_decoder_output_types, }, + { + CLSID_GStreamerVideoDecoder, + MFT_CATEGORY_VIDEO_DECODER, + L"Wine Video Decoder MFT", + MFT_ENUM_FLAG_SYNCMFT, + ARRAY_SIZE(video_decoder_input_types), + video_decoder_input_types, + ARRAY_SIZE(video_decoder_output_types), + video_decoder_output_types, + }, }; unsigned int i; diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 48ac7e05cb1..a4511b91c5f 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -65,6 +65,11 @@ static const struct subtype_info subtype_info_list[] = { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, }; +extern GUID MFVideoFormat_GStreamer; +static const GUID *const video_decoder_input_types[] = +{ + &MFVideoFormat_GStreamer, +}; static const GUID *const video_decoder_output_types[] = { &MFVideoFormat_NV12, @@ -1593,6 +1598,34 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U return hr; } +HRESULT video_decoder_create(REFIID riid, void **out) +{ + struct video_decoder *decoder; + HRESULT hr; + + TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); + + if (FAILED(hr = video_decoder_create_with_types(video_decoder_input_types, ARRAY_SIZE(video_decoder_input_types), + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) + return hr; + + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->input_info.cbSize = 0x1000; + decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->output_info.cbSize = 1920 * 1088 * 2; + + decoder->wg_transform_attrs.output_plane_align = 15; + decoder->wg_transform_attrs.allow_format_change = TRUE; + + TRACE("Created video decoder transform %p.\n", &decoder->IMFTransform_iface); + + hr = IMFTransform_QueryInterface(&decoder->IMFTransform_iface, riid, out); + IMFTransform_Release(&decoder->IMFTransform_iface); + return hr; +} + static const GUID *const h264_decoder_input_types[] = { &MFVideoFormat_H264, diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 2ef6d994274..dc56ad2b0ab 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -95,6 +95,12 @@ coclass GStreamerByteStreamHandler2 {} ] coclass GStreamerAudioDecoder {} +[ + threading(both), + uuid(480b1518-c8e9-4eae-b006-e6300718d85d) +] +coclass GStreamerVideoDecoder {} + [ threading(both), uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) From 85c286e1a01f0367d4dbe54fb49d6ce274397dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Mar 2024 09:54:09 +0100 Subject: [PATCH 247/301] mfreadwrite/reader: Rely on the video processor sample allocator. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 142 -------------------------------------- 1 file changed, 142 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 7c51fbe91cf..74a0aeecf75 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -89,7 +89,6 @@ struct media_stream IMFMediaStream *stream; IMFMediaType *current; struct list transforms; - IMFVideoSampleAllocatorEx *allocator; IMFTransform *transform_service; DWORD id; unsigned int index; @@ -232,8 +231,6 @@ static void media_stream_destroy(struct media_stream *stream) IMFMediaStream_Release(stream->stream); if (stream->current) IMFMediaType_Release(stream->current); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); } static ULONG source_reader_release(struct source_reader *reader) @@ -430,39 +427,6 @@ static void source_reader_response_ready(struct source_reader *reader, struct st stream->requests--; } -static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst) -{ - IMFMediaBuffer *buffer; - LONGLONG time; - DWORD flags; - HRESULT hr; - - IMFSample_CopyAllItems(src, (IMFAttributes *)dst); - - IMFSample_SetSampleDuration(dst, 0); - IMFSample_SetSampleTime(dst, 0); - IMFSample_SetSampleFlags(dst, 0); - - if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time))) - IMFSample_SetSampleDuration(dst, time); - - if (SUCCEEDED(IMFSample_GetSampleTime(src, &time))) - IMFSample_SetSampleTime(dst, time); - - if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags))) - IMFSample_SetSampleFlags(dst, flags); - - if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL))) - { - if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer))) - { - if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer))) - WARN("Failed to copy a buffer, hr %#lx.\n", hr); - IMFMediaBuffer_Release(buffer); - } - } -} - static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status, DWORD stream_flags, LONGLONG timestamp, IMFSample *sample) { @@ -1190,8 +1154,6 @@ static struct stream_response * media_stream_detach_response(struct source_reade static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream) { struct stream_response *response; - IMFSample *sample; - HRESULT hr; LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry) { @@ -1200,26 +1162,6 @@ static struct stream_response *media_stream_pop_response(struct source_reader *r if (!stream) stream = &reader->streams[response->stream_index]; - if (response->sample && stream->allocator) - { - /* Return allocation error to the caller, while keeping original response sample in for later. */ - if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample))) - { - source_reader_copy_sample_buffer(response->sample, sample); - IMFSample_Release(response->sample); - response->sample = sample; - } - else - { - if (!(response = calloc(1, sizeof(*response)))) - return NULL; - - response->status = hr; - response->stream_flags = MF_SOURCE_READERF_ERROR; - return response; - } - } - return media_stream_detach_response(reader, response); } @@ -1632,7 +1574,6 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); ULONG refcount = InterlockedDecrement(&reader->public_refcount); - unsigned int i; TRACE("%p, refcount %lu.\n", iface, refcount); @@ -1652,22 +1593,6 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) LeaveCriticalSection(&reader->cs); } - for (i = 0; i < reader->stream_count; ++i) - { - struct media_stream *stream = &reader->streams[i]; - IMFVideoSampleAllocatorCallback *callback; - - if (!stream->allocator) - continue; - - if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback, - (void **)&callback))) - { - IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL); - IMFVideoSampleAllocatorCallback_Release(callback); - } - } - source_reader_release(reader); } @@ -1918,71 +1843,6 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea return type_set ? S_OK : S_FALSE; } -static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader, - IMFAttributes **attributes) -{ - UINT32 shared = 0, shared_without_mutex = 0; - HRESULT hr; - - if (FAILED(hr = MFCreateAttributes(attributes, 1))) - return hr; - - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared); - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex); - - if (shared_without_mutex) - hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE); - else if (shared) - hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE); - - return hr; -} - -static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index) -{ - struct media_stream *stream = &reader->streams[index]; - IMFAttributes *attributes = NULL; - GUID major = { 0 }; - HRESULT hr; - - IMFMediaType_GetMajorType(stream->current, &major); - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return S_OK; - - if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER)) - return S_OK; - - if (!stream->allocator) - { - if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator))) - { - WARN("Failed to create sample allocator, hr %#lx.\n", hr); - return hr; - } - } - - IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator); - if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager))) - { - WARN("Failed to set device manager, hr %#lx.\n", hr); - return hr; - } - - if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes))) - WARN("Failed to create allocator attributes, hr %#lx.\n", hr); - - if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, - attributes, stream->current))) - { - WARN("Failed to initialize sample allocator, hr %#lx.\n", hr); - } - - if (attributes) - IMFAttributes_Release(attributes); - - return hr; -} - static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced) { UINT32 value; @@ -2232,8 +2092,6 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D hr = source_reader_set_compatible_media_type(reader, index, type); if (hr == S_FALSE) hr = source_reader_create_decoder_for_stream(reader, index, type); - if (SUCCEEDED(hr)) - hr = source_reader_setup_sample_allocator(reader, index); LeaveCriticalSection(&reader->cs); From fd82a6832e16c1d0c635a477c2d7e0be7e76244a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 12:40:48 +0200 Subject: [PATCH 248/301] mfplat/tests: Add more tests for MFCreateMediaBufferFromMediaType. CW-Bug-Id: #20833 --- dlls/mfplat/tests/mfplat.c | 166 ++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index bbd9b17ba1e..71755607b0b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6798,8 +6798,10 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMFMediaType *media_type, *media_type2; unsigned int i, alignment; IMFMediaBuffer *buffer; + IMF2DBuffer *buffer_2d; DWORD length, max; BYTE *data; + LONG pitch; HRESULT hr; if (!pMFCreateMediaBufferFromMediaType) @@ -6814,6 +6816,22 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = MFCreateMediaType(&media_type); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &GUID_NULL); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_GetMaxLength(buffer, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(length == 16, "Got length %#lx.\n", length); + IMFMediaBuffer_Release(buffer); + } + hr = MFCreateMediaType(&media_type2); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); @@ -6874,8 +6892,154 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMFMediaBuffer_Release(buffer); } - IMFMediaType_Release(media_type); IMFMediaType_Release(media_type2); + + + hr = IMFMediaType_DeleteAllItems(media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* MF_MT_SUBTYPE is required unless min length is provided */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); + ok(max == 16, "Unexpected max length.\n"); + ok(length == 0, "Unexpected length.\n"); + ok(!((uintptr_t)data & 0xf), "%u: data at %p is misaligned.\n", i, data); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + } + + /* MF_MT_FRAME_SIZE is required unless min length is provided */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); + ok(max == 16, "Unexpected max length.\n"); + ok(length == 0, "Unexpected length.\n"); + ok(!((uintptr_t)data & 0xf), "%u: data at %p is misaligned.\n", i, data); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + } + + /* MF_MT_SAMPLE_SIZE / MF_MT_FIXED_SIZE_SAMPLES / MF_MT_COMPRESSED don't have any effect */ + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 1024); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, 0); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + + /* MF_MT_FRAME_SIZE forces the buffer size, regardless of min length */ + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)16 << 32 | 32); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); + ok(max == 2048, "Unexpected max length.\n"); + ok(length == 2048, "Unexpected length.\n"); + ok(!((uintptr_t)data & 0xf), "%u: data at %p is misaligned.\n", i, data); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(buffer_2d, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pitch == 64, "got pitch %ld.\n", pitch); + hr = IMF2DBuffer_Unlock2D(buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer_Release(buffer_2d); + + IMFMediaBuffer_Release(buffer); + } + + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 4096, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); + ok(max == 2048, "Unexpected max length.\n"); + ok(length == 2048, "Unexpected length.\n"); + ok(!((uintptr_t)data & 0xf), "%u: data at %p is misaligned.\n", i, data); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(buffer_2d, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pitch == 64, "got pitch %ld.\n", pitch); + hr = IMF2DBuffer_Unlock2D(buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer_Release(buffer_2d); + + IMFMediaBuffer_Release(buffer); + } + + /* MF_MT_DEFAULT_STRIDE is ignored as well */ + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -256); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); + ok(max == 2048, "Unexpected max length.\n"); + ok(length == 2048, "Unexpected length.\n"); + ok(!((uintptr_t)data & 0xf), "%u: data at %p is misaligned.\n", i, data); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(buffer_2d, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pitch == -64, "got pitch %ld.\n", pitch); + hr = IMF2DBuffer_Unlock2D(buffer_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer_Release(buffer_2d); + + IMFMediaBuffer_Release(buffer); + } + + hr = IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_SIZE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* MF_MT_FRAME_SIZE doesn't work with compressed formats */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_H264); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)16 << 32 | 32); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); + todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + IMFMediaType_Release(media_type); } static void validate_media_type(IMFMediaType *mediatype, const WAVEFORMATEX *format) From 4a8f3476a586098c2d1831debed1090fb5d91b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 13:41:47 +0200 Subject: [PATCH 249/301] mfplat: Implement MFCreateMediaBufferFromMediaType for video formats. CW-Bug-Id: #20833 --- dlls/mfplat/buffer.c | 26 ++++++++++++++++++---- dlls/mfplat/tests/mfplat.c | 44 +++++++++++--------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index b7f32f12cdc..acea6482ab9 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1688,8 +1688,10 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO { UINT32 length = 0, block_alignment; LONGLONG avg_length; + GUID major, subtype; + UINT64 frame_size; + BOOL is_yuv; HRESULT hr; - GUID major; TRACE("%p, %s, %lu, %lu, %p.\n", media_type, debugstr_time(duration), min_length, alignment, buffer); @@ -1731,8 +1733,24 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO return create_1d_buffer(length, alignment - 1, buffer); } - else - FIXME("Major type %s is not supported.\n", debugstr_guid(&major)); + else if (IsEqualGUID(&major, &MFMediaType_Video) + && SUCCEEDED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)) + && SUCCEEDED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)) + && mf_format_get_stride(&subtype, frame_size >> 32, &is_yuv)) + { + BOOL bottom_up = FALSE; + UINT32 stride; - return E_NOTIMPL; + if (!is_yuv && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, &stride))) + bottom_up = (int)stride < 0; + + if (SUCCEEDED(hr = create_2d_buffer(frame_size >> 32, (UINT32)frame_size, subtype.Data1, bottom_up, buffer))) + return hr; + } + + if (!min_length) + return FAILED(hr) ? hr : E_INVALIDARG; + + alignment = max(16, alignment); + return create_1d_buffer(min_length, alignment - 1, buffer); } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 71755607b0b..75fe480efc9 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6821,16 +6821,13 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &GUID_NULL); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_GetMaxLength(buffer, &length); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(length == 16, "Got length %#lx.\n", length); IMFMediaBuffer_Release(buffer); - } hr = MFCreateMediaType(&media_type2); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); @@ -6902,11 +6899,9 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); ok(max == 16, "Unexpected max length.\n"); @@ -6915,17 +6910,14 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = IMFMediaBuffer_Unlock(buffer); ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); IMFMediaBuffer_Release(buffer); - } /* MF_MT_FRAME_SIZE is required unless min length is provided */ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 16, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); ok(max == 16, "Unexpected max length.\n"); @@ -6934,29 +6926,26 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = IMFMediaBuffer_Unlock(buffer); ok(hr == S_OK, "Failed to unlock, hr %#lx.\n", hr); IMFMediaBuffer_Release(buffer); - } /* MF_MT_SAMPLE_SIZE / MF_MT_FIXED_SIZE_SAMPLES / MF_MT_COMPRESSED don't have any effect */ hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, 1024); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); hr = IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, 0); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); /* MF_MT_FRAME_SIZE forces the buffer size, regardless of min length */ hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)16 << 32 | 32); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); ok(max == 2048, "Unexpected max length.\n"); @@ -6975,12 +6964,9 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMF2DBuffer_Release(buffer_2d); IMFMediaBuffer_Release(buffer); - } hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 4096, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); ok(max == 2048, "Unexpected max length.\n"); @@ -6999,15 +6985,12 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMF2DBuffer_Release(buffer_2d); IMFMediaBuffer_Release(buffer); - } /* MF_MT_DEFAULT_STRIDE is ignored as well */ hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, -256); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); ok(hr == S_OK, "Failed to lock, hr %#lx.\n", hr); ok(max == 2048, "Unexpected max length.\n"); @@ -7026,7 +7009,6 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMF2DBuffer_Release(buffer_2d); IMFMediaBuffer_Release(buffer); - } hr = IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_SIZE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7037,7 +7019,7 @@ static void test_MFCreateMediaBufferFromMediaType(void) hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)16 << 32 | 32); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = pMFCreateMediaBufferFromMediaType(media_type, 0, 0, 0, &buffer); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); } From 4bca37bd375f2a24658655791579b05ac9153583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Mar 2024 09:54:09 +0100 Subject: [PATCH 250/301] mfreadwrite/reader: Use MFCreateMediaBufferFromMediaType to allocate samples. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 23 ++++++++++++++--------- dlls/mfreadwrite/tests/mfplat.c | 6 +++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 74a0aeecf75..872c0dbd804 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -645,26 +645,31 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); } -static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) +static HRESULT source_reader_allocate_stream_sample(IMFTransform *transform, MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) { + IMFMediaType *media_type; IMFMediaBuffer *buffer; IMFSample *sample; HRESULT hr; *out = NULL; - if (FAILED(hr = MFCreateSample(&sample))) + if (SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type))) + { + hr = MFCreateMediaBufferFromMediaType(media_type, 10000000, info->cbSize, info->cbAlignment, &buffer); + IMFMediaType_Release(media_type); + } + if (FAILED(hr) && FAILED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer))) return hr; - if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer))) + + if (SUCCEEDED(hr = MFCreateSample(&sample))) { if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer))) - { *out = sample; - IMFSample_AddRef(sample); - } - IMFMediaBuffer_Release(buffer); + else + IMFSample_Release(sample); } - IMFSample_Release(sample); + IMFMediaBuffer_Release(buffer); return hr; } @@ -840,7 +845,7 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader IMFMediaType *media_type; if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) - && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) + && FAILED(hr = source_reader_allocate_stream_sample(entry->transform, &stream_info, &out_buffer.pSample))) break; if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index b813c6639ce..d262516056b 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2644,11 +2644,11 @@ static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flag hr = IMFSample_GetBufferByIndex(data->pSample, 0, &buffer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine check_interface(buffer, &IID_IMF2DBuffer2, TRUE); - todo_wine check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); hr = MFGetService((IUnknown *)buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)&unknown); - todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); IMFMediaBuffer_Release(buffer); } From d7a04656a9b4e68747d3b29de21c00bc1fa11918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Apr 2024 12:03:54 +0200 Subject: [PATCH 251/301] mfreadwrite/reader: Request MF_LOW_LATENCY on stream transforms. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 872c0dbd804..775f96aa4b4 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1948,6 +1948,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager); } + IMFAttributes_SetUINT32(attributes, &MF_LOW_LATENCY, 1); entry->attributes_initialized = !d3d_aware; IMFAttributes_Release(attributes); } From 67a068f8b05b4813c1f306d624e89aa3b4f56c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 May 2024 14:59:50 +0200 Subject: [PATCH 252/301] mfreadwrite/reader: Shutdown the queue when public ref is released. Instead of internal ref, otherwise an executing callback might be the one releasing the last ref, and MFUnlockWorkQueue will cancel and then block waiting for the callback itself to finish executing. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 775f96aa4b4..7f30c7776f9 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -257,7 +257,6 @@ static ULONG source_reader_release(struct source_reader *reader) } source_reader_release_responses(reader, NULL); free(reader->streams); - MFUnlockWorkQueue(reader->queue); DeleteCriticalSection(&reader->cs); free(reader); } @@ -1598,6 +1597,7 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) LeaveCriticalSection(&reader->cs); } + MFUnlockWorkQueue(reader->queue); source_reader_release(reader); } From b3de2f79fcf76feb6b6baf914766fbd9668bb3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 May 2024 11:30:15 +0200 Subject: [PATCH 253/301] mf/session: Don't update transform output type if not needed. CW-Bug-Id: #20833 --- dlls/mf/session.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index c57a2861938..eaf5a3a8b1e 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3296,6 +3296,13 @@ static HRESULT transform_stream_update_input_type(struct topo_node *node, UINT i struct transform_stream *stream = &node->u.transform.outputs[output]; UINT id = transform_node_get_stream_id(node, TRUE, output); + /* check if transform output type is still valid or if we need to update it as well */ + if (SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(node->object.transform, id, &new_output_type))) + { + IMFMediaType_Release(new_output_type); + continue; + } + if (SUCCEEDED(hr = transform_stream_update_output_type(node, stream, id, old_output_types[output], &new_output_type))) { From 057f59320715fb04b6c216d145065df882251672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 May 2024 18:04:48 +0200 Subject: [PATCH 254/301] mf/session: Implement D3D device manager propagation. CW-Bug-Id: #20833 --- dlls/mf/mf_private.h | 4 ++ dlls/mf/session.c | 17 +++++ dlls/mf/topology_loader.c | 126 +++++++++++++++++++++++++++++++------- 3 files changed, 125 insertions(+), 22 deletions(-) diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index bbfadaee5d8..726592654c5 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -121,3 +121,7 @@ extern BOOL mf_is_sar_sink(IMFMediaSink *sink); extern HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj); extern HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler); extern HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); + +extern BOOL topology_node_is_d3d_aware(IMFTopologyNode *node); +extern HRESULT topology_node_set_device_manager(IMFTopologyNode *node, IUnknown *device_manager); +extern HRESULT stream_sink_get_device_manager(IMFStreamSink *stream_sink, IUnknown **device_manager); \ No newline at end of file diff --git a/dlls/mf/session.c b/dlls/mf/session.c index eaf5a3a8b1e..0bdd4d606e3 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1746,6 +1746,8 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink))) { + IUnknown *device_manager; + if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type))) { if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE, @@ -1763,6 +1765,21 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod } IMFMediaType_Release(media_type); } + + if (SUCCEEDED(stream_sink_get_device_manager(topo_node->object.sink_stream, &device_manager))) + { + IMFTopologyNode *upstream; + DWORD output; + + if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream, &output))) + { + if (topology_node_is_d3d_aware(upstream)) + topology_node_set_device_manager(upstream, device_manager); + IMFTopologyNode_Release(upstream); + } + + IUnknown_Release(device_manager); + } } IMFMediaSink_Release(media_sink); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 447fbfa04dd..3be64055245 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -24,6 +24,9 @@ #include "winbase.h" #include "mfidl.h" +#include "evr.h" +#include "d3d9.h" +#include "dxva2api.h" #include "wine/debug.h" #include "wine/list.h" @@ -567,25 +570,35 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte return hr; } -static BOOL topology_loader_is_node_d3d_aware(IMFTopologyNode *node) +static BOOL topology_node_get_object_attributes(IMFTopologyNode *node, IMFAttributes **attributes) { - IMFAttributes *attributes; - unsigned int d3d_aware = 0; IMFTransform *transform; + HRESULT hr; - if (FAILED(topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes))) - return FALSE; - - IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware); - IMFAttributes_Release(attributes); - - if (!d3d_aware && SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) { - d3d_aware = mf_is_sample_copier_transform(transform); + hr = IMFTransform_GetAttributes(transform, attributes); IMFTransform_Release(transform); + return hr; } - return !!d3d_aware; + return topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes); +} + +BOOL topology_node_is_d3d_aware(IMFTopologyNode *node) +{ + UINT32 d3d_aware, d3d11_aware; + IMFAttributes *attributes; + + if (FAILED(topology_node_get_object_attributes(node, &attributes))) + return FALSE; + if (FAILED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware))) + d3d_aware = FALSE; + if (FAILED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &d3d11_aware))) + d3d11_aware = FALSE; + IMFAttributes_Release(attributes); + + return d3d_aware || d3d11_aware; } static HRESULT topology_loader_create_copier(IMFTopologyNode *upstream_node, DWORD upstream_output, @@ -641,33 +654,98 @@ static HRESULT topology_loader_connect_copier(struct topoloader_context *context return S_OK; } +HRESULT topology_node_set_device_manager(IMFTopologyNode *node, IUnknown *device_manager) +{ + IMFTransform *transform; + HRESULT hr; + + if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + { + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (LONG_PTR)device_manager); + IMFTransform_Release(transform); + } + + if (SUCCEEDED(hr)) + { + IMFTopologyNode *upstream; + DWORD i, count, output; + + hr = IMFTopologyNode_GetInputCount(node, &count); + + for (i = 0; SUCCEEDED(hr) && i < count; i++) + { + if (FAILED(IMFTopologyNode_GetInput(node, 0, &upstream, &output))) + continue; + + if (topology_node_is_d3d_aware(upstream)) + topology_node_set_device_manager(upstream, device_manager); + + IMFTopologyNode_Release(upstream); + } + } + + return hr; +} + +HRESULT stream_sink_get_device_manager(IMFStreamSink *stream_sink, IUnknown **device_manager) +{ + HRESULT hr; + + if (SUCCEEDED(hr = MFGetService((IUnknown *)stream_sink, &MR_VIDEO_ACCELERATION_SERVICE, + &IID_IMFDXGIDeviceManager, (void **)device_manager))) + return hr; + if (SUCCEEDED(hr = MFGetService((IUnknown *)stream_sink, &MR_VIDEO_ACCELERATION_SERVICE, + &IID_IDirect3DDeviceManager9, (void **)device_manager))) + return hr; + + return hr; +} + /* Right now this should be used for output nodes only. */ -static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context *context, - IMFTopologyNode *node) +static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context *context, + IMFTopologyNode *node, MFTOPOLOGY_DXVA_MODE dxva_mode) { IMFTopologyNode *upstream_node; IMFTransform *copier = NULL; IMFStreamSink *stream_sink; + IUnknown *device_manager; DWORD upstream_output; HRESULT hr; if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) return hr; - if (topology_loader_is_node_d3d_aware(node)) + if (SUCCEEDED(hr = stream_sink_get_device_manager(stream_sink, &device_manager))) { if (SUCCEEDED(IMFTopologyNode_GetInput(node, 0, &upstream_node, &upstream_output))) { - if (!topology_loader_is_node_d3d_aware(upstream_node)) + BOOL needs_copier = dxva_mode == MFTOPOLOGY_DXVA_DEFAULT; + IMFTransform *transform; + + if (needs_copier && SUCCEEDED(topology_node_get_object(upstream_node, &IID_IMFTransform, (void **)&transform))) { - if (SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) - { - hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); - IMFTransform_Release(copier); - } + MFT_OUTPUT_STREAM_INFO info = {0}; + + if (FAILED(IMFTransform_GetOutputStreamInfo(transform, upstream_output, &info)) + || !(info.dwFlags & (MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))) + needs_copier = FALSE; + + IMFTransform_Release(transform); } + + if (needs_copier && SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) + { + hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); + IMFTransform_Release(copier); + } + + if (dxva_mode == MFTOPOLOGY_DXVA_FULL && topology_node_is_d3d_aware(upstream_node)) + topology_node_set_device_manager(upstream_node, device_manager); + IMFTopologyNode_Release(upstream_node); } + + IUnknown_Release(device_manager); } IMFStreamSink_Release(stream_sink); @@ -677,6 +755,7 @@ static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context static void topology_loader_resolve_complete(struct topoloader_context *context) { + MFTOPOLOGY_DXVA_MODE dxva_mode; MF_TOPOLOGY_TYPE node_type; IMFTopologyNode *node; WORD i, node_count; @@ -684,6 +763,9 @@ static void topology_loader_resolve_complete(struct topoloader_context *context) IMFTopology_GetNodeCount(context->output_topology, &node_count); + if (FAILED(IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_DXVA_MODE, (UINT32 *)&dxva_mode))) + dxva_mode = 0; + for (i = 0; i < node_count; ++i) { if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node))) @@ -696,7 +778,7 @@ static void topology_loader_resolve_complete(struct topoloader_context *context) if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL))) IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0); - if (FAILED(hr = topology_loader_connect_d3d_aware_input(context, node))) + if (FAILED(hr = topology_loader_connect_d3d_aware_sink(context, node, dxva_mode))) WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr); } else if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) From 27efe2f693572c11ffd7ba46afed88da9bff847e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Apr 2024 13:08:27 +0200 Subject: [PATCH 255/301] mf/session: Keep previously allocated sample with the transform streams. CW-Bug-Id: #20833 --- dlls/mf/session.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 0bdd4d606e3..4f94d3c30a7 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -155,6 +155,7 @@ struct transform_stream struct list samples; unsigned int requests; unsigned int min_buffer_size; + IMFSample *allocated_sample; BOOL draining; }; @@ -748,6 +749,12 @@ static void transform_stream_drop_events(struct transform_stream *stream) { IMFMediaEvent *event; + if (stream->allocated_sample) + { + IMFSample_Release(stream->allocated_sample); + stream->allocated_sample = NULL; + } + while (SUCCEEDED(transform_stream_pop_event(stream, &event))) IMFMediaEvent_Release(event); } @@ -3177,12 +3184,22 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform, DWORD output, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) { + struct transform_stream *stream = &transform->u.transform.outputs[output]; + DWORD buffer_size, sample_size, input; IMFMediaBuffer *buffer = NULL; struct topo_node *topo_node; - unsigned int buffer_size; - DWORD input; HRESULT hr; + buffer_size = max(stream_info->cbSize, stream->min_buffer_size); + if ((*sample = stream->allocated_sample)) + { + stream->allocated_sample = NULL; + if (SUCCEEDED(IMFSample_GetTotalLength(*sample, &sample_size)) && sample_size >= buffer_size) + return S_OK; + IMFSample_Release(*sample); + *sample = NULL; + } + if (!(topo_node = session_get_topo_node_output(session, transform, output, &input))) { WARN("Failed to node %p/%lu output.\n", transform, output); @@ -3195,8 +3212,6 @@ static HRESULT transform_get_external_output_sample(const struct media_session * } else { - buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output].min_buffer_size); - hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer); if (SUCCEEDED(hr)) hr = MFCreateSample(sample); @@ -3414,6 +3429,11 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) WARN("Failed to queue output sample, hr %#lx\n", hr); } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && !stream->allocated_sample) + { + stream->allocated_sample = buffers[i].pSample; + buffers[i].pSample = NULL; + } } done: From ba81b7854ac948c6f059ac4038085bd9014c210b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 May 2024 12:07:07 +0200 Subject: [PATCH 256/301] winegstreamer: Support hardware buffer conversion with D3D11 video processor. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_processor.c | 270 ++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 8 deletions(-) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 4afdddcb036..097f0fb5da6 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -23,6 +23,9 @@ #include "mftransform.h" #include "wmcodecdsp.h" +#include "initguid.h" +#include "d3d11.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -84,6 +87,7 @@ struct video_processor IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; + IMFSample *input_sample; wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -182,6 +186,237 @@ static HRESULT video_processor_uninit_allocator(struct video_processor *processo return hr; } +static HRESULT video_processor_get_d3d11_resource(IMFSample *sample, ID3D11Resource **resource) +{ + IMFMediaBuffer *buffer; + DWORD count; + HRESULT hr; + + if (FAILED(IMFSample_GetBufferCount(sample, &count)) || count > 1) + return E_FAIL; + + if (SUCCEEDED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer))) + { + IMFDXGIBuffer *dxgi_buffer; + + if (SUCCEEDED(hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer))) + { + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Resource, (void **)resource); + IMFDXGIBuffer_Release(dxgi_buffer); + } + + IMFMediaBuffer_Release(buffer); + } + + return hr; +} + +static HRESULT get_d3d11_video_device(ID3D11Resource *resource, ID3D11VideoDevice **video_device) +{ + ID3D11Device *device; + HRESULT hr; + + ID3D11Resource_GetDevice(resource, &device); + hr = ID3D11Device_QueryInterface(device, &IID_ID3D11VideoDevice, (void **)video_device); + ID3D11Device_Release(device); + return hr; +} + +static HRESULT get_d3d11_video_context(ID3D11Resource *resource, ID3D11VideoContext **video_context) +{ + ID3D11DeviceContext *context; + ID3D11Device *device; + HRESULT hr; + + ID3D11Resource_GetDevice(resource, &device); + ID3D11Device_GetImmediateContext(device, &context); + hr = ID3D11DeviceContext_QueryInterface(context, &IID_ID3D11VideoContext, (void **)video_context); + ID3D11DeviceContext_Release(context); + ID3D11Device_Release(device); + return hr; +} + +static HRESULT create_video_processor_enumerator(ID3D11Resource *resource, UINT64 input_size, UINT64 output_size, + ID3D11VideoDevice **video_device, ID3D11VideoProcessorEnumerator **enumerator) +{ + D3D11_VIDEO_PROCESSOR_CONTENT_DESC enum_desc = {0}; + HRESULT hr; + + enum_desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; + enum_desc.InputFrameRate.Denominator = 1; + enum_desc.InputFrameRate.Numerator = 1; + enum_desc.InputWidth = input_size >> 32; + enum_desc.InputHeight = (UINT32)input_size; + enum_desc.OutputFrameRate.Denominator = 1; + enum_desc.OutputFrameRate.Numerator = 1; + enum_desc.OutputWidth = output_size >> 32; + enum_desc.OutputHeight = (UINT32)output_size; + enum_desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL; + + if (FAILED(hr = get_d3d11_video_device(resource, video_device))) + return hr; + if (FAILED(hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(*video_device, &enum_desc, enumerator))) + { + ID3D11VideoDevice_Release(*video_device); + *video_device = NULL; + } + + return hr; +} + +struct resource_desc +{ + GUID subtype; + UINT64 frame_size; +}; + +static HRESULT init_d3d11_video_processor(const struct resource_desc *input_desc, ID3D11Resource *input, + const struct resource_desc *output_desc, ID3D11Resource *output, ID3D11VideoProcessor **processor, + ID3D11VideoProcessorInputView **input_view, ID3D11VideoProcessorOutputView **output_view) +{ + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_view_desc = {0}; + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_view_desc = {0}; + ID3D11VideoProcessorEnumerator *enumerator; + UINT input_flags = 0, output_flags = 0; + ID3D11VideoDevice *device; + HRESULT hr; + + *processor = NULL; + *input_view = NULL; + *output_view = NULL; + + input_view_desc.FourCC = input_desc->subtype.Data1; + input_view_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; + input_view_desc.Texture2D.MipSlice = 0; + input_view_desc.Texture2D.ArraySlice = 0; + + output_view_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; + output_view_desc.Texture2D.MipSlice = 0; + + /* assume input and output have the same device */ + if (FAILED(hr = create_video_processor_enumerator(input, input_desc->frame_size, + output_desc->frame_size, &device, &enumerator))) + return hr; + + if (FAILED(hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(enumerator, + input_desc->subtype.Data1, &input_flags)) + || FAILED(hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(enumerator, + output_desc->subtype.Data1, &output_flags))) + goto failed; + if (!(input_flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT) + || !(output_flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT)) + { + hr = MF_E_INVALIDMEDIATYPE; + goto failed; + } + + if (FAILED(hr = ID3D11VideoDevice_CreateVideoProcessorInputView(device, input, enumerator, + &input_view_desc, input_view))) + goto failed; + if (FAILED(hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(device, output, enumerator, + &output_view_desc, output_view))) + { + ID3D11VideoProcessorInputView_Release(*input_view); + *input_view = NULL; + goto failed; + } + + if (FAILED(hr = ID3D11VideoDevice_CreateVideoProcessor(device, enumerator, 0, processor))) + { + ID3D11VideoProcessorOutputView_Release(*output_view); + *output_view = NULL; + ID3D11VideoProcessorInputView_Release(*input_view); + *input_view = NULL; + goto failed; + } + +failed: + ID3D11VideoProcessorEnumerator_Release(enumerator); + ID3D11VideoDevice_Release(device); + return hr; +} + +static HRESULT video_processor_process_output_d3d11(struct video_processor *processor, + IMFSample *input_sample, IMFSample *output_sample) +{ + D3D11_VIDEO_PROCESSOR_STREAM streams = {0}; + struct resource_desc input_desc, output_desc; + ID3D11VideoProcessorOutputView *output_view; + ID3D11VideoProcessorInputView *input_view; + ID3D11VideoProcessor *video_processor; + ID3D11VideoContext *video_context; + ID3D11Resource *input, *output; + MFVideoArea aperture; + RECT rect = {0}; + LONGLONG time; + DWORD flags; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetUINT64(processor->input_type, &MF_MT_FRAME_SIZE, &input_desc.frame_size)) + || FAILED(hr = IMFMediaType_GetGUID(processor->input_type, &MF_MT_SUBTYPE, &input_desc.subtype)) + || FAILED(hr = IMFMediaType_GetUINT64(processor->output_type, &MF_MT_FRAME_SIZE, &output_desc.frame_size)) + || FAILED(hr = IMFMediaType_GetGUID(processor->output_type, &MF_MT_SUBTYPE, &output_desc.subtype))) + return hr; + + if (FAILED(hr = video_processor_get_d3d11_resource(input_sample, &input))) + return hr; + if (FAILED(hr = video_processor_get_d3d11_resource(output_sample, &output))) + { + ID3D11Resource_Release(input); + return hr; + } + + if (FAILED(hr = get_d3d11_video_context(input, &video_context))) + goto failed; + if (FAILED(hr = init_d3d11_video_processor(&input_desc, input, &output_desc, output, + &video_processor, &input_view, &output_view))) + { + ID3D11VideoContext_Release(video_context); + goto failed; + } + + streams.Enable = TRUE; + streams.OutputIndex = 0; + streams.InputFrameOrField = 0; + streams.PastFrames = 0; + streams.FutureFrames = 0; + streams.pInputSurface = input_view; + + if (SUCCEEDED(IMFMediaType_GetBlob(processor->input_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), NULL))) + SetRect(&rect, aperture.OffsetX.value, aperture.OffsetY.value, aperture.OffsetX.value + aperture.Area.cx, + aperture.OffsetY.value + aperture.Area.cy); + else + SetRect(&rect, 0, 0, input_desc.frame_size >> 32, (UINT32)input_desc.frame_size); + ID3D11VideoContext_VideoProcessorSetStreamSourceRect(video_context, video_processor, 0, TRUE, &rect); + + if (SUCCEEDED(IMFMediaType_GetBlob(processor->output_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture), NULL))) + SetRect(&rect, aperture.OffsetX.value, aperture.OffsetY.value, aperture.OffsetX.value + aperture.Area.cx, + aperture.OffsetY.value + aperture.Area.cy); + else + SetRect(&rect, 0, 0, output_desc.frame_size >> 32, (UINT32)output_desc.frame_size); + ID3D11VideoContext_VideoProcessorSetStreamDestRect(video_context, video_processor, 0, TRUE, &rect); + + ID3D11VideoContext_VideoProcessorBlt(video_context, video_processor, output_view, 0, 1, &streams); + + IMFSample_CopyAllItems(input_sample, (IMFAttributes *)output_sample); + if (SUCCEEDED(IMFSample_GetSampleDuration(input_sample, &time))) + IMFSample_SetSampleDuration(output_sample, time); + if (SUCCEEDED(IMFSample_GetSampleTime(input_sample, &time))) + IMFSample_SetSampleTime(output_sample, time); + if (SUCCEEDED(IMFSample_GetSampleFlags(input_sample, &flags))) + IMFSample_SetSampleFlags(output_sample, flags); + + ID3D11VideoProcessorOutputView_Release(output_view); + ID3D11VideoProcessorInputView_Release(input_view); + ID3D11VideoProcessor_Release(video_processor); + ID3D11VideoContext_Release(video_context); + +failed: + ID3D11Resource_Release(output); + ID3D11Resource_Release(input); + return hr; +} + static struct video_processor *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_processor, IMFTransform_iface); @@ -655,8 +890,12 @@ static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id if (!impl->wg_transform) return MF_E_TRANSFORM_TYPE_NOT_SET; + if (impl->input_sample) + return MF_E_NOTACCEPTING; - return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue); + impl->input_sample = sample; + IMFSample_AddRef(impl->input_sample); + return S_OK; } static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, @@ -664,7 +903,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f { struct video_processor *impl = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; - IMFSample *output_sample; + IMFSample *input_sample, *output_sample; HRESULT hr; TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -679,23 +918,37 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) return hr; + if (!(input_sample = impl->input_sample)) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + impl->input_sample = NULL; + if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { - if (FAILED(hr = video_processor_init_allocator(impl))) - return hr; - if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(impl->allocator, &output_sample))) + if (FAILED(hr = video_processor_init_allocator(impl)) + || FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(impl->allocator, &output_sample))) + { + IMFSample_Release(input_sample); return hr; + } } else { if (!(output_sample = samples->pSample)) + { + IMFSample_Release(input_sample); return E_INVALIDARG; + } IMFSample_AddRef(output_sample); } - if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, &samples->dwStatus))) - goto done; - wg_sample_queue_flush(impl->wg_sample_queue, false); + if (FAILED(hr = video_processor_process_output_d3d11(impl, input_sample, output_sample))) + { + if (FAILED(hr = wg_transform_push_mf(impl->wg_transform, input_sample, impl->wg_sample_queue))) + goto done; + if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, &samples->dwStatus))) + goto done; + wg_sample_queue_flush(impl->wg_sample_queue, false); + } if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { @@ -705,6 +958,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f done: IMFSample_Release(output_sample); + IMFSample_Release(input_sample); return hr; } From 5b99a17536c3b26677c68595106df9e5745667c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 May 2024 21:12:06 +0200 Subject: [PATCH 257/301] winegstreamer/media-converter: Push segment event before data in push mode. CW-Bug-Id: #20833 --- .../winegstreamer/media-converter/videoconv.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dlls/winegstreamer/media-converter/videoconv.c b/dlls/winegstreamer/media-converter/videoconv.c index d3cb624629f..d976cd2d05c 100644 --- a/dlls/winegstreamer/media-converter/videoconv.c +++ b/dlls/winegstreamer/media-converter/videoconv.c @@ -759,6 +759,23 @@ static gboolean video_conv_push_caps(VideoConv *conv, uint32_t transcode_tag) return ret; } +static gboolean video_conv_push_segment(VideoConv *conv) +{ + struct video_conv_state *state; + GstSegment segment; + + gst_segment_init(&segment, GST_FORMAT_BYTES); + if (!(state = video_conv_lock_state(conv))) + { + GST_ERROR("VideoConv not yet in READY state?"); + return false; + } + segment.stop = state->our_duration; + pthread_mutex_unlock(&conv->state_mutex); + + return push_event(conv->src_pad, gst_event_new_segment(&segment)); +} + static gboolean video_conv_sink_event_caps(VideoConv *conv, GstEvent *event) { struct video_conv_state *state; @@ -843,6 +860,8 @@ static gboolean video_conv_sink_event_eos(VideoConv *conv, GstEvent *event) return false; if (!video_conv_push_caps(conv, transcode_tag)) return false; + if (!video_conv_push_segment(conv)) + return false; /* return false to cancel upstream pads EOS event handling and avoid setting EOS flag */ return false; From be8d19a44a0dbbd66bfe8d4172fddfd3d56db397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 29 Mar 2024 16:27:16 +0100 Subject: [PATCH 258/301] winegstreamer/new_media_source: Use proton demuxer for unsupported formats. CW-Bug-Id: #20833 --- dlls/winegstreamer/unixlib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index a285db2c866..5c2a14ee2f9 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -150,6 +150,10 @@ GstElement *find_element(GstElementFactoryListType type, GstCaps *element_sink_c continue; } + /* ignore protonvideoconverter when manually creating element, use protondemuxer instead */ + if (!strcmp(name, "protonvideoconverter")) + continue; + element = factory_create_element(GST_ELEMENT_FACTORY(tmp->data)); } From 43dc445727a34074aa639978e52f796fc040eaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 May 2024 19:21:27 +0200 Subject: [PATCH 259/301] HACK: winegstreamer/wg_source: Check if stream caps can be decoded or fallback to transcoding. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 111 +++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 4b4a2ab621c..672b4078dc2 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -55,6 +55,7 @@ struct wg_source gchar *url; GstPad *src_pad; GstElement *container; + bool needs_transcoding; GstSegment segment; guint64 max_duration; @@ -385,14 +386,71 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu return GST_FLOW_OK; } +static gboolean check_decoding_support(GstCaps *caps) +{ + GstElement *element, *bin = gst_bin_new("decode-test"), *first = NULL, *last = NULL; + GstPad *peer, *src_pad, *sink_pad; + GstPadTemplate *template; + gboolean ret = false; + + template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps); + src_pad = gst_pad_new_from_template(template, "src"); + g_object_unref(template); + + template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_CAPS_ANY); + sink_pad = gst_pad_new_from_template(template, "sink"); + g_object_unref(template); + + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, caps, GST_CAPS_ANY)) + || !append_element(bin, element, &first, &last)) + goto done; + gst_util_set_object_arg(G_OBJECT(element), "max-threads", "1"); + gst_util_set_object_arg(G_OBJECT(element), "n-threads", "1"); + + if (!link_src_to_element(src_pad, first) || !link_element_to_sink(last, sink_pad) + || !gst_pad_set_active(src_pad, 1) || !gst_pad_set_active(sink_pad, 1)) + goto done; + + gst_element_set_state(bin, GST_STATE_PAUSED); + if (!gst_element_get_state(bin, NULL, NULL, -1) + || !push_event(src_pad, gst_event_new_stream_start("stream")) + || !push_event(src_pad, gst_event_new_caps(caps))) + goto done; + + /* check that the caps event has been accepted */ + if ((peer = gst_pad_get_peer(src_pad))) + { + GST_ERROR("pad %"GST_PTR_FORMAT, peer); + ret = gst_pad_has_current_caps(peer); + gst_object_unref(peer); + } + +done: + gst_element_set_state(bin, GST_STATE_NULL); + gst_object_unref(src_pad); + gst_object_unref(bin); + return ret; +} + static gboolean sink_event_caps(struct wg_source *source, GstPad *pad, GstEvent *event) { struct source_stream *stream = source_stream_from_pad(source, pad); + const char *mime_type; GstCaps *caps; GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); gst_event_parse_caps(event, &caps); + mime_type = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + + if (strcmp(mime_type, "audio/x-raw") && strcmp(mime_type, "video/x-raw") + && !check_decoding_support(caps)) + { + GST_ERROR("Cannot decode caps %"GST_PTR_FORMAT, caps); + source->needs_transcoding = true; + gst_event_unref(event); + return false; + } gst_stream_set_caps(stream->stream, gst_caps_copy(caps)); gst_stream_set_stream_type(stream->stream, stream_type_from_caps(caps)); @@ -647,6 +705,56 @@ NTSTATUS wg_source_create(void *args) return STATUS_UNSUCCESSFUL; } +static NTSTATUS initialize_transcoding(struct wg_source *source) +{ + GstElement *element, *first = NULL, *last = NULL; + GstEvent *event; + guint i; + + gst_element_set_state(source->container, GST_STATE_NULL); + gst_object_unref(source->container); + + for (i = 0; i < ARRAY_SIZE(source->streams); i++) + gst_pad_set_active(source->streams[i].pad, false); + gst_pad_set_active(source->src_pad, false); + + while ((event = gst_atomic_queue_pop(source->seek_queue))) + gst_event_unref(event); + + source->segment.start = 0; + source->needs_transcoding = false; + source->max_duration = 0; + source->stream_count = 0; + + if (!(source->container = gst_bin_new("wg_source"))) + goto error; + GST_OBJECT_FLAG_SET(source->container, GST_BIN_FLAG_STREAMS_AWARE); + + if (!(element = create_element("protondemuxer", "proton")) + || !append_element(source->container, element, &first, &last)) + goto error; + g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), source); + + if (!link_src_to_element(source->src_pad, first)) + goto error; + if (!gst_pad_set_active(source->src_pad, true)) + goto error; + + gst_element_set_state(source->container, GST_STATE_PAUSED); + if (!gst_element_get_state(source->container, NULL, NULL, -1)) + goto error; + + push_event(source->src_pad, create_stream_start_event("wg_source")); + push_event(source->src_pad, gst_event_new_segment(&source->segment)); + + GST_INFO("Re-initialized source %p.", source); + return STATUS_SUCCESS; + +error: + GST_ERROR("Failed to re-initialize source %p", source); + return STATUS_UNSUCCESSFUL; +} + NTSTATUS wg_source_destroy(void *args) { struct wg_source *source = get_source(*(wg_source_t *)args); @@ -788,6 +896,9 @@ NTSTATUS wg_source_push_data(void *args) if (!(ret = gst_pad_push(source->src_pad, buffer)) || ret == GST_FLOW_EOS) return STATUS_SUCCESS; + if (source->needs_transcoding) + return initialize_transcoding(source); + GST_WARNING("Failed to push data buffer, ret %d", ret); source->segment.start -= params->size; return STATUS_UNSUCCESSFUL; From f39c9d20b24ee82ddf17f507b56a0ac4c728275c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Jan 2024 17:36:45 +0100 Subject: [PATCH 260/301] HACK: mfplat: Enable the new media source for all games. CW-Bug-Id: #20833 --- dlls/mfplat/main.c | 15 ++--- dlls/winegstreamer/new_media_source.c | 93 --------------------------- 2 files changed, 4 insertions(+), 104 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 695b86548f3..1c5e16cdbbc 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6298,18 +6298,11 @@ static HRESULT resolver_create_gstreamer_handler(IMFByteStreamHandler **handler) static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_GStreamerByteStreamHandler2 = {0x317df619, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; - const char *env = getenv("WINE_NEW_MEDIA_SOURCE"), *sgi = getenv("SteamGameId"); - if (!env && sgi) - { - if (!strcmp(sgi, "399810") /* Call of Cthulhu */) env = "1"; - if (!strcmp(sgi, "606880") /* Greedfall */) env = "1"; - if (!strcmp(sgi, "692850") /* Bloodstained */) env = "1"; - if (!strcmp(sgi, "782630") /* Twisted Sails */) env = "1"; - if (!strcmp(sgi, "789910") /* Planet of the Apes: Last Frontier */) env = "1"; - } - if (env && atoi(env)) return CoCreateInstance(&CLSID_GStreamerByteStreamHandler2, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + /* CW-Bug-Id: 20833 keep old media source around if we need a comparison point */ + const char *env = getenv("WINE_NEW_MEDIA_SOURCE"); + if (env && !atoi(env)) return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + return CoCreateInstance(&CLSID_GStreamerByteStreamHandler2, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); } static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags, diff --git a/dlls/winegstreamer/new_media_source.c b/dlls/winegstreamer/new_media_source.c index 662118b6f53..75abbbca6f6 100644 --- a/dlls/winegstreamer/new_media_source.c +++ b/dlls/winegstreamer/new_media_source.c @@ -153,93 +153,6 @@ static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const W return S_OK; } -struct media_source_fallback_callback -{ - IMFAsyncCallback IMFAsyncCallback_iface; - IMFAsyncResult *result; - HANDLE event; -}; - -static HRESULT WINAPI media_source_fallback_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI media_source_fallback_callback_AddRef(IMFAsyncCallback *iface) -{ - return 2; -} - -static ULONG WINAPI media_source_fallback_callback_Release(IMFAsyncCallback *iface) -{ - return 1; -} - -static HRESULT WINAPI media_source_fallback_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static HRESULT WINAPI media_source_fallback_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct media_source_fallback_callback *impl = CONTAINING_RECORD(iface, struct media_source_fallback_callback, IMFAsyncCallback_iface); - - IMFAsyncResult_AddRef((impl->result = result)); - SetEvent(impl->event); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl media_source_fallback_callback_vtbl = -{ - media_source_fallback_callback_QueryInterface, - media_source_fallback_callback_AddRef, - media_source_fallback_callback_Release, - media_source_fallback_callback_GetParameters, - media_source_fallback_callback_Invoke, -}; - -static HRESULT create_media_source_fallback(struct object_context *context, IUnknown **object) -{ - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; - struct media_source_fallback_callback callback = {{&media_source_fallback_callback_vtbl}}; - IMFByteStreamHandler *handler; - MF_OBJECT_TYPE type; - HRESULT hr; - - if (!(callback.event = CreateEventW(NULL, FALSE, FALSE, NULL))) - return HRESULT_FROM_WIN32(GetLastError()); - - if (FAILED(hr = CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, - &IID_IMFByteStreamHandler, (void **)&handler))) - { - CloseHandle(callback.event); - return hr; - } - - if (SUCCEEDED(hr = IMFByteStreamHandler_BeginCreateObject(handler, context->stream, NULL, MF_RESOLUTION_MEDIASOURCE, - NULL, NULL, &callback.IMFAsyncCallback_iface, NULL))) - { - WaitForSingleObject(callback.event, INFINITE); - hr = IMFByteStreamHandler_EndCreateObject(handler, callback.result, &type, object); - IMFAsyncResult_Release(callback.result); - } - - IMFByteStreamHandler_Release(handler); - CloseHandle(callback.event); - return hr; -} - struct media_stream { IMFMediaStream IMFMediaStream_iface; @@ -2045,12 +1958,6 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) WARN("Failed to create media source, hr %#lx\n", hr); - if (FAILED(hr)) - { - FIXME("Falling back to old media source, hr %#lx\n", hr); - hr = create_media_source_fallback(context, (IUnknown **)&object); - } - if (SUCCEEDED(hr)) { if (FAILED(hr = result_entry_create(context->result, MF_OBJECT_MEDIASOURCE, object, &entry))) From de9193152ad44a104d892cf3466f6456036e2274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 15:47:00 +0200 Subject: [PATCH 261/301] winegstreamer: Expose a single audio media type from the media source. CW-Bug-Id: #20833 --- dlls/winegstreamer/media_source.c | 40 ------------------------------- 1 file changed, 40 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 8b06c720200..d0e60ab817c 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -467,41 +467,6 @@ static HRESULT init_video_media_types(struct wg_format *format, IMFMediaType *ty return hr; } -static HRESULT init_audio_media_types(struct wg_format *format, IMFMediaType *types[9], DWORD *types_count) -{ - /* Expose at least one PCM and one floating point type for the - consumer to pick from. Moreover, ensure that we expose S16LE first, - as games such as MGSV expect the native media type to be 16 bps. */ - static const enum wg_audio_format audio_types[] = - { - WG_AUDIO_FORMAT_S16LE, - WG_AUDIO_FORMAT_F32LE, - }; - UINT count = *types_count, i; - - BOOL has_native_format = FALSE; - - for (i = 0; i < ARRAY_SIZE(audio_types); i++) - { - struct wg_format new_format; - - new_format = *format; - new_format.u.audio.format = audio_types[i]; - if ((types[count] = mf_media_type_from_wg_format(&new_format))) - { - if (format->u.audio.format == audio_types[i]) - has_native_format = TRUE; - count++; - } - } - - if (!has_native_format && (types[count] = mf_media_type_from_wg_format(format))) - count++; - - *types_count = count; - return S_OK; -} - static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) { IMFStreamDescriptor *descriptor; @@ -518,11 +483,6 @@ static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMF if (FAILED(hr = init_video_media_types(format, types, &count))) goto done; } - else if (format->major_type == WG_MAJOR_TYPE_AUDIO) - { - if (FAILED(hr = init_audio_media_types(format, types, &count))) - goto done; - } assert(count <= ARRAY_SIZE(types)); From a730e09cc1e98bd0e5b1c32d75a4966601c45a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 15:47:21 +0200 Subject: [PATCH 262/301] winegstreamer: Expose a single video media type from the media source. CW-Bug-Id: #20833 --- dlls/winegstreamer/media_source.c | 83 ++----------------------------- 1 file changed, 3 insertions(+), 80 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index d0e60ab817c..999527ac377 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -396,77 +396,6 @@ static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_par return hr; } -static HRESULT init_video_media_types(struct wg_format *format, IMFMediaType *types[9], DWORD *types_count) -{ - /* Try to prefer YUV formats over RGB ones. Most decoders output in the - * YUV color space, and it's generally much less expensive for - * videoconvert to do YUV -> YUV transformations. */ - static const enum wg_video_format video_formats[] = - { - WG_VIDEO_FORMAT_NV12, - WG_VIDEO_FORMAT_YV12, - WG_VIDEO_FORMAT_YUY2, - WG_VIDEO_FORMAT_I420, - WG_VIDEO_FORMAT_BGRA, - WG_VIDEO_FORMAT_BGRx, - WG_VIDEO_FORMAT_RGBA, - }; - UINT count = *types_count, i; - GUID base_subtype; - HRESULT hr; - - if (FAILED(hr = IMFMediaType_GetGUID(types[0], &MF_MT_SUBTYPE, &base_subtype))) - return hr; - - for (i = 0; i < ARRAY_SIZE(video_formats); ++i) - { - struct wg_format new_format = *format; - IMFMediaType *new_type; - - new_format.u.video.format = video_formats[i]; - - if (!(new_type = mf_media_type_from_wg_format(&new_format))) - { - hr = E_OUTOFMEMORY; - goto done; - } - types[count++] = new_type; - - if (video_formats[i] == WG_VIDEO_FORMAT_I420) - { - IMFMediaType *iyuv_type; - - if (FAILED(hr = MFCreateMediaType(&iyuv_type))) - goto done; - if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV))) - goto done; - types[count++] = iyuv_type; - } - } - - for (i = 0; i < count; i++) - { - IMFMediaType_SetUINT32(types[i], &MF_MT_VIDEO_NOMINAL_RANGE, - MFNominalRange_Normal); - - { - /* HACK: Remove MF_MT_DEFAULT_STRIDE for games that incorrectly assume it doesn't change, - * workaround to fix 4e2d1f1d2ed6e57de9103c0fd43bce88e3ad4792 until media source stops decoding - * CW-Bug-Id: #23248 - */ - char const *sgi = getenv("SteamGameId"); - if (sgi && (!strcmp(sgi, "399810") || !strcmp(sgi, "851890") || !strcmp(sgi, "544750"))) - IMFMediaType_DeleteItem(types[i], &MF_MT_DEFAULT_STRIDE); - } - } - -done: - *types_count = count; - return hr; -} - static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) { IMFStreamDescriptor *descriptor; @@ -475,15 +404,9 @@ static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMF DWORD count = 0; HRESULT hr; - if ((types[0] = mf_media_type_from_wg_format(format))) - count = 1; - - if (format->major_type == WG_MAJOR_TYPE_VIDEO) - { - if (FAILED(hr = init_video_media_types(format, types, &count))) - goto done; - } - + if (!(types[0] = mf_media_type_from_wg_format(format))) + return MF_E_INVALIDMEDIATYPE; + count = 1; assert(count <= ARRAY_SIZE(types)); if (FAILED(hr = MFCreateStreamDescriptor(id, count, types, &descriptor))) From f51e993c912a1e6cfd8f30418c1d1b678b43391a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Apr 2024 17:43:38 +0200 Subject: [PATCH 263/301] winegstreamer: Remove now unnecessary stream descriptor media type array. CW-Bug-Id: #20833 --- dlls/winegstreamer/media_source.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 999527ac377..5ddf3d89950 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -396,34 +396,33 @@ static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_par return hr; } -static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) +static HRESULT stream_descriptor_create(UINT32 id, wg_parser_stream_t wg_stream, IMFStreamDescriptor **out) { IMFStreamDescriptor *descriptor; IMFMediaTypeHandler *handler; - IMFMediaType *types[9]; - DWORD count = 0; + IMFMediaType *media_type; + struct wg_format format; HRESULT hr; - if (!(types[0] = mf_media_type_from_wg_format(format))) + wg_parser_stream_get_current_format(wg_stream, &format); + if (!(media_type = mf_media_type_from_wg_format(&format))) return MF_E_INVALIDMEDIATYPE; - count = 1; - assert(count <= ARRAY_SIZE(types)); - - if (FAILED(hr = MFCreateStreamDescriptor(id, count, types, &descriptor))) - goto done; + if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &media_type, &descriptor))) + { + IMFMediaType_Release(media_type); + return hr; + } if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) IMFStreamDescriptor_Release(descriptor); else { - hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, types[0]); + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type); IMFMediaTypeHandler_Release(handler); } -done: - while (count--) - IMFMediaType_Release(types[count]); - *out = SUCCEEDED(hr) ? descriptor : NULL; + IMFMediaType_Release(media_type); + *out = descriptor; return hr; } @@ -1625,10 +1624,8 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc wg_parser_stream_t wg_stream = wg_parser_get_stream(object->wg_parser, i); IMFStreamDescriptor *descriptor; struct media_stream *stream; - struct wg_format format; - wg_parser_stream_get_current_format(wg_stream, &format); - if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) + if (FAILED(hr = stream_descriptor_create(i, wg_stream, &descriptor))) goto fail; if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, wg_stream, &stream))) { From bf8a82c3a1a1d1bc626b4c5e92958488f9132531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 29 Mar 2024 21:56:59 +0100 Subject: [PATCH 264/301] winegstreamer/media_source: Use media type major type when selecting default streams. CW-Bug-Id: #20833 --- dlls/winegstreamer/media_source.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 5ddf3d89950..c564bd994c1 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1373,17 +1373,22 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource * for (i = 0; i < source->stream_count; ++i) { - struct wg_format format; + IMFMediaType *media_type; + GUID major = GUID_NULL; - wg_format_from_stream_descriptor(source->descriptors[i], &format); + if (SUCCEEDED(hr = stream_descriptor_get_media_type(source->descriptors[i], &media_type))) + { + hr = IMFMediaType_GetGUID(media_type, &MF_MT_MAJOR_TYPE, &major); + IMFMediaType_Release(media_type); + } - if (format.major_type >= WG_MAJOR_TYPE_VIDEO) + if (IsEqualGUID(&major, &MFMediaType_Video)) { if (!video_selected && FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i))) WARN("Failed to select stream %u, hr %#lx\n", i, hr); video_selected = TRUE; } - else if (format.major_type >= WG_MAJOR_TYPE_AUDIO) + else if (IsEqualGUID(&major, &MFMediaType_Audio)) { if (!audio_selected && FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i))) WARN("Failed to select stream %u, hr %#lx\n", i, hr); From 33fb12fbad362ab1383f6f752f203a8af26d89f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 May 2024 17:32:51 +0200 Subject: [PATCH 265/301] winegstreamer/media_source: Translate media types directly in the media source. CW-Bug-Id: #20833 --- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/main.c | 106 +++++++++++++++++++----------- dlls/winegstreamer/media_source.c | 29 +++----- dlls/winegstreamer/unixlib.h | 14 ++++ dlls/winegstreamer/wg_parser.c | 84 +++++++++++++++++++++++ 5 files changed, 175 insertions(+), 60 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a19c62c5afa..adefeaba15c 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -83,7 +83,9 @@ uint32_t wg_parser_get_stream_count(wg_parser_t parser); wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index); void wg_parser_stream_get_current_format(wg_parser_stream_t stream, struct wg_format *format); +HRESULT wg_parser_stream_get_current_type_mf(wg_parser_stream_t stream, IMFMediaType **media_type); void wg_parser_stream_get_codec_format(wg_parser_stream_t stream, struct wg_format *format); +HRESULT wg_parser_stream_enable_mf(wg_parser_stream_t stream, IMFMediaType *media_type); void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format *format); void wg_parser_stream_disable(wg_parser_stream_t stream); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 627ce2e266e..374924a3e6a 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -273,6 +273,45 @@ wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index) return params.stream; } +static HRESULT wg_get_media_type_mf(enum unix_funcs unix_func, void *params, + struct wg_media_type *wg_media_type, IMFMediaType **media_type) +{ + NTSTATUS status; + HRESULT hr; + + if ((status = WINE_UNIX_CALL(unix_func, params)) + && status == STATUS_BUFFER_TOO_SMALL) + { + if (!(wg_media_type->u.format = CoTaskMemAlloc(wg_media_type->format_size))) + return E_OUTOFMEMORY; + status = WINE_UNIX_CALL(unix_func, params); + } + + if (status) + { + CoTaskMemFree(wg_media_type->u.format); + WARN("Failed to get output media type, status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + hr = wg_media_type_to_mf(wg_media_type, media_type); + CoTaskMemFree(wg_media_type->u.format); + return hr; +} + +HRESULT wg_parser_stream_get_current_type_mf(wg_parser_stream_t stream, IMFMediaType **media_type) +{ + struct wg_parser_stream_get_current_type_params params = + { + .stream = stream, + }; + + TRACE("stream %#I64x, media_type %p.\n", stream, media_type); + + return wg_get_media_type_mf(unix_wg_parser_stream_get_current_type, ¶ms, + ¶ms.media_type, media_type); +} + void wg_parser_stream_get_current_format(wg_parser_stream_t stream, struct wg_format *format) { struct wg_parser_stream_get_current_format_params params = @@ -312,6 +351,29 @@ void wg_parser_stream_enable(wg_parser_stream_t stream, const struct wg_format * WINE_UNIX_CALL(unix_wg_parser_stream_enable, ¶ms); } +HRESULT wg_parser_stream_enable_mf(wg_parser_stream_t stream, IMFMediaType *media_type) +{ + struct wg_parser_stream_enable_type_params params = + { + .stream = stream, + }; + NTSTATUS status; + HRESULT hr; + + TRACE("stream %#I64x, media_type %p.\n", stream, media_type); + + if (FAILED(hr = wg_media_type_from_mf(media_type, ¶ms.media_type))) + return hr; + if ((status = WINE_UNIX_CALL(unix_wg_parser_stream_enable_type, ¶ms))) + { + WARN("Failed to enable stream, status %#lx.\n", status); + hr = HRESULT_FROM_NT(status); + } + + CoTaskMemFree(params.media_type.u.format); + return hr; +} + void wg_parser_stream_disable(wg_parser_stream_t stream) { TRACE("stream %#I64x.\n", stream); @@ -573,29 +635,11 @@ HRESULT wg_source_get_stream_type(wg_source_t source, UINT32 index, IMFMediaType .source = source, .index = index, }; - NTSTATUS status; - HRESULT hr; TRACE("source %#I64x, index %u, media_type %p\n", source, index, media_type); - if ((status = WINE_UNIX_CALL(unix_wg_source_get_stream_type, ¶ms)) - && status == STATUS_BUFFER_TOO_SMALL) - { - if (!(params.media_type.u.format = CoTaskMemAlloc(params.media_type.format_size))) - return ERROR_OUTOFMEMORY; - status = WINE_UNIX_CALL(unix_wg_source_get_stream_type, ¶ms); - } - - if (status) - { - CoTaskMemFree(params.media_type.u.format); - WARN("Failed to get output media type, status %#lx\n", status); - return HRESULT_FROM_NT(status); - } - - hr = wg_media_type_to_mf(¶ms.media_type, media_type); - CoTaskMemFree(params.media_type.u.format); - return hr; + return wg_get_media_type_mf(unix_wg_source_get_stream_type, ¶ms, + ¶ms.media_type, media_type); } char *wg_source_get_stream_tag(wg_source_t source, UINT32 index, wg_parser_tag tag) @@ -759,29 +803,11 @@ HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **me { .transform = transform, }; - NTSTATUS status; - HRESULT hr; TRACE("transform %#I64x, media_type %p.\n", transform, media_type); - if ((status = WINE_UNIX_CALL(unix_wg_transform_get_output_type, ¶ms)) - && status == STATUS_BUFFER_TOO_SMALL) - { - if (!(params.media_type.u.format = CoTaskMemAlloc(params.media_type.format_size))) - return ERROR_OUTOFMEMORY; - status = WINE_UNIX_CALL(unix_wg_transform_get_output_type, ¶ms); - } - - if (status) - { - CoTaskMemFree(params.media_type.u.format); - WARN("Failed to get output media type, status %#lx\n", status); - return HRESULT_FROM_NT(status); - } - - hr = wg_media_type_to_mf(¶ms.media_type, media_type); - CoTaskMemFree(params.media_type.u.format); - return hr; + return wg_get_media_type_mf(unix_wg_transform_get_output_type, ¶ms, + ¶ms.media_type, media_type); } HRESULT wg_transform_set_output_type(wg_transform_t transform, IMFMediaType *media_type) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index c564bd994c1..eb6ab3d21cd 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -357,19 +357,6 @@ static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, return hr; } -static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format) -{ - IMFMediaType *media_type; - HRESULT hr; - - if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type))) - return hr; - mf_media_type_to_wg_format(media_type, format); - IMFMediaType_Release(media_type); - - return hr; -} - static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_parser_stream_t stream, const GUID *attr, enum wg_parser_tag tag) { @@ -401,11 +388,9 @@ static HRESULT stream_descriptor_create(UINT32 id, wg_parser_stream_t wg_stream, IMFStreamDescriptor *descriptor; IMFMediaTypeHandler *handler; IMFMediaType *media_type; - struct wg_format format; HRESULT hr; - wg_parser_stream_get_current_format(wg_stream, &format); - if (!(media_type = mf_media_type_from_wg_format(&format))) + if (FAILED(hr = wg_parser_stream_get_current_type_mf(wg_stream, &media_type))) return MF_E_INVALIDMEDIATYPE; if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &media_type, &descriptor))) { @@ -481,14 +466,18 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - struct wg_format format; + IMFMediaType *media_type; HRESULT hr; TRACE("source %p, stream %p\n", source, stream); - if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) - WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - wg_parser_stream_enable(stream->wg_stream, &format); + if (SUCCEEDED(hr = stream_descriptor_get_media_type(stream->descriptor, &media_type))) + { + hr = wg_parser_stream_enable_mf(stream->wg_stream, media_type); + IMFMediaType_Release(media_type); + } + if (FAILED(hr)) + WARN("Failed to start media source stream, hr %#lx\n", hr); if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index e039cc35cd6..f9b87e51b93 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -270,6 +270,12 @@ struct wg_parser_get_stream_params wg_parser_stream_t stream; }; +struct wg_parser_stream_get_current_type_params +{ + wg_parser_stream_t stream; + struct wg_media_type media_type; +}; + struct wg_parser_stream_get_current_format_params { wg_parser_stream_t stream; @@ -288,6 +294,12 @@ struct wg_parser_stream_enable_params const struct wg_format *format; }; +struct wg_parser_stream_enable_type_params +{ + wg_parser_stream_t stream; + struct wg_media_type media_type; +}; + struct wg_parser_stream_get_buffer_params { wg_parser_t parser; @@ -515,9 +527,11 @@ enum unix_funcs unix_wg_parser_get_stream_count, unix_wg_parser_get_stream, + unix_wg_parser_stream_get_current_type, unix_wg_parser_stream_get_current_format, unix_wg_parser_stream_get_codec_format, unix_wg_parser_stream_enable, + unix_wg_parser_stream_enable_type, unix_wg_parser_stream_disable, unix_wg_parser_stream_get_buffer, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 65e97153f69..ff866ba2396 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -254,6 +254,16 @@ static NTSTATUS wg_parser_stream_get_current_format(void *args) return S_OK; } +static NTSTATUS wg_parser_stream_get_current_type(void *args) +{ + struct wg_parser_stream_get_current_type_params *params = args; + struct wg_parser_stream *stream = get_stream(params->stream); + + if (!stream->current_caps) + return STATUS_INVALID_PARAMETER; + return caps_to_media_type(stream->current_caps, ¶ms->media_type, 0); +} + static NTSTATUS wg_parser_stream_get_codec_format(void *args) { struct wg_parser_stream_get_codec_format_params *params = args; @@ -294,6 +304,30 @@ static NTSTATUS wg_parser_stream_enable(void *args) return S_OK; } +static NTSTATUS wg_parser_stream_enable_type(void *args) +{ + const struct wg_parser_stream_enable_type_params *params = args; + struct wg_parser_stream *stream = get_stream(params->stream); + struct wg_parser *parser = stream->parser; + + pthread_mutex_lock(&parser->mutex); + + stream->desired_caps = caps_from_media_type(¶ms->media_type); + stream->enabled = true; + + pthread_mutex_unlock(&parser->mutex); + + if (IsEqualGUID(¶ms->media_type.major, &MEDIATYPE_Video) && stream->flip) + { + bool flip = !!(params->media_type.u.video->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep); + + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); + } + + push_event(stream->my_sink, gst_event_new_reconfigure()); + return S_OK; +} + static NTSTATUS wg_parser_stream_disable(void *args) { struct wg_parser_stream *stream = get_stream(*(wg_parser_stream_t *)args); @@ -2246,8 +2280,10 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_stream), X(wg_parser_stream_get_current_format), + X(wg_parser_stream_get_current_type), X(wg_parser_stream_get_codec_format), X(wg_parser_stream_enable), + X(wg_parser_stream_enable_type), X(wg_parser_stream_disable), X(wg_parser_stream_get_buffer), @@ -2356,6 +2392,31 @@ static NTSTATUS wow64_wg_parser_stream_get_current_format(void *args) return wg_parser_stream_get_current_format(¶ms); } +NTSTATUS wow64_wg_parser_stream_get_current_type(void *args) +{ + struct + { + wg_parser_stream_t stream; + struct wg_media_type32 media_type; + } *params32 = args; + struct wg_parser_stream_get_current_type_params params = + { + .stream = params32->stream, + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, + }; + NTSTATUS status; + + status = wg_parser_stream_get_current_type(¶ms); + params32->media_type.major = params.media_type.major; + params32->media_type.format_size = params.media_type.format_size; + return status; +} + static NTSTATUS wow64_wg_parser_stream_get_codec_format(void *args) { struct @@ -2388,6 +2449,27 @@ static NTSTATUS wow64_wg_parser_stream_enable(void *args) return wg_parser_stream_enable(¶ms); } +NTSTATUS wow64_wg_parser_stream_enable_type(void *args) +{ + struct + { + wg_parser_stream_t stream; + struct wg_media_type32 media_type; + } *params32 = args; + struct wg_parser_stream_enable_type_params params = + { + .stream = params32->stream, + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, + }; + + return wg_parser_stream_enable_type(¶ms); +} + static NTSTATUS wow64_wg_parser_stream_get_buffer(void *args) { struct @@ -2764,8 +2846,10 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X(wg_parser_get_stream), X64(wg_parser_stream_get_current_format), + X64(wg_parser_stream_get_current_type), X64(wg_parser_stream_get_codec_format), X64(wg_parser_stream_enable), + X64(wg_parser_stream_enable_type), X(wg_parser_stream_disable), X64(wg_parser_stream_get_buffer), From a9096cc4ec2bdebc539b8b93153cab7a1baaec0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 29 Mar 2024 21:56:59 +0100 Subject: [PATCH 266/301] winegstreamer/wg_parser: Stop auto-plugging on demuxer element pads. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ff866ba2396..e679ad1f217 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -577,7 +577,40 @@ 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); + const GstStructure *structure = gst_caps_get_structure(caps, 0); + const char *name = gst_structure_get_name(structure); + struct wg_parser *parser = user; + GstElementFactory *factory; + GstElement *element; + gboolean parsed; + + if (!parser->output_compressed) + return true; + + /* make sure to autoplug parsers for mpeg audio / video */ + if (!strcmp(name, "audio/mpeg") || !strcmp(name, "video/mpeg")) + { + if (!gst_structure_get_boolean(structure, "parsed", &parsed)) + return true; + return !parsed; + } + + gst_object_ref(pad); + while (GST_IS_GHOST_PAD(pad)) + { + GstGhostPad *ghost = GST_GHOST_PAD(pad); + pad = gst_ghost_pad_get_target(ghost); + gst_object_unref(ghost); + } + + element = gst_pad_get_parent_element(pad); + gst_object_unref(pad); + + factory = gst_element_get_factory(element); + gst_object_unref(element); + + GST_TRACE("factory %"GST_PTR_FORMAT" element %"GST_PTR_FORMAT" pad %"GST_PTR_FORMAT" caps %"GST_PTR_FORMAT"", factory, element, pad, caps); + return !factory || !gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DEMUXER); } gboolean caps_detect_h264(GstCapsFeatures *features, GstStructure *structure, gpointer user_data) From ab578b8865b1a375aab5a7ae9798d68053b42c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 29 Mar 2024 21:56:59 +0100 Subject: [PATCH 267/301] winegstreamer/media_source: Output compressed samples from uridecodebin. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e679ad1f217..2d9c2294182 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2159,6 +2159,7 @@ static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) if (!(element = create_element("uridecodebin", "base"))) return FALSE; + parser->output_compressed = true; gst_bin_add(GST_BIN(parser->container), element); parser->decodebin = element; @@ -2166,6 +2167,7 @@ static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) g_object_set(parser->decodebin, "uri", parser->uri, NULL); g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); + g_signal_connect(element, "autoplug-continue", G_CALLBACK(autoplug_continue_cb), parser); g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); From 128e030272a8665ed7e7d0a3c634b08abdb7cf90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 May 2024 13:36:34 +0200 Subject: [PATCH 268/301] winegstreamer/new_media_source: Send EOS when reading past the end of file. CW-Bug-Id: #20833 --- dlls/winegstreamer/new_media_source.c | 30 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/new_media_source.c b/dlls/winegstreamer/new_media_source.c index 75abbbca6f6..a97d659e58d 100644 --- a/dlls/winegstreamer/new_media_source.c +++ b/dlls/winegstreamer/new_media_source.c @@ -669,6 +669,13 @@ static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { if (FAILED(hr = wg_source_get_position(source->wg_source, &read_offset))) break; + if (read_offset >= source->file_size) + { + if (FAILED(hr = wg_source_push_data(source->wg_source, read_offset, NULL, 0))) + WARN("Failed to push %#lx bytes to source, hr %#lx\n", read_size, hr); + continue; + } + if (FAILED(hr = IMFByteStream_GetCurrentPosition(source->byte_stream, &position))) WARN("Failed to get current byte stream position, hr %#lx\n", hr); else if (position != (read_offset = min(read_offset, source->file_size)) @@ -1936,28 +1943,31 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM WARN("Failed to create wg_source, hr %#lx\n", hr); else if (FAILED(hr = wg_source_push_data(context->wg_source, context->read_offset, context->buffer, size))) WARN("Failed to push wg_source data, hr %#lx\n", hr); - else if (FAILED(hr = wg_source_get_stream_count(context->wg_source, &context->stream_count))) - WARN("Failed to get wg_source status, hr %#lx\n", hr); - else if (!context->stream_count) + else while (SUCCEEDED(hr)) { + UINT32 read_size; QWORD position; - if (FAILED(hr = wg_source_get_position(context->wg_source, &context->read_offset))) + + if (FAILED(hr = wg_source_get_stream_count(context->wg_source, &context->stream_count))) + WARN("Failed to get source stream count, hr %#lx\n", hr); + else if (context->stream_count) + break; + else if (FAILED(hr = wg_source_get_position(context->wg_source, &context->read_offset))) WARN("Failed to get wg_source position, hr %#lx\n", hr); else if (FAILED(hr = IMFByteStream_GetCurrentPosition(context->stream, &position))) WARN("Failed to get current byte stream position, hr %#lx\n", hr); else if (position != (context->read_offset = min(context->read_offset, context->file_size)) && FAILED(hr = IMFByteStream_SetCurrentPosition(context->stream, context->read_offset))) WARN("Failed to set current byte stream position, hr %#lx\n", hr); - else - { - UINT32 read_size = min(SOURCE_BUFFER_SIZE, context->file_size - context->read_offset); + else if ((read_size = min(SOURCE_BUFFER_SIZE, context->file_size - context->read_offset))) return IMFByteStream_BeginRead(context->stream, context->buffer, read_size, &handler->IMFAsyncCallback_iface, state); - } + else if (FAILED(hr = wg_source_push_data(context->wg_source, context->read_offset, NULL, 0))) + WARN("Failed to push wg_source data, hr %#lx\n", hr); } - else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) - WARN("Failed to create media source, hr %#lx\n", hr); + if (SUCCEEDED(hr) && FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) + WARN("Failed to create media source, hr %#lx\n", hr); if (SUCCEEDED(hr)) { if (FAILED(hr = result_entry_create(context->result, MF_OBJECT_MEDIASOURCE, object, &entry))) From f88bfbff39b4ca10bc9bf8bea94402fcbc4b038c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 May 2024 13:37:08 +0200 Subject: [PATCH 269/301] mfreadwrite/reader: Make a copy of the output type in SetCurrentMediaType. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 7f30c7776f9..8a82bb294d1 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2072,6 +2072,7 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D IMFMediaType *type) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + IMFMediaType *output_type; HRESULT hr; TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type); @@ -2091,16 +2092,25 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D if (index >= reader->stream_count) return MF_E_INVALIDSTREAMNUMBER; + if (FAILED(hr = MFCreateMediaType(&output_type))) + return hr; + if (FAILED(IMFMediaType_CopyAllItems(type, (IMFAttributes *)output_type))) + { + IMFMediaType_Release(output_type); + return hr; + } + /* FIXME: setting the output type while streaming should trigger a flush */ EnterCriticalSection(&reader->cs); - hr = source_reader_set_compatible_media_type(reader, index, type); + hr = source_reader_set_compatible_media_type(reader, index, output_type); if (hr == S_FALSE) - hr = source_reader_create_decoder_for_stream(reader, index, type); + hr = source_reader_create_decoder_for_stream(reader, index, output_type); LeaveCriticalSection(&reader->cs); + IMFMediaType_Release(output_type); return hr; } From 6d8fb963b5710592422b98f82cab685ee9c6fd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 May 2024 13:37:08 +0200 Subject: [PATCH 270/301] mfreadwrite/reader: Set MF_MT_AUDIO_BITS_PER_SAMPLE attribute when missing. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 8a82bb294d1..152aca9e7d5 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1894,12 +1894,21 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL list_init(&entry->entry); entry->category = category; - if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio) - && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size))) + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) { UINT32 bytes_per_second; - if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) + /* decoders require to have MF_MT_AUDIO_BITS_PER_SAMPLE attribute set, but the source reader doesn't */ + if (FAILED(IMFMediaType_GetItem(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, NULL))) + { + if (IsEqualGUID(&out_type.guidSubtype, &MFAudioFormat_PCM)) + IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 16); + else if (IsEqualGUID(&out_type.guidSubtype, &MFAudioFormat_Float)) + IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 32); + } + + if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size)) + && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second); } From 5b89b223395a3d9e3afe9765cda899504ca0c0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 May 2024 14:34:11 +0200 Subject: [PATCH 271/301] mfreadwrite/reader: Send MFT_MESSAGE_NOTIFY_START_OF_STREAM on start or seek. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 152aca9e7d5..b87a7f50cc8 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -926,6 +926,22 @@ static HRESULT source_reader_flush_transform_samples(struct source_reader *reade return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK; } +static HRESULT source_reader_notify_transform(struct source_reader *reader, struct media_stream *stream, + struct transform_entry *entry, UINT message) +{ + struct transform_entry *next = NULL; + struct list *ptr; + HRESULT hr; + + if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, message, 0))) + WARN("Failed to notify transform %p message %#x, hr %#lx\n", entry->transform, message, hr); + + return next ? source_reader_notify_transform(reader, stream, next, message) : S_OK; +} + static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream, IMFSample *sample) { @@ -999,6 +1015,7 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re MediaEventType event_type; LONGLONG timestamp; PROPVARIANT value; + struct list *ptr; unsigned int i; HRESULT hr; DWORD id; @@ -1022,9 +1039,6 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re switch (event_type) { case MEEndOfStream: - { - struct list *ptr; - stream->state = STREAM_STATE_EOS; stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED; @@ -1039,10 +1053,16 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL); break; - } case MEStreamSeeked: case MEStreamStarted: stream->state = STREAM_STATE_READY; + + if ((ptr = list_head(&stream->transforms))) + { + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = source_reader_notify_transform(reader, stream, entry, MFT_MESSAGE_NOTIFY_START_OF_STREAM))) + WARN("Failed to drain pending samples, hr %#lx.\n", hr); + } break; case MEStreamStopped: stream->flags |= STREAM_FLAG_STOPPED; From 5c9bf7763f41b74280f52c8d7110ab3cfb8a72d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 May 2024 14:56:04 +0200 Subject: [PATCH 272/301] winegstreamer: Implement drain and flush for the audio decoder. CW-Bug-Id: #20833 --- dlls/winegstreamer/audio_decoder.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/audio_decoder.c index 5b86974cab9..49e75365654 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -482,8 +482,22 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); - return S_OK; + struct audio_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); + + switch (message) + { + case MFT_MESSAGE_COMMAND_DRAIN: + return wg_transform_drain(decoder->wg_transform); + + case MFT_MESSAGE_COMMAND_FLUSH: + return wg_transform_flush(decoder->wg_transform); + + default: + FIXME("Ignoring message %#x.\n", message); + return S_OK; + } } static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) From d74d968050eeda26c67b83c01b698bbae41e703d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 May 2024 19:53:54 +0200 Subject: [PATCH 273/301] winegstreamer: Generate timestamps relative to the first input sample. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index a4511b91c5f..cbe5d627c98 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -808,7 +808,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return wg_transform_flush(decoder->wg_transform); case MFT_MESSAGE_NOTIFY_START_OF_STREAM: - decoder->sample_time = 0; + decoder->sample_time = -1; return S_OK; default: @@ -826,6 +826,9 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS if (!decoder->wg_transform) return MF_E_TRANSFORM_TYPE_NOT_SET; + if (decoder->sample_time == -1 && FAILED(IMFSample_GetSampleTime(sample, (LONGLONG *)&decoder->sample_time))) + decoder->sample_time = 0; + return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); } From fa463d596be9ca360650e4174f58b1386d4bc4eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 May 2024 19:50:16 +0200 Subject: [PATCH 274/301] winegstreamer/new_media_source: Snap seek to the previous keyframe. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 672b4078dc2..6f6ce5ae685 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -841,7 +841,8 @@ NTSTATUS wg_source_set_position(void *args) GST_TRACE("source %p, time %"G_GINT64_MODIFIER"d", source, time); - push_event(source->streams[0].pad, gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, + push_event(source->streams[0].pad, gst_event_new_seek(1.0, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SNAP_BEFORE | GST_SEEK_FLAG_KEY_UNIT, GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1)); for (i = 0; i < source->stream_count; i++) From c529a9dd5e2117c7e430cc705e805a1117176ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 19 Jun 2024 14:23:20 +0200 Subject: [PATCH 275/301] winegstreamer/audio_decoder: Fill output block align and bytes per second if not set. CW-Bug-Id: #20833 --- dlls/winegstreamer/audio_decoder.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/audio_decoder.c b/dlls/winegstreamer/audio_decoder.c index 49e75365654..734622a64ad 100644 --- a/dlls/winegstreamer/audio_decoder.c +++ b/dlls/winegstreamer/audio_decoder.c @@ -384,10 +384,17 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) - return hr; + if (!wfx.Format.nBlockAlign) + wfx.Format.nBlockAlign = wfx.Format.wBitsPerSample * wfx.Format.nChannels / 8; + if (!wfx.Format.nAvgBytesPerSec) + wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec; - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + if (FAILED(hr = MFCreateAudioMediaType(&wfx.Format, (IMFAudioMediaType **)&decoder->output_type))) return hr; if (FAILED(hr = try_create_wg_transform(decoder))) From 2a1ea697e841a9c164bdc277d3dea5a143012e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Jun 2024 21:12:21 +0200 Subject: [PATCH 276/301] mfmediaengine: Ignore MEEndOfPresentation for the video frame sink. This is an indication that the source has ended, and that the session is about to end, but not that all the samples in the session have been decoded and processed. CW-Bug-Id: #20833 CW-Bug-Id: #20833 --- dlls/mfmediaengine/main.c | 4 ---- dlls/mfmediaengine/mediaengine_private.h | 1 - dlls/mfmediaengine/video_frame_sink.c | 8 +------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index d4b3dbbcf3e..b9c4428a974 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -995,10 +995,6 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); break; - - case MEEndOfPresentation: - video_frame_sink_notify_end_of_presentation(engine->presentation.frame_sink); - break; } failed: diff --git a/dlls/mfmediaengine/mediaengine_private.h b/dlls/mfmediaengine/mediaengine_private.h index 9920a5ef19b..75865592905 100644 --- a/dlls/mfmediaengine/mediaengine_private.h +++ b/dlls/mfmediaengine/mediaengine_private.h @@ -26,4 +26,3 @@ HRESULT video_frame_sink_query_iface(struct video_frame_sink *object, REFIID rii ULONG video_frame_sink_release(struct video_frame_sink *sink); int video_frame_sink_get_sample(struct video_frame_sink *sink, IMFSample **sample); HRESULT video_frame_sink_get_pts(struct video_frame_sink *sink, MFTIME clocktime, LONGLONG *pts); -void video_frame_sink_notify_end_of_presentation(struct video_frame_sink *sink); diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index 025b2dd341a..c99058ce048 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -89,7 +89,6 @@ struct video_frame_sink int sample_read_index; BOOL sample_request_pending; BOOL sample_presented; - BOOL eos; CRITICAL_SECTION cs; }; @@ -287,7 +286,7 @@ static HRESULT WINAPI video_frame_sink_stream_GetMediaTypeHandler(IMFStreamSink /* must be called with critical section held */ static void video_frame_sink_stream_request_sample(struct video_frame_sink *sink) { - if (sink->sample_request_pending || sink->eos) + if (sink->sample_request_pending) return; IMFStreamSink_QueueEvent(&sink->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); @@ -1188,11 +1187,6 @@ HRESULT video_frame_sink_get_pts(struct video_frame_sink *sink, MFTIME clocktime return hr; } -void video_frame_sink_notify_end_of_presentation(struct video_frame_sink *sink) -{ - sink->eos = TRUE; -} - ULONG video_frame_sink_release(struct video_frame_sink *sink) { return video_frame_sink_Release(&sink->IMFMediaSink_iface); From 9e28492044dee25b60c7a7bc739a8f902bbd892a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Jun 2024 20:20:36 +0200 Subject: [PATCH 277/301] mfmediaengine: Implement D3D-aware video frame sink. CW-Bug-Id: #20833 CW-Bug-Id: #20833 --- dlls/mfmediaengine/main.c | 82 +++++++++++++++++++++++- dlls/mfmediaengine/mediaengine_private.h | 2 +- dlls/mfmediaengine/video_frame_sink.c | 64 +++++++++++++++++- 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index b9c4428a974..85b4dbb471a 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -1184,7 +1184,7 @@ static HRESULT media_engine_create_video_renderer(struct media_engine *engine, I IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype); - hr = create_video_frame_sink(media_type, &engine->sink_events, &engine->presentation.frame_sink); + hr = create_video_frame_sink(media_type, (IUnknown *)engine->device_manager, &engine->sink_events, &engine->presentation.frame_sink); IMFMediaType_Release(media_type); if (FAILED(hr)) return hr; @@ -2413,6 +2413,83 @@ static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context IMFSample_Release(sample); } +static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D **resource, UINT *subresource) +{ + IMFDXGIBuffer *dxgi_buffer; + IMFMediaBuffer *buffer; + HRESULT hr; + + *resource = NULL; + *subresource = 0; + + if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer))) + return hr; + + if (SUCCEEDED(hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer))) + { + IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, subresource); + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)resource); + IMFDXGIBuffer_Release(dxgi_buffer); + } + + IMFMediaBuffer_Release(buffer); + return hr; +} + +static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Texture2D *dst_texture, + const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) +{ + MFVideoNormalizedRect src_rect_default = {0.0, 0.0, 1.0, 1.0}; + MFARGB color_default = {0, 0, 0, 0}; + D3D11_TEXTURE2D_DESC src_desc; + ID3D11DeviceContext *context; + ID3D11Texture2D *src_texture; + RECT dst_rect_default = {0}; + D3D11_BOX src_box = {0}; + ID3D11Device *device; + IMFSample *sample; + UINT subresource; + HRESULT hr; + + if (!src_rect) + src_rect = &src_rect_default; + if (!dst_rect) + dst_rect = &dst_rect_default; + if (!color) + color = &color_default; + + if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) + return MF_E_UNEXPECTED; + hr = get_d3d11_resource_from_sample(sample, &src_texture, &subresource); + IMFSample_Release(sample); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = media_engine_lock_d3d_device(engine, &device))) + { + ID3D11Texture2D_Release(src_texture); + return hr; + } + + ID3D11Texture2D_GetDesc(src_texture, &src_desc); + + src_box.left = src_rect->left * src_desc.Width; + src_box.top = src_rect->top * src_desc.Height; + src_box.front = 0; + src_box.right = src_rect->right * src_desc.Width; + src_box.bottom = src_rect->bottom * src_desc.Height; + src_box.back = 1; + + ID3D11Device_GetImmediateContext(device, &context); + ID3D11DeviceContext_CopySubresourceRegion(context, (ID3D11Resource *)dst_texture, 0, + dst_rect->left, dst_rect->top, 0, (ID3D11Resource *)src_texture, subresource, &src_box); + ID3D11DeviceContext_Release(context); + + media_engine_unlock_d3d_device(engine, device); + ID3D11Texture2D_Release(src_texture); + return hr; +} + static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { @@ -2578,7 +2655,8 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture))) { - hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); + if (!engine->device_manager || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) + hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); } else diff --git a/dlls/mfmediaengine/mediaengine_private.h b/dlls/mfmediaengine/mediaengine_private.h index 75865592905..cdbdbdb90b0 100644 --- a/dlls/mfmediaengine/mediaengine_private.h +++ b/dlls/mfmediaengine/mediaengine_private.h @@ -20,7 +20,7 @@ struct video_frame_sink; -HRESULT create_video_frame_sink(IMFMediaType *media_type, IMFAsyncCallback *events_callback, +HRESULT create_video_frame_sink(IMFMediaType *media_type, IUnknown *device_manager, IMFAsyncCallback *events_callback, struct video_frame_sink **sink); HRESULT video_frame_sink_query_iface(struct video_frame_sink *object, REFIID riid, void **obj); ULONG video_frame_sink_release(struct video_frame_sink *sink); diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index c99058ce048..57d4172bda8 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -27,6 +27,9 @@ #include "mediaengine_private.h" +#include "initguid.h" +#include "evr.h" + #include "wine/debug.h" #include "wine/list.h" @@ -72,7 +75,9 @@ struct video_frame_sink IMFMediaEventGenerator IMFMediaEventGenerator_iface; IMFStreamSink IMFStreamSink_iface; IMFMediaTypeHandler IMFMediaTypeHandler_iface; + IMFGetService IMFGetService_iface; LONG refcount; + IUnknown *device_manager; IMFMediaType *media_type; IMFMediaType *current_media_type; BOOL is_shut_down; @@ -125,6 +130,11 @@ static struct video_frame_sink *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandle return CONTAINING_RECORD(iface, struct video_frame_sink, IMFMediaTypeHandler_iface); } +static struct video_frame_sink *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct video_frame_sink, IMFGetService_iface); +} + static void video_frame_sink_samples_release(struct video_frame_sink *sink) { for (int i = 0; i < ARRAYSIZE(sink->sample); i++) @@ -161,6 +171,10 @@ static HRESULT WINAPI video_frame_sink_stream_QueryInterface(IMFStreamSink *ifac { *obj = &sink->IMFMediaTypeHandler_iface; } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &sink->IMFGetService_iface; + } else { WARN("Unsupported %s.\n", debugstr_guid(riid)); @@ -574,6 +588,49 @@ static const IMFMediaTypeHandlerVtbl video_frame_sink_stream_type_handler_vtbl = video_frame_sink_stream_type_handler_GetMajorType, }; +static HRESULT WINAPI video_frame_sink_stream_get_service_QueryInterface(IMFGetService *iface, REFIID riid, + void **obj) +{ + struct video_frame_sink *sink = impl_from_IMFGetService(iface); + return IMFStreamSink_QueryInterface(&sink->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI video_frame_sink_stream_get_service_AddRef(IMFGetService *iface) +{ + struct video_frame_sink *sink = impl_from_IMFGetService(iface); + return IMFStreamSink_AddRef(&sink->IMFStreamSink_iface); +} + +static ULONG WINAPI video_frame_sink_stream_get_service_Release(IMFGetService *iface) +{ + struct video_frame_sink *sink = impl_from_IMFGetService(iface); + return IMFStreamSink_Release(&sink->IMFStreamSink_iface); +} + +static HRESULT WINAPI video_frame_sink_stream_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, + void **obj) +{ + struct video_frame_sink *sink = impl_from_IMFGetService(iface); + + if (IsEqualGUID(service, &MR_VIDEO_ACCELERATION_SERVICE)) + { + if (sink->device_manager) + return IUnknown_QueryInterface(sink->device_manager, riid, obj); + return E_NOINTERFACE; + } + + FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid)); + return MF_E_UNSUPPORTED_SERVICE; +} + +static const IMFGetServiceVtbl video_frame_sink_stream_get_service_vtbl = +{ + video_frame_sink_stream_get_service_QueryInterface, + video_frame_sink_stream_get_service_AddRef, + video_frame_sink_stream_get_service_Release, + video_frame_sink_stream_get_service_GetService, +}; + static HRESULT WINAPI video_frame_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) { struct video_frame_sink *sink = impl_from_IMFMediaSink(iface); @@ -627,6 +684,8 @@ static ULONG WINAPI video_frame_sink_Release(IMFMediaSink *iface) if (sink->current_media_type) IMFMediaType_Release(sink->current_media_type); IMFMediaType_Release(sink->media_type); + if (sink->device_manager) + IUnknown_Release(sink->device_manager); if (sink->event_queue) IMFMediaEventQueue_Release(sink->event_queue); if (sink->clock) @@ -1056,7 +1115,7 @@ static const IMFClockStateSinkVtbl video_frame_sink_clock_sink_vtbl = video_frame_sink_clock_sink_OnClockSetRate, }; -HRESULT create_video_frame_sink(IMFMediaType *media_type, IMFAsyncCallback *events_callback, struct video_frame_sink **sink) +HRESULT create_video_frame_sink(IMFMediaType *media_type, IUnknown *device_manager, IMFAsyncCallback *events_callback, struct video_frame_sink **sink) { struct video_frame_sink *object; HRESULT hr; @@ -1069,8 +1128,11 @@ HRESULT create_video_frame_sink(IMFMediaType *media_type, IMFAsyncCallback *even object->IMFMediaEventGenerator_iface.lpVtbl = &video_frame_sink_events_vtbl; object->IMFStreamSink_iface.lpVtbl = &video_frame_sink_stream_vtbl; object->IMFMediaTypeHandler_iface.lpVtbl = &video_frame_sink_stream_type_handler_vtbl; + object->IMFGetService_iface.lpVtbl = &video_frame_sink_stream_get_service_vtbl; object->refcount = 1; object->rate = 1.0f; + if ((object->device_manager = device_manager)) + IUnknown_AddRef(object->device_manager); object->media_type = media_type; IMFAsyncCallback_AddRef(object->callback = events_callback); IMFMediaType_AddRef(object->media_type); From a609b6668b24ab4b98eee85fe46356b2e361f40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Jul 2024 12:44:47 +0200 Subject: [PATCH 278/301] winegstreamer: Continue autoplugging after protonvideoconverter elements. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 2d9c2294182..02db0620fd3 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -609,6 +609,10 @@ static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCap factory = gst_element_get_factory(element); gst_object_unref(element); + name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); + if (!strcmp(name, "protonvideoconverter") || !strcmp(name, "protonaudioconverter")) + return true; + GST_TRACE("factory %"GST_PTR_FORMAT" element %"GST_PTR_FORMAT" pad %"GST_PTR_FORMAT" caps %"GST_PTR_FORMAT"", factory, element, pad, caps); return !factory || !gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DEMUXER); } From 65c8ec0141528b53709a0721378e64924a4d91a1 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 7 May 2024 16:34:19 +0800 Subject: [PATCH 279/301] winegstreamer/wg_parser: HACK: Return untranscoded codec format for transcoded stream. CW-Bug-Id: #21303 CW-Bug-Id: #22008 CW-Bug-Id: #20833 --- .../winegstreamer/media-converter/videoconv.c | 59 ++++++++++--------- dlls/winegstreamer/unix_private.h | 3 +- dlls/winegstreamer/wg_parser.c | 23 ++++++++ 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/dlls/winegstreamer/media-converter/videoconv.c b/dlls/winegstreamer/media-converter/videoconv.c index d976cd2d05c..06174ccc054 100644 --- a/dlls/winegstreamer/media-converter/videoconv.c +++ b/dlls/winegstreamer/media-converter/videoconv.c @@ -1278,7 +1278,7 @@ static void video_conv_init(VideoConv *conv) conv->active_mode = GST_PAD_MODE_NONE; } -static bool codec_info_to_wg_format(char *codec_info, struct wg_format *codec_format) +static bool codec_info_to_wg_format(char *codec_info, GstCaps *caps) { char *codec_name = codec_info; @@ -1290,63 +1290,65 @@ static bool codec_info_to_wg_format(char *codec_info, struct wg_format *codec_fo /* FIXME: Get width, height, fps etc. from codec info string. */ if (strcmp(codec_name, "cinepak") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_CINEPAK; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-cinepak"); } else if (strcmp(codec_name, "h264") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_H264; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-h264"); } else if (strcmp(codec_name, "wmv1") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - codec_format->u.video.format = WG_VIDEO_FORMAT_WMV1; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, "WMV1", NULL); } else if (strcmp(codec_name, "wmv2") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - codec_format->u.video.format = WG_VIDEO_FORMAT_WMV2; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, 2, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, "WMV2", NULL); } else if (strcmp(codec_name, "wmv3") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - codec_format->u.video.format = WG_VIDEO_FORMAT_WMV3; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, "WMV3", NULL); } else if (strcmp(codec_name, "vc1") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; - codec_format->u.video.format = WG_VIDEO_FORMAT_WVC1; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, "WVC1", NULL); } else if (strcmp(codec_name, "wmav1") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 1; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 1, NULL); } else if (strcmp(codec_name, "wmav2") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 2; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 2, NULL); } else if (strcmp(codec_name, "wmapro") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 3; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 3, NULL); } else if (strcmp(codec_name, "wmalossless") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 4; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 4, NULL); } else if (strcmp(codec_name, "xma1") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 1; - codec_format->u.audio.is_xma = true; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-xma"); + gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, 1, NULL); } else if (strcmp(codec_name, "xma2") == 0) { - codec_format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; - codec_format->u.audio.version = 2; - codec_format->u.audio.is_xma = true; + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-xma"); + gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, 2, NULL); } else { @@ -1354,8 +1356,7 @@ static bool codec_info_to_wg_format(char *codec_info, struct wg_format *codec_fo return false; } - GST_INFO("Got codec format major type %u.", codec_format->major_type); - + GST_INFO("Got caps %" GST_PTR_FORMAT, caps); return true; } @@ -1386,7 +1387,7 @@ static GstElement *gst_bin_get_by_type(GstBin * bin, GType type) return element; } -bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, struct wg_format *codec_format) +bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, GstCaps *caps) { struct video_conv_state *state; uint8_t *buffer = NULL; @@ -1429,7 +1430,7 @@ bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index GST_INFO("Got codec info \"%s\" for stream %d.\n", codec_info, stream_index); - ret = codec_info_to_wg_format(codec_info, codec_format); + ret = codec_info_to_wg_format(codec_info, caps); done: if (buffer) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 24a41e36958..cc842c53ecf 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -124,8 +124,7 @@ extern void wg_allocator_release_sample(GstAllocator *allocator, struct wg_sampl /* media-converter */ extern bool media_converter_init(void); -extern bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, - struct wg_format *codec_format); +extern bool get_untranscoded_stream_format(GstElement *container, uint32_t stream_index, GstCaps *caps); static inline void touch_h264_used_tag(void) { diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 02db0620fd3..7a6e0de7ca2 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -269,6 +269,25 @@ static NTSTATUS wg_parser_stream_get_codec_format(void *args) struct wg_parser_stream_get_codec_format_params *params = args; struct wg_parser_stream *stream = get_stream(params->stream); + GST_TRACE("caps %" GST_PTR_FORMAT, stream->current_caps); + + if (stream->current_caps) + { + /* HACK: Return untranscoded codec format for transcoded stream. */ + GstCaps *caps = gst_caps_copy(stream->current_caps); + + if (get_untranscoded_stream_format(stream->parser->container, stream->number, caps)) + { + GST_TRACE("returning caps %" GST_PTR_FORMAT, caps); + wg_format_from_caps(params->format, caps); + gst_caps_unref(caps); + return S_OK; + } + gst_caps_unref(caps); + + GST_WARNING("Failed to get untranscoded codec format for stream %u.\n", stream->number); + } + if (caps_is_compressed(stream->codec_caps)) wg_format_from_caps(params->format, stream->codec_caps); else if (stream->current_caps) @@ -583,6 +602,10 @@ static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCap GstElementFactory *factory; GstElement *element; gboolean parsed; + const char *sgi; + + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "1083650") || !strcmp(sgi, "1097880"))) + return true; if (!parser->output_compressed) return true; From 9269e1f8f3e08de2e6f866bcbe95018fe2cf23a4 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 30 Apr 2024 12:19:16 +0800 Subject: [PATCH 280/301] winegstreamer/video_decoder: HACK: Try use I420 input if failed to create transform. CW-Bug-Id: #21303 CW-Bug-Id: #23630 CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index cbe5d627c98..404280d7bd9 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1252,7 +1252,27 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde } if (FAILED(hr = wg_transform_create_quartz(&decoder->dmo_input_type, type, &decoder->wg_transform_attrs, &decoder->wg_transform))) + { + /* HACK: Try I420 if failed to create gstreamer transform. The reason for + * the failure may be gstreamer decoder plugins are missing in proton. + * In that case, the video is likely to be transcoded already. Transcoded + * video streams are in theora format, and gstreamer theora decoder will + * finally output I420, so we try use I420 input here. */ + DMO_MEDIA_TYPE input_type; + + input_type = decoder->dmo_input_type; + input_type.subtype = MEDIASUBTYPE_I420; + input_type.formattype = FORMAT_VideoInfo; + input_type.cbFormat = sizeof(VIDEOINFOHEADER); + input_type.pbFormat = CoTaskMemAlloc(input_type.cbFormat); + memcpy(input_type.pbFormat, decoder->dmo_input_type.pbFormat, sizeof(VIDEOINFOHEADER)); + + hr = wg_transform_create_quartz(&input_type, type, + &decoder->wg_transform_attrs, &decoder->wg_transform); + FreeMediaType(&input_type); + return hr; + } return S_OK; } From 98b8f9d78a2d8ae009531ac2716e78616e7fb32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Jul 2024 14:26:25 +0200 Subject: [PATCH 281/301] winegstreamer: Check and use embedded caps in codec data. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_media_type.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 1c142745f0e..be3eeaacdc7 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -210,10 +210,13 @@ static GstAudioFormat wave_format_tag_to_gst_audio_format(UINT tag, UINT depth) static GstCaps *caps_from_wave_format_ex(const WAVEFORMATEX *format, UINT32 format_size, const GUID *subtype, UINT64 channel_mask) { GstAudioFormat audio_format = wave_format_tag_to_gst_audio_format(subtype->Data1, format->wBitsPerSample); + const void *codec_data = format + 1; GstCaps *caps; if (IsEqualGUID(subtype, &MFAudioFormat_GStreamer)) - return gst_caps_from_string((char *)(format + 1)); + return gst_caps_from_string(codec_data); + if (format_size > sizeof(*format) + 8 && !strncmp(codec_data, "audio/x-", 8)) + return gst_caps_from_string(codec_data); if (!(caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gst_audio_format_to_string(audio_format), "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, format->nSamplesPerSec, @@ -394,6 +397,7 @@ static BOOL is_mf_video_area_empty(const MFVideoArea *area) static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 format_size) { GstVideoFormat video_format = subtype_to_gst_video_format(&format->guidFormat); + const void *codec_data = format + 1; GstCaps *caps; GST_TRACE("subtype " WG_GUID_FORMAT " %ux%u, FPS " WG_RATIO_FORMAT ", aperture " WG_APERTURE_FORMAT ", " @@ -404,7 +408,9 @@ static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 forma if (format->dwSize > sizeof(*format)) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->dwSize - sizeof(*format)); if (IsEqualGUID(&format->guidFormat, &MFVideoFormat_GStreamer)) - return gst_caps_from_string((char *)(format + 1)); + return gst_caps_from_string(codec_data); + if (format_size > sizeof(*format) + 8 && !strncmp(codec_data, "video/x-", 8)) + return gst_caps_from_string(codec_data); if (!(caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, gst_video_format_to_string(video_format), NULL))) return NULL; From 96dc38a919344d3b63976899f7f98e14ef540cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Jul 2024 14:26:51 +0200 Subject: [PATCH 282/301] winegstreamer: Use H264 GUID when converting caps to video format. CW-Bug-Id: #20833 --- dlls/winegstreamer/video_decoder.c | 1 - dlls/winegstreamer/wg_media_type.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 404280d7bd9..690254a6d3d 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -1639,7 +1639,6 @@ HRESULT video_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; - decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.allow_format_change = TRUE; TRACE("Created video decoder transform %p.\n", &decoder->IMFTransform_iface); diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index be3eeaacdc7..0053c1d5493 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -872,6 +872,8 @@ NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UIN return video_format_from_gst_caps(caps, NULL, media_type->u.video, &media_type->format_size, video_plane_align); if (!strcmp(name, "video/x-cinepak")) return video_format_from_gst_caps(caps, &MFVideoFormat_CVID, media_type->u.video, &media_type->format_size, video_plane_align); + if (!strcmp(name, "video/x-h264")) + return video_format_from_gst_caps(caps, &MFVideoFormat_H264, media_type->u.video, &media_type->format_size, video_plane_align); if (!strcmp(name, "video/x-wmv")) return wmv_video_format_from_gst_caps(caps, media_type->u.video, &media_type->format_size, video_plane_align); if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) From 4c9b4ad1f1d1f314c007b9b1bb08e4aaffe13d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Jul 2024 15:22:33 +0200 Subject: [PATCH 283/301] winegstreamer/media-converter: Avoid leaking lock when dumping is interrupted. CW-Bug-Id: #20833 --- dlls/winegstreamer/media-converter/videoconv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winegstreamer/media-converter/videoconv.c b/dlls/winegstreamer/media-converter/videoconv.c index 06174ccc054..eef5cf85e49 100644 --- a/dlls/winegstreamer/media-converter/videoconv.c +++ b/dlls/winegstreamer/media-converter/videoconv.c @@ -387,6 +387,8 @@ static int video_conv_state_create(struct video_conv_state **out) static void video_conv_state_release(struct video_conv_state *state) { + if ((state->state_flags & VIDEO_CONV_IS_DUMPING)) + pthread_mutex_unlock(&dump_fozdb.mutex); if (state->read_fozdb) fozdb_release(state->read_fozdb); close(state->blank_file); From 8ce06ad5e5fff6f4f256f22e99bcc3931aef3e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Jul 2024 18:29:16 +0200 Subject: [PATCH 284/301] winegstreamer/video_decoder: Register the generic video decoder with more formats. Fixes missing video in Devil May Cry HD Collection / DMC1. CW-Bug-Id: #20833 --- dlls/winegstreamer/mfplat.c | 16 ++++++++++------ dlls/winegstreamer/video_decoder.c | 8 ++++++++ dlls/winegstreamer/wg_media_type.c | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index d81a34a66ba..d565a2794a4 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -362,15 +362,19 @@ HRESULT mfplat_DllRegisterServer(void) }; MFT_REGISTER_TYPE_INFO video_decoder_output_types[] = { + {MFMediaType_Video, MFVideoFormat_NV12}, {MFMediaType_Video, MFVideoFormat_YV12}, + {MFMediaType_Video, MFVideoFormat_IYUV}, + {MFMediaType_Video, MFVideoFormat_I420}, {MFMediaType_Video, MFVideoFormat_YUY2}, {MFMediaType_Video, MFVideoFormat_NV11}, - {MFMediaType_Video, MFVideoFormat_NV12}, - {MFMediaType_Video, MFVideoFormat_RGB32}, - {MFMediaType_Video, MFVideoFormat_RGB24}, - {MFMediaType_Video, MFVideoFormat_RGB565}, - {MFMediaType_Video, MFVideoFormat_RGB555}, - {MFMediaType_Video, MFVideoFormat_RGB8}, + {MFMediaType_Video, MFVideoFormat_UYVY}, + {MFMediaType_Video, MFVideoFormat_YVYU}, + {MFMediaType_Video, DMOVideoFormat_RGB32}, + {MFMediaType_Video, DMOVideoFormat_RGB24}, + {MFMediaType_Video, DMOVideoFormat_RGB565}, + {MFMediaType_Video, DMOVideoFormat_RGB555}, + {MFMediaType_Video, DMOVideoFormat_RGB8}, }; struct mft diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 690254a6d3d..ab937c83b77 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -77,6 +77,14 @@ static const GUID *const video_decoder_output_types[] = &MFVideoFormat_IYUV, &MFVideoFormat_I420, &MFVideoFormat_YUY2, + &MFVideoFormat_UYVY, + &MFVideoFormat_YVYU, + &MFVideoFormat_NV11, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, }; struct video_decoder diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 0053c1d5493..f45ba294a2c 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -378,6 +378,7 @@ static GstVideoFormat subtype_to_gst_video_format(const GUID *subtype) case D3DFMT_R5G6B5: return GST_VIDEO_FORMAT_RGB16; case MAKEFOURCC('A','Y','U','V'): return GST_VIDEO_FORMAT_AYUV; case MAKEFOURCC('I','4','2','0'): return GST_VIDEO_FORMAT_I420; + case MAKEFOURCC('I','Y','U','V'): return GST_VIDEO_FORMAT_I420; case MAKEFOURCC('N','V','1','2'): return GST_VIDEO_FORMAT_NV12; case MAKEFOURCC('U','Y','V','Y'): return GST_VIDEO_FORMAT_UYVY; case MAKEFOURCC('Y','U','Y','2'): return GST_VIDEO_FORMAT_YUY2; From f60fb2e11a5a81e6c519ec2ccf90631fd85b045f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Jul 2024 18:29:37 +0200 Subject: [PATCH 285/301] winegstreamer/new_media_source: Flush queued samples on flush-stop. Fixes garbled first frame in ARK: Survival Evolved. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_source.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 6f6ce5ae685..e81eb1eb596 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -527,6 +527,26 @@ static gboolean sink_event_eos(struct wg_source *source, GstPad *pad, GstEvent * return true; } +static gboolean sink_event_flush_stop(struct wg_source *source, GstPad *pad, GstEvent *event) +{ + struct source_stream *stream = source_stream_from_pad(source, pad); + GstBuffer *buffer; + + GST_TRACE("source %p, %"GST_PTR_FORMAT", %"GST_PTR_FORMAT, source, pad, event); + + if (stream->buffer) + { + gst_buffer_unref(stream->buffer); + stream->buffer = NULL; + } + + while ((buffer = gst_atomic_queue_pop(stream->queue))) + gst_buffer_unref(buffer); + + gst_event_unref(event); + return true; +} + static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) { struct wg_source *source = gst_pad_get_element_private(pad); @@ -541,6 +561,8 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) return sink_event_stream_start(source, pad, event); case GST_EVENT_EOS: return sink_event_eos(source, pad, event); + case GST_EVENT_FLUSH_STOP: + return sink_event_flush_stop(source, pad, event); default: return gst_pad_event_default(pad, parent, event); } @@ -917,6 +939,9 @@ NTSTATUS wg_source_read_data(void *args) GST_TRACE("source %p, index %#x, sample %p", source, index, sample); + if (gst_atomic_queue_length(source->seek_queue)) + return STATUS_PENDING; + if ((status = source_get_stream_buffer(source, index, &buffer))) return status; From 868104d259f088f6696b800bd1c3823c31634017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 Jul 2024 10:51:02 +0200 Subject: [PATCH 286/301] mfplat: Flush D3D11 context after CopySubresourceRegion on unmap. Fixes some garbled video frames when the texture is later used as input by the video processor. CW-Bug-Id: #20833 --- dlls/mfplat/buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index acea6482ab9..d1fd2a99529 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1004,6 +1004,7 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer, MF2DBuffer_LockFlag { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + ID3D11DeviceContext_Flush(immediate_context); } ID3D11DeviceContext_Release(immediate_context); From add4e83d658064572cbe0bdb42250f19216f69b7 Mon Sep 17 00:00:00 2001 From: Brendan McGrath Date: Thu, 18 Jul 2024 17:55:53 +1000 Subject: [PATCH 287/301] winegstreamer: Remove 'au' alignment for h264. h264parse does not correctly determine 'nal' alignment if this caps is provided. CW-Bug-Id: #23226 CW-Bug-Id: #23425 --- dlls/winegstreamer/wg_media_type.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index f45ba294a2c..c1653a71f21 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -303,7 +303,6 @@ static void init_caps_from_video_h264(GstCaps *caps, const MFVIDEOFORMAT *format gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-h264"); gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); - gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); } static void init_caps_from_video_wmv(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size, From a5090ea131a44a3b1960b29d207d0987455b602c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Aug 2024 09:12:08 +0200 Subject: [PATCH 288/301] winegstreamer: Use "avc" H264 stream format when "codec_data" is provided. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_media_type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index c1653a71f21..fe4216e5a2e 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -302,7 +302,7 @@ static void init_caps_from_video_h264(GstCaps *caps, const MFVIDEOFORMAT *format gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-h264"); - gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, format_size - sizeof(*format) ? "avc" : "byte-stream", NULL); } static void init_caps_from_video_wmv(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size, From 5f1801452b221c8bc573221e44ca1dad2394a135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Aug 2024 10:53:00 +0200 Subject: [PATCH 289/301] mfreadwrite: Always try inserting a converter for non-video streams. CW-Bug-Id: #20833 --- dlls/mfreadwrite/reader.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index b87a7f50cc8..3ff8a5f4625 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2022,13 +2022,15 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { - BOOL enable_advanced, allow_processor; + BOOL enable_advanced = FALSE, allow_processor = TRUE; struct media_stream *stream = &reader->streams[index]; IMFMediaType *input_type; unsigned int i = 0; + GUID major; HRESULT hr; - allow_processor = source_reader_allow_video_processor(reader, &enable_advanced); + if (SUCCEEDED(IMFMediaType_GetMajorType(output_type, &major)) && IsEqualGUID(&major, &MFMediaType_Video)) + allow_processor = source_reader_allow_video_processor(reader, &enable_advanced); while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { From e701f2628ad91bc55e6c69eb9f5171e126f46393 Mon Sep 17 00:00:00 2001 From: Etaash Mathamsetty Date: Fri, 5 Jul 2024 17:34:55 -0400 Subject: [PATCH 290/301] mmdevapi: Support getting IAudioClockAdjustment interface. For 4K cutscenes in Ghostbusters: The Video Game Remastered Link: https://github.com/ValveSoftware/wine/pull/245 --- dlls/mmdevapi/client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index c3bb7018bd4..eca19f4d4e3 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -880,6 +880,9 @@ static HRESULT WINAPI client_GetService(IAudioClient3 *iface, REFIID riid, void } else if (IsEqualIID(riid, &IID_IAudioClock)) { IAudioClock_AddRef(&This->IAudioClock_iface); *ppv = &This->IAudioClock_iface; + } else if (IsEqualIID(riid, &IID_IAudioClockAdjustment)) { + IAudioClockAdjustment_AddRef(&This->IAudioClockAdjustment_iface); + *ppv = &This->IAudioClockAdjustment_iface; } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) { IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); *ppv = &This->IAudioStreamVolume_iface; From bc7311843204298fb3280fef73b4b582c9978c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Aug 2024 19:19:33 +0200 Subject: [PATCH 291/301] winegstreamer: Avoid using the aperture for padding with the H264 decoder. It can change stream sizes during playback, and the video info aren't updated accordingly. CW-Bug-Id: #20833 --- dlls/winegstreamer/wg_transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 80d8a1258d8..4ed17d2c516 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -83,7 +83,7 @@ static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, align->padding_right = ((plane_align + 1) - (info->width & plane_align)) & plane_align; align->padding_bottom = ((plane_align + 1) - (info->height & plane_align)) & plane_align; - if (!is_mf_video_area_empty(aperture)) + if (!is_mf_video_area_empty(aperture) && !plane_align) { align->padding_right = max(align->padding_right, video_info->dwWidth - aperture->OffsetX.value - aperture->Area.cx); align->padding_bottom = max(align->padding_bottom, video_info->dwHeight - aperture->OffsetY.value - aperture->Area.cy); From 84c56e50aeb98b19c5dd8b4abfcf3308f48429b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Aug 2024 14:22:51 +0200 Subject: [PATCH 292/301] winegstreamer/resampler: Use WAVEFORMATEX for input/output media types. CW-Bug-Id: #20833 --- dlls/winegstreamer/resampler.c | 123 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index c1ce9897ef1..38478b22ecc 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -45,18 +45,20 @@ struct resampler IUnknown *outer; LONG refcount; - IMFMediaType *input_type; + WAVEFORMATEX *input_format; MFT_INPUT_STREAM_INFO input_info; - IMFMediaType *output_type; + WAVEFORMATEX *output_format; MFT_OUTPUT_STREAM_INFO output_info; wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; }; -static HRESULT try_create_wg_transform(struct resampler *impl) +static HRESULT try_create_wg_transform(struct resampler *impl, WAVEFORMATEX *input_format, WAVEFORMATEX *output_format) { + IMFMediaType *input_type, *output_type; struct wg_transform_attrs attrs = {0}; + HRESULT hr; if (impl->wg_transform) { @@ -64,7 +66,18 @@ static HRESULT try_create_wg_transform(struct resampler *impl) impl->wg_transform = 0; } - return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); + if (FAILED(hr = MFCreateAudioMediaType(input_format, (IMFAudioMediaType **)&input_type))) + return hr; + if (FAILED(hr = MFCreateAudioMediaType(output_format, (IMFAudioMediaType **)&output_type))) + { + IMFMediaType_Release(input_type); + return hr; + } + + hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform); + IMFMediaType_Release(input_type); + IMFMediaType_Release(output_type); + return hr; } static inline struct resampler *impl_from_IUnknown(IUnknown *iface) @@ -122,10 +135,10 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) { if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); - if (impl->input_type) - IMFMediaType_Release(impl->input_type); - if (impl->output_type) - IMFMediaType_Release(impl->output_type); + if (impl->input_format) + CoTaskMemFree(impl->input_format); + if (impl->output_format) + CoTaskMemFree(impl->output_format); wg_sample_queue_destroy(impl->wg_sample_queue); free(impl); @@ -191,7 +204,7 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - if (!impl->input_type || !impl->output_type) + if (!impl->input_format || !impl->output_format) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -207,7 +220,7 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - if (!impl->input_type || !impl->output_type) + if (!impl->input_format || !impl->output_format) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -359,34 +372,34 @@ static HRESULT check_media_type(IMFMediaType *type) static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct resampler *impl = impl_from_IMFTransform(iface); - UINT32 block_alignment; + WAVEFORMATEX *format; + UINT32 value; HRESULT hr; TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); if (FAILED(hr = check_media_type(type))) return hr; - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) + if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value))) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type))) - return hr; - - if (impl->output_type) + if (impl->input_format) { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; + CoTaskMemFree(impl->input_format); + impl->input_format = NULL; + } + if (impl->output_format) + { + CoTaskMemFree(impl->output_format); + impl->output_format = NULL; } - if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->input_type))) - impl->input_info.cbSize = block_alignment; - else + if (SUCCEEDED(hr = MFCreateWaveFormatExFromMFMediaType(type, &format, &value, 0))) { - IMFMediaType_Release(impl->input_type); - impl->input_info.cbSize = 0; - impl->input_type = NULL; + impl->input_info.cbSize = format->nBlockAlign; + impl->input_format = format; } return hr; @@ -395,82 +408,66 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct resampler *impl = impl_from_IMFTransform(iface); - UINT32 block_alignment; + WAVEFORMATEX *format; + UINT32 value; HRESULT hr; TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - if (!impl->input_type) + if (!impl->input_format) return MF_E_TRANSFORM_TYPE_NOT_SET; if (FAILED(hr = check_media_type(type))) return hr; - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) + if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value))) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; - if (!impl->output_type && FAILED(hr = MFCreateMediaType(&impl->output_type))) - return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->output_type))) - goto failed; - - if (FAILED(hr = try_create_wg_transform(impl))) - goto failed; + if (impl->output_format) + { + CoTaskMemFree(impl->output_format); + impl->output_format = NULL; + } - impl->output_info.cbSize = block_alignment; - return hr; + if (SUCCEEDED(hr = MFCreateWaveFormatExFromMFMediaType(type, &format, &value, 0))) + { + if (FAILED(hr = try_create_wg_transform(impl, impl->input_format, format))) + CoTaskMemFree(format); + else + { + impl->output_info.cbSize = format->nBlockAlign; + impl->output_format = format; + } + } -failed: - IMFMediaType_Release(impl->output_type); - impl->output_info.cbSize = 0; - impl->output_type = NULL; return hr; } static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct resampler *impl = impl_from_IMFTransform(iface); - HRESULT hr; TRACE("iface %p, id %#lx, type %p.\n", iface, id, type); if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - - if (!impl->input_type) + if (!impl->input_format) return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) - return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(impl->input_type, (IMFAttributes *)*type))) - IMFMediaType_Release(*type); - - return hr; + return MFCreateAudioMediaType(impl->input_format, (IMFAudioMediaType **)type); } static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct resampler *impl = impl_from_IMFTransform(iface); - HRESULT hr; TRACE("iface %p, id %#lx, type %p.\n", iface, id, type); if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - - if (!impl->output_type) + if (!impl->output_format) return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) - return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(impl->output_type, (IMFAttributes *)*type))) - IMFMediaType_Release(*type); - - return hr; + return MFCreateAudioMediaType(impl->output_format, (IMFAudioMediaType **)type); } static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) From f3697eaca7274e265bad7240d9f12c812b6bc6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Aug 2024 14:22:56 +0200 Subject: [PATCH 293/301] winegstreamer/resampler: Recalculate resampler nBlockAlign and avgBytesPerSec values. CW-Bug-Id: #20833 --- dlls/winegstreamer/resampler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 38478b22ecc..c9c81cde555 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -398,6 +398,8 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (SUCCEEDED(hr = MFCreateWaveFormatExFromMFMediaType(type, &format, &value, 0))) { + format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; impl->input_info.cbSize = format->nBlockAlign; impl->input_format = format; } @@ -432,6 +434,9 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (SUCCEEDED(hr = MFCreateWaveFormatExFromMFMediaType(type, &format, &value, 0))) { + format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; + if (FAILED(hr = try_create_wg_transform(impl, impl->input_format, format))) CoTaskMemFree(format); else From c1885c73928c28fa6c2c4a3b5b244edba703f4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 5 Sep 2024 18:53:25 +0200 Subject: [PATCH 294/301] Revert "HACK: mmdevapi: Disable getting IAudioClockAdjustment via GetService." This reverts commit 8c9e894d95520d94696c52049eeb0a1263241248. --- dlls/mmdevapi/client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index eca19f4d4e3..42a14cf41f6 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -907,6 +907,9 @@ static HRESULT WINAPI client_GetService(IAudioClient3 *iface, REFIID riid, void if (!new_session) IUnknown_AddRef((IUnknown *)*ppv); + } else if (IsEqualIID(riid, &IID_IAudioClockAdjustment)) { + IAudioClockAdjustment_AddRef(&This->IAudioClockAdjustment_iface); + *ppv = &This->IAudioClockAdjustment_iface; } else { FIXME("stub %s\n", debugstr_guid(riid)); hr = E_NOINTERFACE; From de8895716949e3c99e98e15ed66590baf3a7ca15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 5 Sep 2024 18:53:41 +0200 Subject: [PATCH 295/301] Revert "mmdevapi: Support getting IAudioClockAdjustment interface." This reverts commit e701f2628ad91bc55e6c69eb9f5171e126f46393. --- dlls/mmdevapi/client.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 42a14cf41f6..41a9655aa44 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -880,9 +880,6 @@ static HRESULT WINAPI client_GetService(IAudioClient3 *iface, REFIID riid, void } else if (IsEqualIID(riid, &IID_IAudioClock)) { IAudioClock_AddRef(&This->IAudioClock_iface); *ppv = &This->IAudioClock_iface; - } else if (IsEqualIID(riid, &IID_IAudioClockAdjustment)) { - IAudioClockAdjustment_AddRef(&This->IAudioClockAdjustment_iface); - *ppv = &This->IAudioClockAdjustment_iface; } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) { IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); *ppv = &This->IAudioStreamVolume_iface; From 07194e86e0d27a746c201ade036860d837f7cd22 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 4 Sep 2024 20:46:14 -0600 Subject: [PATCH 296/301] ntdll: Allow sending to port 0 on UDP socket to succeed. CW-Bug-Id: #24213 --- dlls/ntdll/unix/socket.c | 8 ++++++++ dlls/ws2_32/tests/sock.c | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 7f0512da627..f79f35e7db4 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1004,6 +1004,14 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) ERR( "failed to convert address\n" ); return STATUS_ACCESS_VIOLATION; } + if (sock_type == SOCK_DGRAM && ((unix_addr.addr.sa_family == AF_INET && !unix_addr.in.sin_port) + || (unix_addr.addr.sa_family == AF_INET6 && !unix_addr.in6.sin6_port))) + { + /* Sending to port 0 succeeds on Windows. Use 'discard' service instead so sendmsg() works on Unix + * while still goes through other parameters validation. */ + WARN( "Trying to use destination port 0, substituing 9.\n" ); + unix_addr.in.sin_port = htons( 9 ); + } #if defined(HAS_IPX) && defined(SOL_IPX) if (async->addr->sa_family == WS_AF_IPX) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 807018efa2c..2b64f43f8b1 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3145,6 +3145,7 @@ static void test_UDP(void) struct sock_info peer[NUM_UDP_PEERS]; char buf[16]; int ss, i, n_recv, n_sent, ret; + struct sockaddr_in6 addr6; struct sockaddr_in addr; int sock; struct send_udp_thread_param udp_thread_param; @@ -3229,6 +3230,26 @@ static void test_UDP(void) CloseHandle( udp_thread_param.start_event ); closesocket(sock); + + /* Test sending to port 0. */ + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + ok( sock != INVALID_SOCKET, "got error %u.\n", WSAGetLastError() ); + memset( &addr, 0, sizeof(addr) ); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); + ret = sendto( sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, sizeof(addr) ); + ok( ret == sizeof(buf), "got ret %d, error %u.\n", ret, WSAGetLastError() ); + closesocket(sock); + + sock = socket( AF_INET6, SOCK_DGRAM, 0 ); + ok( sock != INVALID_SOCKET, "got error %u.\n", WSAGetLastError() ); + memset( &addr6, 0, sizeof(addr6) ); + addr6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "::1", &addr6.sin6_addr ); + ok( ret, "got error %u.\n", WSAGetLastError() ); + ret = sendto( sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr6, sizeof(addr6) ); + ok( ret == sizeof(buf), "got ret %d, error %u.\n", ret, WSAGetLastError() ); + closesocket(sock); } static void test_WSASocket(void) From edb8528f6792e3b1f040385ea510cefd21e03dbd Mon Sep 17 00:00:00 2001 From: Brendan McGrath Date: Tue, 3 Sep 2024 13:49:27 +1000 Subject: [PATCH 297/301] winegstreamer: Allow application to drain queue. Pushing all queued input immediately causes gstreamer to process all frames in advance and queue them in the output_queue of the transform. This results in a large amount of memory usage that can cause an OOM issue. This patch allows the queue to be drained at the rate required by the application. (cherry picked from commit 4a6c1c124ac30576845cbf6e9936697ca80c9998) CW-Bug-Id: #24132 --- dlls/winegstreamer/wg_transform.c | 68 +++++++++++++++++++------------ 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 4ed17d2c516..5adb7d3994e 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -62,6 +62,8 @@ struct wg_transform GstCaps *desired_caps; GstCaps *output_caps; GstCaps *input_caps; + + bool draining; }; static struct wg_transform *get_transform(wg_transform_t trans) @@ -857,6 +859,13 @@ NTSTATUS wg_transform_push_data(void *args) GstBuffer *buffer; guint length; + if (transform->draining) + { + GST_INFO("Refusing %u bytes, transform is draining", sample->size); + params->result = MF_E_NOTACCEPTING; + return STATUS_SUCCESS; + } + length = gst_atomic_queue_length(transform->input_queue); if (length >= transform->attrs.input_queue_length + 1) { @@ -1071,6 +1080,33 @@ static NTSTATUS read_transform_output(struct wg_sample *sample, GstBuffer *buffe return STATUS_SUCCESS; } +static NTSTATUS complete_drain(struct wg_transform *transform) +{ + if (transform->draining && gst_atomic_queue_length(transform->input_queue) == 0) + { + GstEvent *event; + transform->draining = false; + if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, -1)) + || !push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_eos()) + || !push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_stream_start("stream")) + || !push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_segment(&transform->segment)) + || !push_event(transform->my_src, event)) + goto error; + } + + return STATUS_SUCCESS; + +error: + GST_ERROR("Failed to drain transform %p.", transform); + return STATUS_UNSUCCESSFUL; +} + static bool get_transform_output(struct wg_transform *transform, struct wg_sample *sample) { GstBuffer *input_buffer; @@ -1083,6 +1119,8 @@ static bool get_transform_output(struct wg_transform *transform, struct wg_sampl { if ((ret = gst_pad_push(transform->my_src, input_buffer))) GST_WARNING("Failed to push transform input, error %d", ret); + + complete_drain(transform); } /* Remove the sample so the allocator cannot use it */ @@ -1198,36 +1236,12 @@ NTSTATUS wg_transform_get_status(void *args) NTSTATUS wg_transform_drain(void *args) { struct wg_transform *transform = get_transform(*(wg_transform_t *)args); - GstBuffer *input_buffer; - GstFlowReturn ret; - GstEvent *event; - GST_LOG("transform %p", transform); + GST_LOG("transform %p, draining %d buffers", transform, gst_atomic_queue_length(transform->input_queue)); - while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) - { - if ((ret = gst_pad_push(transform->my_src, input_buffer))) - GST_WARNING("Failed to push transform input, error %d", ret); - } + transform->draining = true; - if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, -1)) - || !push_event(transform->my_src, event)) - goto error; - if (!(event = gst_event_new_eos()) - || !push_event(transform->my_src, event)) - goto error; - if (!(event = gst_event_new_stream_start("stream")) - || !push_event(transform->my_src, event)) - goto error; - if (!(event = gst_event_new_segment(&transform->segment)) - || !push_event(transform->my_src, event)) - goto error; - - return STATUS_SUCCESS; - -error: - GST_ERROR("Failed to drain transform %p.", transform); - return STATUS_UNSUCCESSFUL; + return complete_drain(transform); } NTSTATUS wg_transform_flush(void *args) From bda0dc2244191ebf0a0add8f08fb39db8abe6bd6 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Thu, 29 Feb 2024 13:15:02 +0100 Subject: [PATCH 298/301] include: Add TCP_KEEPCNT and TCP_KEEPINTVL definitions. (cherry picked from commit 6d2a900487bb9a41f16de4f0092cc9345580e356) CW-Bug-Id: #24237 --- include/ws2ipdef.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/ws2ipdef.h b/include/ws2ipdef.h index fcb1f56c005..72e2dad2fa5 100644 --- a/include/ws2ipdef.h +++ b/include/ws2ipdef.h @@ -313,6 +313,8 @@ typedef struct WS(in6_pktinfo) { #define TCP_OFFLOAD_PREFERENCE 11 #define TCP_CONGESTION_ALGORITHM 12 #define TCP_DELAY_FIN_ACK 13 +#define TCP_KEEPCNT 16 +#define TCP_KEEPINTVL 17 #else /* WS_TCP_NODELAY is defined elsewhere */ #define WS_TCP_EXPEDITED_1122 2 @@ -327,6 +329,8 @@ typedef struct WS(in6_pktinfo) { #define WS_TCP_OFFLOAD_PREFERENCE 11 #define WS_TCP_CONGESTION_ALGORITHM 12 #define WS_TCP_DELAY_FIN_ACK 13 +#define WS_TCP_KEEPCNT 16 +#define WS_TCP_KEEPINTVL 17 #endif /* USE_WS_PREFIX */ #define PROTECTION_LEVEL_UNRESTRICTED 10 From c797df3d96b816a8a4dedb52284fb9f575475f0f Mon Sep 17 00:00:00 2001 From: Florian Will Date: Thu, 29 Feb 2024 13:02:52 +0100 Subject: [PATCH 299/301] ws2_32/tests: Test TCP_KEEP{ALIVE,CNT,INTVL} options. (cherry picked from commit 26136fda8deceae60357f82acb89121efad30b8f) CW-Bug-Id: #24237 --- dlls/ws2_32/tests/sock.c | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 2b64f43f8b1..11e975bd08c 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1193,6 +1193,7 @@ static void test_set_getsockopt(void) DWORD values[3]; BOOL accepts_large_value; BOOL bool_value; + BOOL allow_noprotoopt; /* for old windows or wine todo */ } test_optsize[] = { @@ -1210,6 +1211,9 @@ static void test_set_getsockopt(void) {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDTIMEO, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_OPENTYPE, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_NODELAY, TRUE, {1, 1, 1}, {0}, TRUE}, + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPALIVE, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* wine todo */ + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPCNT, FALSE, {0, 0, 4}, {0}, FALSE, FALSE, TRUE}, /* win10+, wine todo*/ + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPINTVL, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* win10+, wine todo */ {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_LOOP, TRUE, {1, 1, 4}, {0}, TRUE, TRUE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_TTL, TRUE, {1, 1, 4}, {0}, FALSE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_PKTINFO, FALSE, {0, 0, 4}, {0}, TRUE, TRUE}, @@ -1453,6 +1457,36 @@ static void test_set_getsockopt(void) ok(!err, "getsockopt TCP_NODELAY failed\n"); ok(!value, "TCP_NODELAY should be 0\n"); + size = sizeof(DWORD); + value = 3600; + err = setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, 4); + todo_wine ok(!err, "setsockopt TCP_KEEPALIVE failed\n"); + value = 0; + err = getsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, &size); + todo_wine ok(!err, "getsockopt TCP_KEEPALIVE failed\n"); + todo_wine ok(value == 3600, "TCP_KEEPALIVE should be 3600, is %ld\n", value); + + /* TCP_KEEPCNT and TCP_KEEPINTVL are supported on win10 and later */ + value = 5; + err = setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char*)&value, 4); + todo_wine ok(!err || broken(WSAGetLastError() == WSAENOPROTOOPT), + "setsockopt TCP_KEEPCNT failed: %d\n", WSAGetLastError()); + + if (!err) + { + value = 0; + err = getsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char*)&value, &size); + ok(!err, "getsockopt TCP_KEEPCNT failed\n"); + ok(value == 5, "TCP_KEEPCNT should be 5, is %ld\n", value); + + err = setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&value, 4); + ok(!err, "setsockopt TCP_KEEPINTVL failed\n"); + value = 0; + err = getsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&value, &size); + ok(!err, "getsockopt TCP_KEEPINTVL failed\n"); + ok(value == 5, "TCP_KEEPINTVL should be 5, is %ld\n", value); + } + /* Test for erroneously passing a value instead of a pointer as optval */ size = sizeof(char); err = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)1, size); @@ -1517,7 +1551,15 @@ static void test_set_getsockopt(void) size = sizeof(save_value); err = getsockopt(s2, test_optsize[i].level, test_optsize[i].optname, (char*)&save_value, &size); - ok(!err, "Unexpected getsockopt result %d.\n", err); + ok(!err || (test_optsize[i].allow_noprotoopt && WSAGetLastError() == WSAENOPROTOOPT), + "Unexpected getsockopt result %d.\n", err); + + if (err) + { + closesocket(s2); + winetest_pop_context(); + continue; + } value64 = 0xffffffff00000001; err = setsockopt(s2, test_optsize[i].level, test_optsize[i].optname, (char *)&value64, sizeof(value64)); From 243b2b4b3a00dbe31901918de09f2452e9af67e8 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Thu, 29 Feb 2024 13:48:32 +0100 Subject: [PATCH 300/301] ws2_32: Implement TCP_KEEP{ALIVE,CNT,INTVL} options. (cherry picked from commit 8dc5242e2998afed87bc57db5798eea85877094e) CW-Bug-Id: #24237 --- dlls/ntdll/unix/socket.c | 28 ++++++++++++++++++ dlls/ws2_32/socket.c | 63 ++++++++++++++++++++++++++++++++++++++++ dlls/ws2_32/tests/sock.c | 18 ++++++------ include/wine/afd.h | 6 ++++ 4 files changed, 106 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index f79f35e7db4..329da8cd4fd 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -2534,6 +2534,34 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc case IOCTL_AFD_WINE_SET_TCP_NODELAY: return do_setsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, in_buffer, in_size ); +#if defined(TCP_KEEPIDLE) + /* TCP_KEEPALIVE on Windows is often called TCP_KEEPIDLE on Unix */ + case IOCTL_AFD_WINE_GET_TCP_KEEPALIVE: + return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPIDLE, out_buffer, out_size ); + + case IOCTL_AFD_WINE_SET_TCP_KEEPALIVE: + return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPIDLE, in_buffer, in_size ); +#elif defined(TCP_KEEPALIVE) + /* Mac */ + case IOCTL_AFD_WINE_GET_TCP_KEEPALIVE: + return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPALIVE, out_buffer, out_size ); + + case IOCTL_AFD_WINE_SET_TCP_KEEPALIVE: + return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPALIVE, in_buffer, in_size ); +#endif + + case IOCTL_AFD_WINE_GET_TCP_KEEPINTVL: + return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPINTVL, out_buffer, out_size ); + + case IOCTL_AFD_WINE_SET_TCP_KEEPINTVL: + return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPINTVL, in_buffer, in_size ); + + case IOCTL_AFD_WINE_GET_TCP_KEEPCNT: + return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPCNT, out_buffer, out_size ); + + case IOCTL_AFD_WINE_SET_TCP_KEEPCNT: + return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPCNT, in_buffer, in_size ); + default: { if ((code >> 16) == FILE_DEVICE_NETWORK) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 6aab249a1b8..eb84558cbac 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1931,6 +1931,36 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl *optlen = 1; return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_NODELAY, optval, optlen ); + case TCP_KEEPALIVE: + if (*optlen < sizeof(DWORD) || !optval) + { + *optlen = 0; + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + *optlen = sizeof(DWORD); + return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPALIVE, optval, optlen ); + + case TCP_KEEPCNT: + if (*optlen < sizeof(DWORD) || !optval) + { + *optlen = 0; + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + *optlen = sizeof(DWORD); + return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPCNT, optval, optlen ); + + case TCP_KEEPINTVL: + if (*optlen < sizeof(DWORD) || !optval) + { + *optlen = 0; + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + *optlen = sizeof(DWORD); + return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPINTVL, optval, optlen ); + default: FIXME( "unrecognized TCP option %#x\n", optname ); SetLastError( WSAENOPROTOOPT ); @@ -3325,6 +3355,12 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int break; /* case NSPROTO_IPX */ case IPPROTO_TCP: + if (optlen < 0) + { + SetLastError(WSAENOBUFS); + return SOCKET_ERROR; + } + switch(optname) { case TCP_NODELAY: @@ -3336,6 +3372,33 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int value = *optval; return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_NODELAY, (char*)&value, sizeof(value) ); + case TCP_KEEPALIVE: + if (optlen < sizeof(DWORD) || !optval) + { + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + value = *(DWORD*)optval; + return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPALIVE, (char*)&value, sizeof(value) ); + + case TCP_KEEPCNT: + if (optlen < sizeof(DWORD) || !optval) + { + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + value = *(DWORD*)optval; + return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPCNT, (char*)&value, sizeof(value) ); + + case TCP_KEEPINTVL: + if (optlen < sizeof(DWORD) || !optval) + { + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + value = *(DWORD*)optval; + return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPINTVL, (char*)&value, sizeof(value) ); + default: FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname); SetLastError(WSAENOPROTOOPT); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 11e975bd08c..c390b186956 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1193,7 +1193,7 @@ static void test_set_getsockopt(void) DWORD values[3]; BOOL accepts_large_value; BOOL bool_value; - BOOL allow_noprotoopt; /* for old windows or wine todo */ + BOOL allow_noprotoopt; /* for old windows only, must work on wine */ } test_optsize[] = { @@ -1211,9 +1211,9 @@ static void test_set_getsockopt(void) {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDTIMEO, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_OPENTYPE, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_NODELAY, TRUE, {1, 1, 1}, {0}, TRUE}, - {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPALIVE, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* wine todo */ - {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPCNT, FALSE, {0, 0, 4}, {0}, FALSE, FALSE, TRUE}, /* win10+, wine todo*/ - {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPINTVL, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* win10+, wine todo */ + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPALIVE, FALSE, {0, 0, 4}, {0}, TRUE}, + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPCNT, FALSE, {0, 0, 4}, {0}, FALSE, FALSE, TRUE}, /* win10+ */ + {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPINTVL, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* win10+ */ {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_LOOP, TRUE, {1, 1, 4}, {0}, TRUE, TRUE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_TTL, TRUE, {1, 1, 4}, {0}, FALSE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_PKTINFO, FALSE, {0, 0, 4}, {0}, TRUE, TRUE}, @@ -1460,16 +1460,16 @@ static void test_set_getsockopt(void) size = sizeof(DWORD); value = 3600; err = setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, 4); - todo_wine ok(!err, "setsockopt TCP_KEEPALIVE failed\n"); + ok(!err, "setsockopt TCP_KEEPALIVE failed\n"); value = 0; err = getsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, &size); - todo_wine ok(!err, "getsockopt TCP_KEEPALIVE failed\n"); - todo_wine ok(value == 3600, "TCP_KEEPALIVE should be 3600, is %ld\n", value); + ok(!err, "getsockopt TCP_KEEPALIVE failed\n"); + ok(value == 3600, "TCP_KEEPALIVE should be 3600, is %ld\n", value); /* TCP_KEEPCNT and TCP_KEEPINTVL are supported on win10 and later */ value = 5; err = setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char*)&value, 4); - todo_wine ok(!err || broken(WSAGetLastError() == WSAENOPROTOOPT), + ok(!err || broken(WSAGetLastError() == WSAENOPROTOOPT), "setsockopt TCP_KEEPCNT failed: %d\n", WSAGetLastError()); if (!err) @@ -1551,7 +1551,7 @@ static void test_set_getsockopt(void) size = sizeof(save_value); err = getsockopt(s2, test_optsize[i].level, test_optsize[i].optname, (char*)&save_value, &size); - ok(!err || (test_optsize[i].allow_noprotoopt && WSAGetLastError() == WSAENOPROTOOPT), + ok(!err || broken(test_optsize[i].allow_noprotoopt && WSAGetLastError() == WSAENOPROTOOPT), "Unexpected getsockopt result %d.\n", err); if (err) diff --git a/include/wine/afd.h b/include/wine/afd.h index 788adb4a495..aba559ebd8a 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -285,6 +285,12 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 ); #define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296) #define IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(297) #define IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(298) +#define IOCTL_AFD_WINE_GET_TCP_KEEPALIVE WINE_AFD_IOC(299) +#define IOCTL_AFD_WINE_SET_TCP_KEEPALIVE WINE_AFD_IOC(300) +#define IOCTL_AFD_WINE_GET_TCP_KEEPCNT WINE_AFD_IOC(301) +#define IOCTL_AFD_WINE_SET_TCP_KEEPCNT WINE_AFD_IOC(302) +#define IOCTL_AFD_WINE_GET_TCP_KEEPINTVL WINE_AFD_IOC(303) +#define IOCTL_AFD_WINE_SET_TCP_KEEPINTVL WINE_AFD_IOC(304) struct afd_iovec { From b6335b4a77ed8c53232153ed1bee078128a1e974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Pi=C3=B3rkowski?= Date: Tue, 10 Sep 2024 00:40:45 +0000 Subject: [PATCH 301/301] fsync: Fix checking if futex_waitv is available. Check for EPERM in addition to ENOSYS when checking futex_waitv's availability. EPERM is returned in environments where the futex_waitv syscall is blocked. --- dlls/ntdll/unix/fsync.c | 2 +- server/fsync.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index c3da44e4f26..675f20c775e 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -171,7 +171,7 @@ int do_fsync(void) if (do_fsync_cached == -1) { syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS && errno != EPERM; } return do_fsync_cached; diff --git a/server/fsync.c b/server/fsync.c index dc50aa0a1f3..8097b86fcea 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -59,7 +59,7 @@ int do_fsync(void) if (do_fsync_cached == -1) { syscall( __NR_futex_waitv, 0, 0, 0, 0, 0); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS && errno != EPERM; } return do_fsync_cached;