From bcfed21ea1925e06c1f0db0e86cb2380300b8aa9 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 22 Feb 2022 10:25:44 +1100 Subject: [PATCH] Updated mfplat-streaming-support patchset --- ...CK-Use-a-different-gst-registry-file.patch | 40 + ...CK-Try-harder-to-register-winegstrea.patch | 60 + ...ter-winegstreamer-interfaces-on-load.patch | 50 + ...amer-Create-static-pads-on-wg_transf.patch | 223 ++++ ...amer-Introduce-new-wg_transform-stru.patch | 293 +++++ ...amer-Introduce-new-WG_MAJOR_TYPE_WMA.patch | 344 ++++++ ...amer-Move-format-helpers-to-a-dedica.patch | 933 +++++++++++++++ ...er-Allow-videoconvert-to-parallelize.patch | 29 + ...er-Use-capssetter-to-ignore-non-defa.patch | 95 ++ ...mer-Add-push-mode-path-for-wg_parser.patch | 867 -------------- ...-a-reference-on-the-IMediaPosition-i.patch | 97 ++ ...MFCreateDXGIDeviceManager-to-avoid-t.patch | 34 + ...ent-ASF-Reader-filter-as-a-simple-fi.patch | 1035 +++++++++++++++++ ...ivate-source-pad-in-push-mode-if-it.patch} | 65 +- ...h-stream-start-and-segment-events-i.patch} | 18 +- ...r-Introduce-H.264-decoder-transform.patch} | 61 +- ...r-Register-the-AAC-decoder-transform.patch | 53 - ...lement-GetInputAvailableType-for-de.patch} | 29 +- ...lement-GetOutputAvailableType-for-d.patch} | 8 +- ...lement-SetInputType-for-decode-tran.patch} | 87 +- ...lement-SetOutputType-for-decode-tra.patch} | 6 +- ...lement-Get-Input-Output-StreamInfo-.patch} | 8 +- ...i-stub-GetAttributes-for-decoder-tr.patch} | 10 +- ...egister-the-H.264-decoder-transform.patch} | 18 +- ...mer-Introduce-AAC-decoder-transform.patch} | 210 +--- ...ame-GStreamer-objects-to-be-more-ge.patch} | 21 +- ...ort-streams-backwards-in-media-sour.patch} | 11 +- ...lement-Get-Input-Output-StreamInfo-.patch} | 20 +- ...i-stub-Get-Attributes-functions-for.patch} | 44 +- ...ntroduce-color-conversion-transform.patch} | 52 +- ...ister-the-color-conversion-transfor.patch} | 32 +- ...lement-GetInputAvailableType-for-co.patch} | 8 +- ...lement-SetInputType-for-color-conve.patch} | 8 +- ...lement-GetOutputAvailableType-for-c.patch} | 8 +- ...negstreamer-Implement-MF_SD_LANGUAGE.patch | 131 --- ...lement-SetOutputType-for-color-conv.patch} | 8 +- ...lement-ProcessMessage-for-color-con.patch} | 10 +- ...n-t-rely-on-max_size-in-unseekable-p.patch | 29 - ...lement-Get-Input-Output-StreamInfo-.patch} | 12 +- ...rd-failure-from-SetOutputType-when-.patch} | 8 +- ...fault-Frame-size-if-one-isn-t-availa.patch | 44 - ...dle-flush-command-in-audio-converst.patch} | 12 +- ...MFCreateDXGIDeviceManager-to-avoid-t.patch | 26 - ...the-default-configuration-select-on.patch} | 14 +- ...plement-IMFTransform-GetOutputCurren.patch | 54 + ...er-Implement-stream-draining-support.patch | 178 +++ ...d-an-explicit-result-to-wg_parser_pu.patch | 190 +++ ...block-wg_parser_get_next_read_offset.patch | 26 + ...date-offset-according-to-the-size-of.patch | 26 + ...t-src_getrange_cb-allocate-the-buffe.patch | 56 + ...-Implement-unseekable-stream-support.patch | 436 +++++++ ...lement-Process-Input-Output-for-dec.patch} | 178 +-- ...lement-ProcessMessage-for-decoder-t.patch} | 15 +- ...lement-Process-Input-Output-for-aud.patch} | 241 ++-- ...lement-Process-Input-Output-for-col.patch} | 160 ++- ...negstreamer-Implement-MF_SD_LANGUAGE.patch | 184 +++ ...lement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch} | 31 +- ...d-videobox-element-and-aperture-supp.patch | 376 ++++++ ...y-require-videobox-element-for-pars.patch} | 60 +- ...ed-full-buffer-in-audio-converter-Pr.patch | 48 + ...d-MFVideoFormat_ARGB32-output-for-th.patch | 37 + ...turn-S_OK-from-WMA-decoder-ProcessMe.patch | 29 + ...er-Introduce-new-wg_transform-struct.patch | 326 ++++++ ...troduce-new-wg_encoded_format-struct.patch | 185 +++ ...eate-static-pads-on-wg_transform-str.patch | 236 ++++ ...okup-create-and-link-a-decoder-eleme.patch | 207 ++++ ...nd-stream-start-and-caps-events-on-c.patch | 59 + ...d-an-audioconverter-and-audioresampl.patch | 100 ++ ...r-Implement-WMA-decoder-ProcessInput.patch | 249 ++++ ...-Implement-WMA-decoder-ProcessOutput.patch | 407 +++++++ ...pport-XMAudio2-input-format-in-WMA-d.patch | 116 ++ ...troduce-new-H264-decoder-transform-s.patch | 363 ++++++ ...turn-S_OK-from-H264-decoder-GetAttri.patch | 37 + ...turn-S_OK-from-H264-decoder-ProcessM.patch | 36 + ...-Implement-H264-decoder-SetInputType.patch | 89 ++ ...plement-H264-decoder-GetOutputAvaila.patch | 196 ++++ ...plement-H264-decoder-GetInputAvailab.patch | 56 + ...Implement-H264-decoder-SetOutputType.patch | 93 ++ ...plement-H264-decoder-GetInputStreamI.patch | 50 + ...plement-H264-decoder-GetOutputStream.patch | 55 + ...d-H264-encoded-format-support-in-wg_.patch | 264 +++++ ...-Implement-H264-decoder-ProcessInput.patch | 63 + ...Implement-H264-decoder-ProcessOutput.patch | 83 ++ ...d-timestamps-and-duration-to-H264-de.patch | 87 ++ ...pport-dynamic-wg_transform-video-for.patch | 285 +++++ ...xup-H264-decoder-NV12-plane-alignmen.patch | 112 ++ ...e-an-optional-h264parse-wg_transform.patch | 44 + ...er-Fake-H264-timestamps-if-framerate.patch | 106 ++ ...set-internal-format-on-BEGIN_STREAMI.patch | 49 + ...implement-AAC-decoder-using-wg_trans.patch | 878 ++++++++++++++ ...ter-failing-to-create-decodebin-pars.patch | 154 +++ ...mer-After-failing-to-create-decodebi.patch | 25 + ...e-unlimited-buffering-for-the-WM-rea.patch | 26 + ...er-Report-streams-in-reverse-order-f.patch | 26 + patches/mfplat-streaming-support/definition | 1 - patches/patchinstall.sh | 110 ++ 96 files changed, 10756 insertions(+), 1913 deletions(-) create mode 100644 patches/mfplat-streaming-support/0001-winegstreamer-HACK-Use-a-different-gst-registry-file.patch create mode 100644 patches/mfplat-streaming-support/0002-winegstreamer-HACK-Try-harder-to-register-winegstrea.patch create mode 100644 patches/mfplat-streaming-support/0003-mfplat-Register-winegstreamer-interfaces-on-load.patch create mode 100644 patches/mfplat-streaming-support/0004-Revert-winegstreamer-Create-static-pads-on-wg_transf.patch create mode 100644 patches/mfplat-streaming-support/0005-Revert-winegstreamer-Introduce-new-wg_transform-stru.patch create mode 100644 patches/mfplat-streaming-support/0006-Revert-winegstreamer-Introduce-new-WG_MAJOR_TYPE_WMA.patch create mode 100644 patches/mfplat-streaming-support/0007-Revert-winegstreamer-Move-format-helpers-to-a-dedica.patch create mode 100644 patches/mfplat-streaming-support/0008-winegstreamer-Allow-videoconvert-to-parallelize.patch create mode 100644 patches/mfplat-streaming-support/0009-HACK-winegstreamer-Use-capssetter-to-ignore-non-defa.patch delete mode 100644 patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch create mode 100644 patches/mfplat-streaming-support/0010-HACK-quartz-Keep-a-reference-on-the-IMediaPosition-i.patch create mode 100644 patches/mfplat-streaming-support/0011-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch create mode 100644 patches/mfplat-streaming-support/0012-HACK-qasf-Implement-ASF-Reader-filter-as-a-simple-fi.patch rename patches/mfplat-streaming-support/{0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch => 0013-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch} (51%) rename patches/mfplat-streaming-support/{0002-winegstreamer-Push-stream-start-and-segment-events-i.patch => 0014-winegstreamer-Push-stream-start-and-segment-events-i.patch} (77%) rename patches/mfplat-streaming-support/{0003-winegstreamer-Introduce-H.264-decoder-transform.patch => 0015-winegstreamer-Introduce-H.264-decoder-transform.patch} (87%) delete mode 100644 patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch rename patches/mfplat-streaming-support/{0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch => 0016-winegstreamer-Implement-GetInputAvailableType-for-de.patch} (87%) rename patches/mfplat-streaming-support/{0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch => 0017-winegstreamer-Implement-GetOutputAvailableType-for-d.patch} (91%) rename patches/mfplat-streaming-support/{0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch => 0018-winegstreamer-Implement-SetInputType-for-decode-tran.patch} (87%) rename patches/mfplat-streaming-support/{0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch => 0019-winegstreamer-Implement-SetOutputType-for-decode-tra.patch} (95%) rename patches/mfplat-streaming-support/{0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch => 0020-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch} (95%) rename patches/mfplat-streaming-support/{0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch => 0021-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch} (77%) rename patches/mfplat-streaming-support/{0013-winegstreamer-Register-the-H.264-decoder-transform.patch => 0022-winegstreamer-Register-the-H.264-decoder-transform.patch} (73%) rename patches/mfplat-streaming-support/{0014-winegstreamer-Introduce-AAC-decoder-transform.patch => 0023-winegstreamer-Introduce-AAC-decoder-transform.patch} (56%) rename patches/mfplat-streaming-support/{0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch => 0024-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch} (74%) rename patches/mfplat-streaming-support/{0017-winegstreamer-Report-streams-backwards-in-media-sour.patch => 0025-winegstreamer-Report-streams-backwards-in-media-sour.patch} (78%) rename patches/mfplat-streaming-support/{0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch => 0026-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch} (81%) rename patches/mfplat-streaming-support/{0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch => 0027-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch} (71%) rename patches/mfplat-streaming-support/{0021-winegstreamer-Introduce-color-conversion-transform.patch => 0028-winegstreamer-Introduce-color-conversion-transform.patch} (90%) rename patches/mfplat-streaming-support/{0022-winegstreamer-Register-the-color-conversion-transfor.patch => 0029-winegstreamer-Register-the-color-conversion-transfor.patch} (68%) rename patches/mfplat-streaming-support/{0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch => 0030-winegstreamer-Implement-GetInputAvailableType-for-co.patch} (92%) rename patches/mfplat-streaming-support/{0024-winegstreamer-Implement-SetInputType-for-color-conve.patch => 0031-winegstreamer-Implement-SetInputType-for-color-conve.patch} (95%) rename patches/mfplat-streaming-support/{0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch => 0032-winegstreamer-Implement-GetOutputAvailableType-for-c.patch} (91%) delete mode 100644 patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch rename patches/mfplat-streaming-support/{0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch => 0033-winegstreamer-Implement-SetOutputType-for-color-conv.patch} (96%) rename patches/mfplat-streaming-support/{0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch => 0034-winegstreamer-Implement-ProcessMessage-for-color-con.patch} (81%) delete mode 100644 patches/mfplat-streaming-support/0035-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch rename patches/mfplat-streaming-support/{0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch => 0035-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch} (91%) rename patches/mfplat-streaming-support/{0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch => 0036-mf-topology-Forward-failure-from-SetOutputType-when-.patch} (81%) delete mode 100644 patches/mfplat-streaming-support/0037-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch rename patches/mfplat-streaming-support/{0031-winegstreamer-Handle-flush-command-in-audio-converst.patch => 0037-winegstreamer-Handle-flush-command-in-audio-converst.patch} (68%) delete mode 100644 patches/mfplat-streaming-support/0038-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch rename patches/mfplat-streaming-support/{0032-winegstreamer-In-the-default-configuration-select-on.patch => 0038-winegstreamer-In-the-default-configuration-select-on.patch} (83%) create mode 100644 patches/mfplat-streaming-support/0039-winegstreamer-Implement-IMFTransform-GetOutputCurren.patch create mode 100644 patches/mfplat-streaming-support/0040-winegstreamer-Implement-stream-draining-support.patch create mode 100644 patches/mfplat-streaming-support/0041-winegstreamer-Add-an-explicit-result-to-wg_parser_pu.patch create mode 100644 patches/mfplat-streaming-support/0042-winegstreamer-Unblock-wg_parser_get_next_read_offset.patch create mode 100644 patches/mfplat-streaming-support/0043-winegstreamer-Update-offset-according-to-the-size-of.patch create mode 100644 patches/mfplat-streaming-support/0044-winegstreamer-Let-src_getrange_cb-allocate-the-buffe.patch create mode 100644 patches/mfplat-streaming-support/0045-winegstreamer-Implement-unseekable-stream-support.patch rename patches/mfplat-streaming-support/{0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch => 0046-winegstreamer-Implement-Process-Input-Output-for-dec.patch} (77%) rename patches/mfplat-streaming-support/{0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch => 0047-winegstreamer-Implement-ProcessMessage-for-decoder-t.patch} (87%) rename patches/mfplat-streaming-support/{0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch => 0048-winegstreamer-Implement-Process-Input-Output-for-aud.patch} (57%) rename patches/mfplat-streaming-support/{0027-winegstreamer-Implement-Process-Input-Output-for-col.patch => 0049-winegstreamer-Implement-Process-Input-Output-for-col.patch} (66%) create mode 100644 patches/mfplat-streaming-support/0050-winegstreamer-Implement-MF_SD_LANGUAGE.patch rename patches/mfplat-streaming-support/{0036-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch => 0051-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch} (73%) create mode 100644 patches/mfplat-streaming-support/0052-winegstreamer-Add-videobox-element-and-aperture-supp.patch rename patches/mfplat-streaming-support/{0034-winegstreamer-Only-require-videobox-element-for-pars.patch => 0053-winegstreamer-Only-require-videobox-element-for-pars.patch} (57%) create mode 100644 patches/mfplat-streaming-support/0054-winegstreamer-Feed-full-buffer-in-audio-converter-Pr.patch create mode 100644 patches/mfplat-streaming-support/0055-winegstreamer-Add-MFVideoFormat_ARGB32-output-for-th.patch create mode 100644 patches/mfplat-streaming-support/0056-winegstreamer-Return-S_OK-from-WMA-decoder-ProcessMe.patch create mode 100644 patches/mfplat-streaming-support/0057-winegstreamer-Introduce-new-wg_transform-struct.patch create mode 100644 patches/mfplat-streaming-support/0058-winegstreamer-Introduce-new-wg_encoded_format-struct.patch create mode 100644 patches/mfplat-streaming-support/0059-winegstreamer-Create-static-pads-on-wg_transform-str.patch create mode 100644 patches/mfplat-streaming-support/0060-winegstreamer-Lookup-create-and-link-a-decoder-eleme.patch create mode 100644 patches/mfplat-streaming-support/0061-winegstreamer-Send-stream-start-and-caps-events-on-c.patch create mode 100644 patches/mfplat-streaming-support/0062-winegstreamer-Add-an-audioconverter-and-audioresampl.patch create mode 100644 patches/mfplat-streaming-support/0063-winegstreamer-Implement-WMA-decoder-ProcessInput.patch create mode 100644 patches/mfplat-streaming-support/0064-winegstreamer-Implement-WMA-decoder-ProcessOutput.patch create mode 100644 patches/mfplat-streaming-support/0065-winegstreamer-Support-XMAudio2-input-format-in-WMA-d.patch create mode 100644 patches/mfplat-streaming-support/0066-winegstreamer-Introduce-new-H264-decoder-transform-s.patch create mode 100644 patches/mfplat-streaming-support/0067-winegstreamer-Return-S_OK-from-H264-decoder-GetAttri.patch create mode 100644 patches/mfplat-streaming-support/0068-winegstreamer-Return-S_OK-from-H264-decoder-ProcessM.patch create mode 100644 patches/mfplat-streaming-support/0069-winegstreamer-Implement-H264-decoder-SetInputType.patch create mode 100644 patches/mfplat-streaming-support/0070-winegstreamer-Implement-H264-decoder-GetOutputAvaila.patch create mode 100644 patches/mfplat-streaming-support/0071-winegstreamer-Implement-H264-decoder-GetInputAvailab.patch create mode 100644 patches/mfplat-streaming-support/0072-winegstreamer-Implement-H264-decoder-SetOutputType.patch create mode 100644 patches/mfplat-streaming-support/0073-winegstreamer-Implement-H264-decoder-GetInputStreamI.patch create mode 100644 patches/mfplat-streaming-support/0074-winegstreamer-Implement-H264-decoder-GetOutputStream.patch create mode 100644 patches/mfplat-streaming-support/0075-winegstreamer-Add-H264-encoded-format-support-in-wg_.patch create mode 100644 patches/mfplat-streaming-support/0076-winegstreamer-Implement-H264-decoder-ProcessInput.patch create mode 100644 patches/mfplat-streaming-support/0077-winegstreamer-Implement-H264-decoder-ProcessOutput.patch create mode 100644 patches/mfplat-streaming-support/0078-winegstreamer-Add-timestamps-and-duration-to-H264-de.patch create mode 100644 patches/mfplat-streaming-support/0079-winegstreamer-Support-dynamic-wg_transform-video-for.patch create mode 100644 patches/mfplat-streaming-support/0080-winegstreamer-Fixup-H264-decoder-NV12-plane-alignmen.patch create mode 100644 patches/mfplat-streaming-support/0081-winegstreamer-Use-an-optional-h264parse-wg_transform.patch create mode 100644 patches/mfplat-streaming-support/0082-HACK-winegstreamer-Fake-H264-timestamps-if-framerate.patch create mode 100644 patches/mfplat-streaming-support/0083-winegstreamer-Reset-internal-format-on-BEGIN_STREAMI.patch create mode 100644 patches/mfplat-streaming-support/0084-winegstreamer-Reimplement-AAC-decoder-using-wg_trans.patch create mode 100644 patches/mfplat-streaming-support/0085-winegstreamer-After-failing-to-create-decodebin-pars.patch create mode 100644 patches/mfplat-streaming-support/0086-fixup-winegstreamer-After-failing-to-create-decodebi.patch create mode 100644 patches/mfplat-streaming-support/0087-winegstreamer-Use-unlimited-buffering-for-the-WM-rea.patch create mode 100644 patches/mfplat-streaming-support/0088-HACK-winegstreamer-Report-streams-in-reverse-order-f.patch diff --git a/patches/mfplat-streaming-support/0001-winegstreamer-HACK-Use-a-different-gst-registry-file.patch b/patches/mfplat-streaming-support/0001-winegstreamer-HACK-Use-a-different-gst-registry-file.patch new file mode 100644 index 00000000..b4c9ec27 --- /dev/null +++ b/patches/mfplat-streaming-support/0001-winegstreamer-HACK-Use-a-different-gst-registry-file.patch @@ -0,0 +1,40 @@ +From 1fa010a636a2a30224ce07081d94bd3e6d9597c8 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 30 Jan 2020 10:16:19 -0600 +Subject: [PATCH 01/88] winegstreamer: HACK: Use a different gst registry file + per architecture + +--- + dlls/winegstreamer/wg_parser.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 5a2e970a4dd..40c394c3caf 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1556,6 +1556,22 @@ static void init_gstreamer_once(void) + int argc = ARRAY_SIZE(args) - 1; + char **argv = args; + GError *err; ++ const char *e; ++ ++ if ((e = getenv("WINE_GST_REGISTRY_DIR"))) ++ { ++ char gst_reg[PATH_MAX]; ++#if defined(__x86_64__) ++ const char *arch = "/registry.x86_64.bin"; ++#elif defined(__i386__) ++ const char *arch = "/registry.i386.bin"; ++#else ++#error Bad arch ++#endif ++ strcpy(gst_reg, e); ++ strcat(gst_reg, arch); ++ setenv("GST_REGISTRY_1_0", gst_reg, 1); ++ } + + if (!gst_init_check(&argc, &argv, &err)) + { +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0002-winegstreamer-HACK-Try-harder-to-register-winegstrea.patch b/patches/mfplat-streaming-support/0002-winegstreamer-HACK-Try-harder-to-register-winegstrea.patch new file mode 100644 index 00000000..bf4abe11 --- /dev/null +++ b/patches/mfplat-streaming-support/0002-winegstreamer-HACK-Try-harder-to-register-winegstrea.patch @@ -0,0 +1,60 @@ +From effc9dd4081fe44b67080b3cb73f51be21e0bd51 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Tue, 28 Jan 2020 14:30:43 -0600 +Subject: [PATCH 02/88] winegstreamer: HACK: Try harder to register + winegstreamer filters. + +--- + dlls/quartz/filtergraph.c | 17 +++++++++++++++++ + dlls/winegstreamer/main.c | 2 ++ + 2 files changed, 19 insertions(+) + +diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c +index 1849174cf97..55462244ea9 100644 +--- a/dlls/quartz/filtergraph.c ++++ b/dlls/quartz/filtergraph.c +@@ -5600,11 +5600,28 @@ static const IUnknownVtbl IInner_VTable = + FilterGraphInner_Release + }; + ++static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) ++{ ++ HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); ++ if (mod) ++ { ++ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); ++ proc(); ++ FreeLibrary(mod); ++ } ++ return TRUE; ++} ++ + static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded) + { ++ static INIT_ONCE once = INIT_ONCE_STATIC_INIT; + struct filter_graph *object; + HRESULT hr; + ++ /* HACK: our build system makes it difficult to load gstreamer on prefix ++ * creation, so it won't get registered. Do that here instead. */ ++ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); ++ + *out = NULL; + + if (!(object = calloc(1, sizeof(*object)))) +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index f85e9995525..95b22abebb7 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -564,6 +564,8 @@ HRESULT WINAPI DllRegisterServer(void) + + TRACE(".\n"); + ++ init_gstreamer(); ++ + if (FAILED(hr = __wine_register_resources())) + return hr; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0003-mfplat-Register-winegstreamer-interfaces-on-load.patch b/patches/mfplat-streaming-support/0003-mfplat-Register-winegstreamer-interfaces-on-load.patch new file mode 100644 index 00000000..1a8616ff --- /dev/null +++ b/patches/mfplat-streaming-support/0003-mfplat-Register-winegstreamer-interfaces-on-load.patch @@ -0,0 +1,50 @@ +From 3487366d10a749104ac47d0dda66ab54843a94a3 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 18 Dec 2020 14:08:04 -0600 +Subject: [PATCH 03/88] mfplat: Register winegstreamer interfaces on load + +See also "winegstreamer: HACK: Try harder to register winegstreamer +filters." +--- + dlls/mfplat/main.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c +index 7991152f7a7..72ce560c772 100644 +--- a/dlls/mfplat/main.c ++++ b/dlls/mfplat/main.c +@@ -1583,6 +1583,18 @@ HRESULT WINAPI MFTGetInfo(CLSID clsid, WCHAR **name, MFT_REGISTER_TYPE_INFO **in + return hr; + } + ++static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) ++{ ++ HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); ++ if (mod) ++ { ++ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); ++ proc(); ++ FreeLibrary(mod); ++ } ++ return TRUE; ++} ++ + /*********************************************************************** + * MFStartup (mfplat.@) + */ +@@ -1590,9 +1602,12 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) + { + #define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 ) + #define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 ) ++ static INIT_ONCE once = INIT_ONCE_STATIC_INIT; + + TRACE("%#lx, %#lx.\n", version, flags); + ++ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); ++ + if (version != MF_VERSION_XP && version != MF_VERSION_WIN7) + return MF_E_BAD_STARTUP_VERSION; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0004-Revert-winegstreamer-Create-static-pads-on-wg_transf.patch b/patches/mfplat-streaming-support/0004-Revert-winegstreamer-Create-static-pads-on-wg_transf.patch new file mode 100644 index 00000000..ef399691 --- /dev/null +++ b/patches/mfplat-streaming-support/0004-Revert-winegstreamer-Create-static-pads-on-wg_transf.patch @@ -0,0 +1,223 @@ +From fb5e9adb5eb72fa5d8369ec2e014985450432329 Mon Sep 17 00:00:00 2001 +From: Thomas Crider +Date: Sat, 19 Feb 2022 16:58:07 -0700 +Subject: [PATCH 04/88] Revert "winegstreamer: Create static pads on + wg_transform struct." + +This reverts commit 71bf5b24d7efabfcacfa707198efc4be0da3e446. +--- + dlls/winegstreamer/gst_private.h | 3 +- + dlls/winegstreamer/main.c | 9 ++---- + dlls/winegstreamer/unixlib.h | 2 -- + dlls/winegstreamer/wg_format.c | 40 ++---------------------- + dlls/winegstreamer/wg_transform.c | 51 +------------------------------ + dlls/winegstreamer/wma_decoder.c | 2 +- + 6 files changed, 7 insertions(+), 100 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index a63daaf04b9..8bc9f838d29 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -96,8 +96,7 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); + +-struct wg_transform *wg_transform_create(const struct wg_format *input_format, +- const struct wg_format *output_format); ++struct wg_transform *wg_transform_create(void); + void wg_transform_destroy(struct wg_transform *transform); + + unsigned int wg_format_get_max_size(const struct wg_format *format); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 95b22abebb7..af5a691371d 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -254,14 +254,9 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); + } + +-struct wg_transform *wg_transform_create(const struct wg_format *input_format, +- const struct wg_format *output_format) ++struct wg_transform *wg_transform_create(void) + { +- struct wg_transform_create_params params = +- { +- .input_format = input_format, +- .output_format = output_format, +- }; ++ struct wg_transform_create_params params = {0}; + + if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) + return NULL; +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 4adbb694766..8e3f5e84bfb 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -232,8 +232,6 @@ struct wg_parser_stream_seek_params + struct wg_transform_create_params + { + struct wg_transform *transform; +- const struct wg_format *input_format; +- const struct wg_format *output_format; + }; + + enum unix_funcs +diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c +index 40b9acfefff..8f771bb8abd 100644 +--- a/dlls/winegstreamer/wg_format.c ++++ b/dlls/winegstreamer/wg_format.c +@@ -394,43 +394,6 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) + return caps; + } + +-static GstCaps *wg_format_to_caps_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.wma.version) +- gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.wma.version, NULL); +- +- if (format->u.wma.bitrate) +- gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.wma.bitrate, NULL); +- if (format->u.wma.rate) +- gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.wma.rate, NULL); +- if (format->u.wma.depth) +- gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.wma.depth, NULL); +- if (format->u.wma.channels) +- gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.wma.channels, NULL); +- if (format->u.wma.block_align) +- gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.wma.block_align, NULL); +- +- if (format->u.wma.codec_data_len) +- { +- if (!(buffer = gst_buffer_new_and_alloc(format->u.wma.codec_data_len))) +- { +- gst_caps_unref(caps); +- return NULL; +- } +- +- gst_buffer_fill(buffer, 0, format->u.wma.codec_data, format->u.wma.codec_data_len); +- gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); +- gst_buffer_unref(buffer); +- } +- +- return caps; +-} +- + GstCaps *wg_format_to_caps(const struct wg_format *format) + { + switch (format->major_type) +@@ -438,7 +401,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) + case WG_MAJOR_TYPE_UNKNOWN: + return NULL; + case WG_MAJOR_TYPE_WMA: +- return wg_format_to_caps_wma(format); ++ GST_FIXME("WMA format not implemented!\n"); ++ return NULL; + case WG_MAJOR_TYPE_AUDIO: + return wg_format_to_caps_audio(format); + case WG_MAJOR_TYPE_VIDEO: +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index e4545774428..2f225e5bc55 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -44,29 +44,13 @@ GST_DEBUG_CATEGORY_EXTERN(wine); + + struct wg_transform + { +- GstPad *my_src, *my_sink; ++ int dummy; + }; + +-static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) +-{ +- struct wg_transform *transform = gst_pad_get_element_private(pad); +- +- GST_INFO("transform %p, buffer %p.", transform, buffer); +- +- gst_buffer_unref(buffer); +- +- return GST_FLOW_OK; +-} +- + NTSTATUS wg_transform_destroy(void *args) + { + struct wg_transform *transform = args; + +- if (transform->my_sink) +- g_object_unref(transform->my_sink); +- if (transform->my_src) +- g_object_unref(transform->my_src); +- + free(transform); + return STATUS_SUCCESS; + } +@@ -74,10 +58,6 @@ NTSTATUS wg_transform_destroy(void *args) + 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; +- GstCaps *src_caps = NULL, *sink_caps = NULL; +- GstPadTemplate *template = NULL; + struct wg_transform *transform; + NTSTATUS status; + +@@ -89,38 +69,9 @@ NTSTATUS wg_transform_create(void *args) + if (!(transform = calloc(1, sizeof(*transform)))) + goto done; + +- if (!(src_caps = wg_format_to_caps(&input_format))) +- goto done; +- if (!(sink_caps = wg_format_to_caps(&output_format))) +- goto done; +- +- if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) +- goto done; +- if (!(transform->my_src = gst_pad_new_from_template(template, "src"))) +- goto done; +- g_object_unref(template); +- template = NULL; +- +- if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps))) +- goto done; +- if (!(transform->my_sink = gst_pad_new_from_template(template, "sink"))) +- goto done; +- g_object_unref(template); +- template = NULL; +- +- gst_pad_set_element_private(transform->my_sink, transform); +- gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); +- + status = STATUS_SUCCESS; + + done: +- if (template) +- g_object_unref(template); +- if (sink_caps) +- gst_caps_unref(sink_caps); +- if (src_caps) +- gst_caps_unref(src_caps); +- + if (status) + { + GST_ERROR("Failed to create winegstreamer transform."); +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 6c198706944..b14261706a7 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -78,7 +78,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + +- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) ++ if (!(decoder->wg_transform = wg_transform_create())) + return E_FAIL; + + return S_OK; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0005-Revert-winegstreamer-Introduce-new-wg_transform-stru.patch b/patches/mfplat-streaming-support/0005-Revert-winegstreamer-Introduce-new-wg_transform-stru.patch new file mode 100644 index 00000000..816c17c4 --- /dev/null +++ b/patches/mfplat-streaming-support/0005-Revert-winegstreamer-Introduce-new-wg_transform-stru.patch @@ -0,0 +1,293 @@ +From 51f5ec2a0fd00995b4ff155a89e46c7dff8e338b Mon Sep 17 00:00:00 2001 +From: Thomas Crider +Date: Sat, 19 Feb 2022 16:58:23 -0700 +Subject: [PATCH 05/88] Revert "winegstreamer: Introduce new wg_transform + struct." + +This reverts commit 51a262d368afca3ec1edf50a850dbd5339194280. +--- + dlls/winegstreamer/Makefile.in | 1 - + dlls/winegstreamer/gst_private.h | 3 -- + dlls/winegstreamer/main.c | 14 ----- + dlls/winegstreamer/unix_private.h | 5 -- + dlls/winegstreamer/unixlib.h | 8 --- + dlls/winegstreamer/wg_parser.c | 13 +---- + dlls/winegstreamer/wg_transform.c | 88 ------------------------------- + dlls/winegstreamer/wma_decoder.c | 11 ---- + 8 files changed, 2 insertions(+), 141 deletions(-) + delete mode 100644 dlls/winegstreamer/wg_transform.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index 0bcdb3eec65..d9805e3d797 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -14,7 +14,6 @@ C_SRCS = \ + quartz_parser.c \ + wg_format.c \ + wg_parser.c \ +- wg_transform.c \ + wm_asyncreader.c \ + wm_reader.c \ + wm_syncreader.c \ +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 8bc9f838d29..3584f465218 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -96,9 +96,6 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); + +-struct wg_transform *wg_transform_create(void); +-void wg_transform_destroy(struct wg_transform *transform); +- + unsigned int wg_format_get_max_size(const struct wg_format *format); + + HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index af5a691371d..51a71d3b4a5 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -254,20 +254,6 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); + } + +-struct wg_transform *wg_transform_create(void) +-{ +- struct wg_transform_create_params params = {0}; +- +- if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) +- return NULL; +- return params.transform; +-} +- +-void wg_transform_destroy(struct wg_transform *transform) +-{ +- __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); +-} +- + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + if (reason == DLL_PROCESS_ATTACH) +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index f9c4da2f6ea..b483638403d 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -25,13 +25,8 @@ + + #include + +-extern bool init_gstreamer(void) DECLSPEC_HIDDEN; +- + extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; + extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; + extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; + +-extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; +-extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +- + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 8e3f5e84bfb..45ec606fc6a 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -229,11 +229,6 @@ struct wg_parser_stream_seek_params + DWORD start_flags, stop_flags; + }; + +-struct wg_transform_create_params +-{ +- struct wg_transform *transform; +-}; +- + enum unix_funcs + { + unix_wg_parser_create, +@@ -262,9 +257,6 @@ enum unix_funcs + + unix_wg_parser_stream_get_duration, + unix_wg_parser_stream_seek, +- +- unix_wg_transform_create, +- unix_wg_transform_destroy, + }; + + #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 40c394c3caf..66f60d27477 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1586,13 +1586,6 @@ static void init_gstreamer_once(void) + gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); + } + +-bool init_gstreamer(void) +-{ +- static pthread_once_t init_once = PTHREAD_ONCE_INIT; +- +- return !pthread_once(&init_once, init_gstreamer_once); +-} +- + static NTSTATUS wg_parser_create(void *args) + { + static const init_gst_cb init_funcs[] = +@@ -1603,10 +1596,11 @@ static NTSTATUS wg_parser_create(void *args) + [WG_PARSER_WAVPARSE] = wave_parser_init_gst, + }; + ++ static pthread_once_t once = PTHREAD_ONCE_INIT; + struct wg_parser_create_params *params = args; + struct wg_parser *parser; + +- if (!init_gstreamer()) ++ if (pthread_once(&once, init_gstreamer_once)) + return E_FAIL; + + if (!(parser = calloc(1, sizeof(*parser)))) +@@ -1673,7 +1667,4 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + + X(wg_parser_stream_get_duration), + X(wg_parser_stream_seek), +- +- X(wg_transform_create), +- X(wg_transform_destroy), + }; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +deleted file mode 100644 +index 2f225e5bc55..00000000000 +--- a/dlls/winegstreamer/wg_transform.c ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* +- * GStreamer transform backend +- * +- * 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 +- */ +- +-#if 0 +-#pragma makedep unix +-#endif +- +-#include "config.h" +- +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-#include "ntstatus.h" +-#define WIN32_NO_STATUS +-#include "winternl.h" +-#include "dshow.h" +- +-#include "unix_private.h" +- +-GST_DEBUG_CATEGORY_EXTERN(wine); +-#define GST_CAT_DEFAULT wine +- +-struct wg_transform +-{ +- int dummy; +-}; +- +-NTSTATUS wg_transform_destroy(void *args) +-{ +- struct wg_transform *transform = args; +- +- free(transform); +- return STATUS_SUCCESS; +-} +- +-NTSTATUS wg_transform_create(void *args) +-{ +- struct wg_transform_create_params *params = args; +- struct wg_transform *transform; +- NTSTATUS status; +- +- if (!init_gstreamer()) +- return STATUS_UNSUCCESSFUL; +- +- status = STATUS_NO_MEMORY; +- +- if (!(transform = calloc(1, sizeof(*transform)))) +- goto done; +- +- status = STATUS_SUCCESS; +- +-done: +- if (status) +- { +- GST_ERROR("Failed to create winegstreamer transform."); +- if (transform) +- wg_transform_destroy(transform); +- } +- else +- { +- GST_INFO("Created winegstreamer transform %p.", transform); +- params->transform = transform; +- } +- +- return status; +-} +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index b14261706a7..31f735a5b1d 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -53,8 +53,6 @@ struct wma_decoder + LONG refcount; + IMFMediaType *input_type; + IMFMediaType *output_type; +- +- struct wg_transform *wg_transform; + }; + + static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) +@@ -66,10 +64,6 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) + { + struct wg_format input_format, output_format; + +- if (decoder->wg_transform) +- wg_transform_destroy(decoder->wg_transform); +- decoder->wg_transform = NULL; +- + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; +@@ -78,9 +72,6 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + +- if (!(decoder->wg_transform = wg_transform_create())) +- return E_FAIL; +- + return S_OK; + } + +@@ -128,8 +119,6 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) + + 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) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0006-Revert-winegstreamer-Introduce-new-WG_MAJOR_TYPE_WMA.patch b/patches/mfplat-streaming-support/0006-Revert-winegstreamer-Introduce-new-WG_MAJOR_TYPE_WMA.patch new file mode 100644 index 00000000..c69d0a6d --- /dev/null +++ b/patches/mfplat-streaming-support/0006-Revert-winegstreamer-Introduce-new-WG_MAJOR_TYPE_WMA.patch @@ -0,0 +1,344 @@ +From 01b1caa979ab811edb7b859bc8f84ee68053a991 Mon Sep 17 00:00:00 2001 +From: Thomas Crider +Date: Sat, 19 Feb 2022 16:58:47 -0700 +Subject: [PATCH 06/88] Revert "winegstreamer: Introduce new WG_MAJOR_TYPE_WMA + major type." + +This reverts commit 76e2883c4ace29279dce8ea58787871046227b1a. +--- + dlls/winegstreamer/mfplat.c | 109 ++++++----------------------- + dlls/winegstreamer/quartz_parser.c | 8 --- + dlls/winegstreamer/unixlib.h | 12 ---- + dlls/winegstreamer/wg_format.c | 7 -- + dlls/winegstreamer/wm_reader.c | 8 --- + dlls/winegstreamer/wma_decoder.c | 18 ----- + 6 files changed, 21 insertions(+), 141 deletions(-) + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 9b3fc429d32..a111bbe196d 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -635,10 +635,6 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) + case WG_MAJOR_TYPE_UNKNOWN: + return NULL; + +- case WG_MAJOR_TYPE_WMA: +- FIXME("WMA format not implemented!\n"); +- return NULL; +- + case WG_MAJOR_TYPE_AUDIO: + return mf_media_type_from_wg_format_audio(format); + +@@ -650,11 +646,17 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) + return NULL; + } + +-static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *subtype, struct wg_format *format) ++static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_format *format) + { + UINT32 rate, channels, channel_mask, depth; + unsigned int i; ++ GUID subtype; + ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ { ++ FIXME("Subtype is not set.\n"); ++ return; ++ } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) + { + FIXME("Sample rate is not set.\n"); +@@ -690,20 +692,26 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *sub + + for (i = 0; i < ARRAY_SIZE(audio_formats); ++i) + { +- if (IsEqualGUID(subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) ++ if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) + { + format->u.audio.format = audio_formats[i].format; + return; + } + } +- FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); ++ FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(&subtype), depth); + } + +-static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) ++static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_format *format) + { + UINT64 frame_rate, frame_size; + unsigned int i; ++ GUID subtype; + ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ { ++ FIXME("Subtype is not set.\n"); ++ return; ++ } + if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + FIXME("Frame size is not set.\n"); +@@ -724,80 +732,18 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub + + for (i = 0; i < ARRAY_SIZE(video_formats); ++i) + { +- if (IsEqualGUID(subtype, video_formats[i].subtype)) ++ if (IsEqualGUID(&subtype, video_formats[i].subtype)) + { + format->u.video.format = video_formats[i].format; + return; + } + } +- FIXME("Unrecognized video subtype %s.\n", debugstr_guid(subtype)); +-} +- +-static void mf_media_type_to_wg_format_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +-{ +- UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; +- BYTE codec_data[64]; +- UINT32 version; +- +- 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_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) +- { +- FIXME("Block alignment is not set.\n"); +- return; +- } +- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) +- { +- FIXME("Depth is not set.\n"); +- return; +- } +- if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) +- { +- FIXME("Codec data is not set.\n"); +- return; +- } +- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) +- { +- FIXME("Bitrate is not set.\n"); +- bytes_per_second = 0; +- } +- +- if (IsEqualGUID(subtype, &MEDIASUBTYPE_MSAUDIO1)) +- version = 1; +- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV8)) +- version = 2; +- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV9)) +- version = 3; +- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) +- version = 4; +- else +- { +- assert(0); +- return; +- } +- +- format->major_type = WG_MAJOR_TYPE_WMA; +- format->u.wma.version = version; +- format->u.wma.bitrate = bytes_per_second * 8; +- format->u.wma.rate = rate; +- format->u.wma.depth = depth; +- format->u.wma.channels = channels; +- format->u.wma.block_align = block_align; +- format->u.wma.codec_data_len = codec_data_len; +- memcpy(format->u.wma.codec_data, codec_data, codec_data_len); ++ FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); + } + + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) + { +- GUID major_type, subtype; ++ GUID major_type; + + memset(format, 0, sizeof(*format)); + +@@ -806,24 +752,11 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) + FIXME("Major type is not set.\n"); + return; + } +- if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) +- { +- FIXME("Subtype is not set.\n"); +- return; +- } + + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) +- { +- if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || +- IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || +- IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || +- IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) +- mf_media_type_to_wg_format_wma(type, &subtype, format); +- else +- mf_media_type_to_wg_format_audio(type, &subtype, format); +- } ++ mf_media_type_to_wg_format_audio(type, format); + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) +- mf_media_type_to_wg_format_video(type, &subtype, format); ++ mf_media_type_to_wg_format_video(type, format); + else + FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); + } +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index e06c55ccfe0..45313ebda27 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -319,10 +319,6 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) + break; + } + +- case WG_MAJOR_TYPE_WMA: +- FIXME("WMA format not implemented!\n"); +- return 0; +- + case WG_MAJOR_TYPE_UNKNOWN: + FIXME("Cannot guess maximum sample size for unknown format.\n"); + return 0; +@@ -417,10 +413,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool + case WG_MAJOR_TYPE_UNKNOWN: + return false; + +- case WG_MAJOR_TYPE_WMA: +- FIXME("WMA format not implemented!\n"); +- return false; +- + case WG_MAJOR_TYPE_AUDIO: + return amt_from_wg_format_audio(mt, format); + +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 45ec606fc6a..82bb534b938 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -37,7 +37,6 @@ struct wg_format + WG_MAJOR_TYPE_UNKNOWN, + WG_MAJOR_TYPE_VIDEO, + WG_MAJOR_TYPE_AUDIO, +- WG_MAJOR_TYPE_WMA, + } major_type; + + union +@@ -89,17 +88,6 @@ struct wg_format + uint32_t channel_mask; /* In WinMM format. */ + uint32_t rate; + } audio; +- struct +- { +- uint32_t version; +- uint32_t bitrate; +- uint32_t rate; +- uint32_t depth; +- uint32_t channels; +- uint32_t block_align; +- uint32_t codec_data_len; +- unsigned char codec_data[64]; +- } wma; + } u; + }; + +diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c +index 8f771bb8abd..8952acc1c2e 100644 +--- a/dlls/winegstreamer/wg_format.c ++++ b/dlls/winegstreamer/wg_format.c +@@ -400,9 +400,6 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) + { + case WG_MAJOR_TYPE_UNKNOWN: + return NULL; +- case WG_MAJOR_TYPE_WMA: +- GST_FIXME("WMA format not implemented!\n"); +- return NULL; + case WG_MAJOR_TYPE_AUDIO: + return wg_format_to_caps_audio(format); + case WG_MAJOR_TYPE_VIDEO: +@@ -422,10 +419,6 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) + case WG_MAJOR_TYPE_UNKNOWN: + return false; + +- case WG_MAJOR_TYPE_WMA: +- GST_FIXME("WMA format not implemented!\n"); +- return false; +- + case WG_MAJOR_TYPE_AUDIO: + return a->u.audio.format == b->u.audio.format + && a->u.audio.channels == b->u.audio.channels +diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c +index 01518c6b9a8..d40afb66afd 100644 +--- a/dlls/winegstreamer/wm_reader.c ++++ b/dlls/winegstreamer/wm_reader.c +@@ -1687,9 +1687,6 @@ HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output + *count = ARRAY_SIZE(video_formats); + break; + +- case WG_MAJOR_TYPE_WMA: +- FIXME("WMA format not implemented!\n"); +- /* fallthrough */ + case WG_MAJOR_TYPE_AUDIO: + case WG_MAJOR_TYPE_UNKNOWN: + *count = 1; +@@ -1736,9 +1733,6 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, + format.u.audio.format = WG_AUDIO_FORMAT_S16LE; + break; + +- case WG_MAJOR_TYPE_WMA: +- FIXME("WMA format not implemented!\n"); +- break; + case WG_MAJOR_TYPE_UNKNOWN: + break; + } +@@ -1814,8 +1808,6 @@ static const char *get_major_type_string(enum wg_major_type type) + return "video"; + case WG_MAJOR_TYPE_UNKNOWN: + return "unknown"; +- case WG_MAJOR_TYPE_WMA: +- return "wma"; + } + assert(0); + return NULL; +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 31f735a5b1d..78316059052 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -60,21 +60,6 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) + return CONTAINING_RECORD(iface, struct wma_decoder, IUnknown_inner); + } + +-static HRESULT try_create_wg_transform(struct wma_decoder *decoder) +-{ +- struct wg_format input_format, output_format; +- +- 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; +- +- return S_OK; +-} +- + static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) + { + struct wma_decoder *decoder = impl_from_IUnknown(iface); +@@ -453,9 +438,6 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF + if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) + goto failed; + +- if (FAILED(hr = try_create_wg_transform(decoder))) +- goto failed; +- + return S_OK; + + failed: +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0007-Revert-winegstreamer-Move-format-helpers-to-a-dedica.patch b/patches/mfplat-streaming-support/0007-Revert-winegstreamer-Move-format-helpers-to-a-dedica.patch new file mode 100644 index 00000000..de0fbecf --- /dev/null +++ b/patches/mfplat-streaming-support/0007-Revert-winegstreamer-Move-format-helpers-to-a-dedica.patch @@ -0,0 +1,933 @@ +From 9f3feb4b3f4d3225e0733254fb673b675b975525 Mon Sep 17 00:00:00 2001 +From: Thomas Crider +Date: Sat, 19 Feb 2022 16:59:35 -0700 +Subject: [PATCH 07/88] Revert "winegstreamer: Move format helpers to a + dedicated source." + +This reverts commit a288b94831bcd9ef65c23475d8499e53fea69c18. +--- + dlls/winegstreamer/Makefile.in | 1 - + dlls/winegstreamer/unix_private.h | 32 --- + dlls/winegstreamer/wg_format.c | 436 ------------------------------ + dlls/winegstreamer/wg_parser.c | 397 ++++++++++++++++++++++++++- + 4 files changed, 395 insertions(+), 471 deletions(-) + delete mode 100644 dlls/winegstreamer/unix_private.h + delete mode 100644 dlls/winegstreamer/wg_format.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index d9805e3d797..c53e914e246 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -12,7 +12,6 @@ C_SRCS = \ + media_source.c \ + mfplat.c \ + quartz_parser.c \ +- wg_format.c \ + wg_parser.c \ + wm_asyncreader.c \ + wm_reader.c \ +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +deleted file mode 100644 +index b483638403d..00000000000 +--- a/dlls/winegstreamer/unix_private.h ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* +- * winegstreamer Unix library interface +- * +- * Copyright 2020-2021 Zebediah Figura 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 +- */ +- +-#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H +-#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H +- +-#include "unixlib.h" +- +-#include +- +-extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; +-extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; +-extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; +- +-#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ +diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c +deleted file mode 100644 +index 8952acc1c2e..00000000000 +--- a/dlls/winegstreamer/wg_format.c ++++ /dev/null +@@ -1,436 +0,0 @@ +-/* +- * GStreamer format helpers +- * +- * Copyright 2010 Maarten Lankhorst for CodeWeavers +- * Copyright 2010 Aric Stewart for CodeWeavers +- * Copyright 2019-2020 Zebediah Figura +- * +- * 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 +- +-#include "winternl.h" +-#include "dshow.h" +- +-#include "unix_private.h" +- +-GST_DEBUG_CATEGORY_EXTERN(wine); +-#define GST_CAT_DEFAULT wine +- +-static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) +-{ +- switch (format) +- { +- case GST_AUDIO_FORMAT_U8: +- return WG_AUDIO_FORMAT_U8; +- case GST_AUDIO_FORMAT_S16LE: +- return WG_AUDIO_FORMAT_S16LE; +- case GST_AUDIO_FORMAT_S24LE: +- return WG_AUDIO_FORMAT_S24LE; +- case GST_AUDIO_FORMAT_S32LE: +- return WG_AUDIO_FORMAT_S32LE; +- case GST_AUDIO_FORMAT_F32LE: +- return WG_AUDIO_FORMAT_F32LE; +- case GST_AUDIO_FORMAT_F64LE: +- return WG_AUDIO_FORMAT_F64LE; +- default: +- return WG_AUDIO_FORMAT_UNKNOWN; +- } +-} +- +-static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) +-{ +- static const uint32_t position_map[] = +- { +- SPEAKER_FRONT_LEFT, +- SPEAKER_FRONT_RIGHT, +- SPEAKER_FRONT_CENTER, +- SPEAKER_LOW_FREQUENCY, +- SPEAKER_BACK_LEFT, +- SPEAKER_BACK_RIGHT, +- SPEAKER_FRONT_LEFT_OF_CENTER, +- SPEAKER_FRONT_RIGHT_OF_CENTER, +- SPEAKER_BACK_CENTER, +- 0, +- SPEAKER_SIDE_LEFT, +- SPEAKER_SIDE_RIGHT, +- SPEAKER_TOP_FRONT_LEFT, +- SPEAKER_TOP_FRONT_RIGHT, +- SPEAKER_TOP_FRONT_CENTER, +- SPEAKER_TOP_CENTER, +- SPEAKER_TOP_BACK_LEFT, +- SPEAKER_TOP_BACK_RIGHT, +- 0, +- 0, +- SPEAKER_TOP_BACK_CENTER, +- }; +- +- if (position == GST_AUDIO_CHANNEL_POSITION_MONO) +- return SPEAKER_FRONT_CENTER; +- +- if (position >= 0 && position < ARRAY_SIZE(position_map)) +- return position_map[position]; +- return 0; +-} +- +-static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) +-{ +- uint32_t mask = 0, position; +- unsigned int i; +- +- for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) +- { +- if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) +- { +- GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); +- return 0; +- } +- /* Make sure it's also in WinMM order. WinMM mandates that channels be +- * ordered, as it were, from least to most significant SPEAKER_* bit. +- * Hence we fail if the current channel was already specified, or if any +- * higher bit was already specified. */ +- if (mask & ~(position - 1)) +- { +- GST_WARNING("Unsupported channel order."); +- return 0; +- } +- mask |= position; +- } +- return mask; +-} +- +-static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) +-{ +- format->major_type = WG_MAJOR_TYPE_AUDIO; +- format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); +- format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); +- format->u.audio.channel_mask = wg_channel_mask_from_gst(info); +- format->u.audio.rate = GST_AUDIO_INFO_RATE(info); +-} +- +-static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) +-{ +- switch (format) +- { +- case GST_VIDEO_FORMAT_BGRA: +- return WG_VIDEO_FORMAT_BGRA; +- case GST_VIDEO_FORMAT_BGRx: +- return WG_VIDEO_FORMAT_BGRx; +- case GST_VIDEO_FORMAT_BGR: +- return WG_VIDEO_FORMAT_BGR; +- case GST_VIDEO_FORMAT_RGB15: +- return WG_VIDEO_FORMAT_RGB15; +- case GST_VIDEO_FORMAT_RGB16: +- return WG_VIDEO_FORMAT_RGB16; +- case GST_VIDEO_FORMAT_AYUV: +- return WG_VIDEO_FORMAT_AYUV; +- case GST_VIDEO_FORMAT_I420: +- return WG_VIDEO_FORMAT_I420; +- case GST_VIDEO_FORMAT_NV12: +- return WG_VIDEO_FORMAT_NV12; +- case GST_VIDEO_FORMAT_UYVY: +- return WG_VIDEO_FORMAT_UYVY; +- case GST_VIDEO_FORMAT_YUY2: +- return WG_VIDEO_FORMAT_YUY2; +- case GST_VIDEO_FORMAT_YV12: +- return WG_VIDEO_FORMAT_YV12; +- case GST_VIDEO_FORMAT_YVYU: +- return WG_VIDEO_FORMAT_YVYU; +- default: +- return WG_VIDEO_FORMAT_UNKNOWN; +- } +-} +- +-static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) +-{ +- format->major_type = WG_MAJOR_TYPE_VIDEO; +- format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); +- format->u.video.width = GST_VIDEO_INFO_WIDTH(info); +- format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); +- format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); +- format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); +-} +- +-static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) +-{ +- const GstStructure *structure = gst_caps_get_structure(caps, 0); +- gint layer, channels, rate; +- +- if (!gst_structure_get_int(structure, "layer", &layer)) +- { +- GST_WARNING("Missing \"layer\" value."); +- return; +- } +- if (!gst_structure_get_int(structure, "channels", &channels)) +- { +- GST_WARNING("Missing \"channels\" value."); +- return; +- } +- if (!gst_structure_get_int(structure, "rate", &rate)) +- { +- GST_WARNING("Missing \"rate\" value."); +- return; +- } +- +- format->major_type = WG_MAJOR_TYPE_AUDIO; +- +- if (layer == 1) +- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; +- else if (layer == 2) +- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; +- else if (layer == 3) +- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; +- +- format->u.audio.channels = channels; +- format->u.audio.rate = rate; +-} +- +-static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) +-{ +- const GstStructure *structure = gst_caps_get_structure(caps, 0); +- gint width, height, fps_n, fps_d; +- +- if (!gst_structure_get_int(structure, "width", &width)) +- { +- GST_WARNING("Missing \"width\" value."); +- return; +- } +- if (!gst_structure_get_int(structure, "height", &height)) +- { +- GST_WARNING("Missing \"height\" value."); +- return; +- } +- if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) +- { +- fps_n = 0; +- fps_d = 1; +- } +- +- format->major_type = WG_MAJOR_TYPE_VIDEO; +- format->u.video.format = WG_VIDEO_FORMAT_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; +-} +- +-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); +- +- memset(format, 0, sizeof(*format)); +- +- 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")) +- { +- wg_format_from_caps_audio_mpeg(format, caps); +- } +- else if (!strcmp(name, "video/x-cinepak")) +- { +- wg_format_from_caps_video_cinepak(format, caps); +- } +- else +- { +- gchar *str = gst_caps_to_string(caps); +- +- GST_FIXME("Unhandled caps %s.", str); +- g_free(str); +- } +-} +- +-static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) +-{ +- switch (format) +- { +- case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; +- case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; +- case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; +- case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; +- case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; +- case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; +- default: return GST_AUDIO_FORMAT_UNKNOWN; +- } +-} +- +-static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) +-{ +- const uint32_t orig_mask = mask; +- unsigned int i; +- DWORD bit; +- +- static const GstAudioChannelPosition position_map[] = +- { +- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, +- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, +- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, +- GST_AUDIO_CHANNEL_POSITION_LFE1, +- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, +- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, +- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, +- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, +- GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, +- GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, +- GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, +- GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, +- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, +- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, +- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, +- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, +- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, +- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, +- }; +- +- for (i = 0; i < channel_count; ++i) +- { +- positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; +- if (BitScanForward(&bit, mask)) +- { +- if (bit < ARRAY_SIZE(position_map)) +- positions[i] = position_map[bit]; +- else +- GST_WARNING("Invalid channel mask %#x.\n", orig_mask); +- mask &= ~(1 << bit); +- } +- else +- { +- GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); +- } +- } +-} +- +-static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) +-{ +- GstAudioChannelPosition positions[32]; +- GstAudioFormat audio_format; +- GstAudioInfo info; +- +- if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) +- return NULL; +- +- wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); +- gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); +- return gst_audio_info_to_caps(&info); +-} +- +-static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) +-{ +- switch (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_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; +- case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; +- case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; +- case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; +- case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; +- case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; +- case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; +- default: return GST_VIDEO_FORMAT_UNKNOWN; +- } +-} +- +-static GstCaps *wg_format_to_caps_video(const struct wg_format *format) +-{ +- GstVideoFormat video_format; +- GstVideoInfo info; +- unsigned int i; +- GstCaps *caps; +- +- if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) +- return NULL; +- +- gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); +- if ((caps = gst_video_info_to_caps(&info))) +- { +- /* Clear some fields that shouldn't prevent us from connecting. */ +- for (i = 0; i < gst_caps_get_size(caps); ++i) +- { +- gst_structure_remove_fields(gst_caps_get_structure(caps, i), +- "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); +- } +- } +- return caps; +-} +- +-GstCaps *wg_format_to_caps(const struct wg_format *format) +-{ +- switch (format->major_type) +- { +- case WG_MAJOR_TYPE_UNKNOWN: +- return NULL; +- case WG_MAJOR_TYPE_AUDIO: +- return wg_format_to_caps_audio(format); +- case WG_MAJOR_TYPE_VIDEO: +- return wg_format_to_caps_video(format); +- } +- assert(0); +- return NULL; +-} +- +-bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) +-{ +- if (a->major_type != b->major_type) +- return false; +- +- switch (a->major_type) +- { +- case WG_MAJOR_TYPE_UNKNOWN: +- return false; +- +- case WG_MAJOR_TYPE_AUDIO: +- return a->u.audio.format == b->u.audio.format +- && a->u.audio.channels == b->u.audio.channels +- && a->u.audio.rate == b->u.audio.rate; +- +- case WG_MAJOR_TYPE_VIDEO: +- /* Do not compare FPS. */ +- return a->u.video.format == b->u.video.format +- && a->u.video.width == b->u.video.width +- && abs(a->u.video.height) == abs(b->u.video.height); +- } +- +- assert(0); +- return false; +-} +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 66f60d27477..0a6cf927187 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -37,7 +37,7 @@ + #include "winternl.h" + #include "dshow.h" + +-#include "unix_private.h" ++#include "unixlib.h" + + typedef enum + { +@@ -51,7 +51,7 @@ typedef enum + * debug logging instead of Wine debug logging. In order to be safe we forbid + * any use of Wine debug logging in this entire file. */ + +-GST_DEBUG_CATEGORY(wine); ++GST_DEBUG_CATEGORY_STATIC(wine); + #define GST_CAT_DEFAULT wine + + typedef BOOL (*init_gst_cb)(struct wg_parser *parser); +@@ -111,6 +111,399 @@ struct wg_parser_stream + uint64_t duration; + }; + ++static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) ++{ ++ switch (format) ++ { ++ case GST_AUDIO_FORMAT_U8: ++ return WG_AUDIO_FORMAT_U8; ++ case GST_AUDIO_FORMAT_S16LE: ++ return WG_AUDIO_FORMAT_S16LE; ++ case GST_AUDIO_FORMAT_S24LE: ++ return WG_AUDIO_FORMAT_S24LE; ++ case GST_AUDIO_FORMAT_S32LE: ++ return WG_AUDIO_FORMAT_S32LE; ++ case GST_AUDIO_FORMAT_F32LE: ++ return WG_AUDIO_FORMAT_F32LE; ++ case GST_AUDIO_FORMAT_F64LE: ++ return WG_AUDIO_FORMAT_F64LE; ++ default: ++ return WG_AUDIO_FORMAT_UNKNOWN; ++ } ++} ++ ++static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) ++{ ++ static const uint32_t position_map[] = ++ { ++ SPEAKER_FRONT_LEFT, ++ SPEAKER_FRONT_RIGHT, ++ SPEAKER_FRONT_CENTER, ++ SPEAKER_LOW_FREQUENCY, ++ SPEAKER_BACK_LEFT, ++ SPEAKER_BACK_RIGHT, ++ SPEAKER_FRONT_LEFT_OF_CENTER, ++ SPEAKER_FRONT_RIGHT_OF_CENTER, ++ SPEAKER_BACK_CENTER, ++ 0, ++ SPEAKER_SIDE_LEFT, ++ SPEAKER_SIDE_RIGHT, ++ SPEAKER_TOP_FRONT_LEFT, ++ SPEAKER_TOP_FRONT_RIGHT, ++ SPEAKER_TOP_FRONT_CENTER, ++ SPEAKER_TOP_CENTER, ++ SPEAKER_TOP_BACK_LEFT, ++ SPEAKER_TOP_BACK_RIGHT, ++ 0, ++ 0, ++ SPEAKER_TOP_BACK_CENTER, ++ }; ++ ++ if (position == GST_AUDIO_CHANNEL_POSITION_MONO) ++ return SPEAKER_FRONT_CENTER; ++ ++ if (position >= 0 && position < ARRAY_SIZE(position_map)) ++ return position_map[position]; ++ return 0; ++} ++ ++static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) ++{ ++ uint32_t mask = 0, position; ++ unsigned int i; ++ ++ for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) ++ { ++ if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) ++ { ++ GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); ++ return 0; ++ } ++ /* Make sure it's also in WinMM order. WinMM mandates that channels be ++ * ordered, as it were, from least to most significant SPEAKER_* bit. ++ * Hence we fail if the current channel was already specified, or if any ++ * higher bit was already specified. */ ++ if (mask & ~(position - 1)) ++ { ++ GST_WARNING("Unsupported channel order."); ++ return 0; ++ } ++ mask |= position; ++ } ++ return mask; ++} ++ ++static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) ++{ ++ format->major_type = WG_MAJOR_TYPE_AUDIO; ++ format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); ++ format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); ++ format->u.audio.channel_mask = wg_channel_mask_from_gst(info); ++ format->u.audio.rate = GST_AUDIO_INFO_RATE(info); ++} ++ ++static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) ++{ ++ switch (format) ++ { ++ case GST_VIDEO_FORMAT_BGRA: ++ return WG_VIDEO_FORMAT_BGRA; ++ case GST_VIDEO_FORMAT_BGRx: ++ return WG_VIDEO_FORMAT_BGRx; ++ case GST_VIDEO_FORMAT_BGR: ++ return WG_VIDEO_FORMAT_BGR; ++ case GST_VIDEO_FORMAT_RGB15: ++ return WG_VIDEO_FORMAT_RGB15; ++ case GST_VIDEO_FORMAT_RGB16: ++ return WG_VIDEO_FORMAT_RGB16; ++ case GST_VIDEO_FORMAT_AYUV: ++ return WG_VIDEO_FORMAT_AYUV; ++ case GST_VIDEO_FORMAT_I420: ++ return WG_VIDEO_FORMAT_I420; ++ case GST_VIDEO_FORMAT_NV12: ++ return WG_VIDEO_FORMAT_NV12; ++ case GST_VIDEO_FORMAT_UYVY: ++ return WG_VIDEO_FORMAT_UYVY; ++ case GST_VIDEO_FORMAT_YUY2: ++ return WG_VIDEO_FORMAT_YUY2; ++ case GST_VIDEO_FORMAT_YV12: ++ return WG_VIDEO_FORMAT_YV12; ++ case GST_VIDEO_FORMAT_YVYU: ++ return WG_VIDEO_FORMAT_YVYU; ++ default: ++ return WG_VIDEO_FORMAT_UNKNOWN; ++ } ++} ++ ++static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) ++{ ++ format->major_type = WG_MAJOR_TYPE_VIDEO; ++ format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); ++ format->u.video.width = GST_VIDEO_INFO_WIDTH(info); ++ format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); ++ format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); ++ format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); ++} ++ ++static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) ++{ ++ const GstStructure *structure = gst_caps_get_structure(caps, 0); ++ gint layer, channels, rate; ++ ++ if (!gst_structure_get_int(structure, "layer", &layer)) ++ { ++ GST_WARNING("Missing \"layer\" value."); ++ return; ++ } ++ if (!gst_structure_get_int(structure, "channels", &channels)) ++ { ++ GST_WARNING("Missing \"channels\" value."); ++ return; ++ } ++ if (!gst_structure_get_int(structure, "rate", &rate)) ++ { ++ GST_WARNING("Missing \"rate\" value."); ++ return; ++ } ++ ++ format->major_type = WG_MAJOR_TYPE_AUDIO; ++ ++ if (layer == 1) ++ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; ++ else if (layer == 2) ++ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; ++ else if (layer == 3) ++ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; ++ ++ format->u.audio.channels = channels; ++ format->u.audio.rate = rate; ++} ++ ++static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) ++{ ++ const GstStructure *structure = gst_caps_get_structure(caps, 0); ++ gint width, height, fps_n, fps_d; ++ ++ if (!gst_structure_get_int(structure, "width", &width)) ++ { ++ GST_WARNING("Missing \"width\" value."); ++ return; ++ } ++ if (!gst_structure_get_int(structure, "height", &height)) ++ { ++ GST_WARNING("Missing \"height\" value."); ++ return; ++ } ++ if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) ++ { ++ fps_n = 0; ++ fps_d = 1; ++ } ++ ++ format->major_type = WG_MAJOR_TYPE_VIDEO; ++ format->u.video.format = WG_VIDEO_FORMAT_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; ++} ++ ++static 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); ++ ++ memset(format, 0, sizeof(*format)); ++ ++ 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")) ++ { ++ wg_format_from_caps_audio_mpeg(format, caps); ++ } ++ else if (!strcmp(name, "video/x-cinepak")) ++ { ++ wg_format_from_caps_video_cinepak(format, caps); ++ } ++ else ++ { ++ gchar *str = gst_caps_to_string(caps); ++ ++ GST_FIXME("Unhandled caps %s.", str); ++ g_free(str); ++ } ++} ++ ++static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) ++{ ++ switch (format) ++ { ++ case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; ++ case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; ++ case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; ++ case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; ++ case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; ++ case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; ++ default: return GST_AUDIO_FORMAT_UNKNOWN; ++ } ++} ++ ++static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) ++{ ++ const uint32_t orig_mask = mask; ++ unsigned int i; ++ DWORD bit; ++ ++ static const GstAudioChannelPosition position_map[] = ++ { ++ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, ++ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, ++ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_LFE1, ++ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, ++ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, ++ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, ++ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, ++ GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, ++ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, ++ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, ++ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, ++ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, ++ }; ++ ++ for (i = 0; i < channel_count; ++i) ++ { ++ positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; ++ if (BitScanForward(&bit, mask)) ++ { ++ if (bit < ARRAY_SIZE(position_map)) ++ positions[i] = position_map[bit]; ++ else ++ GST_WARNING("Invalid channel mask %#x.\n", orig_mask); ++ mask &= ~(1 << bit); ++ } ++ else ++ { ++ GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); ++ } ++ } ++} ++ ++static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) ++{ ++ GstAudioChannelPosition positions[32]; ++ GstAudioFormat audio_format; ++ GstAudioInfo info; ++ ++ if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) ++ return NULL; ++ ++ wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); ++ gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); ++ return gst_audio_info_to_caps(&info); ++} ++ ++static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) ++{ ++ switch (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_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; ++ case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; ++ case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; ++ case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; ++ case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; ++ case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; ++ case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; ++ default: return GST_VIDEO_FORMAT_UNKNOWN; ++ } ++} ++ ++static GstCaps *wg_format_to_caps_video(const struct wg_format *format) ++{ ++ GstVideoFormat video_format; ++ GstVideoInfo info; ++ unsigned int i; ++ GstCaps *caps; ++ ++ if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) ++ return NULL; ++ ++ gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); ++ if ((caps = gst_video_info_to_caps(&info))) ++ { ++ /* Clear some fields that shouldn't prevent us from connecting. */ ++ for (i = 0; i < gst_caps_get_size(caps); ++i) ++ { ++ gst_structure_remove_fields(gst_caps_get_structure(caps, i), ++ "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); ++ } ++ } ++ return caps; ++} ++ ++static GstCaps *wg_format_to_caps(const struct wg_format *format) ++{ ++ switch (format->major_type) ++ { ++ case WG_MAJOR_TYPE_UNKNOWN: ++ return NULL; ++ case WG_MAJOR_TYPE_AUDIO: ++ return wg_format_to_caps_audio(format); ++ case WG_MAJOR_TYPE_VIDEO: ++ return wg_format_to_caps_video(format); ++ } ++ assert(0); ++ return NULL; ++} ++ ++static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) ++{ ++ if (a->major_type != b->major_type) ++ return false; ++ ++ switch (a->major_type) ++ { ++ case WG_MAJOR_TYPE_UNKNOWN: ++ return false; ++ ++ case WG_MAJOR_TYPE_AUDIO: ++ return a->u.audio.format == b->u.audio.format ++ && a->u.audio.channels == b->u.audio.channels ++ && a->u.audio.rate == b->u.audio.rate; ++ ++ case WG_MAJOR_TYPE_VIDEO: ++ /* Do not compare FPS. */ ++ return a->u.video.format == b->u.video.format ++ && a->u.video.width == b->u.video.width ++ && abs(a->u.video.height) == abs(b->u.video.height); ++ } ++ ++ assert(0); ++ return false; ++} ++ + static NTSTATUS wg_parser_get_stream_count(void *args) + { + struct wg_parser_get_stream_count_params *params = args; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0008-winegstreamer-Allow-videoconvert-to-parallelize.patch b/patches/mfplat-streaming-support/0008-winegstreamer-Allow-videoconvert-to-parallelize.patch new file mode 100644 index 00000000..a89d3e9d --- /dev/null +++ b/patches/mfplat-streaming-support/0008-winegstreamer-Allow-videoconvert-to-parallelize.patch @@ -0,0 +1,29 @@ +From 6e5861b34f4359129d0ebec199e2106db4b7be43 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 21 Oct 2020 16:03:21 -0500 +Subject: [PATCH 08/88] winegstreamer: Allow videoconvert to parallelize. + +Not sure if this should be called a hack. It's not the *best* solution to the problem, but it's not a wrong one either. + +Signed-off-by: Zebediah Figura +--- + dlls/winegstreamer/wg_parser.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 0a6cf927187..5f3b4375b4c 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1189,6 +1189,9 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + if (!(vconv = create_element("videoconvert", "base"))) + goto out; + ++ /* Let GStreamer choose a default number of threads. */ ++ gst_util_set_object_arg(G_OBJECT(vconv), "n-threads", "0"); ++ + /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ + if (!(flip = create_element("videoflip", "good"))) + goto out; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0009-HACK-winegstreamer-Use-capssetter-to-ignore-non-defa.patch b/patches/mfplat-streaming-support/0009-HACK-winegstreamer-Use-capssetter-to-ignore-non-defa.patch new file mode 100644 index 00000000..e1669afd --- /dev/null +++ b/patches/mfplat-streaming-support/0009-HACK-winegstreamer-Use-capssetter-to-ignore-non-defa.patch @@ -0,0 +1,95 @@ +From 6317747d6b4ec2e94d92bd5f1dd4b73710cf02c4 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Tue, 20 Oct 2020 17:03:24 -0500 +Subject: [PATCH 09/88] HACK: winegstreamer: Use capssetter to ignore + non-default YUV color spaces. + +--- + dlls/winegstreamer/wg_parser.c | 53 ++++++++++++++++++++++++++++++++-- + 1 file changed, 51 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 5f3b4375b4c..b93b2c182ae 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1176,7 +1176,53 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + + if (!strcmp(name, "video/x-raw")) + { +- GstElement *deinterlace, *vconv, *flip, *vconv2; ++ GstElement *capssetter, *deinterlace, *vconv, *flip, *vconv2; ++ ++ /* Hack?: Flatten down the colorimetry to default values, without ++ * actually modifying the video at all. ++ * ++ * We want to do color matrix conversions when converting from YUV to ++ * RGB or vice versa. We do *not* want to do color matrix conversions ++ * when converting YUV <-> YUV or RGB <-> RGB, because these are slow ++ * (it essentially means always using the slow path, never going through ++ * liborc). However, we have two videoconvert elements, and it's ++ * basically impossible to know what conversions each is going to do ++ * until caps are negotiated (without depending on some implementation ++ * details, and even then it'snot exactly trivial). And setting ++ * matrix-mode after caps are negotiated has no effect. ++ * ++ * Nor can we just retain colorimetry information the way we retain ++ * other caps values, because videoconvert automatically clears it if ++ * not doing passthrough. I think that this would only happen if we have ++ * to do a double conversion, but that is possible. Not likely, but I ++ * don't want to have to be the one to find out that there's still a ++ * game broken. ++ * ++ * [Note that we'd actually kind of like to retain colorimetry ++ * information, just in case it does ever become relevant to pass that ++ * on to the next DirectShow filter. Hence I think the correct solution ++ * for upstream is to get videoconvert to Not Do That.] ++ * ++ * So as a fallback solution, we force an identity transformation of ++ * the caps to those with a "default" color matrix—i.e. transform the ++ * caps, but not the data. We do this by *pre*pending a capssetter to ++ * the front of the chain, and we remove the matrix-mode setting for the ++ * videoconvert elements. ++ */ ++ if (!(capssetter = gst_element_factory_make("capssetter", NULL))) ++ { ++ GST_ERROR("Failed to create capssetter, are %u-bit GStreamer \"good\" plugins installed?\n", ++ 8 * (int)sizeof(void *)); ++ goto out; ++ } ++ gst_util_set_object_arg(G_OBJECT(capssetter), "join", "true"); ++ /* Actually, this is invalid, but it causes videoconvert to use default ++ * colorimetry as a result. Yes, this is depending on undocumented ++ * implementation details. It's a hack. ++ * ++ * Sadly there doesn't seem to be a way to get capssetter to clear ++ * certain fields while leaving others untouched. */ ++ gst_util_set_object_arg(G_OBJECT(capssetter), "caps", "video/x-raw,colorimetry=0:0:0:0"); + + /* DirectShow can express interlaced video, but downstream filters can't + * necessarily consume it. In particular, the video renderer can't. */ +@@ -1202,6 +1248,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + goto out; + + /* The bin takes ownership of these elements. */ ++ gst_bin_add(GST_BIN(parser->container), capssetter); ++ gst_element_sync_state_with_parent(capssetter); + gst_bin_add(GST_BIN(parser->container), deinterlace); + gst_element_sync_state_with_parent(deinterlace); + gst_bin_add(GST_BIN(parser->container), vconv); +@@ -1211,11 +1259,12 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + gst_bin_add(GST_BIN(parser->container), vconv2); + gst_element_sync_state_with_parent(vconv2); + ++ gst_element_link(capssetter, deinterlace); + gst_element_link(deinterlace, vconv); + gst_element_link(vconv, flip); + gst_element_link(flip, vconv2); + +- stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); ++ stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); + stream->post_src = gst_element_get_static_pad(vconv2, "src"); + stream->flip = flip; + } +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch b/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch deleted file mode 100644 index c10d3846..00000000 --- a/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch +++ /dev/null @@ -1,867 +0,0 @@ -From b8e243fcb8d17525a0688e8371bcfe490264baf1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:40:46 -0400 -Subject: [PATCH] winegstreamer: Add push-mode path for wg_parser. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/gst_private.h | 28 +- - dlls/winegstreamer/media_source.c | 4 +- - dlls/winegstreamer/quartz_parser.c | 4 +- - dlls/winegstreamer/wg_parser.c | 426 +++++++++++++++++++++++++---- - 4 files changed, 408 insertions(+), 54 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 215cf4577d4..25694aae84d 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -136,6 +136,14 @@ struct wg_format - } u; - }; - -+struct wg_rect -+{ -+ uint32_t left; -+ uint32_t right; -+ uint32_t top; -+ uint32_t bottom; -+}; -+ - enum wg_parser_event_type - { - WG_PARSER_EVENT_NONE = 0, -@@ -165,6 +173,14 @@ struct wg_parser_event - }; - C_ASSERT(sizeof(struct wg_parser_event) == 40); - -+enum wg_read_result -+{ -+ WG_READ_SUCCESS, -+ WG_READ_FAILURE, -+ WG_READ_FLUSHING, -+ WG_READ_EOS, -+}; -+ - struct unix_funcs - { - struct wg_parser *(CDECL *wg_decodebin_parser_create)(void); -@@ -174,6 +190,8 @@ struct unix_funcs - void (CDECL *wg_parser_destroy)(struct wg_parser *parser); - - HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); -+ HRESULT (CDECL *wg_parser_connect_unseekable)(struct wg_parser *parser, -+ const struct wg_format *in_format, uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures); - void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); - - void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); -@@ -181,7 +199,11 @@ struct unix_funcs - - bool (CDECL *wg_parser_get_read_request)(struct wg_parser *parser, - void **data, uint64_t *offset, uint32_t *size); -- void (CDECL *wg_parser_complete_read_request)(struct wg_parser *parser, bool ret); -+ /* bytes_available indicates the actual size of the input packet, or 0 if the source source pad isn't aware of packets. -+ If this value is lower or equal to the requested buffer size, it signifies the number of valid bytes set, if this -+ value is higher than the requested buffer size, it means that a push mode pad should query for the rest of packet, -+ concatenate the result, then submit it downstream. */ -+ void (CDECL *wg_parser_complete_read_request)(struct wg_parser *parser, enum wg_read_result ret, uint32_t bytes_available); - - void (CDECL *wg_parser_set_unlimited_buffering)(struct wg_parser *parser); - -@@ -189,7 +211,7 @@ struct unix_funcs - struct wg_parser_stream *(CDECL *wg_parser_get_stream)(struct wg_parser *parser, uint32_t index); - - void (CDECL *wg_parser_stream_get_preferred_format)(struct wg_parser_stream *stream, struct wg_format *format); -- void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format); -+ void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture); - void (CDECL *wg_parser_stream_disable)(struct wg_parser_stream *stream); - - bool (CDECL *wg_parser_stream_get_event)(struct wg_parser_stream *stream, struct wg_parser_event *event); -@@ -204,6 +226,8 @@ struct unix_funcs - /* start_pos and stop_pos are in 100-nanosecond units. */ - bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); -+ /* true: The stream has fully drained or has been flushed. false: An event is available. */ -+ bool (CDECL *wg_parser_stream_drain)(struct wg_parser_stream *stream); - }; - - extern const struct unix_funcs *unix_funcs; -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 05544ef7abe..054e87edb7b 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -305,7 +305,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm - IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); - - mf_media_type_to_wg_format(current_mt, &format); -- unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format); -+ unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format, NULL); - - IMFMediaType_Release(current_mt); - IMFMediaTypeHandler_Release(mth); -@@ -548,7 +548,7 @@ static DWORD CALLBACK read_thread(void *arg) - hr = IMFByteStream_Read(byte_stream, data, size, &ret_size); - if (SUCCEEDED(hr) && ret_size != size) - ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); -- unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr)); -+ unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, ret_size); - } - - TRACE("Media source is shutting down; exiting.\n"); -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index fc1b72cd958..4b0f2c215d1 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -799,7 +799,7 @@ static DWORD CALLBACK read_thread(void *arg) - if (!unix_funcs->wg_parser_get_read_request(filter->wg_parser, &data, &offset, &size)) - continue; - hr = IAsyncReader_SyncRead(filter->reader, offset, size, data); -- unix_funcs->wg_parser_complete_read_request(filter->wg_parser, SUCCEEDED(hr)); -+ unix_funcs->wg_parser_complete_read_request(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, size); - } - - TRACE("Streaming stopped; exiting.\n"); -@@ -1447,7 +1447,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, - - ret = amt_to_wg_format(&pin->pin.pin.mt, &format); - assert(ret); -- unix_funcs->wg_parser_stream_enable(pin->wg_stream, &format); -+ unix_funcs->wg_parser_stream_enable(pin->wg_stream, &format, NULL); - - /* We do need to drop any buffers that might have been sent with the old - * caps, but this will be handled in parser_init_stream(). */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 1afe92f04ac..d010b1e6eed 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -47,7 +47,7 @@ struct wg_parser - BOOL (*init_gst)(struct wg_parser *parser); - - struct wg_parser_stream **streams; -- unsigned int stream_count; -+ unsigned int stream_count, expected_stream_count; - - GstElement *container, *decodebin; - GstBus *bus; -@@ -61,7 +61,7 @@ struct wg_parser - pthread_mutex_t mutex; - - pthread_cond_t init_cond; -- bool no_more_pads, has_duration, error, pull_mode; -+ bool no_more_pads, has_duration, error, pull_mode, seekable; - - pthread_cond_t read_cond, read_done_cond; - struct -@@ -70,10 +70,12 @@ struct wg_parser - uint64_t offset; - uint32_t size; - bool done; -- bool ret; -+ enum wg_read_result ret; - } read_request; - -- bool flushing, sink_connected; -+ bool flushing, sink_connected, draining; -+ -+ struct wg_format input_format; - }; - - struct wg_parser_stream -@@ -81,9 +83,10 @@ struct wg_parser_stream - struct wg_parser *parser; - - GstPad *their_src, *post_sink, *post_src, *my_sink; -- GstElement *flip; -+ GstElement *flip, *box; - GstSegment segment; - struct wg_format preferred_format, current_format; -+ struct wg_rect aperture; - - pthread_cond_t event_cond, event_empty_cond; - struct wg_parser_event event; -@@ -574,6 +577,9 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser) - { - unsigned int i; - -+ if (!parser->seekable) -+ return; -+ - pthread_mutex_lock(&parser->mutex); - parser->flushing = true; - pthread_mutex_unlock(&parser->mutex); -@@ -587,6 +593,9 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser) - - static void CDECL wg_parser_end_flush(struct wg_parser *parser) - { -+ if (!parser->seekable) -+ return; -+ - pthread_mutex_lock(&parser->mutex); - parser->flushing = false; - pthread_mutex_unlock(&parser->mutex); -@@ -597,7 +606,7 @@ static bool CDECL wg_parser_get_read_request(struct wg_parser *parser, - { - pthread_mutex_lock(&parser->mutex); - -- while (parser->sink_connected && !parser->read_request.data) -+ while (parser->sink_connected && (!parser->read_request.data || parser->read_request.done)) - pthread_cond_wait(&parser->read_cond, &parser->mutex); - - if (!parser->sink_connected) -@@ -614,14 +623,25 @@ static bool CDECL wg_parser_get_read_request(struct wg_parser *parser, - return true; - } - --static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, bool ret) -+static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, enum wg_read_result ret, uint32_t bytes_available) - { - pthread_mutex_lock(&parser->mutex); -- parser->read_request.done = true; - parser->read_request.ret = ret; -- parser->read_request.data = NULL; -- pthread_mutex_unlock(&parser->mutex); -+ if (ret == WG_READ_SUCCESS && bytes_available < parser->read_request.size) -+ { -+ parser->read_request.offset += bytes_available; -+ parser->read_request.size -= bytes_available; -+ parser->read_request.data = (unsigned char *)parser->read_request.data + bytes_available; -+ } -+ else -+ { -+ parser->read_request.data = NULL; -+ /* reuse size parameter to indicate how many more bytes are left to write */ -+ parser->read_request.size = bytes_available; -+ } -+ parser->read_request.done = true; - pthread_cond_signal(&parser->read_done_cond); -+ pthread_mutex_unlock(&parser->mutex); - } - - static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) -@@ -633,11 +653,15 @@ static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) - - static void CDECL wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) - { -- *format = stream->preferred_format; -+ if (stream->has_caps) -+ *format = stream->preferred_format; - } - --static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) -+static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) - { -+ if (!stream->parser->seekable) -+ return; -+ - stream->current_format = *format; - stream->enabled = true; - -@@ -666,6 +690,18 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const - gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "none"); - break; - } -+ -+ if (aperture) -+ { -+ if (aperture->left) -+ g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); -+ if (aperture->top) -+ g_object_set(G_OBJECT(stream->box), "top", -aperture->top, NULL); -+ if (aperture->right) -+ g_object_set(G_OBJECT(stream->box), "right", aperture->right - format->u.video.width, NULL); -+ if (aperture->bottom) -+ g_object_set(G_OBJECT(stream->box), "bottom", aperture->bottom - format->u.video.height, NULL); -+ } - } - - gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); -@@ -694,6 +730,11 @@ static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, st - - *event = stream->event; - -+ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up -+ due to pull_data never being called again */ -+ if (stream->event.type == WG_PARSER_EVENT_EOS) -+ stream->eos = true; -+ - if (stream->event.type != WG_PARSER_EVENT_BUFFER) - { - stream->event.type = WG_PARSER_EVENT_NONE; -@@ -754,6 +795,9 @@ static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double - GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; - GstSeekFlags flags = 0; - -+ if (!stream->parser->seekable) -+ return false; -+ - if (start_flags & AM_SEEKING_SeekToKeyFrame) - flags |= GST_SEEK_FLAG_KEY_UNIT; - if (start_flags & AM_SEEKING_Segment) -@@ -770,6 +814,43 @@ static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double - GST_FORMAT_TIME, flags, start_type, start_pos * 100, stop_type, stop_pos * 100)); - } - -+static bool CDECL wg_parser_stream_drain(struct wg_parser_stream *stream) -+{ -+ struct wg_parser *parser = stream->parser; -+ bool ret; -+ -+ pthread_mutex_lock(&parser->mutex); -+ -+ /* Sanity check making sure caller didn't try to drain an already-EOS or unselected stream. -+ There's no reason for a caller to do this, but it could be an accident in which case we -+ should indicate that the stream is drained instead of locking-up. */ -+ if (!stream->enabled || stream->eos) -+ { -+ pthread_mutex_unlock(&parser->mutex); -+ return true; -+ } -+ -+ parser->draining = true; -+ pthread_cond_signal(&parser->read_done_cond); -+ -+ /* We must wait for either an event to occur or the drain to complete. -+ Since drains are blocking, we assign this responsibility to the thread -+ pulling data, as the pipeline will not need to pull more data until -+ the drain completes. If one input buffer yields more than one output -+ buffer, the chain callback blocks on the wg_parser_stream_buffer_release -+ for the first buffer, which would never be called if the drain function -+ hadn't completed. */ -+ while (!parser->flushing && parser->draining && stream->event.type == WG_PARSER_EVENT_NONE) -+ pthread_cond_wait(&stream->event_cond, &parser->mutex); -+ -+ ret = stream->event.type == WG_PARSER_EVENT_NONE; -+ parser->draining = false; -+ -+ pthread_mutex_unlock(&stream->parser->mutex); -+ -+ return ret; -+} -+ - static void CDECL wg_parser_stream_notify_qos(struct wg_parser_stream *stream, - bool underflow, double proportion, int64_t diff, uint64_t timestamp) - { -@@ -1084,14 +1165,27 @@ static GstElement *create_element(const char *name, const char *plugin_set) - static struct wg_parser_stream *create_stream(struct wg_parser *parser) - { - struct wg_parser_stream *stream, **new_array; -+ unsigned int i; - char pad_name[19]; - -- if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) -- return NULL; -- parser->streams = new_array; -+ for (i = 0; i < parser->expected_stream_count; i++) -+ { -+ if (!parser->streams[i]->parser) -+ { -+ stream = parser->streams[i]; -+ break; -+ } -+ } - -- if (!(stream = calloc(1, sizeof(*stream)))) -- return NULL; -+ if (i == parser->expected_stream_count) -+ { -+ if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) -+ return NULL; -+ parser->streams = new_array; -+ -+ if (!(stream = calloc(1, sizeof(*stream)))) -+ return NULL; -+ } - - gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED); - -@@ -1131,7 +1225,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - - if (!strcmp(name, "video/x-raw")) - { -- GstElement *deinterlace, *vconv, *flip, *vconv2; -+ GstElement *deinterlace, *vconv, *flip, *videobox, *vconv2; - - /* DirectShow can express interlaced video, but downstream filters can't - * necessarily consume it. In particular, the video renderer can't. */ -@@ -1148,11 +1242,30 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - if (!(flip = create_element("videoflip", "good"))) - goto out; - -+ if (!(videobox = gst_element_factory_make("videobox", NULL))) -+ { -+ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ goto out; -+ } -+ - /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert - * to do the final conversion. */ - if (!(vconv2 = create_element("videoconvert", "base"))) - goto out; - -+ if (!parser->seekable) -+ { -+ if (stream->aperture.left) -+ g_object_set(G_OBJECT(videobox), "left", -stream->aperture.left, NULL); -+ if (stream->aperture.bottom) -+ g_object_set(G_OBJECT(videobox), "top", -stream->aperture.top, NULL); -+ if (stream->aperture.right) -+ g_object_set(G_OBJECT(videobox), "right", stream->aperture.right - stream->current_format.u.video.width, NULL); -+ if (stream->aperture.bottom) -+ g_object_set(G_OBJECT(videobox), "bottom", stream->aperture.bottom - stream->current_format.u.video.height, NULL); -+ } -+ - /* The bin takes ownership of these elements. */ - gst_bin_add(GST_BIN(parser->container), deinterlace); - gst_element_sync_state_with_parent(deinterlace); -@@ -1160,16 +1273,20 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_element_sync_state_with_parent(vconv); - gst_bin_add(GST_BIN(parser->container), flip); - gst_element_sync_state_with_parent(flip); -+ gst_bin_add(GST_BIN(parser->container), videobox); -+ gst_element_sync_state_with_parent(videobox); - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); -- gst_element_link(flip, vconv2); -+ gst_element_link(flip, videobox); -+ gst_element_link(videobox, vconv2); - - stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; -+ stream->box = videobox; - } - else if (!strcmp(name, "audio/x-raw")) - { -@@ -1253,23 +1370,25 @@ static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user) - g_free(name); - } - --static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, -- guint64 offset, guint size, GstBuffer **buffer) -+static GstFlowReturn pull_data(struct wg_parser *parser, guint64 offset, guint size, guint *size_read, GstBuffer **buffer) - { -- struct wg_parser *parser = gst_pad_get_element_private(pad); - GstBuffer *new_buffer = NULL; -+ enum wg_read_result ret; - GstMapInfo map_info; -- bool ret; -+ unsigned int i; - -- GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer); -+ GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", parser->my_src, offset, size, *buffer); - - if (offset == GST_BUFFER_OFFSET_NONE) - offset = parser->next_pull_offset; - parser->next_pull_offset = offset + size; -- if (offset >= parser->file_size) -- return GST_FLOW_EOS; -- if (offset + size >= parser->file_size) -- size = parser->file_size - offset; -+ if (parser->seekable) -+ { -+ if (offset >= parser->file_size) -+ return GST_FLOW_EOS; -+ if (offset + size >= parser->file_size) -+ size = parser->file_size - offset; -+ } - - if (!*buffer) - *buffer = new_buffer = gst_buffer_new_and_alloc(size); -@@ -1278,6 +1397,14 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - - pthread_mutex_lock(&parser->mutex); - -+ if (parser->draining) -+ { -+ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); -+ parser->draining = false; -+ for (i = 0; i < parser->stream_count; i++) -+ pthread_cond_signal(&parser->streams[i]->event_cond); -+ } -+ - assert(!parser->read_request.data); - parser->read_request.data = map_info.data; - parser->read_request.offset = offset; -@@ -1289,8 +1416,36 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - * the upstream pin to flush if necessary. We should never be blocked on - * read_thread() not running. */ - -- while (!parser->read_request.done) -+ while (!parser->read_request.done && !parser->draining) -+ { - pthread_cond_wait(&parser->read_done_cond, &parser->mutex); -+ if (parser->draining) -+ { -+ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); -+ parser->draining = false; -+ for (i = 0; i < parser->stream_count; i++) -+ pthread_cond_signal(&parser->streams[i]->event_cond); -+ } -+ if (size != parser->read_request.size && parser->read_request.data) -+ { -+ if (size_read) -+ { -+ *size_read = size - parser->read_request.size; -+ parser->read_request.done = true; -+ break; -+ } -+ else -+ { -+ parser->read_request.done = false; -+ pthread_cond_signal(&parser->read_cond); -+ } -+ } -+ } -+ -+ parser->read_request.data = NULL; -+ -+ if (size_read && parser->read_request.size > size) -+ *size_read = parser->read_request.size; - - ret = parser->read_request.ret; - -@@ -1298,12 +1453,29 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - - gst_buffer_unmap(*buffer, &map_info); - -+ if (size_read) -+ size = min(*size_read, size); -+ -+ gst_buffer_set_size(*buffer, size); -+ - GST_LOG("Request returned %d.", ret); - -- if (!ret && new_buffer) -+ if (ret != WG_READ_SUCCESS && new_buffer) - gst_buffer_unref(new_buffer); - -- return ret ? GST_FLOW_OK : GST_FLOW_ERROR; -+ return ret == WG_READ_SUCCESS ? GST_FLOW_OK : -+ ret == WG_READ_FAILURE ? GST_FLOW_ERROR : -+ ret == WG_READ_FLUSHING ? GST_FLOW_FLUSHING : -+ ret == WG_READ_EOS ? GST_FLOW_EOS : -+ GST_FLOW_ERROR; -+} -+ -+static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, -+ guint64 offset, guint size, GstBuffer **buffer) -+{ -+ struct wg_parser *parser = gst_pad_get_element_private(pad); -+ -+ return pull_data(parser, offset, size, NULL, buffer); - } - - static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) -@@ -1322,7 +1494,7 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); - return TRUE; - } -- else if (format == GST_FORMAT_BYTES) -+ else if (format == GST_FORMAT_BYTES && parser->seekable) - { - gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size); - return TRUE; -@@ -1336,15 +1508,42 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format)); - return FALSE; - } -+ if (!parser->seekable) -+ return FALSE; - gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size); - return TRUE; - - case GST_QUERY_SCHEDULING: -- gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); -+ gst_query_set_scheduling(query, parser->seekable ? GST_SCHEDULING_FLAG_SEEKABLE : GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0); - gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); - gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); - return TRUE; - -+ case GST_QUERY_CAPS: -+ { -+ GstCaps *caps, *filter, *temp; -+ -+ gst_query_parse_caps(query, &filter); -+ -+ if (parser->input_format.major_type) -+ caps = wg_format_to_caps(&parser->input_format); -+ else -+ caps = gst_caps_new_any(); -+ if (!caps) -+ return FALSE; -+ -+ if (filter) -+ { -+ temp = gst_caps_intersect(caps, filter); -+ gst_caps_unref(caps); -+ caps = temp; -+ } -+ -+ gst_query_set_caps_result(query, caps); -+ gst_caps_unref(caps); -+ return TRUE; -+ } -+ - default: - GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); - return FALSE; -@@ -1354,42 +1553,115 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - static void *push_data(void *arg) - { - struct wg_parser *parser = arg; -- GstBuffer *buffer; -+ GstBuffer *last_buffer = NULL; -+ ULONG alloc_size = 16384; - GstSegment *segment; - guint max_size; - - GST_DEBUG("Starting push thread."); - -- if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) -- { -- GST_ERROR("Failed to allocate memory."); -- return NULL; -- } -- - max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; - - gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); - -+ if (parser->input_format.major_type) -+ gst_pad_push_event(parser->my_src, gst_event_new_caps(wg_format_to_caps(&parser->input_format))); -+ - segment = gst_segment_new(); - gst_segment_init(segment, GST_FORMAT_BYTES); - gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); - -+ assert(!(GST_PAD_IS_FLUSHING(parser->my_src))); -+ - for (;;) - { -+ GstBuffer *buffer = NULL; -+ unsigned int i; - ULONG size; - int ret; - - if (parser->next_offset >= max_size) - break; -- size = min(16384, max_size - parser->next_offset); -+ size = min(alloc_size, max_size - parser->next_offset); - -- if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) -+ ret = pull_data(parser, parser->next_offset, size, &size, &buffer); -+ -+ /* When we are in unseekable push mode, the pushing pad is responsible for handling flushing. */ -+ if (!parser->seekable && ret == GST_FLOW_FLUSHING) - { -+ if (last_buffer) -+ { -+ gst_buffer_unref(last_buffer); -+ last_buffer = NULL; -+ } -+ -+ gst_pad_push_event(parser->my_src, gst_event_new_seek(1.0f, -+ GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)); -+ -+ continue; -+ } -+ -+ if (!parser->seekable && ret == GST_FLOW_EOS) -+ { -+ if (last_buffer) -+ { -+ gst_buffer_unref(last_buffer); -+ last_buffer = NULL; -+ } -+ -+ gst_pad_push_event(parser->my_src, gst_event_new_eos()); -+ pthread_mutex_lock(&parser->mutex); -+ for (i = 0; i < parser->stream_count; i++) -+ { -+ if (!parser->streams[i]->enabled) -+ continue; -+ while (!parser->streams[i]->flushing && !parser->streams[i]->eos) -+ pthread_cond_wait(&parser->streams[i]->event_empty_cond, &parser->mutex); -+ parser->streams[i]->eos = false; -+ } -+ -+ if (parser->flushing) -+ { -+ pthread_mutex_unlock(&parser->mutex); -+ continue; -+ } -+ -+ pthread_mutex_unlock(&parser->mutex); -+ -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_BYTES); -+ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); -+ -+ continue; -+ } -+ -+ if (ret < 0) -+ { -+ if (last_buffer) -+ { -+ gst_buffer_unref(last_buffer); -+ last_buffer = NULL; -+ } -+ - GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); - break; - } - -- parser->next_offset += size; -+ parser->next_offset += gst_buffer_get_size(buffer); -+ -+ if (last_buffer) -+ { -+ buffer = gst_buffer_append(last_buffer, buffer); -+ last_buffer = NULL; -+ assert(alloc_size >= size); -+ } -+ -+ if (size > gst_buffer_get_size(buffer)) -+ { -+ last_buffer = buffer; -+ alloc_size = (size + 0xfff) & ~0xfff; -+ continue; -+ } - - buffer->duration = buffer->pts = -1; - if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) -@@ -1399,8 +1671,6 @@ static void *push_data(void *arg) - } - } - -- gst_buffer_unref(buffer); -- - gst_pad_push_event(parser->my_src, gst_event_new_eos()); - - GST_DEBUG("Stopping push thread."); -@@ -1416,6 +1686,12 @@ static gboolean activate_push(GstPad *pad, gboolean activate) - { - if (parser->push_thread) - { -+ pthread_mutex_lock(&parser->mutex); -+ parser->read_request.ret = WG_READ_FAILURE; -+ parser->read_request.data = NULL; -+ parser->read_request.done = true; -+ pthread_mutex_unlock(&parser->mutex); -+ pthread_cond_signal(&parser->read_done_cond); - pthread_join(parser->push_thread, NULL); - parser->push_thread = 0; - } -@@ -1581,13 +1857,11 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - return ret; - } - --static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) -+static HRESULT wg_parser_connect_inner(struct wg_parser *parser) - { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", - GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); -- unsigned int i; - -- parser->file_size = file_size; - parser->sink_connected = true; - - if (!parser->bus) -@@ -1609,6 +1883,20 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s - parser->start_offset = parser->next_offset = parser->stop_offset = 0; - parser->next_pull_offset = 0; - -+ return S_OK; -+} -+ -+static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) -+{ -+ unsigned int i; -+ HRESULT hr; -+ -+ parser->seekable = true; -+ parser->file_size = file_size; -+ -+ if ((hr = wg_parser_connect_inner(parser))) -+ return hr; -+ - if (!parser->init_gst(parser)) - return E_FAIL; - -@@ -1690,6 +1978,43 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s - return S_OK; - } - -+static HRESULT CDECL wg_parser_connect_unseekable(struct wg_parser *parser, -+ const struct wg_format *in_format, uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures) -+{ -+ unsigned int i; -+ HRESULT hr; -+ -+ parser->seekable = false; -+ parser->flushing = false; -+ /* since typefind is not available here, we must have an input_format */ -+ parser->input_format = *in_format; -+ -+ if ((hr = wg_parser_connect_inner(parser))) -+ return hr; -+ -+ parser->stop_offset = -1; -+ -+ parser->expected_stream_count = stream_count; -+ parser->streams = calloc(stream_count, sizeof(*parser->streams)); -+ -+ for (i = 0; i < stream_count; i++) -+ { -+ parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); -+ parser->streams[i]->current_format = out_formats[i]; -+ if (apertures) -+ parser->streams[i]->aperture = apertures[i]; -+ parser->streams[i]->enabled = true; -+ } -+ -+ if (!parser->init_gst(parser)) -+ return E_FAIL; -+ -+ if (parser->stream_count < parser->expected_stream_count) -+ return E_FAIL; -+ -+ return S_OK; -+} -+ - static void free_stream(struct wg_parser_stream *stream) - { - if (stream->their_src) -@@ -1760,6 +2085,9 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - if (!(element = create_element("decodebin", "base"))) - return FALSE; - -+ if (parser->input_format.major_type) -+ g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); -+ - gst_bin_add(GST_BIN(parser->container), element); - parser->decodebin = element; - -@@ -2015,6 +2343,7 @@ static const struct unix_funcs funcs = - wg_parser_destroy, - - wg_parser_connect, -+ wg_parser_connect_unseekable, - wg_parser_disconnect, - - wg_parser_begin_flush, -@@ -2039,6 +2368,7 @@ static const struct unix_funcs funcs = - - wg_parser_stream_get_duration, - wg_parser_stream_seek, -+ wg_parser_stream_drain, - }; - - NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out) --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0010-HACK-quartz-Keep-a-reference-on-the-IMediaPosition-i.patch b/patches/mfplat-streaming-support/0010-HACK-quartz-Keep-a-reference-on-the-IMediaPosition-i.patch new file mode 100644 index 00000000..1a3eb850 --- /dev/null +++ b/patches/mfplat-streaming-support/0010-HACK-quartz-Keep-a-reference-on-the-IMediaPosition-i.patch @@ -0,0 +1,97 @@ +From 9d51154a13d10305bfbb8a0e242feef0063e3957 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 6 Jul 2021 14:06:11 +0200 +Subject: [PATCH 10/88] HACK: quartz: Keep a reference on the IMediaPosition + interface. + +In the same way we do for IMediaSeeking. Both interfaces are actually +implemented with a shared refcount and releasing both makes the filter +be destroyed. + +For Tokyo Xanadu eX+ crash on launch. + +CW-Bug-Id: #18994 +--- + dlls/quartz/filtergraph.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c +index 55462244ea9..c602d6236ba 100644 +--- a/dlls/quartz/filtergraph.c ++++ b/dlls/quartz/filtergraph.c +@@ -61,6 +61,7 @@ struct filter + struct list entry; + IBaseFilter *filter; + IMediaSeeking *seeking; ++ IMediaPosition *position; + WCHAR *name; + BOOL sorting; + }; +@@ -542,6 +543,7 @@ static BOOL has_output_pins(IBaseFilter *filter) + + static void update_seeking(struct filter *filter) + { ++ IMediaPosition *position; + IMediaSeeking *seeking; + + if (!filter->seeking) +@@ -560,11 +562,19 @@ static void update_seeking(struct filter *filter) + IMediaSeeking_Release(seeking); + } + } ++ ++ if (!filter->position) ++ { ++ /* Tokyo Xanadu eX+, same as above, same developer, destroys its filter when ++ * its IMediaPosition interface is released, so cache the interface instead ++ * of querying for it every time. */ ++ if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&position))) ++ filter->position = position; ++ } + } + + static BOOL is_renderer(struct filter *filter) + { +- IMediaPosition *media_position; + IAMFilterMiscFlags *flags; + BOOL ret = FALSE; + +@@ -574,16 +584,11 @@ static BOOL is_renderer(struct filter *filter) + ret = TRUE; + IAMFilterMiscFlags_Release(flags); + } +- else if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&media_position))) +- { +- if (!has_output_pins(filter->filter)) +- ret = TRUE; +- IMediaPosition_Release(media_position); +- } + else + { + update_seeking(filter); +- if (filter->seeking && !has_output_pins(filter->filter)) ++ if ((filter->seeking || filter->position) && ++ !has_output_pins(filter->filter)) + ret = TRUE; + } + return ret; +@@ -654,6 +659,7 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, + list_add_head(&graph->filters, &entry->entry); + entry->sorting = FALSE; + entry->seeking = NULL; ++ entry->position = NULL; + ++graph->version; + + return duplicate_name ? VFW_S_DUPLICATE_NAME : hr; +@@ -721,6 +727,8 @@ static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilte + { + IBaseFilter_SetSyncSource(pFilter, NULL); + IBaseFilter_Release(pFilter); ++ if (entry->position) ++ IMediaPosition_Release(entry->position); + if (entry->seeking) + IMediaSeeking_Release(entry->seeking); + list_remove(&entry->entry); +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0011-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch b/patches/mfplat-streaming-support/0011-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch new file mode 100644 index 00000000..d47379f0 --- /dev/null +++ b/patches/mfplat-streaming-support/0011-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch @@ -0,0 +1,34 @@ +From aaa59bf183211a525221252672fdfc7be6de01e6 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 16:54:44 -0400 +Subject: [PATCH 11/88] mfplat: Stub out MFCreateDXGIDeviceManager, to avoid + the d3d path. + +--- + dlls/mfplat/main.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c +index 72ce560c772..ba2f46693a8 100644 +--- a/dlls/mfplat/main.c ++++ b/dlls/mfplat/main.c +@@ -9246,9 +9246,16 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = + HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) + { + struct dxgi_device_manager *object; ++ const char *do_not_create = getenv("PROTON_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); + + TRACE("%p, %p.\n", token, manager); + ++ if (do_not_create && do_not_create[0] != '\0') ++ { ++ FIXME("stubbing out\n"); ++ return E_NOTIMPL; ++ } ++ + if (!token || !manager) + return E_POINTER; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0012-HACK-qasf-Implement-ASF-Reader-filter-as-a-simple-fi.patch b/patches/mfplat-streaming-support/0012-HACK-qasf-Implement-ASF-Reader-filter-as-a-simple-fi.patch new file mode 100644 index 00000000..e5991134 --- /dev/null +++ b/patches/mfplat-streaming-support/0012-HACK-qasf-Implement-ASF-Reader-filter-as-a-simple-fi.patch @@ -0,0 +1,1035 @@ +From 3762eef67e4f78e7e570d48814af6774004b0453 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 6 Jul 2021 14:04:51 +0200 +Subject: [PATCH 12/88] HACK: qasf: Implement ASF Reader filter as a simple + file source. + +Shamelessly copied from quartz filesource.c. + +It then exposes a single MEDIATYPE_Stream pin, which should be +automatically plugged to the GStreamer decodebin filter and then to +application provided renderer. + +This is not how it's supposed to work, and it should instead be more +like a splitter filter able to expose compressed streams (and possibly +uncompressed streams too), and be implemented on top of wmvcore to +forward its interfaces as services, but this seems to work. + +The specific AttemptConnection implementation also seems important for +Tokyo Xanadu eX+, as using the default implementation with IMemInputPin +interface seems to cause it to crash as well. + +For Tokyo Xanadu eX+ crash on launch. + +CW-Bug-Id: #18994 +--- + dlls/qasf/Makefile.in | 2 +- + dlls/qasf/asfreader.c | 887 +++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 834 insertions(+), 55 deletions(-) + +diff --git a/dlls/qasf/Makefile.in b/dlls/qasf/Makefile.in +index ee8fd0451e1..cc82f7736c3 100644 +--- a/dlls/qasf/Makefile.in ++++ b/dlls/qasf/Makefile.in +@@ -1,5 +1,5 @@ + MODULE = qasf.dll +-IMPORTS = strmbase dmoguids strmiids uuid ole32 oleaut32 ++IMPORTS = strmbase dmoguids strmiids uuid ole32 oleaut32 kernelbase + + C_SRCS = \ + asfreader.c \ +diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c +index a037728079f..129da3db13f 100644 +--- a/dlls/qasf/asfreader.c ++++ b/dlls/qasf/asfreader.c +@@ -18,35 +18,341 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + ++#define NONAMELESSUNION ++#define NONAMELESSSTRUCT ++ + #include "qasf_private.h" + ++#include "wine/debug.h" ++#include "wine/heap.h" ++#include "uuids.h" ++#include "vfwmsgs.h" ++#include "winbase.h" ++#include "winreg.h" ++#include "shlwapi.h" ++#include ++ + WINE_DEFAULT_DEBUG_CHANNEL(quartz); + ++/* see IAsyncReader::Request on MSDN for the explanation of this */ ++#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) ++#define BYTES_FROM_MEDIATIME(time) ((time) / 10000000) ++ ++static const AM_MEDIA_TYPE default_mt = ++{ ++ {0xe436eb83,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}}, /* MEDIATYPE_Stream */ ++ {0,0,0,{0,0,0,0,0,0,0,0}}, ++ TRUE, ++ FALSE, ++ 1, ++ {0,0,0,{0,0,0,0,0,0,0,0}}, ++ NULL, ++ 0, ++ NULL ++}; ++ ++struct request ++{ ++ IMediaSample *sample; ++ DWORD_PTR cookie; ++ OVERLAPPED ovl; ++}; ++ + struct asf_reader + { + struct strmbase_filter filter; + IFileSourceFilter IFileSourceFilter_iface; + +- AM_MEDIA_TYPE type; +- WCHAR *filename; ++ struct strmbase_source source; ++ IAsyncReader IAsyncReader_iface; ++ ++ LPOLESTR pszFileName; ++ AM_MEDIA_TYPE mt; ++ HANDLE file, port, io_thread; ++ LARGE_INTEGER file_size; ++ CRITICAL_SECTION sample_cs; ++ BOOL flushing; ++ struct request *requests; ++ unsigned int max_requests; ++ CONDITION_VARIABLE sample_cv; + }; + +-static inline struct asf_reader *impl_reader_from_strmbase_filter(struct strmbase_filter *iface) ++static const struct strmbase_source_ops source_ops; ++ ++static inline struct asf_reader *impl_from_strmbase_filter(struct strmbase_filter *iface) + { + return CONTAINING_RECORD(iface, struct asf_reader, filter); + } + ++static inline struct asf_reader *impl_from_IFileSourceFilter(IFileSourceFilter *iface) ++{ ++ return CONTAINING_RECORD(iface, struct asf_reader, IFileSourceFilter_iface); ++} ++ ++static const IFileSourceFilterVtbl FileSource_Vtbl; ++static const IAsyncReaderVtbl FileAsyncReader_Vtbl; ++ ++static int byte_from_hex_char(WCHAR c) ++{ ++ if ('0' <= c && c <= '9') return c - '0'; ++ if ('a' <= c && c <= 'f') return c - 'a' + 10; ++ if ('A' <= c && c <= 'F') return c - 'A' + 10; ++ return -1; ++} ++ ++static BOOL process_pattern_string(const WCHAR *pattern, HANDLE file) ++{ ++ ULONG size, offset, i, ret_size; ++ BYTE *mask, *expect, *actual; ++ int d; ++ BOOL ret = TRUE; ++ ++ /* format: "offset, size, mask, value" */ ++ ++ offset = wcstol(pattern, NULL, 10); ++ ++ if (!(pattern = wcschr(pattern, ','))) ++ return FALSE; ++ pattern++; ++ ++ size = wcstol(pattern, NULL, 10); ++ mask = heap_alloc(size); ++ expect = heap_alloc(size); ++ memset(mask, 0xff, size); ++ ++ if (!(pattern = wcschr(pattern, ','))) ++ { ++ heap_free(mask); ++ heap_free(expect); ++ return FALSE; ++ } ++ pattern++; ++ while (byte_from_hex_char(*pattern) == -1 && (*pattern != ',')) ++ pattern++; ++ ++ for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++) ++ { ++ if (i % 2) ++ mask[i / 2] |= d; ++ else ++ mask[i / 2] = d << 4; ++ } ++ ++ if (!(pattern = wcschr(pattern, ','))) ++ { ++ heap_free(mask); ++ heap_free(expect); ++ return FALSE; ++ } ++ pattern++; ++ while (byte_from_hex_char(*pattern) == -1 && (*pattern != ',')) ++ pattern++; ++ ++ for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++) ++ { ++ if (i % 2) ++ expect[i / 2] |= d; ++ else ++ expect[i / 2] = d << 4; ++ } ++ ++ actual = heap_alloc(size); ++ SetFilePointer(file, offset, NULL, FILE_BEGIN); ++ if (!ReadFile(file, actual, size, &ret_size, NULL) || ret_size != size) ++ { ++ heap_free(actual); ++ heap_free(expect); ++ heap_free(mask); ++ return FALSE; ++ } ++ ++ for (i = 0; i < size; ++i) ++ { ++ if ((actual[i] & mask[i]) != expect[i]) ++ { ++ ret = FALSE; ++ break; ++ } ++ } ++ ++ heap_free(actual); ++ heap_free(expect); ++ heap_free(mask); ++ ++ /* If there is a following tuple, then we must match that as well. */ ++ if (ret && (pattern = wcschr(pattern, ','))) ++ return process_pattern_string(pattern + 1, file); ++ ++ return ret; ++} ++ ++BOOL get_media_type(const WCHAR *filename, GUID *majortype, GUID *subtype, GUID *source_clsid) ++{ ++ WCHAR extensions_path[278] = L"Media Type\\Extensions\\"; ++ DWORD majortype_idx, size; ++ const WCHAR *ext; ++ HKEY parent_key; ++ HANDLE file; ++ ++ if ((ext = wcsrchr(filename, '.'))) ++ { ++ WCHAR guidstr[39]; ++ HKEY key; ++ ++ wcscat(extensions_path, ext); ++ if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, extensions_path, 0, KEY_READ, &key)) ++ { ++ size = sizeof(guidstr); ++ if (majortype && !RegQueryValueExW(key, L"Media Type", NULL, NULL, (BYTE *)guidstr, &size)) ++ CLSIDFromString(guidstr, majortype); ++ ++ size = sizeof(guidstr); ++ if (subtype && !RegQueryValueExW(key, L"Subtype", NULL, NULL, (BYTE *)guidstr, &size)) ++ CLSIDFromString(guidstr, subtype); ++ ++ size = sizeof(guidstr); ++ if (source_clsid && !RegQueryValueExW(key, L"Source Filter", NULL, NULL, (BYTE *)guidstr, &size)) ++ CLSIDFromString(guidstr, source_clsid); ++ ++ RegCloseKey(key); ++ return FALSE; ++ } ++ } ++ ++ if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, ++ OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) ++ { ++ WARN("Failed to open file %s, error %u.\n", debugstr_w(filename), GetLastError()); ++ return FALSE; ++ } ++ ++ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Media Type", 0, KEY_READ, &parent_key)) ++ { ++ CloseHandle(file); ++ return FALSE; ++ } ++ ++ for (majortype_idx = 0; ; ++majortype_idx) ++ { ++ WCHAR majortype_str[39]; ++ HKEY majortype_key; ++ DWORD subtype_idx; ++ ++ size = ARRAY_SIZE(majortype_str); ++ if (RegEnumKeyExW(parent_key, majortype_idx, majortype_str, &size, NULL, NULL, NULL, NULL)) ++ break; ++ ++ if (!wcscmp(majortype_str, L"Extensions")) ++ continue; ++ ++ if (RegOpenKeyExW(parent_key, majortype_str, 0, KEY_READ, &majortype_key)) ++ continue; ++ ++ for (subtype_idx = 0; ; ++subtype_idx) ++ { ++ WCHAR subtype_str[39], *pattern; ++ DWORD value_idx, max_size; ++ HKEY subtype_key; ++ ++ size = ARRAY_SIZE(subtype_str); ++ if (RegEnumKeyExW(majortype_key, subtype_idx, subtype_str, &size, NULL, NULL, NULL, NULL)) ++ break; ++ ++ if (RegOpenKeyExW(majortype_key, subtype_str, 0, KEY_READ, &subtype_key)) ++ continue; ++ ++ if (RegQueryInfoKeyW(subtype_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_size, NULL, NULL)) ++ continue; ++ ++ pattern = heap_alloc(max_size); ++ ++ for (value_idx = 0; ; ++value_idx) ++ { ++ /* The longest name we should encounter is "Source Filter". */ ++ WCHAR value_name[14], source_clsid_str[39]; ++ DWORD value_len = ARRAY_SIZE(value_name); ++ ++ size = max_size; ++ if (RegEnumValueW(subtype_key, value_idx, value_name, &value_len, ++ NULL, NULL, (BYTE *)pattern, &max_size)) ++ break; ++ ++ if (!wcscmp(value_name, L"Source Filter")) ++ continue; ++ ++ if (!process_pattern_string(pattern, file)) ++ continue; ++ ++ if (majortype) ++ CLSIDFromString(majortype_str, majortype); ++ if (subtype) ++ CLSIDFromString(subtype_str, subtype); ++ size = sizeof(source_clsid_str); ++ if (source_clsid && !RegQueryValueExW(subtype_key, L"Source Filter", ++ NULL, NULL, (BYTE *)source_clsid_str, &size)) ++ CLSIDFromString(source_clsid_str, source_clsid); ++ ++ heap_free(pattern); ++ RegCloseKey(subtype_key); ++ RegCloseKey(majortype_key); ++ RegCloseKey(parent_key); ++ CloseHandle(file); ++ return TRUE; ++ } ++ ++ heap_free(pattern); ++ RegCloseKey(subtype_key); ++ } ++ ++ RegCloseKey(majortype_key); ++ } ++ ++ RegCloseKey(parent_key); ++ CloseHandle(file); ++ return FALSE; ++} ++ + static struct strmbase_pin *asf_reader_get_pin(struct strmbase_filter *iface, unsigned int index) + { ++ struct asf_reader *filter = impl_from_strmbase_filter(iface); ++ ++ if (!index && filter->pszFileName) ++ return &filter->source.pin; + return NULL; + } + + static void asf_reader_destroy(struct strmbase_filter *iface) + { +- struct asf_reader *filter = impl_reader_from_strmbase_filter(iface); ++ struct asf_reader *filter = impl_from_strmbase_filter(iface); ++ ++ if (filter->pszFileName) ++ { ++ unsigned int i; ++ ++ if (filter->source.pin.peer) ++ IPin_Disconnect(filter->source.pin.peer); ++ ++ IPin_Disconnect(&filter->source.pin.IPin_iface); ++ ++ if (filter->requests) ++ { ++ for (i = 0; i < filter->max_requests; ++i) ++ CloseHandle(filter->requests[i].ovl.hEvent); ++ free(filter->requests); ++ } ++ CloseHandle(filter->file); ++ filter->sample_cs.DebugInfo->Spare[0] = 0; ++ DeleteCriticalSection(&filter->sample_cs); ++ strmbase_source_cleanup(&filter->source); ++ ++ free(filter->pszFileName); ++ FreeMediaType(&filter->mt); ++ } + +- free(filter->filename); +- FreeMediaType(&filter->type); ++ PostQueuedCompletionStatus(filter->port, 0, 1, NULL); ++ WaitForSingleObject(filter->io_thread, INFINITE); ++ CloseHandle(filter->io_thread); ++ CloseHandle(filter->port); + + strmbase_filter_cleanup(&filter->filter); + free(filter); +@@ -54,7 +360,7 @@ static void asf_reader_destroy(struct strmbase_filter *iface) + + static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) + { +- struct asf_reader *filter = impl_reader_from_strmbase_filter(iface); ++ struct asf_reader *filter = impl_from_strmbase_filter(iface); + + if (IsEqualGUID(iid, &IID_IFileSourceFilter)) + { +@@ -66,110 +372,583 @@ static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID + return E_NOINTERFACE; + } + +-static struct strmbase_filter_ops filter_ops = ++static const struct strmbase_filter_ops filter_ops = + { + .filter_get_pin = asf_reader_get_pin, + .filter_destroy = asf_reader_destroy, + .filter_query_interface = asf_reader_query_interface, + }; + +-static inline struct asf_reader *impl_from_IFileSourceFilter(IFileSourceFilter *iface) ++static DWORD CALLBACK io_thread(void *arg) + { +- return CONTAINING_RECORD(iface, struct asf_reader, IFileSourceFilter_iface); ++ struct asf_reader *filter = arg; ++ struct request *req; ++ OVERLAPPED *ovl; ++ ULONG_PTR key; ++ DWORD size; ++ BOOL ret; ++ ++ for (;;) ++ { ++ ret = GetQueuedCompletionStatus(filter->port, &size, &key, &ovl, INFINITE); ++ ++ if (ret && key) ++ break; ++ ++ EnterCriticalSection(&filter->sample_cs); ++ ++ req = CONTAINING_RECORD(ovl, struct request, ovl); ++ TRACE("Got sample %u.\n", req - filter->requests); ++ assert(req >= filter->requests && req < filter->requests + filter->max_requests); ++ ++ if (ret) ++ WakeConditionVariable(&filter->sample_cv); ++ else ++ { ++ ERR("GetQueuedCompletionStatus() returned failure, error %u.\n", GetLastError()); ++ req->sample = NULL; ++ } ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ } ++ ++ return 0; + } + +-static HRESULT WINAPI filesourcefilter_QueryInterface(IFileSourceFilter *iface, REFIID iid, void **out) ++HRESULT asf_reader_create(IUnknown *outer, IUnknown **out) + { +- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); ++ struct asf_reader *object; ++ ++ if (!(object = calloc(1, sizeof(*object)))) ++ return E_OUTOFMEMORY; + +- return IBaseFilter_QueryInterface(&filter->filter.IBaseFilter_iface, iid, out); ++ strmbase_filter_init(&object->filter, outer, &CLSID_AsyncReader, &filter_ops); ++ ++ object->IFileSourceFilter_iface.lpVtbl = &FileSource_Vtbl; ++ object->IAsyncReader_iface.lpVtbl = &FileAsyncReader_Vtbl; ++ ++ InitializeCriticalSection(&object->sample_cs); ++ object->sample_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.sample_cs"); ++ InitializeConditionVariable(&object->sample_cv); ++ object->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); ++ object->io_thread = CreateThread(NULL, 0, io_thread, object, 0, NULL); ++ ++ TRACE("Created file source %p.\n", object); ++ *out = &object->filter.IUnknown_inner; ++ return S_OK; + } + +-static ULONG WINAPI filesourcefilter_AddRef(IFileSourceFilter *iface) ++static HRESULT WINAPI FileSource_QueryInterface(IFileSourceFilter * iface, REFIID riid, LPVOID * ppv) + { + struct asf_reader *filter = impl_from_IFileSourceFilter(iface); ++ return IBaseFilter_QueryInterface(&filter->filter.IBaseFilter_iface, riid, ppv); ++} + ++static ULONG WINAPI FileSource_AddRef(IFileSourceFilter * iface) ++{ ++ struct asf_reader *filter = impl_from_IFileSourceFilter(iface); + return IBaseFilter_AddRef(&filter->filter.IBaseFilter_iface); + } + +-static ULONG WINAPI filesourcefilter_Release(IFileSourceFilter *iface) ++static ULONG WINAPI FileSource_Release(IFileSourceFilter * iface) + { + struct asf_reader *filter = impl_from_IFileSourceFilter(iface); +- + return IBaseFilter_Release(&filter->filter.IBaseFilter_iface); + } + +-static HRESULT WINAPI filesourcefilter_Load(IFileSourceFilter *iface, LPCOLESTR filename, const AM_MEDIA_TYPE *type) ++static HRESULT WINAPI FileSource_Load(IFileSourceFilter * iface, LPCOLESTR pszFileName, const AM_MEDIA_TYPE * pmt) + { +- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); ++ struct asf_reader *This = impl_from_IFileSourceFilter(iface); ++ HANDLE hFile; + +- TRACE("filter %p, filename %s, type %p.\n", filter, debugstr_w(filename), type); +- strmbase_dump_media_type(type); ++ TRACE("%p->(%s, %p)\n", This, debugstr_w(pszFileName), pmt); ++ strmbase_dump_media_type(pmt); + +- if (!filename) ++ if (!pszFileName) + return E_POINTER; + +- if (filter->filename) +- return E_FAIL; ++ /* open file */ ++ /* FIXME: check the sharing values that native uses */ ++ hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); ++ ++ if (hFile == INVALID_HANDLE_VALUE) ++ { ++ return HRESULT_FROM_WIN32(GetLastError()); ++ } ++ ++ if (!GetFileSizeEx(hFile, &This->file_size)) ++ { ++ WARN("Could not get file size.\n"); ++ CloseHandle(hFile); ++ return HRESULT_FROM_WIN32(GetLastError()); ++ } ++ ++ if (This->pszFileName) ++ { ++ free(This->pszFileName); ++ FreeMediaType(&This->mt); ++ } + +- if (!(filter->filename = wcsdup(filename))) ++ if (!(This->pszFileName = wcsdup(pszFileName))) ++ { ++ CloseHandle(hFile); + return E_OUTOFMEMORY; ++ } ++ ++ strmbase_source_init(&This->source, &This->filter, L"Output", &source_ops); ++ BaseFilterImpl_IncrementPinVersion(&This->filter); ++ ++ This->file = hFile; ++ This->flushing = FALSE; ++ This->requests = NULL; + +- if (type) +- CopyMediaType(&filter->type, type); ++ if (!pmt) ++ { ++ CopyMediaType(&This->mt, &default_mt); ++ if (get_media_type(pszFileName, &This->mt.majortype, &This->mt.subtype, NULL)) ++ { ++ TRACE("Found major type %s, subtype %s.\n", ++ debugstr_guid(&This->mt.majortype), debugstr_guid(&This->mt.subtype)); ++ } ++ } ++ else ++ CopyMediaType(&This->mt, pmt); + + return S_OK; + } + +-static HRESULT WINAPI filesourcefilter_GetCurFile(IFileSourceFilter *iface, LPOLESTR *filename, AM_MEDIA_TYPE *type) ++static HRESULT WINAPI FileSource_GetCurFile(IFileSourceFilter *iface, LPOLESTR *ppszFileName, AM_MEDIA_TYPE *mt) + { +- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); ++ struct asf_reader *This = impl_from_IFileSourceFilter(iface); + +- TRACE("filter %p, filename %p, type %p.\n", filter, filename, type); ++ TRACE("filter %p, filename %p, mt %p.\n", This, ppszFileName, mt); + +- if (!filename) ++ if (!ppszFileName) + return E_POINTER; +- *filename = NULL; + +- if (type) ++ /* copy file name & media type if available, otherwise clear the outputs */ ++ if (This->pszFileName) + { +- type->majortype = filter->type.majortype; +- type->subtype = filter->type.subtype; +- type->lSampleSize = filter->type.lSampleSize; +- type->pUnk = filter->type.pUnk; +- type->cbFormat = filter->type.cbFormat; ++ *ppszFileName = CoTaskMemAlloc((wcslen(This->pszFileName) + 1) * sizeof(WCHAR)); ++ wcscpy(*ppszFileName, This->pszFileName); ++ if (mt) ++ CopyMediaType(mt, &This->mt); + } +- +- if (filter->filename) ++ else + { +- *filename = CoTaskMemAlloc((wcslen(filter->filename) + 1) * sizeof(WCHAR)); +- wcscpy(*filename, filter->filename); ++ *ppszFileName = NULL; ++ if (mt) ++ memset(mt, 0, sizeof(AM_MEDIA_TYPE)); + } + + return S_OK; + } + +-static const IFileSourceFilterVtbl filesourcefilter_vtbl = ++static const IFileSourceFilterVtbl FileSource_Vtbl = + { +- filesourcefilter_QueryInterface, +- filesourcefilter_AddRef, +- filesourcefilter_Release, +- filesourcefilter_Load, +- filesourcefilter_GetCurFile, ++ FileSource_QueryInterface, ++ FileSource_AddRef, ++ FileSource_Release, ++ FileSource_Load, ++ FileSource_GetCurFile + }; + +-HRESULT asf_reader_create(IUnknown *outer, IUnknown **out) ++static inline struct asf_reader *impl_from_strmbase_pin(struct strmbase_pin *iface) + { +- struct asf_reader *object; ++ return CONTAINING_RECORD(iface, struct asf_reader, source.pin); ++} + +- if (!(object = calloc(1, sizeof(*object)))) ++static inline struct asf_reader *impl_from_IAsyncReader(IAsyncReader *iface) ++{ ++ return CONTAINING_RECORD(iface, struct asf_reader, IAsyncReader_iface); ++} ++ ++static HRESULT source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) ++{ ++ struct asf_reader *filter = impl_from_strmbase_pin(iface); ++ ++ if (IsEqualGUID(&mt->majortype, &filter->mt.majortype) ++ && (!IsEqualGUID(&mt->subtype, &GUID_NULL) ++ || IsEqualGUID(&filter->mt.subtype, &GUID_NULL))) ++ return S_OK; ++ ++ return S_FALSE; ++} ++ ++static HRESULT source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) ++{ ++ struct asf_reader *filter = impl_from_strmbase_pin(iface); ++ ++ if (index > 1) ++ return VFW_S_NO_MORE_ITEMS; ++ ++ if (index == 0) ++ CopyMediaType(mt, &filter->mt); ++ else if (index == 1) ++ CopyMediaType(mt, &default_mt); ++ return S_OK; ++} ++ ++static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) ++{ ++ struct asf_reader *filter = impl_from_strmbase_pin(iface); ++ ++ if (IsEqualGUID(iid, &IID_IAsyncReader)) ++ *out = &filter->IAsyncReader_iface; ++ else ++ return E_NOINTERFACE; ++ ++ IUnknown_AddRef((IUnknown *)*out); ++ return S_OK; ++} ++ ++/* Function called as a helper to IPin_Connect */ ++/* specific AM_MEDIA_TYPE - it cannot be NULL */ ++/* this differs from standard OutputPin_AttemptConnection only in that it ++ * doesn't need the IMemInputPin interface on the receiving pin */ ++static HRESULT WINAPI FileAsyncReaderPin_AttemptConnection(struct strmbase_source *This, ++ IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) ++{ ++ HRESULT hr; ++ ++ TRACE("%p->(%p, %p)\n", This, pReceivePin, pmt); ++ ++ if (This->pin.ops->pin_query_accept(&This->pin, pmt) != S_OK) ++ return VFW_E_TYPE_NOT_ACCEPTED; ++ ++ This->pin.peer = pReceivePin; ++ IPin_AddRef(pReceivePin); ++ CopyMediaType(&This->pin.mt, pmt); ++ ++ hr = IPin_ReceiveConnection(pReceivePin, &This->pin.IPin_iface, pmt); ++ ++ if (FAILED(hr)) ++ { ++ IPin_Release(This->pin.peer); ++ This->pin.peer = NULL; ++ FreeMediaType(&This->pin.mt); ++ } ++ ++ TRACE(" -- %x\n", hr); ++ return hr; ++} ++ ++static const struct strmbase_source_ops source_ops = ++{ ++ .base.pin_query_accept = source_query_accept, ++ .base.pin_get_media_type = source_get_media_type, ++ .base.pin_query_interface = source_query_interface, ++ .pfnAttemptConnection = FileAsyncReaderPin_AttemptConnection, ++}; ++ ++static HRESULT WINAPI FileAsyncReader_QueryInterface(IAsyncReader *iface, REFIID iid, void **out) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); ++} ++ ++static ULONG WINAPI FileAsyncReader_AddRef(IAsyncReader * iface) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ return IPin_AddRef(&filter->source.pin.IPin_iface); ++} ++ ++static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ return IPin_Release(&filter->source.pin.IPin_iface); ++} ++ ++static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader *iface, ++ IMemAllocator *preferred, ALLOCATOR_PROPERTIES *props, IMemAllocator **ret_allocator) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ IMemAllocator *allocator; ++ unsigned int i; ++ HRESULT hr; ++ ++ TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter, preferred, props, ret_allocator); ++ ++ if (!props->cbAlign) ++ props->cbAlign = 1; ++ ++ *ret_allocator = NULL; ++ ++ if (preferred) ++ IMemAllocator_AddRef(allocator = preferred); ++ else if (FAILED(hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, ++ CLSCTX_INPROC, &IID_IMemAllocator, (void **)&allocator))) ++ return hr; ++ ++ if (FAILED(hr = IMemAllocator_SetProperties(allocator, props, props))) ++ { ++ IMemAllocator_Release(allocator); ++ return hr; ++ } ++ ++ if (filter->requests) ++ { ++ for (i = 0; i < filter->max_requests; ++i) ++ CloseHandle(filter->requests[i].ovl.hEvent); ++ free(filter->requests); ++ } ++ ++ filter->max_requests = props->cBuffers; ++ TRACE("Maximum request count: %u.\n", filter->max_requests); ++ if (!(filter->requests = calloc(filter->max_requests, sizeof(filter->requests[0])))) ++ { ++ IMemAllocator_Release(allocator); + return E_OUTOFMEMORY; ++ } + +- strmbase_filter_init(&object->filter, outer, &CLSID_WMAsfReader, &filter_ops); +- object->IFileSourceFilter_iface.lpVtbl = &filesourcefilter_vtbl; ++ for (i = 0; i < filter->max_requests; ++i) ++ filter->requests[i].ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + +- TRACE("Created WM ASF reader %p.\n", object); +- *out = &object->filter.IUnknown_inner; ++ *ret_allocator = allocator; ++ return S_OK; ++} ++ ++static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader *iface, IMediaSample *sample, DWORD_PTR cookie) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ REFERENCE_TIME start, end; ++ struct request *req; ++ unsigned int i; ++ HRESULT hr; ++ BYTE *data; ++ ++ TRACE("filter %p, sample %p, cookie %#lx.\n", filter, sample, cookie); ++ ++ if (!sample) ++ return E_POINTER; ++ ++ if (FAILED(hr = IMediaSample_GetTime(sample, &start, &end))) ++ return hr; ++ ++ if (BYTES_FROM_MEDIATIME(start) >= filter->file_size.QuadPart) ++ return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); ++ ++ if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) ++ return hr; ++ ++ EnterCriticalSection(&filter->sample_cs); ++ if (filter->flushing) ++ { ++ LeaveCriticalSection(&filter->sample_cs); ++ return VFW_E_WRONG_STATE; ++ } ++ ++ for (i = 0; i < filter->max_requests; ++i) ++ { ++ if (!filter->requests[i].sample) ++ break; ++ } ++ assert(i < filter->max_requests); ++ req = &filter->requests[i]; ++ ++ req->ovl.u.s.Offset = BYTES_FROM_MEDIATIME(start); ++ req->ovl.u.s.OffsetHigh = BYTES_FROM_MEDIATIME(start) >> 32; ++ /* No reference is taken. */ ++ ++ if (ReadFile(filter->file, data, BYTES_FROM_MEDIATIME(end - start), NULL, &req->ovl) ++ || GetLastError() == ERROR_IO_PENDING) ++ { ++ hr = S_OK; ++ req->sample = sample; ++ req->cookie = cookie; ++ } ++ else ++ hr = HRESULT_FROM_WIN32(GetLastError()); ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ return hr; ++} ++ ++static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader *iface, ++ DWORD timeout, IMediaSample **sample, DWORD_PTR *cookie) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ unsigned int i; ++ ++ TRACE("filter %p, timeout %u, sample %p, cookie %p.\n", filter, timeout, sample, cookie); ++ ++ *sample = NULL; ++ *cookie = 0; ++ ++ EnterCriticalSection(&filter->sample_cs); ++ ++ do ++ { ++ if (filter->flushing) ++ { ++ LeaveCriticalSection(&filter->sample_cs); ++ return VFW_E_WRONG_STATE; ++ } ++ ++ for (i = 0; i < filter->max_requests; ++i) ++ { ++ struct request *req = &filter->requests[i]; ++ DWORD size; ++ ++ if (req->sample && GetOverlappedResult(filter->file, &req->ovl, &size, FALSE)) ++ { ++ REFERENCE_TIME start, end; ++ ++ IMediaSample_SetActualDataLength(req->sample, size); ++ start = MEDIATIME_FROM_BYTES(((ULONGLONG)req->ovl.u.s.OffsetHigh << 32) + req->ovl.u.s.Offset); ++ end = start + MEDIATIME_FROM_BYTES(size); ++ IMediaSample_SetTime(req->sample, &start, &end); ++ ++ *sample = req->sample; ++ *cookie = req->cookie; ++ req->sample = NULL; ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ TRACE("Returning sample %u.\n", i); ++ return S_OK; ++ } ++ } ++ } while (SleepConditionVariableCS(&filter->sample_cv, &filter->sample_cs, timeout)); ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ return VFW_E_TIMEOUT; ++} ++ ++static BOOL sync_read(HANDLE file, LONGLONG offset, LONG length, BYTE *buffer, DWORD *read_len) ++{ ++ OVERLAPPED ovl = {0}; ++ BOOL ret; ++ ++ ovl.hEvent = (HANDLE)((ULONG_PTR)CreateEventW(NULL, TRUE, FALSE, NULL) | 1); ++ ovl.u.s.Offset = (DWORD)offset; ++ ovl.u.s.OffsetHigh = offset >> 32; ++ ++ *read_len = 0; ++ ++ ret = ReadFile(file, buffer, length, NULL, &ovl); ++ if (ret || GetLastError() == ERROR_IO_PENDING) ++ ret = GetOverlappedResult(file, &ovl, read_len, TRUE); ++ ++ TRACE("Returning %u bytes.\n", *read_len); ++ ++ CloseHandle(ovl.hEvent); ++ return ret; ++} ++ ++static HRESULT WINAPI FileAsyncReader_SyncReadAligned(IAsyncReader *iface, IMediaSample *sample) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ REFERENCE_TIME start_time, end_time; ++ DWORD read_len; ++ BYTE *buffer; ++ LONG length; ++ HRESULT hr; ++ BOOL ret; ++ ++ TRACE("filter %p, sample %p.\n", filter, sample); ++ ++ hr = IMediaSample_GetTime(sample, &start_time, &end_time); ++ ++ if (SUCCEEDED(hr)) ++ hr = IMediaSample_GetPointer(sample, &buffer); ++ ++ if (SUCCEEDED(hr)) ++ { ++ length = BYTES_FROM_MEDIATIME(end_time - start_time); ++ ret = sync_read(filter->file, BYTES_FROM_MEDIATIME(start_time), length, buffer, &read_len); ++ if (ret) ++ hr = (read_len == length) ? S_OK : S_FALSE; ++ else if (GetLastError() == ERROR_HANDLE_EOF) ++ hr = S_OK; ++ else ++ hr = HRESULT_FROM_WIN32(GetLastError()); ++ } ++ ++ if (SUCCEEDED(hr)) ++ IMediaSample_SetActualDataLength(sample, read_len); ++ ++ return hr; ++} ++ ++static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader *iface, ++ LONGLONG offset, LONG length, BYTE *buffer) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ DWORD read_len; ++ HRESULT hr; ++ BOOL ret; ++ ++ TRACE("filter %p, offset %s, length %d, buffer %p.\n", ++ filter, wine_dbgstr_longlong(offset), length, buffer); ++ ++ ret = sync_read(filter->file, offset, length, buffer, &read_len); ++ if (ret) ++ hr = (read_len == length) ? S_OK : S_FALSE; ++ else if (GetLastError() == ERROR_HANDLE_EOF) ++ hr = S_FALSE; ++ else ++ hr = HRESULT_FROM_WIN32(GetLastError()); ++ ++ return hr; ++} ++ ++static HRESULT WINAPI FileAsyncReader_Length(IAsyncReader *iface, LONGLONG *total, LONGLONG *available) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ ++ TRACE("iface %p, total %p, available %p.\n", iface, total, available); ++ ++ *available = *total = filter->file_size.QuadPart; + + return S_OK; + } ++ ++static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ unsigned int i; ++ ++ TRACE("iface %p.\n", iface); ++ ++ EnterCriticalSection(&filter->sample_cs); ++ ++ filter->flushing = TRUE; ++ for (i = 0; i < filter->max_requests; ++i) ++ filter->requests[i].sample = NULL; ++ CancelIoEx(filter->file, NULL); ++ WakeAllConditionVariable(&filter->sample_cv); ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface) ++{ ++ struct asf_reader *filter = impl_from_IAsyncReader(iface); ++ ++ TRACE("iface %p.\n", iface); ++ ++ EnterCriticalSection(&filter->sample_cs); ++ ++ filter->flushing = FALSE; ++ ++ LeaveCriticalSection(&filter->sample_cs); ++ ++ return S_OK; ++} ++ ++static const IAsyncReaderVtbl FileAsyncReader_Vtbl = ++{ ++ FileAsyncReader_QueryInterface, ++ FileAsyncReader_AddRef, ++ FileAsyncReader_Release, ++ FileAsyncReader_RequestAllocator, ++ FileAsyncReader_Request, ++ FileAsyncReader_WaitForNext, ++ FileAsyncReader_SyncReadAligned, ++ FileAsyncReader_SyncRead, ++ FileAsyncReader_Length, ++ FileAsyncReader_BeginFlush, ++ FileAsyncReader_EndFlush, ++}; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch b/patches/mfplat-streaming-support/0013-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch similarity index 51% rename from patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch rename to patches/mfplat-streaming-support/0013-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch index 477dff97..85a9d738 100644 --- a/patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch +++ b/patches/mfplat-streaming-support/0013-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch @@ -1,8 +1,8 @@ -From 1adbc46410773bdd75d844280738be677bb75906 Mon Sep 17 00:00:00 2001 +From 75d383ab1c6b3c3872b895164c816d11de1d821c Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 9 Mar 2021 16:53:09 -0500 -Subject: [PATCH] winegstreamer: Activate source pad in push mode if it isn't - activated in pull mode. +Subject: [PATCH 13/88] winegstreamer: Activate source pad in push mode if it + isn't activated in pull mode. Since our source pad is not part of any element, gstreamer won't end up activating it directly through the state transition. Instead, if the downstream element doesn't @@ -11,14 +11,14 @@ we activate our pad in push mode. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/wg_parser.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) + dlls/winegstreamer/wg_parser.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index cd12a23d0c8..9b4c9c1c9ed 100644 +index b93b2c182ae..d7412409a27 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -61,7 +61,7 @@ struct wg_parser +@@ -75,7 +75,7 @@ struct wg_parser pthread_mutex_t mutex; pthread_cond_t init_cond; @@ -27,7 +27,7 @@ index cd12a23d0c8..9b4c9c1c9ed 100644 pthread_cond_t read_cond, read_done_cond; struct -@@ -1358,9 +1358,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode +@@ -1528,9 +1528,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode GST_DEBUG("%s source pad for parser %p in %s mode.", activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode)); @@ -40,7 +40,16 @@ index cd12a23d0c8..9b4c9c1c9ed 100644 return TRUE; case GST_PAD_MODE_PUSH: return activate_push(pad, activate); -@@ -1636,6 +1639,8 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) +@@ -1695,6 +1698,8 @@ static NTSTATUS wg_parser_connect(void *args) + goto out; + + gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + { +@@ -1833,6 +1838,8 @@ static NTSTATUS wg_parser_disconnect(void *args) pthread_mutex_unlock(&parser->mutex); gst_element_set_state(parser->container, GST_STATE_NULL); @@ -49,42 +58,6 @@ index cd12a23d0c8..9b4c9c1c9ed 100644 gst_pad_unlink(parser->my_src, parser->their_sink); gst_object_unref(parser->my_src); gst_object_unref(parser->their_sink); -@@ -1687,6 +1692,8 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - } - - gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) - { -@@ -1734,6 +1741,8 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) - } - - gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) - { -@@ -1784,6 +1793,8 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) - - gst_pad_set_active(stream->my_sink, 1); - gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) - { -@@ -1825,6 +1836,8 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) - - gst_pad_set_active(stream->my_sink, 1); - gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) - { -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch b/patches/mfplat-streaming-support/0014-winegstreamer-Push-stream-start-and-segment-events-i.patch similarity index 77% rename from patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch rename to patches/mfplat-streaming-support/0014-winegstreamer-Push-stream-start-and-segment-events-i.patch index 56a488cc..83158c7e 100644 --- a/patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch +++ b/patches/mfplat-streaming-support/0014-winegstreamer-Push-stream-start-and-segment-events-i.patch @@ -1,8 +1,8 @@ -From 2740496b0c1f878593899e6dc88390413bf835f1 Mon Sep 17 00:00:00 2001 +From c8a074d72e06a8e44cb9390126e656800d249e08 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 10 Mar 2021 10:43:03 -0500 -Subject: [PATCH] winegstreamer: Push stream-start and segment events in push - mode. +Subject: [PATCH 14/88] winegstreamer: Push stream-start and segment events in + push mode. Signed-off-by: Derek Lesho --- @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 13 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 9b4c9c1c9ed..879aece63b7 100644 +index d7412409a27..c6e8bbcb26b 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -1279,6 +1279,7 @@ static void *push_data(void *arg) +@@ -1449,6 +1449,7 @@ static void *push_data(void *arg) { struct wg_parser *parser = arg; GstBuffer *buffer; @@ -21,7 +21,7 @@ index 9b4c9c1c9ed..879aece63b7 100644 guint max_size; GST_DEBUG("Starting push thread."); -@@ -1291,6 +1292,12 @@ static void *push_data(void *arg) +@@ -1461,6 +1462,12 @@ static void *push_data(void *arg) max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; @@ -34,7 +34,7 @@ index 9b4c9c1c9ed..879aece63b7 100644 for (;;) { ULONG size; -@@ -1425,6 +1432,7 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) +@@ -1595,6 +1602,7 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) GstEvent *flush_event; GstSeekFlags flags; gint64 cur, stop; @@ -42,7 +42,7 @@ index 9b4c9c1c9ed..879aece63b7 100644 guint32 seqnum; gdouble rate; -@@ -1458,7 +1466,12 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) +@@ -1628,7 +1636,12 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) gst_event_set_seqnum(flush_event, seqnum); gst_pad_push_event(parser->my_src, flush_event); if (thread) @@ -56,5 +56,5 @@ index 9b4c9c1c9ed..879aece63b7 100644 return TRUE; -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch b/patches/mfplat-streaming-support/0015-winegstreamer-Introduce-H.264-decoder-transform.patch similarity index 87% rename from patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch rename to patches/mfplat-streaming-support/0015-winegstreamer-Introduce-H.264-decoder-transform.patch index b501922c..34f26582 100644 --- a/patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch +++ b/patches/mfplat-streaming-support/0015-winegstreamer-Introduce-H.264-decoder-transform.patch @@ -1,24 +1,24 @@ -From 915e18d44c16f08f27ea4bf0e8bb46221b055ce0 Mon Sep 17 00:00:00 2001 +From 95180a07deb9e543627a8705da2bc73ccfff70a5 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 10 Mar 2021 13:09:51 -0500 -Subject: [PATCH] winegstreamer: Introduce H.264 decoder transform. +Subject: [PATCH 15/88] winegstreamer: Introduce H.264 decoder transform. Signed-off-by: Derek Lesho --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/decode_transform.c | 301 +++++++++++++++++++ dlls/winegstreamer/gst_private.h | 2 + + dlls/winegstreamer/main.c | 3 + dlls/winegstreamer/mfplat.c | 1 + dlls/winegstreamer/winegstreamer_classes.idl | 6 + - include/mfidl.idl | 1 + - 6 files changed, 312 insertions(+) + 6 files changed, 314 insertions(+) create mode 100644 dlls/winegstreamer/decode_transform.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 4d5dece64b3..7459cccf7e4 100644 +index c53e914e246..3da8c614ed2 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in -@@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin +@@ -8,6 +8,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) C_SRCS = \ audioconvert.c \ @@ -334,51 +334,58 @@ index 00000000000..f5d4763bde4 + return S_OK; +} diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 55a62361966..cdf90d52025 100644 +index 3584f465218..588aa50bccd 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h -@@ -219,4 +219,6 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI +@@ -119,6 +119,8 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + HRESULT audio_converter_create(REFIID riid, void **ret); +HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; + - #endif /* __GST_PRIVATE_INCLUDED__ */ + struct wm_stream + { + struct wm_reader *reader; +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 51a71d3b4a5..8f487655748 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -547,6 +547,9 @@ HRESULT WINAPI DllRegisterServer(void) + + init_gstreamer(); + ++ if (FAILED(hr = mfplat_DllRegisterServer())) ++ return hr; ++ + if (FAILED(hr = __wine_register_resources())) + return hr; + diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index dcbd03137ba..4bff7ee9241 100644 +index a111bbe196d..8b455a67aa2 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -412,6 +412,7 @@ class_objects[] = +@@ -408,6 +408,7 @@ class_objects[] = { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, -+ { &CLSID_CMSH264DecoderMFT, &decode_transform_create }, ++ { &CLSID_MSH264DecoderMFT, &decode_transform_create }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 072ec90eea4..064a6872c79 100644 +index 90dc1dc839b..022f5f80980 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -67,3 +67,9 @@ coclass GStreamerByteStreamHandler {} - uuid(6a170414-aad9-4693-b806-3a0c47c570d6) +@@ -73,3 +73,9 @@ coclass WINEAudioConverter { } + uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) ] - coclass WINEAudioConverter { } + coclass CWMADecMediaObject {}; + +[ + threading(both), + uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) +] +coclass CMSH264DecoderMFT { } -diff --git a/include/mfidl.idl b/include/mfidl.idl -index 5b16c08bb90..f28a0669804 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1579,3 +1579,4 @@ cpp_quote("EXTERN_GUID(MF_XVP_CALLER_ALLOCATES_OUTPUT, 0x4a2cabc, 0x0cab, 0x40b1 - cpp_quote("EXTERN_GUID(MF_XVP_SAMPLE_LOCK_TIMEOUT, 0xaa4ddb29, 0x5134, 0x4363, 0xac, 0x72, 0x83, 0xec, 0x4b, 0xc1, 0x04, 0x26);") - - cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") -+cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch b/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch deleted file mode 100644 index 0e34b2b0..00000000 --- a/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch +++ /dev/null @@ -1,53 +0,0 @@ -From aa96c5c8ae43df1ce01e6db11a64c04a768dc231 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 17:00:27 -0400 -Subject: [PATCH] winegstreamer: Register the AAC decoder transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 9c95450bd99..955afff20dc 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -473,6 +473,17 @@ static const GUID *h264_decoder_output_types[] = - &MFVideoFormat_YV12, - }; - -+static WCHAR aac_decoderW[] = L"AAC Decoder"; -+static const GUID *aac_decoder_input_types[] = -+{ -+ &MFAudioFormat_AAC, -+}; -+static const GUID *aac_decoder_output_types[] = -+{ -+ &MFAudioFormat_Float, -+ &MFAudioFormat_PCM, -+}; -+ - static const struct mft - { - const GUID *clsid; -@@ -509,6 +520,17 @@ mfts[] = - ARRAY_SIZE(h264_decoder_output_types), - h264_decoder_output_types, - }, -+ { -+ &CLSID_CMSAACDecMFT, -+ &MFT_CATEGORY_AUDIO_DECODER, -+ aac_decoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Audio, -+ ARRAY_SIZE(aac_decoder_input_types), -+ aac_decoder_input_types, -+ ARRAY_SIZE(aac_decoder_output_types), -+ aac_decoder_output_types, -+ }, - }; - - HRESULT mfplat_DllRegisterServer(void) --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch b/patches/mfplat-streaming-support/0016-winegstreamer-Implement-GetInputAvailableType-for-de.patch similarity index 87% rename from patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch rename to patches/mfplat-streaming-support/0016-winegstreamer-Implement-GetInputAvailableType-for-de.patch index 2f3ae8be..ece3beb8 100644 --- a/patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch +++ b/patches/mfplat-streaming-support/0016-winegstreamer-Implement-GetInputAvailableType-for-de.patch @@ -1,8 +1,8 @@ -From 42278cb728ff00fdd44e5ca04a68d3fd34c79f15 Mon Sep 17 00:00:00 2001 +From 26157534099bf6653456d66d964c5c2f09f9a9a7 Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Wed, 10 Mar 2021 14:14:21 -0500 -Subject: [PATCH] winegstreamer: Implement ::GetInputAvailableType for decode - transform. +Date: Tue, 14 Dec 2021 13:36:27 +0100 +Subject: [PATCH 16/88] winegstreamer: Implement ::GetInputAvailableType for + decode transform. Signed-off-by: Derek Lesho --- @@ -112,12 +112,12 @@ index f5d4763bde4..55a0c1c6c9b 100644 return S_OK; } diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index cdf90d52025..2d2ebbda61f 100644 +index 588aa50bccd..b9379487ac2 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h -@@ -219,6 +219,10 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI +@@ -119,7 +119,11 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + HRESULT audio_converter_create(REFIID riid, void **ret); -HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; +enum decoder_type @@ -126,12 +126,13 @@ index cdf90d52025..2d2ebbda61f 100644 +}; +HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - #endif /* __GST_PRIVATE_INCLUDED__ */ + struct wm_stream + { diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 4bff7ee9241..f8f83031b7e 100644 +index 8b455a67aa2..93ddb90a070 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -402,6 +402,11 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a +@@ -398,6 +398,11 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; @@ -143,15 +144,15 @@ index 4bff7ee9241..f8f83031b7e 100644 static const struct class_object { const GUID *clsid; -@@ -412,7 +417,7 @@ class_objects[] = +@@ -408,7 +413,7 @@ class_objects[] = { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, -- { &CLSID_CMSH264DecoderMFT, &decode_transform_create }, -+ { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, +- { &CLSID_MSH264DecoderMFT, &decode_transform_create }, ++ { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch b/patches/mfplat-streaming-support/0017-winegstreamer-Implement-GetOutputAvailableType-for-d.patch similarity index 91% rename from patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch rename to patches/mfplat-streaming-support/0017-winegstreamer-Implement-GetOutputAvailableType-for-d.patch index 23e8989a..0b09a3cf 100644 --- a/patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch +++ b/patches/mfplat-streaming-support/0017-winegstreamer-Implement-GetOutputAvailableType-for-d.patch @@ -1,8 +1,8 @@ -From 360b07b3ba1bc9fdb8225b64bc4a1ada43256087 Mon Sep 17 00:00:00 2001 +From bfa940843cf60483a21e9dc135328d19f839f13a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 10 Mar 2021 14:23:09 -0500 -Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for decode - transform. +Subject: [PATCH 17/88] winegstreamer: Implement ::GetOutputAvailableType for + decode transform. Signed-off-by: Derek Lesho --- @@ -53,5 +53,5 @@ index 55a0c1c6c9b..3c71fddd67c 100644 static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch b/patches/mfplat-streaming-support/0018-winegstreamer-Implement-SetInputType-for-decode-tran.patch similarity index 87% rename from patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch rename to patches/mfplat-streaming-support/0018-winegstreamer-Implement-SetInputType-for-decode-tran.patch index 580b2684..42c41d0b 100644 --- a/patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch +++ b/patches/mfplat-streaming-support/0018-winegstreamer-Implement-SetInputType-for-decode-tran.patch @@ -1,14 +1,15 @@ -From 328f8b7e095596cb11d86484665062591aebcf55 Mon Sep 17 00:00:00 2001 +From 29aad7626e6a5bcdabdacb579ff3e9b707ed8452 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 11 Mar 2021 12:33:02 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetInputType for decode transform. +Subject: [PATCH 18/88] winegstreamer: Implement ::SetInputType for decode + transform. Signed-off-by: Derek Lesho --- dlls/winegstreamer/decode_transform.c | 80 ++++++++++++++++++++++++++- - dlls/winegstreamer/gst_private.h | 10 ++++ dlls/winegstreamer/mfplat.c | 17 +++++- dlls/winegstreamer/quartz_parser.c | 1 + + dlls/winegstreamer/unixlib.h | 10 ++++ dlls/winegstreamer/wg_parser.c | 76 +++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 4 deletions(-) @@ -125,35 +126,11 @@ index 3c71fddd67c..f709ef32fc1 100644 *obj = &object->IMFTransform_iface; return S_OK; } -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 2d2ebbda61f..215cf4577d4 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -97,9 +97,19 @@ struct wg_format - WG_VIDEO_FORMAT_YVYU, - - WG_VIDEO_FORMAT_CINEPAK, -+ -+ WG_VIDEO_FORMAT_H264, - } format; - uint32_t width, height; - uint32_t fps_n, fps_d; -+ union -+ { -+ struct -+ { -+ uint32_t profile; -+ uint32_t level; -+ } h264; -+ } compressed; - } video; - struct - { diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index f8f83031b7e..9d1cbd87746 100644 +index 93ddb90a070..4fe11b7b6b8 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -533,6 +533,7 @@ video_formats[] = +@@ -554,6 +554,7 @@ video_formats[] = {&MFVideoFormat_YUY2, WG_VIDEO_FORMAT_YUY2}, {&MFVideoFormat_YV12, WG_VIDEO_FORMAT_YV12}, {&MFVideoFormat_YVYU, WG_VIDEO_FORMAT_YVYU}, @@ -161,7 +138,7 @@ index f8f83031b7e..9d1cbd87746 100644 }; static const struct -@@ -719,10 +720,22 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma +@@ -741,10 +742,22 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma if (IsEqualGUID(&subtype, video_formats[i].subtype)) { format->u.video.format = video_formats[i].format; @@ -187,22 +164,46 @@ index f8f83031b7e..9d1cbd87746 100644 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 09a916d7f5c..fc1b72cd958 100644 +index 45313ebda27..0328b5ed4f5 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c -@@ -268,6 +268,7 @@ static unsigned int get_image_size(const struct wg_format *format) - return width * height * 3; +@@ -271,6 +271,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) + * but as long as every sample fits into our allocator, we're fine. */ + return width * height * 3; - case WG_VIDEO_FORMAT_UNKNOWN: -+ case WG_VIDEO_FORMAT_H264: - break; - } ++ case WG_VIDEO_FORMAT_H264: + case WG_VIDEO_FORMAT_UNKNOWN: + FIXME("Cannot guess maximum sample size for unknown video format.\n"); + return 0; +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 82bb534b938..f3db631d16d 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -62,9 +62,19 @@ struct wg_format + WG_VIDEO_FORMAT_YVYU, + WG_VIDEO_FORMAT_CINEPAK, ++ ++ WG_VIDEO_FORMAT_H264, + } format; + int32_t width, height; + uint32_t fps_n, fps_d; ++ union ++ { ++ struct ++ { ++ uint32_t profile; ++ uint32_t level; ++ } h264; ++ } compressed; + } video; + struct + { diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 879aece63b7..1afe92f04ac 100644 +index c6e8bbcb26b..c2141fae2af 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -387,6 +387,22 @@ static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t +@@ -406,6 +406,22 @@ static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t } } @@ -225,7 +226,7 @@ index 879aece63b7..1afe92f04ac 100644 static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) { GstAudioChannelPosition positions[32]; -@@ -428,6 +444,65 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) +@@ -447,6 +463,65 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) unsigned int i; GstCaps *caps; @@ -291,14 +292,14 @@ index 879aece63b7..1afe92f04ac 100644 if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) return NULL; -@@ -587,6 +662,7 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const +@@ -655,6 +730,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) case WG_VIDEO_FORMAT_YVYU: case WG_VIDEO_FORMAT_UNKNOWN: case WG_VIDEO_FORMAT_CINEPAK: + case WG_VIDEO_FORMAT_H264: - gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "none"); break; } + -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch b/patches/mfplat-streaming-support/0019-winegstreamer-Implement-SetOutputType-for-decode-tra.patch similarity index 95% rename from patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch rename to patches/mfplat-streaming-support/0019-winegstreamer-Implement-SetOutputType-for-decode-tra.patch index 344776f6..6d94efbe 100644 --- a/patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch +++ b/patches/mfplat-streaming-support/0019-winegstreamer-Implement-SetOutputType-for-decode-tra.patch @@ -1,7 +1,7 @@ -From b116bcc5c294697eb537255bb2ddffa1e7dad5c0 Mon Sep 17 00:00:00 2001 +From 760c4df96ca2e4deb5c7c7e26fb81713a9393e5e Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 11 Mar 2021 12:58:32 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetOutputType for decode +Subject: [PATCH 19/88] winegstreamer: Implement ::SetOutputType for decode transform. Signed-off-by: Derek Lesho @@ -112,5 +112,5 @@ index f709ef32fc1..0848cb47c9d 100644 static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0020-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch similarity index 95% rename from patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch rename to patches/mfplat-streaming-support/0020-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch index 7d621ff4..d60f6047 100644 --- a/patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch +++ b/patches/mfplat-streaming-support/0020-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -1,8 +1,8 @@ -From 359da83b2d725c927797bedc15095312453607ad Mon Sep 17 00:00:00 2001 +From 372d42fdb36cef1e845eb8ac9d461d5f03974605 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 11 Mar 2021 14:40:32 -0500 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - decode transform. +Subject: [PATCH 20/88] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for decode transform. Signed-off-by: Derek Lesho --- @@ -102,5 +102,5 @@ index 0848cb47c9d..dadd161bcc9 100644 InitializeCriticalSection(&object->cs); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch b/patches/mfplat-streaming-support/0021-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch similarity index 77% rename from patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch rename to patches/mfplat-streaming-support/0021-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch index 49ab42f7..4811a1cf 100644 --- a/patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch +++ b/patches/mfplat-streaming-support/0021-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch @@ -1,7 +1,7 @@ -From ea3b78cc1f9d9a8e52441878f3bb62bf5df845a1 Mon Sep 17 00:00:00 2001 +From 95e4c7c7d5de17f6635f7028b364cacbdadb2e58 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 16:55:15 -0400 -Subject: [PATCH] winegstreamer: Semi-stub ::GetAttributes for decoder +Subject: [PATCH 21/88] winegstreamer: Semi-stub ::GetAttributes for decoder transform. Signed-off-by: Derek Lesho @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 04a07647de4..f0e8527631c 100644 +index dadd161bcc9..fb282d850ff 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c -@@ -257,9 +257,9 @@ static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD +@@ -216,9 +216,9 @@ static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { @@ -26,5 +26,5 @@ index 04a07647de4..f0e8527631c 100644 static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch b/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-H.264-decoder-transform.patch similarity index 73% rename from patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch rename to patches/mfplat-streaming-support/0022-winegstreamer-Register-the-H.264-decoder-transform.patch index 57f0e1a5..fc1efb2c 100644 --- a/patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch +++ b/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-H.264-decoder-transform.patch @@ -1,7 +1,7 @@ -From cf4b63609020ce6009d01264b689ed18925a19df Mon Sep 17 00:00:00 2001 +From 8f392bb6b5de063a22fbb9ceb6e77a8f49bd7745 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 16:57:11 -0400 -Subject: [PATCH] winegstreamer: Register the H.264 decoder transform. +Subject: [PATCH 22/88] winegstreamer: Register the H.264 decoder transform. Signed-off-by: Derek Lesho --- @@ -9,10 +9,10 @@ Signed-off-by: Derek Lesho 1 file changed, 25 insertions(+) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 9d1cbd87746..35b2f2c3224 100644 +index 4fe11b7b6b8..a4494822500 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -453,6 +453,20 @@ static const GUID *audio_converter_supported_types[] = +@@ -463,6 +463,20 @@ static const GUID *const wma_decoder_output_types[] = &MFAudioFormat_Float, }; @@ -33,12 +33,12 @@ index 9d1cbd87746..35b2f2c3224 100644 static const struct mft { const GUID *clsid; -@@ -478,6 +492,17 @@ mfts[] = - ARRAY_SIZE(audio_converter_supported_types), - audio_converter_supported_types, +@@ -499,6 +513,17 @@ mfts[] = + ARRAY_SIZE(wma_decoder_output_types), + wma_decoder_output_types, }, + { -+ &CLSID_CMSH264DecoderMFT, ++ &CLSID_MSH264DecoderMFT, + &MFT_CATEGORY_VIDEO_DECODER, + h264_decoderW, + MFT_ENUM_FLAG_SYNCMFT, @@ -52,5 +52,5 @@ index 9d1cbd87746..35b2f2c3224 100644 HRESULT mfplat_DllRegisterServer(void) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch b/patches/mfplat-streaming-support/0023-winegstreamer-Introduce-AAC-decoder-transform.patch similarity index 56% rename from patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch rename to patches/mfplat-streaming-support/0023-winegstreamer-Introduce-AAC-decoder-transform.patch index 12639c87..97d221a5 100644 --- a/patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch +++ b/patches/mfplat-streaming-support/0023-winegstreamer-Introduce-AAC-decoder-transform.patch @@ -1,21 +1,20 @@ -From 126e32c17f934f80dac678d20ecb6e297b354b73 Mon Sep 17 00:00:00 2001 +From 8234bc8886ba39e341ff4c771ac41f5529d67088 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 16:59:29 -0400 -Subject: [PATCH] winegstreamer: Introduce AAC decoder transform. +Subject: [PATCH 23/88] winegstreamer: Introduce AAC decoder transform. Signed-off-by: Derek Lesho --- dlls/winegstreamer/decode_transform.c | 10 ++++ - dlls/winegstreamer/gst_private.h | 17 ++++++ - dlls/winegstreamer/mfplat.c | 63 +++++++++++++++++++- - dlls/winegstreamer/quartz_parser.c | 1 + - dlls/winegstreamer/wg_parser.c | 62 +++++++++++++++++++ + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/mfplat.c | 58 +++++++++++++++++++- + dlls/winegstreamer/quartz_parser.c | 2 + + dlls/winegstreamer/unixlib.h | 16 ++++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 ++ - include/mfidl.idl | 1 + - 7 files changed, 159 insertions(+), 1 deletion(-) + 6 files changed, 92 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index f0e8527631c..bb9bd6d6327 100644 +index fb282d850ff..4967fc49012 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -33,6 +33,9 @@ const GUID *h264_input_types[] = {&MFVideoFormat_H264}; @@ -41,40 +40,12 @@ index f0e8527631c..bb9bd6d6327 100644 + } }; - struct pipeline_event + struct mf_decoder diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 25694aae84d..6407aff484c 100644 +index b9379487ac2..73d5e88b164 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h -@@ -127,11 +127,27 @@ struct wg_format - WG_AUDIO_FORMAT_MPEG1_LAYER1, - WG_AUDIO_FORMAT_MPEG1_LAYER2, - WG_AUDIO_FORMAT_MPEG1_LAYER3, -+ -+ WG_AUDIO_FORMAT_AAC, - } format; - - uint32_t channels; - uint32_t channel_mask; /* In WinMM format. */ - uint32_t rate; -+ -+ union -+ { -+ struct -+ { -+ uint32_t payload_type; -+ uint32_t indication; -+ /* The definition of this structure is found in ISO/IEC 14496-3, -+ which we don't have access to, so we'll just keep -+ the size set to the largest instance we've seen used. */ -+ unsigned char audio_specifc_config[2]; -+ uint32_t asp_size; -+ } aac; -+ } compressed; - } audio; - } u; - }; -@@ -256,6 +272,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; +@@ -122,6 +122,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret); enum decoder_type { DECODER_TYPE_H264, @@ -83,30 +54,18 @@ index 25694aae84d..6407aff484c 100644 HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 35b2f2c3224..9c95450bd99 100644 +index a4494822500..e22cd51c8a9 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -407,6 +407,11 @@ static HRESULT h264_decoder_create(REFIID riid, void **ret) - return decode_transform_create(riid, ret, DECODER_TYPE_H264); - } - -+static HRESULT aac_decoder_create(REFIID riid, void **ret) -+{ -+ return decode_transform_create(riid, ret, DECODER_TYPE_AAC); -+} -+ - static const struct class_object - { - const GUID *clsid; -@@ -418,6 +423,7 @@ class_objects[] = +@@ -414,6 +414,7 @@ class_objects[] = { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, - { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, -+ { &CLSID_CMSAACDecMFT, &aac_decoder_create }, + { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, ++ { &CLSID_MSAACDecMFT, &aac_decoder_create }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -@@ -599,7 +605,8 @@ static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format * +@@ -620,7 +621,8 @@ static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format * IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, audio_formats[i].depth); IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, format->u.audio.rate); IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, format->u.audio.channels); @@ -114,9 +73,9 @@ index 35b2f2c3224..9c95450bd99 100644 + if (format->u.audio.channel_mask) + IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask); IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, format->u.audio.channels * audio_formats[i].depth / 8); - return type; -@@ -688,6 +695,8 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma +@@ -710,6 +712,8 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma channel_mask = KSAUDIO_SPEAKER_MONO; else if (channels == 2) channel_mask = KSAUDIO_SPEAKER_STEREO; @@ -125,7 +84,7 @@ index 35b2f2c3224..9c95450bd99 100644 else { FIXME("Channel mask is not set.\n"); -@@ -700,6 +709,58 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma +@@ -722,6 +726,58 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma format->u.audio.channel_mask = channel_mask; format->u.audio.rate = rate; @@ -185,7 +144,7 @@ index 35b2f2c3224..9c95450bd99 100644 { if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index 4b0f2c215d1..c192f4ec38b 100644 +index 0328b5ed4f5..8ea9291904e 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -100,6 +100,7 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format * @@ -196,91 +155,51 @@ index 4b0f2c215d1..c192f4ec38b 100644 return false; case WG_AUDIO_FORMAT_MPEG1_LAYER1: -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index d010b1e6eed..e017be29ad1 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -401,6 +401,13 @@ static void wg_set_caps_from_wg_format(GstCaps *caps, const struct wg_format *fo - gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); - break; - } -+ case WG_MAJOR_TYPE_AUDIO: -+ { -+ 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); -+ if (format->u.audio.channel_mask) -+ gst_caps_set_simple(caps, "channel-mask", G_TYPE_INT, format->u.audio.channel_mask, NULL); -+ } - default: - break; - } -@@ -412,6 +419,61 @@ static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) - GstAudioFormat audio_format; - GstAudioInfo info; +@@ -313,6 +314,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) + case WG_AUDIO_FORMAT_MPEG1_LAYER3: + return 40000; -+ /* compressed types */ ++ case WG_AUDIO_FORMAT_AAC: + case WG_AUDIO_FORMAT_UNKNOWN: + FIXME("Cannot guess maximum sample size for unknown audio format.\n"); + return 0; +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index f3db631d16d..d9c675ea873 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -92,11 +92,27 @@ struct wg_format + WG_AUDIO_FORMAT_MPEG1_LAYER1, + WG_AUDIO_FORMAT_MPEG1_LAYER2, + WG_AUDIO_FORMAT_MPEG1_LAYER3, + -+ if (format->u.audio.format == WG_AUDIO_FORMAT_AAC) -+ { -+ const char *profile, *level; -+ GstBuffer *audio_specific_config; -+ GstCaps *caps = gst_caps_new_empty_simple("audio/mpeg"); -+ wg_set_caps_from_wg_format(caps, format); -+ -+ gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); -+ -+ switch (format->u.audio.compressed.aac.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; -+ 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; -+ default: -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); -+ }; -+ -+ switch (format->u.audio.compressed.aac.indication) -+ { -+ case 0x29: profile = "lc"; level = "2"; break; -+ case 0x2A: profile = "lc"; level = "4"; break; -+ case 0x2B: profile = "lc"; level = "5"; break; -+ default: -+ GST_DEBUG("Unrecognized profile-level-indication %u\n", format->u.audio.compressed.aac.indication); -+ /* fallthrough */ -+ case 0x00: case 0xFE: profile = level = NULL; break; /* unspecified */ -+ } -+ -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ audio_specific_config = gst_buffer_new_allocate(NULL, format->u.audio.compressed.aac.asp_size, NULL); -+ gst_buffer_fill(audio_specific_config, 0, format->u.audio.compressed.aac.audio_specifc_config, format->u.audio.compressed.aac.asp_size); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, audio_specific_config, NULL); -+ gst_buffer_unref(audio_specific_config); -+ -+ return caps; -+ } -+ -+ /* uncompressed_types */ -+ - if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) - return NULL; ++ WG_AUDIO_FORMAT_AAC, + } format; + uint32_t channels; + uint32_t channel_mask; /* In WinMM format. */ + uint32_t rate; ++ ++ union ++ { ++ struct ++ { ++ uint32_t payload_type; ++ uint32_t indication; ++ /* The definition of this structure is found in ISO/IEC 14496-3, ++ which we don't have access to, so we'll just keep ++ the size set to the largest instance we've seen used. */ ++ unsigned char audio_specifc_config[2]; ++ uint32_t asp_size; ++ } aac; ++ } compressed; + } audio; + } u; + }; diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 064a6872c79..4c58d83403b 100644 +index 022f5f80980..630522f30b1 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -73,3 +73,9 @@ coclass WINEAudioConverter { } +@@ -79,3 +79,9 @@ coclass CWMADecMediaObject {}; uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) ] coclass CMSH264DecoderMFT { } @@ -290,15 +209,6 @@ index 064a6872c79..4c58d83403b 100644 + uuid(32d186a7-218f-4c75-8876-dd77273a8999) +] +coclass CMSAACDecMFT { } -diff --git a/include/mfidl.idl b/include/mfidl.idl -index f28a0669804..72d288daa3f 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1580,3 +1580,4 @@ cpp_quote("EXTERN_GUID(MF_XVP_SAMPLE_LOCK_TIMEOUT, 0xaa4ddb29, 0x5134, 0x4363, 0 - - cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") - cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") -+cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch b/patches/mfplat-streaming-support/0024-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch similarity index 74% rename from patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch rename to patches/mfplat-streaming-support/0024-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch index 88e43ec5..d1aaf2c1 100644 --- a/patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch +++ b/patches/mfplat-streaming-support/0024-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch @@ -1,7 +1,8 @@ -From c9062f7721878e9687969cc0908afb442955a367 Mon Sep 17 00:00:00 2001 +From 2b8e7b14bfb8ad19d767bb378b24869f574f04f5 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 17:00:51 -0400 -Subject: [PATCH] winegstreamer: Rename GStreamer objects to be more generic. +Subject: [PATCH 24/88] winegstreamer: Rename GStreamer objects to be more + generic. Signed-off-by: Derek Lesho --- @@ -9,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index e017be29ad1..528e30098fb 100644 +index c2141fae2af..1d34437318e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -1255,7 +1255,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) +@@ -1196,7 +1196,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) pthread_cond_init(&stream->event_cond, NULL); pthread_cond_init(&stream->event_empty_cond, NULL); @@ -21,16 +22,16 @@ index e017be29ad1..528e30098fb 100644 stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK); gst_pad_set_element_private(stream->my_sink, stream); gst_pad_set_chain_function(stream->my_sink, sink_chain_cb); -@@ -1921,7 +1921,7 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) +@@ -1753,7 +1753,7 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + static NTSTATUS wg_parser_connect(void *args) { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); - - parser->sink_connected = true; -@@ -1935,7 +1935,7 @@ static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + const struct wg_parser_connect_params *params = args; + struct wg_parser *parser = params->parser; +@@ -1772,7 +1772,7 @@ static NTSTATUS wg_parser_connect(void *args) parser->container = gst_bin_new(NULL); gst_element_set_bus(parser->container, parser->bus); @@ -40,5 +41,5 @@ index e017be29ad1..528e30098fb 100644 gst_pad_set_query_function(parser->my_src, src_query_cb); gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch b/patches/mfplat-streaming-support/0025-winegstreamer-Report-streams-backwards-in-media-sour.patch similarity index 78% rename from patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch rename to patches/mfplat-streaming-support/0025-winegstreamer-Report-streams-backwards-in-media-sour.patch index c5199c4e..ed95c67d 100644 --- a/patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch +++ b/patches/mfplat-streaming-support/0025-winegstreamer-Report-streams-backwards-in-media-sour.patch @@ -1,7 +1,8 @@ -From c2c1f1422c2583bb04fc3ab2a47ebb5cc92f4163 Mon Sep 17 00:00:00 2001 +From 9986fba2a9fd7f37a9d27a0257c8b20f59c56d8f Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 17:01:54 -0400 -Subject: [PATCH] winegstreamer: Report streams backwards in media source. +Subject: [PATCH 25/88] winegstreamer: Report streams backwards in media + source. Signed-off-by: Derek Lesho --- @@ -9,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 054e87edb7b..e991d3ec2a7 100644 +index bccbf888a4a..2ed31666cad 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c -@@ -1363,7 +1363,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ +@@ -1491,7 +1491,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); for (i = 0; i < object->stream_count; i++) { @@ -22,5 +23,5 @@ index 054e87edb7b..e991d3ec2a7 100644 if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0026-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch similarity index 81% rename from patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch rename to patches/mfplat-streaming-support/0026-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch index c1fec189..9cb30c2f 100644 --- a/patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch +++ b/patches/mfplat-streaming-support/0026-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -1,8 +1,8 @@ -From 9a7c5f23fb352d424e7fc83262f5c49e5521dc69 Mon Sep 17 00:00:00 2001 +From 5eef24de0657d410169e9d6a3f0c62e7e1ebded3 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 15:12:20 -0400 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - audio conversion transform. +Subject: [PATCH 26/88] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for audio conversion transform. Signed-off-by: Derek Lesho --- @@ -10,18 +10,18 @@ Signed-off-by: Derek Lesho 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 8405f3bedc5..4ad64d58e47 100644 +index d5723cdf58f..56aa96770b7 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c -@@ -123,16 +123,50 @@ static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD in +@@ -115,16 +115,50 @@ static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD in static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { -- FIXME("%p %u %p.\n", iface, id, info); +- FIXME("%p, %lu, %p.\n", iface, id, info); + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - return E_NOTIMPL; -+ TRACE("%p %u %p.\n", iface, id, info); ++ TRACE("%p, %lu, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; @@ -44,11 +44,11 @@ index 8405f3bedc5..4ad64d58e47 100644 static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { -- FIXME("%p %u %p.\n", iface, id, info); +- FIXME("%p. %lu, %p.\n", iface, id, info); + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - return E_NOTIMPL; -+ TRACE("%p %u %p.\n", iface, id, info); ++ TRACE("%p. %lu, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; @@ -69,5 +69,5 @@ index 8405f3bedc5..4ad64d58e47 100644 static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch b/patches/mfplat-streaming-support/0027-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch similarity index 71% rename from patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch rename to patches/mfplat-streaming-support/0027-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch index 2086a0b2..04626c92 100644 --- a/patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch +++ b/patches/mfplat-streaming-support/0027-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch @@ -1,8 +1,8 @@ -From 39cabd61d7f01a53ae22eb33103ea549b8687259 Mon Sep 17 00:00:00 2001 +From baf0a7e95e8601833e46769c16745d742431b1a4 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 15:19:32 -0400 -Subject: [PATCH] winegstreamer: Semi-stub Get*Attributes functions for audio - converter transform. +Subject: [PATCH 27/88] winegstreamer: Semi-stub Get*Attributes functions for + audio converter transform. Signed-off-by: Derek Lesho --- @@ -10,18 +10,18 @@ Signed-off-by: Derek Lesho 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 4ad64d58e47..43fe8b04e64 100644 +index 56aa96770b7..a4258c6aecd 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c -@@ -39,6 +39,7 @@ struct audio_converter - LONGLONG buffer_pts, buffer_dur; - struct wg_parser *parser; - struct wg_parser_stream *stream; +@@ -35,6 +35,7 @@ struct audio_converter + IMFMediaType *input_type; + IMFMediaType *output_type; + CRITICAL_SECTION cs; + IMFAttributes *attributes, *output_attributes; }; static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) -@@ -84,6 +85,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) +@@ -80,6 +81,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) { transform->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&transform->cs); @@ -29,10 +29,10 @@ index 4ad64d58e47..43fe8b04e64 100644 + IMFAttributes_Release(transform->attributes); + if (transform->output_attributes) + IMFAttributes_Release(transform->output_attributes); - if (transform->stream) - unix_funcs->wg_parser_disconnect(transform->parser); - if (transform->parser) -@@ -171,9 +176,14 @@ static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, D + free(transform); + } + +@@ -163,9 +168,14 @@ static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, D static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { @@ -49,15 +49,15 @@ index 4ad64d58e47..43fe8b04e64 100644 } static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -@@ -187,9 +197,17 @@ static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *ifa +@@ -179,9 +189,17 @@ static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *ifa static HRESULT WINAPI audio_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { -- FIXME("%p, %u, %p.\n", iface, id, attributes); +- FIXME("%p, %lu, %p.\n", iface, id, attributes); + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - return E_NOTIMPL; -+ TRACE("%p, %u, %p.\n", iface, id, attributes); ++ TRACE("%p, %lu, %p.\n", iface, id, attributes); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; @@ -69,7 +69,7 @@ index 4ad64d58e47..43fe8b04e64 100644 } static HRESULT WINAPI audio_converter_DeleteInputStream(IMFTransform *iface, DWORD id) -@@ -860,6 +878,7 @@ static const IMFTransformVtbl audio_converter_vtbl = +@@ -601,6 +619,7 @@ static const IMFTransformVtbl audio_converter_vtbl = HRESULT audio_converter_create(REFIID riid, void **ret) { struct audio_converter *object; @@ -77,7 +77,7 @@ index 4ad64d58e47..43fe8b04e64 100644 TRACE("%s %p\n", debugstr_guid(riid), ret); -@@ -872,6 +891,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) +@@ -613,6 +632,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); @@ -93,9 +93,9 @@ index 4ad64d58e47..43fe8b04e64 100644 + return hr; + } + - if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) - { - ERR("Failed to create audio converter due to GStreamer error.\n"); + *ret = &object->IMFTransform_iface; + return S_OK; + } -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch b/patches/mfplat-streaming-support/0028-winegstreamer-Introduce-color-conversion-transform.patch similarity index 90% rename from patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch rename to patches/mfplat-streaming-support/0028-winegstreamer-Introduce-color-conversion-transform.patch index d32e679a..d6a1471c 100644 --- a/patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch +++ b/patches/mfplat-streaming-support/0028-winegstreamer-Introduce-color-conversion-transform.patch @@ -1,7 +1,7 @@ -From 921e29cce50dd75b14e334ea21238d5312af8659 Mon Sep 17 00:00:00 2001 +From aec53333c8c27975efa46d99d8e87cd91d93ec33 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 15:35:20 -0400 -Subject: [PATCH] winegstreamer: Introduce color conversion transform. +Subject: [PATCH 28/88] winegstreamer: Introduce color conversion transform. Serves as a wrapper of videoconvert, and exposes the CColorConverterDMO MFT interface. @@ -10,17 +10,17 @@ Signed-off-by: Derek Lesho dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/colorconvert.c | 298 +++++++++++++++++++ dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 2 + + dlls/winegstreamer/mfplat.c | 1 + dlls/winegstreamer/winegstreamer_classes.idl | 6 + include/wmcodecdsp.idl | 5 + - 6 files changed, 313 insertions(+) + 6 files changed, 312 insertions(+) create mode 100644 dlls/winegstreamer/colorconvert.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 7459cccf7e4..ec688f4425b 100644 +index 3da8c614ed2..74bcc35364b 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in -@@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin +@@ -8,6 +8,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) C_SRCS = \ audioconvert.c \ @@ -333,42 +333,34 @@ index 00000000000..1f0d061a30c + return S_OK; +} diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index ee6d19e74b6..0827f70112f 100644 +index 73d5e88b164..d3271518f8f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h -@@ -269,6 +269,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DE - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; +@@ -118,6 +118,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format); + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; -+HRESULT color_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + HRESULT audio_converter_create(REFIID riid, void **ret); ++HRESULT color_converter_create(REFIID riid, void **ret); enum decoder_type { diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 955afff20dc..3fc18be69d5 100644 +index e22cd51c8a9..6f6ec956b2b 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -22,6 +22,7 @@ - #include "mfapi.h" - #include "ks.h" - #include "ksmedia.h" -+#include "wmcodecdsp.h" - - #include "wine/debug.h" - -@@ -422,6 +423,7 @@ class_objects[] = +@@ -413,6 +413,7 @@ class_objects[] = { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, + { &CLSID_CColorConvertDMO, &color_converter_create }, - { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_CMSAACDecMFT, &aac_decoder_create }, + { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, + { &CLSID_MSAACDecMFT, &aac_decoder_create }, }; diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 4c58d83403b..093fca3521e 100644 +index 630522f30b1..5762430a5cd 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -79,3 +79,9 @@ coclass CMSH264DecoderMFT { } +@@ -85,3 +85,9 @@ coclass CMSH264DecoderMFT { } uuid(32d186a7-218f-4c75-8876-dd77273a8999) ] coclass CMSAACDecMFT { } @@ -379,18 +371,18 @@ index 4c58d83403b..093fca3521e 100644 +] +coclass CColorConvertDMO { } diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl -index 61381bee6d4..87305422332 100644 +index ae2a42419b4..711179fe1d2 100644 --- a/include/wmcodecdsp.idl +++ b/include/wmcodecdsp.idl -@@ -30,3 +30,8 @@ coclass CMP3DecMediaObject {} - uuid(f447b69e-1884-4a7e-8055-346f74d6edb3) +@@ -49,3 +49,8 @@ coclass CWMADecMediaObject {}; + uuid(93af0c51-2275-45d2-a35b-f2ba21caed00) ] - coclass CResamplerMediaObject {} + coclass AACMFTEncoder {}; + +[ + uuid(98230571-0087-4204-b020-3282538e57d3) +] +coclass CColorConvertDMO {} -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch b/patches/mfplat-streaming-support/0029-winegstreamer-Register-the-color-conversion-transfor.patch similarity index 68% rename from patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch rename to patches/mfplat-streaming-support/0029-winegstreamer-Register-the-color-conversion-transfor.patch index 57777e86..a1902c0d 100644 --- a/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch +++ b/patches/mfplat-streaming-support/0029-winegstreamer-Register-the-color-conversion-transfor.patch @@ -1,18 +1,18 @@ -From 3efa160ba459f7763a8df6e8f67621e34dcb1697 Mon Sep 17 00:00:00 2001 +From 7e5a1d66b93df6e2dd29a753190bbe9c0c31993e Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 15:37:17 -0400 -Subject: [PATCH] winegstreamer: Register the color conversion transform. +Subject: [PATCH 29/88] winegstreamer: Register the color conversion transform. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/mfplat.c | 33 ++++++++++++++++++++++++++++++++- - 1 file changed, 32 insertions(+), 1 deletion(-) + dlls/winegstreamer/mfplat.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 3fc18be69d5..eb57c1e3459 100644 +index 6f6ec956b2b..54874ad43ee 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -461,6 +461,26 @@ static const GUID *audio_converter_supported_types[] = +@@ -465,6 +465,26 @@ static const GUID *const wma_decoder_output_types[] = &MFAudioFormat_Float, }; @@ -39,11 +39,11 @@ index 3fc18be69d5..eb57c1e3459 100644 static WCHAR h264_decoderW[] = L"H.264 Decoder"; static const GUID *h264_decoder_input_types[] = { -@@ -511,6 +531,17 @@ mfts[] = - ARRAY_SIZE(audio_converter_supported_types), - audio_converter_supported_types, +@@ -516,7 +536,18 @@ mfts[] = + wma_decoder_output_types, }, -+ { + { +- &CLSID_MSH264DecoderMFT, + &CLSID_CColorConvertDMO, + &MFT_CATEGORY_VIDEO_EFFECT, + color_converterW, @@ -54,18 +54,20 @@ index 3fc18be69d5..eb57c1e3459 100644 + ARRAY_SIZE(color_converter_supported_types), + color_converter_supported_types, + }, - { - &CLSID_CMSH264DecoderMFT, ++ { ++ &CLSID_MSAACDecMFT, &MFT_CATEGORY_VIDEO_DECODER, -@@ -539,7 +570,7 @@ HRESULT mfplat_DllRegisterServer(void) + h264_decoderW, + MFT_ENUM_FLAG_SYNCMFT, +@@ -532,7 +563,7 @@ HRESULT mfplat_DllRegisterServer(void) { unsigned int i, j; HRESULT hr; -- MFT_REGISTER_TYPE_INFO input_types[2], output_types[2]; +- MFT_REGISTER_TYPE_INFO input_types[4], output_types[2]; + MFT_REGISTER_TYPE_INFO input_types[15], output_types[15]; for (i = 0; i < ARRAY_SIZE(mfts); i++) { -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch b/patches/mfplat-streaming-support/0030-winegstreamer-Implement-GetInputAvailableType-for-co.patch similarity index 92% rename from patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch rename to patches/mfplat-streaming-support/0030-winegstreamer-Implement-GetInputAvailableType-for-co.patch index 2fff72a8..ac390fe7 100644 --- a/patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch +++ b/patches/mfplat-streaming-support/0030-winegstreamer-Implement-GetInputAvailableType-for-co.patch @@ -1,8 +1,8 @@ -From 58e51b924b35d5130410fe0424eaf2143bfaf7fe Mon Sep 17 00:00:00 2001 +From e0a8b0048e9507ad457cb6b3b9a535331528dd71 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 15:41:33 -0400 -Subject: [PATCH] winegstreamer: Implement ::GetInputAvailableType for color - conversion transform. +Subject: [PATCH 30/88] winegstreamer: Implement ::GetInputAvailableType for + color conversion transform. Signed-off-by: Derek Lesho --- @@ -77,5 +77,5 @@ index 1f0d061a30c..078782daaed 100644 static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch b/patches/mfplat-streaming-support/0031-winegstreamer-Implement-SetInputType-for-color-conve.patch similarity index 95% rename from patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch rename to patches/mfplat-streaming-support/0031-winegstreamer-Implement-SetInputType-for-color-conve.patch index d1a75464..5057765c 100644 --- a/patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch +++ b/patches/mfplat-streaming-support/0031-winegstreamer-Implement-SetInputType-for-color-conve.patch @@ -1,8 +1,8 @@ -From d2f19c1167d5c81366734fe8434871402cb0c766 Mon Sep 17 00:00:00 2001 +From c396ea3ccf731d454fddb3a3f7c8e04dc0e5be8b Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 16:01:18 -0400 -Subject: [PATCH] winegstreamer: Implement ::SetInputType for color conversion - transform. +Subject: [PATCH 31/88] winegstreamer: Implement ::SetInputType for color + conversion transform. Signed-off-by: Derek Lesho --- @@ -118,5 +118,5 @@ index 078782daaed..06186ed7846 100644 return S_OK; } -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch b/patches/mfplat-streaming-support/0032-winegstreamer-Implement-GetOutputAvailableType-for-c.patch similarity index 91% rename from patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch rename to patches/mfplat-streaming-support/0032-winegstreamer-Implement-GetOutputAvailableType-for-c.patch index b3ed0d64..f5d17577 100644 --- a/patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch +++ b/patches/mfplat-streaming-support/0032-winegstreamer-Implement-GetOutputAvailableType-for-c.patch @@ -1,8 +1,8 @@ -From 152cabdaa23d053e4e0893fb0add8de728482b6d Mon Sep 17 00:00:00 2001 +From c5ccac06781882e1debd710e2f0c3e1aaf46565a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 16:04:31 -0400 -Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for color - conversion transform. +Subject: [PATCH 32/88] winegstreamer: Implement ::GetOutputAvailableType for + color conversion transform. Signed-off-by: Derek Lesho --- @@ -60,5 +60,5 @@ index 06186ed7846..6d7064a4482 100644 static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch b/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch deleted file mode 100644 index e21b793b..00000000 --- a/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 1ac609517c8822051e435eaa4452eeb60730602a Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 15:25:17 -0400 -Subject: [PATCH] winegstreamer: Implement MF_SD_LANGUAGE. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/media_source.c | 20 +++++++++++++++++++- - dlls/winegstreamer/wg_parser.c | 27 +++++++++++++++++++++++++++ - 3 files changed, 47 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 0827f70112f..f616b8a5d9d 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -240,6 +240,7 @@ struct unix_funcs - - /* Returns the duration in 100-nanosecond units. */ - uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); -+ char * (CDECL *wg_parser_stream_get_language)(struct wg_parser_stream *stream); - /* start_pos and stop_pos are in 100-nanosecond units. */ - bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index f9e3ab7506a..e8266a442e0 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1364,7 +1364,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); - for (i = 0; i < object->stream_count; i++) - { -- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); -+ IMFStreamDescriptor **descriptor = &descriptors[object->stream_count - 1 - i]; -+ DWORD language_len; -+ WCHAR *languageW; -+ char *language; -+ -+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); -+ -+ if ((language = unix_funcs->wg_parser_stream_get_language(object->streams[i]->wg_stream))) -+ { -+ if ((language_len = MultiByteToWideChar(CP_UTF8, 0, language, -1, NULL, 0))) -+ { -+ languageW = malloc(language_len * sizeof(WCHAR)); -+ if (MultiByteToWideChar(CP_UTF8, 0, language, -1, languageW, language_len)) -+ { -+ IMFStreamDescriptor_SetString(*descriptor, &MF_SD_LANGUAGE, languageW); -+ } -+ free(languageW); -+ } -+ } - } - - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 23a170f6f74..93bf85f719e 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -96,6 +96,7 @@ struct wg_parser_stream - bool flushing, eos, enabled, has_caps; - - uint64_t duration; -+ gchar *language_code; - }; - - static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) -@@ -851,6 +852,11 @@ static uint64_t CDECL wg_parser_stream_get_duration(struct wg_parser_stream *str - return stream->duration; - } - -+static char * CDECL wg_parser_stream_get_language(struct wg_parser_stream *stream) -+{ -+ return stream->language_code; -+} -+ - static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) - { -@@ -1919,6 +1925,22 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - return ret; - } - -+static gchar *query_language(GstPad *pad) -+{ -+ GstTagList *tag_list; -+ GstEvent *tag_event; -+ gchar *ret = NULL; -+ -+ if ((tag_event = gst_pad_get_sticky_event(pad, GST_EVENT_TAG, 0))) -+ { -+ gst_event_parse_tag(tag_event, &tag_list); -+ gst_tag_list_get_string(tag_list, "language-code", &ret); -+ gst_event_unref(tag_event); -+ } -+ -+ return ret; -+} -+ - static HRESULT wg_parser_connect_inner(struct wg_parser *parser) - { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", -@@ -1969,6 +1991,7 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s - struct wg_parser_stream *stream = parser->streams[i]; - gint64 duration; - -+ stream->language_code = query_language(stream->their_src); - while (!stream->has_caps && !parser->error) - pthread_cond_wait(&parser->init_cond, &parser->mutex); - -@@ -2098,6 +2121,9 @@ static void free_stream(struct wg_parser_stream *stream) - pthread_cond_destroy(&stream->event_cond); - pthread_cond_destroy(&stream->event_empty_cond); - -+ if (stream->language_code) -+ g_free(stream->language_code); -+ - free(stream); - } - -@@ -2522,6 +2548,7 @@ static const struct unix_funcs funcs = - wg_parser_stream_notify_qos, - - wg_parser_stream_get_duration, -+ wg_parser_stream_get_language, - wg_parser_stream_seek, - wg_parser_stream_drain, - }; --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch b/patches/mfplat-streaming-support/0033-winegstreamer-Implement-SetOutputType-for-color-conv.patch similarity index 96% rename from patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch rename to patches/mfplat-streaming-support/0033-winegstreamer-Implement-SetOutputType-for-color-conv.patch index f4bf654a..349d9e6b 100644 --- a/patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch +++ b/patches/mfplat-streaming-support/0033-winegstreamer-Implement-SetOutputType-for-color-conv.patch @@ -1,8 +1,8 @@ -From 3e4845c62cd142d15115caa119c5e34ed58d247a Mon Sep 17 00:00:00 2001 +From 75d114aad6addbf24d1ecc22ca223aae02586b9c Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 16:26:28 -0400 -Subject: [PATCH] winegstreamer: Implement ::SetOutputType for color conversion - transform. +Subject: [PATCH 33/88] winegstreamer: Implement ::SetOutputType for color + conversion transform. Signed-off-by: Derek Lesho --- @@ -149,5 +149,5 @@ index 6d7064a4482..e001c6c827e 100644 static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch b/patches/mfplat-streaming-support/0034-winegstreamer-Implement-ProcessMessage-for-color-con.patch similarity index 81% rename from patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch rename to patches/mfplat-streaming-support/0034-winegstreamer-Implement-ProcessMessage-for-color-con.patch index 138b05c5..ea7b26d8 100644 --- a/patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch +++ b/patches/mfplat-streaming-support/0034-winegstreamer-Implement-ProcessMessage-for-color-con.patch @@ -1,7 +1,7 @@ -From 8f8220184eccd249c8a0760def9ad39b08d1b4c6 Mon Sep 17 00:00:00 2001 +From 112153e5fd44f225c80b6abbec0bffa36da0bbf3 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 16:50:47 -0400 -Subject: [PATCH] winegstreamer: Implement ::ProcessMessage for color +Subject: [PATCH 34/88] winegstreamer: Implement ::ProcessMessage for color conversion MFT. Signed-off-by: Derek Lesho @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index a543b9d77af..8d2f7a7d643 100644 +index e001c6c827e..0e8980659a5 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -530,9 +530,17 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id +@@ -472,9 +472,17 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { @@ -34,5 +34,5 @@ index a543b9d77af..8d2f7a7d643 100644 static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0035-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch b/patches/mfplat-streaming-support/0035-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch deleted file mode 100644 index 07f4c4fc..00000000 --- a/patches/mfplat-streaming-support/0035-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2247c1fbc8e07a837bda763aa4e6317cb898cfd8 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 22 Mar 2021 15:50:29 -0400 -Subject: [PATCH] winegstreamer: Don't rely on max_size in unseekable parser. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/wg_parser.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 691abe8c48d..b3113718208 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1670,9 +1670,9 @@ static void *push_data(void *arg) - ULONG size; - int ret; - -- if (parser->next_offset >= max_size) -+ if (parser->seekable && parser->next_offset >= max_size) - break; -- size = min(alloc_size, max_size - parser->next_offset); -+ size = parser->seekable ? min(alloc_size, max_size - parser->next_offset) : alloc_size; - - ret = pull_data(parser, parser->next_offset, size, &size, &buffer); - --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0035-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch similarity index 91% rename from patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch rename to patches/mfplat-streaming-support/0035-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch index 3b2f4e18..9d056a3d 100644 --- a/patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch +++ b/patches/mfplat-streaming-support/0035-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -1,8 +1,8 @@ -From b7ad7106bc49fbad2cbf611afda09cedf428d735 Mon Sep 17 00:00:00 2001 +From 6a2f654147260fa022d1f045506dd4ed5c6ec1e4 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 17 Mar 2021 17:01:11 -0400 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - color conversion transform. +Subject: [PATCH 35/88] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for color conversion transform. Signed-off-by: Derek Lesho --- @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 8d2f7a7d643..6f3723b2b1e 100644 +index 0e8980659a5..db4ca4e3fbe 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -141,16 +141,72 @@ static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD in +@@ -133,16 +133,72 @@ static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD in static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { @@ -91,5 +91,5 @@ index 8d2f7a7d643..6f3723b2b1e 100644 static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch b/patches/mfplat-streaming-support/0036-mf-topology-Forward-failure-from-SetOutputType-when-.patch similarity index 81% rename from patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch rename to patches/mfplat-streaming-support/0036-mf-topology-Forward-failure-from-SetOutputType-when-.patch index 911b5b36..a102931f 100644 --- a/patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch +++ b/patches/mfplat-streaming-support/0036-mf-topology-Forward-failure-from-SetOutputType-when-.patch @@ -1,7 +1,7 @@ -From 00f584011dc50bff1cca0ec675091240a81f5547 Mon Sep 17 00:00:00 2001 +From b576c16ac5bbfc425a6255b091b6f7dc829f8cb4 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 18 Mar 2021 13:53:42 -0400 -Subject: [PATCH] mf/topology: Forward failure from ::SetOutputType when +Subject: [PATCH 36/88] mf/topology: Forward failure from ::SetOutputType when resolving topology. Signed-off-by: Derek Lesho @@ -10,7 +10,7 @@ Signed-off-by: Derek Lesho 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c -index f97c0cc75d3..34459912fb0 100644 +index ff90bc2c8af..6ea80862583 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2122,8 +2122,7 @@ static HRESULT connect_to_sink(struct transform_output_type *output_type, struct @@ -24,5 +24,5 @@ index f97c0cc75d3..34459912fb0 100644 static HRESULT connect_to_converter(struct transform_output_type *output_type, struct connect_context *context) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0037-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch b/patches/mfplat-streaming-support/0037-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch deleted file mode 100644 index 7e07a675..00000000 --- a/patches/mfplat-streaming-support/0037-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 04b35311e8a0242c13b9c885f3b077ff38e3130c Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 20 Jun 2021 14:46:57 +1000 -Subject: [PATCH] winegstreamer: Default Frame size if one isn't available - -Stop crash when loading steam ---- - dlls/winegstreamer/mfplat.c | 15 ++++++++------- - 1 file changed, 8 insertions(+), 7 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index eb57c1e3459..4aaa96fba95 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -838,18 +838,19 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma - FIXME("Subtype is not set.\n"); - return; - } -- if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) -- { -- FIXME("Frame size is not set.\n"); -- return; -- } - - format->major_type = WG_MAJOR_TYPE_VIDEO; -- format->u.video.width = (UINT32)(frame_size >> 32); -- format->u.video.height = (UINT32)frame_size; -+ 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)) && (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.fps_n = (UINT32)(frame_rate >> 32); --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch b/patches/mfplat-streaming-support/0037-winegstreamer-Handle-flush-command-in-audio-converst.patch similarity index 68% rename from patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch rename to patches/mfplat-streaming-support/0037-winegstreamer-Handle-flush-command-in-audio-converst.patch index f5a5b85b..c64a53bb 100644 --- a/patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch +++ b/patches/mfplat-streaming-support/0037-winegstreamer-Handle-flush-command-in-audio-converst.patch @@ -1,8 +1,8 @@ -From c6ef447acb3f45e08a07e0a47beeb2d2d963658f Mon Sep 17 00:00:00 2001 +From 7dad9c2c92351194857e9722a0dd72d280abac0f Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 18 Mar 2021 14:53:49 -0400 -Subject: [PATCH] winegstreamer: Handle flush command in audio converstion - transform. +Subject: [PATCH 37/88] winegstreamer: Handle flush command in audio + converstion transform. Signed-off-by: Derek Lesho --- @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 1 insertion(+) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 43fe8b04e64..1584fefe577 100644 +index a4258c6aecd..afa6bd682a6 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c -@@ -618,6 +618,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME +@@ -563,6 +563,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME switch(message) { @@ -22,5 +22,5 @@ index 43fe8b04e64..1584fefe577 100644 return S_OK; default: -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0038-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch b/patches/mfplat-streaming-support/0038-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch deleted file mode 100644 index c7122429..00000000 --- a/patches/mfplat-streaming-support/0038-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 06dbd32747a1451deb12d1bebc9cbf5a56dfdca5 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 16:54:44 -0400 -Subject: [PATCH] mfplat: Stub out MFCreateDXGIDeviceManager, to avoid the d3d - path. - ---- - dlls/mfplat/main.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c -index 7fd713261fc..9e458ea49bb 100644 ---- a/dlls/mfplat/main.c -+++ b/dlls/mfplat/main.c -@@ -8891,6 +8891,8 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man - - TRACE("%p, %p.\n", token, manager); - -+ return E_NOTIMPL; -+ - if (!token || !manager) - return E_POINTER; - --- -2.30.2 - diff --git a/patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch b/patches/mfplat-streaming-support/0038-winegstreamer-In-the-default-configuration-select-on.patch similarity index 83% rename from patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch rename to patches/mfplat-streaming-support/0038-winegstreamer-In-the-default-configuration-select-on.patch index b91e39d0..11ff0ba2 100644 --- a/patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch +++ b/patches/mfplat-streaming-support/0038-winegstreamer-In-the-default-configuration-select-on.patch @@ -1,7 +1,7 @@ -From f522876d3f350e23b7aa6e9a9ec8819d88031338 Mon Sep 17 00:00:00 2001 +From 856636245cd3de1bc91d76146e18fef864ec7065 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 4 Dec 2020 16:17:11 -0500 -Subject: [PATCH] winegstreamer: In the default configuration, select one +Subject: [PATCH 38/88] winegstreamer: In the default configuration, select one stream of each major type. --- @@ -9,18 +9,18 @@ Subject: [PATCH] winegstreamer: In the default configuration, select one 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index e991d3ec2a7..f9e3ab7506a 100644 +index 2ed31666cad..c97348cc2d6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c -@@ -1273,6 +1273,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = +@@ -1397,6 +1397,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) { + BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; + unsigned int stream_count = UINT_MAX; struct media_source *object; - UINT64 total_pres_time = 0; -@@ -1369,9 +1370,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ +@@ -1497,9 +1498,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) goto fail; @@ -51,5 +51,5 @@ index e991d3ec2a7..f9e3ab7506a 100644 } free(descriptors); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0039-winegstreamer-Implement-IMFTransform-GetOutputCurren.patch b/patches/mfplat-streaming-support/0039-winegstreamer-Implement-IMFTransform-GetOutputCurren.patch new file mode 100644 index 00000000..172aaca0 --- /dev/null +++ b/patches/mfplat-streaming-support/0039-winegstreamer-Implement-IMFTransform-GetOutputCurren.patch @@ -0,0 +1,54 @@ +From fc96686a97ff86e036a4324299392c66250a77fc Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 18 Oct 2021 12:29:34 -0500 +Subject: [PATCH 39/88] winegstreamer: Implement + IMFTransform::GetOutputCurrentType in colorconvert + +CW-Bug-Id: #19465 +--- + dlls/winegstreamer/colorconvert.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index db4ca4e3fbe..baf429d42f9 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -493,9 +493,33 @@ static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, D + + static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) + { +- FIXME("%p, %u, %p.\n", iface, id, type); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ IMFMediaType *ret; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p.\n", converter, id, type); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (FAILED(hr = MFCreateMediaType(&ret))) ++ return hr; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->output_type) ++ hr = IMFMediaType_CopyAllItems(converter->output_type, (IMFAttributes *)ret); ++ else ++ hr = MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ if (SUCCEEDED(hr)) ++ *type = ret; ++ else ++ IMFMediaType_Release(ret); ++ ++ return hr; + } + + static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0040-winegstreamer-Implement-stream-draining-support.patch b/patches/mfplat-streaming-support/0040-winegstreamer-Implement-stream-draining-support.patch new file mode 100644 index 00000000..966ffdb9 --- /dev/null +++ b/patches/mfplat-streaming-support/0040-winegstreamer-Implement-stream-draining-support.patch @@ -0,0 +1,178 @@ +From 5f724ac4f148607141e93868ba97edb4c0135cbd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 14 Dec 2021 22:31:29 +0100 +Subject: [PATCH 40/88] winegstreamer: Implement stream draining support. + +--- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/main.c | 5 +++ + dlls/winegstreamer/unixlib.h | 2 + + dlls/winegstreamer/wg_parser.c | 70 +++++++++++++++++++++++++++++++- + 4 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index d3271518f8f..6149ae5959c 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -95,6 +95,7 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); + /* start_pos and stop_pos are in 100-nanosecond units. */ + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); ++bool wg_parser_stream_drain(struct wg_parser_stream *stream); + + unsigned int wg_format_get_max_size(const struct wg_format *format); + +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 8f487655748..66b7a1195ee 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -254,6 +254,11 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); + } + ++bool wg_parser_stream_drain(struct wg_parser_stream *stream) ++{ ++ return !__wine_unix_call(unix_handle, unix_wg_parser_stream_drain, stream); ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + if (reason == DLL_PROCESS_ATTACH) +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index d9c675ea873..fc9d0c3c80d 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -271,6 +271,8 @@ enum unix_funcs + + unix_wg_parser_stream_get_duration, + unix_wg_parser_stream_seek, ++ ++ unix_wg_parser_stream_drain, + }; + + #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 1d34437318e..f70c1a449c7 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -87,7 +87,7 @@ struct wg_parser + GstFlowReturn ret; + } read_request; + +- bool flushing, sink_connected; ++ bool flushing, sink_connected, draining; + + bool unlimited_buffering; + }; +@@ -769,6 +769,16 @@ static NTSTATUS wg_parser_stream_get_event(void *args) + + *params->event = stream->event; + ++ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up ++ due to pull_data never being called again */ ++ if (stream->event.type == WG_PARSER_EVENT_EOS) ++ stream->eos = true; ++ ++ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up ++ due to pull_data never being called again */ ++ if (stream->event.type == WG_PARSER_EVENT_EOS) ++ stream->eos = true; ++ + if (stream->event.type != WG_PARSER_EVENT_BUFFER) + { + stream->event.type = WG_PARSER_EVENT_NONE; +@@ -859,6 +869,44 @@ static NTSTATUS wg_parser_stream_seek(void *args) + return S_OK; + } + ++static NTSTATUS wg_parser_stream_drain(void *args) ++{ ++ struct wg_parser_stream *stream = args; ++ struct wg_parser *parser = stream->parser; ++ bool ret; ++ ++ pthread_mutex_lock(&parser->mutex); ++ ++ /* Sanity check making sure caller didn't try to drain an already-EOS or unselected stream. ++ There's no reason for a caller to do this, but it could be an accident in which case we ++ should indicate that the stream is drained instead of locking-up. */ ++ if (!stream->enabled || stream->eos) ++ { ++ pthread_mutex_unlock(&parser->mutex); ++ return true; ++ } ++ ++ parser->draining = true; ++ pthread_cond_signal(&parser->read_done_cond); ++ ++ /* We must wait for either an event to occur or the drain to complete. ++ Since drains are blocking, we assign this responsibility to the thread ++ pulling data, as the pipeline will not need to pull more data until ++ the drain completes. If one input buffer yields more than one output ++ buffer, the chain callback blocks on the wg_parser_stream_buffer_release ++ for the first buffer, which would never be called if the drain function ++ hadn't completed. */ ++ while (!parser->flushing && parser->draining && stream->event.type == WG_PARSER_EVENT_NONE) ++ pthread_cond_wait(&stream->event_cond, &parser->mutex); ++ ++ ret = stream->event.type == WG_PARSER_EVENT_NONE; ++ parser->draining = false; ++ ++ pthread_mutex_unlock(&stream->parser->mutex); ++ ++ return ret; ++} ++ + static NTSTATUS wg_parser_stream_notify_qos(void *args) + { + const struct wg_parser_stream_notify_qos_params *params = args; +@@ -1431,6 +1479,7 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + { + struct wg_parser *parser = gst_pad_get_element_private(pad); + GstFlowReturn ret; ++ unsigned int i; + + GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, size %u, buffer %p.", pad, offset, size, *buffer); + +@@ -1452,6 +1501,14 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + + pthread_mutex_lock(&parser->mutex); + ++ if (parser->draining) ++ { ++ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); ++ parser->draining = false; ++ for (i = 0; i < parser->stream_count; i++) ++ pthread_cond_signal(&parser->streams[i]->event_cond); ++ } ++ + assert(!parser->read_request.size); + parser->read_request.buffer = *buffer; + parser->read_request.offset = offset; +@@ -1464,7 +1521,16 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + * read_thread() not running. */ + + while (!parser->read_request.done) ++ { + pthread_cond_wait(&parser->read_done_cond, &parser->mutex); ++ if (parser->draining) ++ { ++ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); ++ parser->draining = false; ++ for (i = 0; i < parser->stream_count; i++) ++ pthread_cond_signal(&parser->streams[i]->event_cond); ++ } ++ } + + *buffer = parser->read_request.buffer; + ret = parser->read_request.ret; +@@ -2208,4 +2274,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + + X(wg_parser_stream_get_duration), + X(wg_parser_stream_seek), ++ ++ X(wg_parser_stream_drain), + }; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0041-winegstreamer-Add-an-explicit-result-to-wg_parser_pu.patch b/patches/mfplat-streaming-support/0041-winegstreamer-Add-an-explicit-result-to-wg_parser_pu.patch new file mode 100644 index 00000000..64881696 --- /dev/null +++ b/patches/mfplat-streaming-support/0041-winegstreamer-Add-an-explicit-result-to-wg_parser_pu.patch @@ -0,0 +1,190 @@ +From 6cc6888966a9d0d7da6ed866ece791ca0e6afd61 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 11:26:41 +0100 +Subject: [PATCH 41/88] winegstreamer: Add an explicit result to + wg_parser_push_data. + +--- + dlls/winegstreamer/gst_private.h | 2 +- + dlls/winegstreamer/main.c | 3 ++- + dlls/winegstreamer/media_source.c | 4 ++-- + dlls/winegstreamer/quartz_parser.c | 2 +- + dlls/winegstreamer/unixlib.h | 9 +++++++++ + dlls/winegstreamer/wg_parser.c | 19 ++++++++++++++++++- + dlls/winegstreamer/wm_reader.c | 8 ++++---- + 7 files changed, 37 insertions(+), 10 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 6149ae5959c..c156d87450c 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -74,7 +74,7 @@ void wg_parser_begin_flush(struct wg_parser *parser); + void wg_parser_end_flush(struct wg_parser *parser); + + bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); +-void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size); ++void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size); + + uint32_t wg_parser_get_stream_count(struct wg_parser *parser); + struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 66b7a1195ee..db05594f464 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -120,11 +120,12 @@ bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, + return true; + } + +-void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size) ++void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) + { + struct wg_parser_push_data_params params = + { + .parser = parser, ++ .result = result, + .data = data, + .size = size, + }; +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index c97348cc2d6..fd6479d9879 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -644,7 +644,7 @@ static DWORD CALLBACK read_thread(void *arg) + * an error when reading past the file size. */ + if (!size) + { +- wg_parser_push_data(source->wg_parser, data, 0); ++ wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0); + continue; + } + +@@ -662,7 +662,7 @@ static DWORD CALLBACK read_thread(void *arg) + ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); + else if (ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); +- wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); ++ wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size); + } + + free(data); +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index 8ea9291904e..c44bd141c56 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -876,7 +876,7 @@ static DWORD CALLBACK read_thread(void *arg) + if (FAILED(hr)) + ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); + +- wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? data : NULL, size); ++ wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size); + } + + free(data); +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index fc9d0c3c80d..f20ee5bb52f 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -125,6 +125,14 @@ enum wg_parser_event_type + WG_PARSER_EVENT_SEGMENT, + }; + ++enum wg_read_result ++{ ++ WG_READ_SUCCESS, ++ WG_READ_FAILURE, ++ WG_READ_FLUSHING, ++ WG_READ_EOS, ++}; ++ + struct wg_parser_event + { + enum wg_parser_event_type type; +@@ -177,6 +185,7 @@ struct wg_parser_get_next_read_offset_params + struct wg_parser_push_data_params + { + struct wg_parser *parser; ++ enum wg_read_result result; + const void *data; + UINT32 size; + }; +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index f70c1a449c7..df4dca4a69f 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -647,16 +647,33 @@ static NTSTATUS wg_parser_get_next_read_offset(void *args) + return S_OK; + } + ++static GstFlowReturn wg_read_result_to_gst(enum wg_read_result result) ++{ ++ switch (result) ++ { ++ case WG_READ_SUCCESS: return GST_FLOW_OK; ++ case WG_READ_FAILURE: return GST_FLOW_ERROR; ++ case WG_READ_FLUSHING: return GST_FLOW_FLUSHING; ++ case WG_READ_EOS: return GST_FLOW_EOS; ++ } ++ return GST_FLOW_ERROR; ++} ++ + static NTSTATUS wg_parser_push_data(void *args) + { + const struct wg_parser_push_data_params *params = args; + struct wg_parser *parser = params->parser; ++ enum wg_read_result result = params->result; + const void *data = params->data; + uint32_t size = params->size; + + pthread_mutex_lock(&parser->mutex); + +- if (data) ++ if (result != WG_READ_SUCCESS) ++ { ++ parser->read_request.ret = wg_read_result_to_gst(result); ++ } ++ else if (data) + { + if (size) + { +diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c +index d40afb66afd..ee37abee811 100644 +--- a/dlls/winegstreamer/wm_reader.c ++++ b/dlls/winegstreamer/wm_reader.c +@@ -573,7 +573,7 @@ static DWORD CALLBACK read_thread(void *arg) + + if (!size) + { +- wg_parser_push_data(reader->wg_parser, data, 0); ++ wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0); + continue; + } + +@@ -592,7 +592,7 @@ static DWORD CALLBACK read_thread(void *arg) + || !ReadFile(file, data, size, &ret_size, NULL)) + { + ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError()); +- wg_parser_push_data(reader->wg_parser, NULL, 0); ++ wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); + continue; + } + } +@@ -603,14 +603,14 @@ static DWORD CALLBACK read_thread(void *arg) + if (FAILED(hr)) + { + ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); +- wg_parser_push_data(reader->wg_parser, NULL, 0); ++ wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); + continue; + } + } + + if (ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); +- wg_parser_push_data(reader->wg_parser, data, ret_size); ++ wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size); + } + + free(data); +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0042-winegstreamer-Unblock-wg_parser_get_next_read_offset.patch b/patches/mfplat-streaming-support/0042-winegstreamer-Unblock-wg_parser_get_next_read_offset.patch new file mode 100644 index 00000000..f3585e25 --- /dev/null +++ b/patches/mfplat-streaming-support/0042-winegstreamer-Unblock-wg_parser_get_next_read_offset.patch @@ -0,0 +1,26 @@ +From e6f2e0b82e251f650c00c6e270fb615a19a16e19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 11:51:33 +0100 +Subject: [PATCH 42/88] winegstreamer: Unblock wg_parser_get_next_read_offset + on read errors too. + +--- + dlls/winegstreamer/wg_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index df4dca4a69f..a11fc8c4f68 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -631,7 +631,7 @@ static NTSTATUS wg_parser_get_next_read_offset(void *args) + + pthread_mutex_lock(&parser->mutex); + +- while (parser->sink_connected && !parser->read_request.size) ++ while (parser->sink_connected && (!parser->read_request.size || parser->read_request.done)) + pthread_cond_wait(&parser->read_cond, &parser->mutex); + + if (!parser->sink_connected) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0043-winegstreamer-Update-offset-according-to-the-size-of.patch b/patches/mfplat-streaming-support/0043-winegstreamer-Update-offset-according-to-the-size-of.patch new file mode 100644 index 00000000..1eea1fe4 --- /dev/null +++ b/patches/mfplat-streaming-support/0043-winegstreamer-Update-offset-according-to-the-size-of.patch @@ -0,0 +1,26 @@ +From 6c81e31b53f5b3f3fd798e3d3fb43f9a2df8fa5b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 11:51:33 +0100 +Subject: [PATCH 43/88] winegstreamer: Update offset according to the size of + the buffer read. + +--- + dlls/winegstreamer/wg_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index a11fc8c4f68..42c727fbd0b 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1642,7 +1642,7 @@ static void *push_data(void *arg) + break; + } + +- parser->next_offset += size; ++ parser->next_offset += gst_buffer_get_size(buffer); + + buffer->duration = buffer->pts = -1; + if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0044-winegstreamer-Let-src_getrange_cb-allocate-the-buffe.patch b/patches/mfplat-streaming-support/0044-winegstreamer-Let-src_getrange_cb-allocate-the-buffe.patch new file mode 100644 index 00000000..173579c4 --- /dev/null +++ b/patches/mfplat-streaming-support/0044-winegstreamer-Let-src_getrange_cb-allocate-the-buffe.patch @@ -0,0 +1,56 @@ +From 542e27319af4903ddd557b7269ef52f2fee627d7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 13:54:05 +0100 +Subject: [PATCH 44/88] winegstreamer: Let src_getrange_cb allocate the buffer + in push_data. + +GStreamer documentation also states that gst_pad_push caller loses its +buffer reference, so whatever we were doing looks wrong here. +--- + dlls/winegstreamer/wg_parser.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 42c727fbd0b..0b67a6836c4 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1607,18 +1607,12 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + static void *push_data(void *arg) + { + struct wg_parser *parser = arg; +- GstBuffer *buffer; + GstSegment *segment; ++ GstBuffer *buffer; + guint max_size; + + GST_DEBUG("Starting push thread."); + +- if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) +- { +- GST_ERROR("Failed to allocate memory."); +- return NULL; +- } +- + max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; + + gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); +@@ -1636,6 +1630,7 @@ static void *push_data(void *arg) + break; + size = min(16384, max_size - parser->next_offset); + ++ buffer = NULL; + if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) + { + GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); +@@ -1652,8 +1647,6 @@ static void *push_data(void *arg) + } + } + +- gst_buffer_unref(buffer); +- + gst_pad_push_event(parser->my_src, gst_event_new_eos()); + + GST_DEBUG("Stopping push thread."); +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0045-winegstreamer-Implement-unseekable-stream-support.patch b/patches/mfplat-streaming-support/0045-winegstreamer-Implement-unseekable-stream-support.patch new file mode 100644 index 00000000..65c61c08 --- /dev/null +++ b/patches/mfplat-streaming-support/0045-winegstreamer-Implement-unseekable-stream-support.patch @@ -0,0 +1,436 @@ +From 7a63ae845a7d1d630ae838ddebc25a20c54df889 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 10:25:48 +0100 +Subject: [PATCH 45/88] winegstreamer: Implement unseekable stream support. + +--- + dlls/winegstreamer/gst_private.h | 2 + + dlls/winegstreamer/main.c | 14 +++ + dlls/winegstreamer/unixlib.h | 9 ++ + dlls/winegstreamer/wg_parser.c | 197 ++++++++++++++++++++++++++++--- + 4 files changed, 203 insertions(+), 19 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index c156d87450c..6e7c53782c8 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -68,6 +68,8 @@ struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buff + void wg_parser_destroy(struct wg_parser *parser); + + HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); ++HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, ++ uint32_t stream_count, const struct wg_format *out_formats); + void wg_parser_disconnect(struct wg_parser *parser); + + void wg_parser_begin_flush(struct wg_parser *parser); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index db05594f464..316becdbc97 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -91,6 +91,20 @@ HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) + return __wine_unix_call(unix_handle, unix_wg_parser_connect, ¶ms); + } + ++HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, ++ uint32_t stream_count, const struct wg_format *out_formats) ++{ ++ struct wg_parser_connect_unseekable_params params = ++ { ++ .parser = parser, ++ .in_format = in_format, ++ .stream_count = stream_count, ++ .out_formats = out_formats, ++ }; ++ ++ return __wine_unix_call(unix_handle, unix_wg_parser_connect_unseekable, ¶ms); ++} ++ + void wg_parser_disconnect(struct wg_parser *parser) + { + __wine_unix_call(unix_handle, unix_wg_parser_disconnect, parser); +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index f20ee5bb52f..e5d87716734 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -175,6 +175,14 @@ struct wg_parser_connect_params + UINT64 file_size; + }; + ++struct wg_parser_connect_unseekable_params ++{ ++ struct wg_parser *parser; ++ const struct wg_format *in_format; ++ UINT32 stream_count; ++ const struct wg_format *out_formats; ++}; ++ + struct wg_parser_get_next_read_offset_params + { + struct wg_parser *parser; +@@ -258,6 +266,7 @@ enum unix_funcs + unix_wg_parser_destroy, + + unix_wg_parser_connect, ++ unix_wg_parser_connect_unseekable, + unix_wg_parser_disconnect, + + unix_wg_parser_begin_flush, +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 0b67a6836c4..ab850b899f3 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -61,7 +61,7 @@ struct wg_parser + init_gst_cb init_gst; + + struct wg_parser_stream **streams; +- unsigned int stream_count; ++ unsigned int stream_count, expected_stream_count; + + GstElement *container, *decodebin; + GstBus *bus; +@@ -75,7 +75,7 @@ struct wg_parser + pthread_mutex_t mutex; + + pthread_cond_t init_cond; +- bool no_more_pads, has_duration, error, pull_mode; ++ bool no_more_pads, has_duration, error, pull_mode, seekable; + + pthread_cond_t read_cond, read_done_cond; + struct +@@ -90,6 +90,7 @@ struct wg_parser + bool flushing, sink_connected, draining; + + bool unlimited_buffering; ++ struct wg_format input_format; + }; + + struct wg_parser_stream +@@ -600,6 +601,9 @@ static NTSTATUS wg_parser_begin_flush(void *args) + struct wg_parser *parser = args; + unsigned int i; + ++ if (!parser->seekable) ++ return S_OK; ++ + pthread_mutex_lock(&parser->mutex); + parser->flushing = true; + pthread_mutex_unlock(&parser->mutex); +@@ -617,6 +621,9 @@ static NTSTATUS wg_parser_end_flush(void *args) + { + struct wg_parser *parser = args; + ++ if (!parser->seekable) ++ return S_OK; ++ + pthread_mutex_lock(&parser->mutex); + parser->flushing = false; + pthread_mutex_unlock(&parser->mutex); +@@ -711,7 +718,9 @@ static NTSTATUS wg_parser_stream_get_preferred_format(void *args) + { + const struct wg_parser_stream_get_preferred_format_params *params = args; + +- *params->format = params->stream->preferred_format; ++ if (params->stream->has_caps) ++ *params->format = params->stream->preferred_format; ++ + return S_OK; + } + +@@ -721,6 +730,9 @@ static NTSTATUS wg_parser_stream_enable(void *args) + struct wg_parser_stream *stream = params->stream; + const struct wg_format *format = params->format; + ++ if (!stream->parser->seekable) ++ return S_OK; ++ + stream->current_format = *format; + stream->enabled = true; + +@@ -867,6 +879,9 @@ static NTSTATUS wg_parser_stream_seek(void *args) + DWORD stop_flags = params->stop_flags; + GstSeekFlags flags = 0; + ++ if (!params->stream->parser->seekable) ++ return E_FAIL; ++ + if (start_flags & AM_SEEKING_SeekToKeyFrame) + flags |= GST_SEEK_FLAG_KEY_UNIT; + if (start_flags & AM_SEEKING_Segment) +@@ -1246,14 +1261,27 @@ static GstElement *create_element(const char *name, const char *plugin_set) + static struct wg_parser_stream *create_stream(struct wg_parser *parser) + { + struct wg_parser_stream *stream, **new_array; ++ unsigned int i; + char pad_name[19]; + +- if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) +- return NULL; +- parser->streams = new_array; ++ for (i = 0; i < parser->expected_stream_count; i++) ++ { ++ if (!parser->streams[i]->parser) ++ { ++ stream = parser->streams[i]; ++ break; ++ } ++ } + +- if (!(stream = calloc(1, sizeof(*stream)))) +- return NULL; ++ if (i == parser->expected_stream_count) ++ { ++ if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) ++ return NULL; ++ parser->streams = new_array; ++ ++ if (!(stream = calloc(1, sizeof(*stream)))) ++ return NULL; ++ } + + gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED); + +@@ -1575,7 +1603,7 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); + return TRUE; + } +- else if (format == GST_FORMAT_BYTES) ++ else if (format == GST_FORMAT_BYTES && parser->seekable) + { + gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size); + return TRUE; +@@ -1589,15 +1617,42 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format)); + return FALSE; + } ++ if (!parser->seekable) ++ return FALSE; + gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size); + return TRUE; + + case GST_QUERY_SCHEDULING: +- gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); ++ gst_query_set_scheduling(query, parser->seekable ? GST_SCHEDULING_FLAG_SEEKABLE : GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); + return TRUE; + ++ case GST_QUERY_CAPS: ++ { ++ GstCaps *caps, *filter, *temp; ++ ++ gst_query_parse_caps(query, &filter); ++ ++ if (parser->input_format.major_type) ++ caps = wg_format_to_caps(&parser->input_format); ++ else ++ caps = gst_caps_new_any(); ++ if (!caps) ++ return FALSE; ++ ++ if (filter) ++ { ++ temp = gst_caps_intersect(caps, filter); ++ gst_caps_unref(caps); ++ caps = temp; ++ } ++ ++ gst_query_set_caps_result(query, caps); ++ gst_caps_unref(caps); ++ return TRUE; ++ } ++ + default: + GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); + return FALSE; +@@ -1607,16 +1662,31 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + static void *push_data(void *arg) + { + struct wg_parser *parser = arg; ++ ULONG alloc_size = 16384; ++ GstCaps *caps = NULL; + GstSegment *segment; + GstBuffer *buffer; ++ unsigned int i; + guint max_size; + + GST_DEBUG("Starting push thread."); + ++ if (parser->input_format.major_type) ++ caps = wg_format_to_caps(&parser->input_format); ++ ++ if (parser->input_format.major_type == WG_MAJOR_TYPE_VIDEO) ++ { ++ GstVideoInfo info; ++ gst_video_info_from_caps(&info, caps); ++ alloc_size = info.size; ++ } ++ + max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; + + gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); + ++ if (caps) gst_pad_push_event(parser->my_src, gst_event_new_caps(caps)); ++ + segment = gst_segment_new(); + gst_segment_init(segment, GST_FORMAT_BYTES); + gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); +@@ -1626,13 +1696,47 @@ static void *push_data(void *arg) + ULONG size; + int ret; + +- if (parser->next_offset >= max_size) ++ if (parser->seekable && parser->next_offset >= max_size) + break; +- size = min(16384, max_size - parser->next_offset); ++ size = parser->seekable ? min(alloc_size, max_size - parser->next_offset) : alloc_size; + + buffer = NULL; +- if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) ++ if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer) < 0)) + { ++ /* When we are in unseekable push mode, the pushing pad is responsible for handling flushing. */ ++ if (!parser->seekable && ret == GST_FLOW_FLUSHING) ++ { ++ gst_pad_push_event(parser->my_src, gst_event_new_seek(1.0f, ++ GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)); ++ continue; ++ } ++ ++ if (!parser->seekable && ret == GST_FLOW_EOS) ++ { ++ gst_pad_push_event(parser->my_src, gst_event_new_eos()); ++ pthread_mutex_lock(&parser->mutex); ++ for (i = 0; i < parser->stream_count; i++) ++ { ++ if (!parser->streams[i]->enabled) ++ continue; ++ while (!parser->streams[i]->flushing && !parser->streams[i]->eos) ++ pthread_cond_wait(&parser->streams[i]->event_empty_cond, &parser->mutex); ++ parser->streams[i]->eos = false; ++ } ++ ++ if (parser->flushing) ++ { ++ pthread_mutex_unlock(&parser->mutex); ++ continue; ++ } ++ pthread_mutex_unlock(&parser->mutex); ++ ++ segment = gst_segment_new(); ++ gst_segment_init(segment, GST_FORMAT_BYTES); ++ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); ++ continue; ++ } ++ + GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); + break; + } +@@ -1827,16 +1931,11 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) + return ret; + } + +-static NTSTATUS wg_parser_connect(void *args) ++static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + { + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", + GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); +- const struct wg_parser_connect_params *params = args; +- struct wg_parser *parser = params->parser; +- unsigned int i; +- int ret; + +- parser->file_size = params->file_size; + parser->sink_connected = true; + + if (!parser->bus) +@@ -1859,6 +1958,23 @@ static NTSTATUS wg_parser_connect(void *args) + parser->next_pull_offset = 0; + parser->error = false; + ++ return S_OK; ++} ++ ++static NTSTATUS wg_parser_connect(void *args) ++{ ++ const struct wg_parser_connect_params *params = args; ++ struct wg_parser *parser = params->parser; ++ unsigned int i; ++ HRESULT hr; ++ int ret; ++ ++ parser->seekable = true; ++ parser->file_size = params->file_size; ++ ++ if ((hr = wg_parser_connect_inner(parser))) ++ return hr; ++ + if (!parser->init_gst(parser)) + goto out; + +@@ -1988,6 +2104,45 @@ out: + return E_FAIL; + } + ++static NTSTATUS wg_parser_connect_unseekable(void *args) ++{ ++ const struct wg_parser_connect_unseekable_params *params = args; ++ const struct wg_format *out_formats = params->out_formats; ++ const struct wg_format *in_format = params->in_format; ++ uint32_t stream_count = params->stream_count; ++ struct wg_parser *parser = params->parser; ++ unsigned int i; ++ HRESULT hr; ++ ++ parser->seekable = false; ++ parser->flushing = false; ++ /* since typefind is not available here, we must have an input_format */ ++ parser->input_format = *in_format; ++ ++ if ((hr = wg_parser_connect_inner(parser))) ++ return hr; ++ ++ parser->stop_offset = -1; ++ ++ parser->expected_stream_count = stream_count; ++ parser->streams = calloc(stream_count, sizeof(*parser->streams)); ++ ++ for (i = 0; i < stream_count; i++) ++ { ++ parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); ++ parser->streams[i]->current_format = out_formats[i]; ++ parser->streams[i]->enabled = true; ++ } ++ ++ if (!parser->init_gst(parser)) ++ return E_FAIL; ++ ++ if (parser->stream_count < parser->expected_stream_count) ++ return E_FAIL; ++ ++ return S_OK; ++} ++ + static NTSTATUS wg_parser_disconnect(void *args) + { + struct wg_parser *parser = args; +@@ -2037,6 +2192,9 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + if (!(element = create_element("decodebin", "base"))) + return FALSE; + ++ if (parser->input_format.major_type) ++ g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); ++ + gst_bin_add(GST_BIN(parser->container), element); + parser->decodebin = element; + +@@ -2262,6 +2420,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + X(wg_parser_destroy), + + X(wg_parser_connect), ++ X(wg_parser_connect_unseekable), + X(wg_parser_disconnect), + + X(wg_parser_begin_flush), +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch b/patches/mfplat-streaming-support/0046-winegstreamer-Implement-Process-Input-Output-for-dec.patch similarity index 77% rename from patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch rename to patches/mfplat-streaming-support/0046-winegstreamer-Implement-Process-Input-Output-for-dec.patch index bd8a8e66..b30467ad 100644 --- a/patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch +++ b/patches/mfplat-streaming-support/0046-winegstreamer-Implement-Process-Input-Output-for-dec.patch @@ -1,20 +1,20 @@ -From 7585c2809396ce0a506749b5c2435ced429f3b32 Mon Sep 17 00:00:00 2001 +From 4518afa81504bbbd86fd3ee62683169730255277 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 16:53:02 -0400 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for decoder - transform. +Subject: [PATCH 46/88] winegstreamer: Implement ::Process(Input/Output) for + decoder transform. -Signed-off-by: Derek Lesho --- - dlls/winegstreamer/decode_transform.c | 532 +++++++++++++++++++++++++- - 1 file changed, 526 insertions(+), 6 deletions(-) + dlls/winegstreamer/decode_transform.c | 542 +++++++++++++++++++++++++- + dlls/winegstreamer/wg_parser.c | 4 + + 2 files changed, 540 insertions(+), 6 deletions(-) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index dadd161bcc9..c30780ba7ff 100644 +index 4967fc49012..c2b70c10f41 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c -@@ -51,14 +51,47 @@ static struct decoder_desc - }, +@@ -61,14 +61,47 @@ static struct decoder_desc + } }; +struct pipeline_event @@ -63,15 +63,35 @@ index dadd161bcc9..c30780ba7ff 100644 }; static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -@@ -114,7 +147,15 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) +@@ -124,7 +157,35 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) decoder->output_type = NULL; } -+ if (decoder->wg_stream) -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); -+ + if (decoder->wg_parser) -+ unix_funcs->wg_parser_destroy(decoder->wg_parser); ++ { ++ /* NULL wg_parser is possible if the wg_parser creation failed. */ ++ ++ if (decoder->wg_stream) ++ wg_parser_disconnect(decoder->wg_parser); ++ ++ EnterCriticalSection(&decoder->event_cs); ++ decoder->helper_thread_shutdown = TRUE; ++ WakeAllConditionVariable(&decoder->event_cv); ++ LeaveCriticalSection(&decoder->event_cs); ++ ++ EnterCriticalSection(&decoder->help_cs); ++ WakeAllConditionVariable(&decoder->help_cv); ++ LeaveCriticalSection(&decoder->help_cs); ++ ++ if (WaitForSingleObject(decoder->helper_thread, 10000) != WAIT_OBJECT_0) ++ FIXME("Failed waiting for helper thread to terminate.\n"); ++ CloseHandle(decoder->helper_thread); ++ if (WaitForSingleObject(decoder->read_thread, 10000) != WAIT_OBJECT_0) ++ FIXME("Failed waiting for read thread to terminate.\n"); ++ CloseHandle(decoder->read_thread); ++ ++ wg_parser_destroy(decoder->wg_parser); ++ } + DeleteCriticalSection(&decoder->cs); + DeleteCriticalSection(&decoder->help_cs); @@ -79,33 +99,33 @@ index dadd161bcc9..c30780ba7ff 100644 heap_free(decoder); } -@@ -341,6 +382,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF +@@ -351,6 +412,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF EnterCriticalSection(&decoder->cs); + if (decoder->wg_stream) + { + decoder->wg_stream = NULL; -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ wg_parser_disconnect(decoder->wg_parser); + } + if (decoder->input_type) { IMFMediaType_Release(decoder->input_type); -@@ -379,6 +426,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF +@@ -389,6 +456,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF hr = S_OK; + if (decoder->wg_stream) + { + decoder->wg_stream = NULL; -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ wg_parser_disconnect(decoder->wg_parser); + } + if (!decoder->input_type) hr = MFCreateMediaType(&decoder->input_type); -@@ -388,6 +441,16 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF +@@ -398,6 +471,16 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF decoder->input_type = NULL; } @@ -122,33 +142,33 @@ index dadd161bcc9..c30780ba7ff 100644 LeaveCriticalSection(&decoder->cs); return hr; } -@@ -412,6 +475,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM +@@ -422,6 +505,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM EnterCriticalSection(&decoder->cs); + if (decoder->wg_stream) + { + decoder->wg_stream = NULL; -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ wg_parser_disconnect(decoder->wg_parser); + } + if (decoder->output_type) { IMFMediaType_Release(decoder->output_type); -@@ -450,6 +519,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM +@@ -460,6 +549,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM hr = S_OK; + if (decoder->wg_stream) + { + decoder->wg_stream = NULL; -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ wg_parser_disconnect(decoder->wg_parser); + } + if (!decoder->output_type) hr = MFCreateMediaType(&decoder->output_type); -@@ -459,6 +534,16 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM +@@ -469,6 +564,16 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM decoder->output_type = NULL; } @@ -165,7 +185,7 @@ index dadd161bcc9..c30780ba7ff 100644 LeaveCriticalSection(&decoder->cs); return hr; } -@@ -505,6 +590,124 @@ static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMF +@@ -515,6 +620,117 @@ static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMF return E_NOTIMPL; } @@ -180,16 +200,16 @@ index dadd161bcc9..c30780ba7ff 100644 + while(!decoder->helper_thread_shutdown && decoder->help_request.type == HELP_REQ_NONE) + SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); + if (decoder->helper_thread_shutdown) ++ { ++ LeaveCriticalSection(&decoder->help_cs); + return 0; ++ } + + switch(decoder->help_request.type) + { + case HELP_REQ_START_PARSER: + { + struct wg_format input_format, output_format; -+ struct wg_rect wg_aperture = {0}; -+ MFVideoArea *aperture = NULL; -+ UINT32 aperture_size; + + decoder->help_request.type = HELP_REQ_NONE; + LeaveCriticalSection(&decoder->help_cs); @@ -197,32 +217,20 @@ index dadd161bcc9..c30780ba7ff 100644 + mf_media_type_to_wg_format(decoder->input_type, &input_format); + mf_media_type_to_wg_format(decoder->output_type, &output_format); + -+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type, -+ &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size))) -+ { -+ TRACE("Decoded media's aperture: x: %u %u/65536, y: %u %u/65536, area: %u x %u\n", -+ aperture->OffsetX.value, aperture->OffsetX.fract, -+ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy); -+ -+ /* TODO: verify aperture params? */ -+ -+ wg_aperture.left = aperture->OffsetX.value; -+ wg_aperture.top = aperture->OffsetY.value; -+ wg_aperture.right = aperture->Area.cx; -+ wg_aperture.bottom = aperture->Area.cy; -+ -+ CoTaskMemFree(aperture); -+ } -+ -+ unix_funcs->wg_parser_connect_unseekable(decoder->wg_parser, -+ &input_format, 1, &output_format, aperture ? &wg_aperture : NULL); ++ wg_parser_connect_unseekable(decoder->wg_parser, &input_format, 1, &output_format); + + EnterCriticalSection(&decoder->event_cs); -+ while (decoder->event.type != PIPELINE_EVENT_NONE) ++ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) + SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); + ++ if (decoder->helper_thread_shutdown) ++ { ++ LeaveCriticalSection(&decoder->event_cs); ++ return 0; ++ } ++ + decoder->event.type = PIPELINE_EVENT_PARSER_STARTED; -+ decoder->event.u.parser_started.stream = unix_funcs->wg_parser_get_stream(decoder->wg_parser, 0); ++ decoder->event.u.parser_started.stream = wg_parser_get_stream(decoder->wg_parser, 0); + + LeaveCriticalSection(&decoder->event_cs); + WakeAllConditionVariable(&decoder->event_cv); @@ -240,25 +248,30 @@ index dadd161bcc9..c30780ba7ff 100644 +static DWORD CALLBACK read_thread_func(PVOID ctx) +{ + struct mf_decoder *decoder = (struct mf_decoder *)ctx; -+ void *data; + uint64_t offset; + uint32_t size; + + for (;;) + { -+ if (!unix_funcs->wg_parser_get_read_request(decoder->wg_parser, &data, &offset, &size)) -+ continue; -+ + if (decoder->helper_thread_shutdown) + break; + ++ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size)) ++ continue; ++ + EnterCriticalSection(&decoder->event_cs); -+ while (decoder->event.type != PIPELINE_EVENT_NONE) ++ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) + SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); + ++ if (decoder->helper_thread_shutdown) ++ { ++ LeaveCriticalSection(&decoder->event_cs); ++ break; ++ } ++ + decoder->event.type = PIPELINE_EVENT_READ_REQUEST; + WakeAllConditionVariable(&decoder->event_cv); -+ while (decoder->event.type == PIPELINE_EVENT_READ_REQUEST) ++ while (!decoder->helper_thread_shutdown && decoder->event.type == PIPELINE_EVENT_READ_REQUEST) + SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); + LeaveCriticalSection(&decoder->event_cs); + } @@ -290,7 +303,7 @@ index dadd161bcc9..c30780ba7ff 100644 static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { FIXME("%p, %u %lu.\n", iface, message, param); -@@ -514,17 +717,318 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE +@@ -524,17 +740,315 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { @@ -303,7 +316,6 @@ index dadd161bcc9..c30780ba7ff 100644 + DWORD buffer_size; + uint32_t size = 0; + uint64_t offset; -+ void *data; - return E_NOTIMPL; + TRACE("%p, %u, %p, %#x.\n", decoder, id, sample, flags); @@ -344,7 +356,7 @@ index dadd161bcc9..c30780ba7ff 100644 + } + } + -+ if (decoder->wg_stream && !unix_funcs->wg_parser_stream_drain(decoder->wg_stream)) ++ if (decoder->wg_stream && !wg_parser_stream_drain(decoder->wg_stream)) + { + LeaveCriticalSection(&decoder->cs); + return MF_E_NOTACCEPTING; @@ -365,7 +377,7 @@ index dadd161bcc9..c30780ba7ff 100644 + { + uint32_t copy_size; + -+ if (!unix_funcs->wg_parser_get_read_request(decoder->wg_parser, &data, &offset, &size)) ++ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size)) + continue; + + copy_size = min(size, buffer_size); @@ -373,15 +385,13 @@ index dadd161bcc9..c30780ba7ff 100644 + if (offset != decoder->offset_tracker) + { + ERR("A seek is needed, MFTs don't support this!\n"); -+ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_FAILURE, 0); ++ wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0); + IMFMediaBuffer_Unlock(buffer); + hr = E_FAIL; + goto done; + } + -+ memcpy(data, buffer_data, copy_size); -+ -+ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_SUCCESS, buffer_size); ++ wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size); + + decoder->offset_tracker += copy_size; + @@ -469,10 +479,10 @@ index dadd161bcc9..c30780ba7ff 100644 + } + } + -+ if (unix_funcs->wg_parser_stream_drain(decoder->wg_stream)) ++ if (wg_parser_stream_drain(decoder->wg_stream)) + { + /* this would be unexpected, as we should get the EOS-event when a drain command completes. */ -+ //assert (!decoder->draining); ++ assert (!decoder->draining); + + LeaveCriticalSection(&decoder->cs); + return MF_E_TRANSFORM_NEED_MORE_INPUT; @@ -480,7 +490,7 @@ index dadd161bcc9..c30780ba7ff 100644 + + for (;;) + { -+ if (!unix_funcs->wg_parser_stream_get_event(decoder->wg_stream, &event)) ++ if (!wg_parser_stream_get_event(decoder->wg_stream, &event)) + { + LeaveCriticalSection(&decoder->cs); + return E_FAIL; @@ -568,7 +578,7 @@ index dadd161bcc9..c30780ba7ff 100644 + goto out; + } + -+ if (!unix_funcs->wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) ++ if (!wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) + { + hr = E_FAIL; + goto out; @@ -598,7 +608,7 @@ index dadd161bcc9..c30780ba7ff 100644 + + out: + if (SUCCEEDED(hr)) -+ unix_funcs->wg_parser_stream_release_buffer(decoder->wg_stream); ++ wg_parser_stream_release_buffer(decoder->wg_stream); + LeaveCriticalSection(&decoder->cs); + + if (FAILED(hr)) @@ -613,7 +623,7 @@ index dadd161bcc9..c30780ba7ff 100644 } static const IMFTransformVtbl mf_decoder_vtbl = -@@ -560,6 +1064,7 @@ static const IMFTransformVtbl mf_decoder_vtbl = +@@ -570,6 +1084,7 @@ static const IMFTransformVtbl mf_decoder_vtbl = HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) { struct mf_decoder *object; @@ -621,7 +631,7 @@ index dadd161bcc9..c30780ba7ff 100644 TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); -@@ -573,6 +1078,21 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) +@@ -583,6 +1098,21 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) object->video = decoder_descs[type].major_type == &MFMediaType_Video; InitializeCriticalSection(&object->cs); @@ -630,19 +640,37 @@ index dadd161bcc9..c30780ba7ff 100644 + InitializeConditionVariable(&object->help_cv); + InitializeConditionVariable(&object->event_cv); + -+ object->helper_thread = CreateThread(NULL, 0, helper_thread_func, object, 0, NULL); -+ object->read_thread = CreateThread(NULL, 0, read_thread_func, object, 0, NULL); -+ -+ if (!(parser = unix_funcs->wg_decodebin_parser_create())) ++ if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE))) + { + ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type); + IMFTransform_Release(&object->IMFTransform_iface); + return E_OUTOFMEMORY; + } + object->wg_parser = parser; ++ ++ object->helper_thread = CreateThread(NULL, 0, helper_thread_func, object, 0, NULL); ++ object->read_thread = CreateThread(NULL, 0, read_thread_func, object, 0, NULL); *obj = &object->IMFTransform_iface; return S_OK; +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index ab850b899f3..3d6202a209a 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -2150,9 +2150,13 @@ static NTSTATUS wg_parser_disconnect(void *args) + + /* Unblock all of our streams. */ + pthread_mutex_lock(&parser->mutex); ++ parser->flushing = true; ++ parser->no_more_pads = true; ++ pthread_cond_signal(&parser->init_cond); + for (i = 0; i < parser->stream_count; ++i) + { + parser->streams[i]->flushing = true; ++ pthread_cond_signal(&parser->streams[i]->event_cond); + pthread_cond_signal(&parser->streams[i]->event_empty_cond); + } + pthread_mutex_unlock(&parser->mutex); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch b/patches/mfplat-streaming-support/0047-winegstreamer-Implement-ProcessMessage-for-decoder-t.patch similarity index 87% rename from patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch rename to patches/mfplat-streaming-support/0047-winegstreamer-Implement-ProcessMessage-for-decoder-t.patch index 0b17b3a6..1ee43492 100644 --- a/patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch +++ b/patches/mfplat-streaming-support/0047-winegstreamer-Implement-ProcessMessage-for-decoder-t.patch @@ -1,19 +1,18 @@ -From 52a5aeb27602c0cccf12889dae5b9577d4af6cc8 Mon Sep 17 00:00:00 2001 +From d152c0c2bbd0bcb42b45fcde8f0ce2f13ba90eec Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 16:54:03 -0400 -Subject: [PATCH] winestreamer: Implement ::ProcessMessage for decoder +Subject: [PATCH 47/88] winegstreamer: Implement ::ProcessMessage for decoder transform. -Signed-off-by: Derek Lesho --- dlls/winegstreamer/decode_transform.c | 96 ++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index c30780ba7ff..04a07647de4 100644 +index c2b70c10f41..6f1363ff1f3 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c -@@ -710,9 +710,101 @@ static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) +@@ -733,9 +733,101 @@ static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { @@ -69,7 +68,7 @@ index c30780ba7ff..04a07647de4 100644 + pip_event = get_pipeline_event(decoder); + assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); + -+ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_EOS, 0); ++ wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0); + + EnterCriticalSection(&decoder->event_cs); + decoder->event.type = PIPELINE_EVENT_NONE; @@ -94,7 +93,7 @@ index c30780ba7ff..04a07647de4 100644 + pip_event = get_pipeline_event(decoder); + assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); + -+ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_FLUSHING, 0); ++ wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0); + + EnterCriticalSection(&decoder->event_cs); + decoder->event.type = PIPELINE_EVENT_NONE; @@ -118,5 +117,5 @@ index c30780ba7ff..04a07647de4 100644 static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch b/patches/mfplat-streaming-support/0048-winegstreamer-Implement-Process-Input-Output-for-aud.patch similarity index 57% rename from patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch rename to patches/mfplat-streaming-support/0048-winegstreamer-Implement-Process-Input-Output-for-aud.patch index 77f1895a..eff1db63 100644 --- a/patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch +++ b/patches/mfplat-streaming-support/0048-winegstreamer-Implement-Process-Input-Output-for-aud.patch @@ -1,18 +1,17 @@ -From de9678f6fad286785562c01548a9b724c7e27460 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 14:07:52 -0400 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for audio - conversion transform. +From 12a15d2c61816d3d0f55da07fd349088a6042db0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 10:59:45 +0100 +Subject: [PATCH 48/88] winegstreamer: Implement ::Process(Input/Output) for + audio conversion transform. -Signed-off-by: Derek Lesho --- - dlls/winegstreamer/audioconvert.c | 280 +++++++++++++++++++++++++++++- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/wg_parser.c | 93 ++++++++++ - 3 files changed, 367 insertions(+), 7 deletions(-) + dlls/winegstreamer/audioconvert.c | 277 +++++++++++++++++++++++++++++- + dlls/winegstreamer/unixlib.h | 1 + + dlls/winegstreamer/wg_parser.c | 61 +++++++ + 3 files changed, 332 insertions(+), 7 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 33350fb3566..8405f3bedc5 100644 +index afa6bd682a6..e7c1fb97f23 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -35,6 +35,10 @@ struct audio_converter @@ -23,41 +22,41 @@ index 33350fb3566..8405f3bedc5 100644 + LONGLONG buffer_pts, buffer_dur; + struct wg_parser *parser; + struct wg_parser_stream *stream; + IMFAttributes *attributes, *output_attributes; }; - static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) -@@ -80,6 +84,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); +@@ -85,6 +89,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) + IMFAttributes_Release(transform->attributes); + if (transform->output_attributes) + IMFAttributes_Release(transform->output_attributes); + if (transform->stream) -+ unix_funcs->wg_parser_disconnect(transform->parser); ++ wg_parser_disconnect(transform->parser); + if (transform->parser) -+ unix_funcs->wg_parser_destroy(transform->parser); ++ wg_parser_destroy(transform->parser); free(transform); } -@@ -272,6 +280,7 @@ fail: +@@ -324,6 +332,7 @@ fail: static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { GUID major_type, subtype; + struct wg_format format; - DWORD unused; + UINT32 unused; HRESULT hr; -@@ -291,6 +300,11 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -343,6 +352,11 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id if (converter->input_type) { + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } IMFMediaType_Release(converter->input_type); converter->input_type = NULL; } -@@ -317,6 +331,10 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -369,6 +383,10 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) return MF_E_INVALIDTYPE; @@ -68,13 +67,13 @@ index 33350fb3566..8405f3bedc5 100644 if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; -@@ -336,6 +354,21 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -388,6 +406,21 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id converter->input_type = NULL; } + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } + @@ -83,22 +82,22 @@ index 33350fb3566..8405f3bedc5 100644 + struct wg_format output_format; + mf_media_type_to_wg_format(converter->output_type, &output_format); + -+ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) -+ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) ++ converter->stream = wg_parser_get_stream(converter->parser, 0); + } + LeaveCriticalSection(&converter->cs); return hr; -@@ -345,6 +378,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -397,6 +430,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i { struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); GUID major_type, subtype; + struct wg_format format; - DWORD unused; + UINT32 unused; HRESULT hr; -@@ -353,9 +387,6 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -405,9 +439,6 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i if (id != 0) return MF_E_INVALIDSTREAMNUMBER; @@ -108,19 +107,19 @@ index 33350fb3566..8405f3bedc5 100644 if (!type) { if (flags & MFT_SET_TYPE_TEST_ONLY) -@@ -365,6 +396,11 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -417,6 +448,11 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i if (converter->output_type) { + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } IMFMediaType_Release(converter->output_type); converter->output_type = NULL; } -@@ -391,6 +427,10 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -443,6 +479,10 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) return MF_E_INVALIDTYPE; @@ -131,13 +130,13 @@ index 33350fb3566..8405f3bedc5 100644 if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; -@@ -410,6 +450,21 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -462,6 +502,21 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i converter->output_type = NULL; } + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } + @@ -146,32 +145,31 @@ index 33350fb3566..8405f3bedc5 100644 + struct wg_format input_format; + mf_media_type_to_wg_format(converter->input_type, &input_format); + -+ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) -+ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) ++ converter->stream = wg_parser_get_stream(converter->parser, 0); + } + LeaveCriticalSection(&converter->cs); return hr; -@@ -521,17 +576,221 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME +@@ -574,17 +629,218 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { -- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); +- FIXME("%p, %lu, %p, %#lx.\n", iface, id, sample, flags); + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); + IMFMediaBuffer *buffer = NULL; + unsigned char *buffer_data; + DWORD buffer_size; + uint64_t offset; + uint32_t size; -+ void *data; + HRESULT hr; - return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ TRACE("%p, %lu, %p, %#lx.\n", iface, id, sample, flags); + + if (flags) -+ WARN("Unsupported flags %#x.\n", flags); ++ WARN("Unsupported flags %#lx.\n", flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; @@ -198,12 +196,10 @@ index 33350fb3566..8405f3bedc5 100644 + + for (;;) + { -+ if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) ++ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) + continue; + -+ memcpy(data, buffer_data, min(buffer_size, size)); -+ -+ unix_funcs->wg_parser_complete_read_request(converter->parser, WG_READ_SUCCESS, buffer_size); ++ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); + + if (buffer_size <= size) + break; @@ -229,7 +225,7 @@ index 33350fb3566..8405f3bedc5 100644 static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { -- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); +- FIXME("%p, %#lx, %lu, %p, %p.\n", iface, flags, count, samples, status); + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); + IMFSample *allocated_sample = NULL; + IMFMediaBuffer *buffer = NULL; @@ -239,10 +235,10 @@ index 33350fb3566..8405f3bedc5 100644 + HRESULT hr = S_OK; - return E_NOTIMPL; -+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ TRACE("%p, %#lx, %lu, %p, %p.\n", iface, flags, count, samples, status); + + if (flags) -+ WARN("Unsupported flags %#x.\n", flags); ++ WARN("Unsupported flags %#lx.\n", flags); + + if (!count) + return S_OK; @@ -269,7 +265,7 @@ index 33350fb3566..8405f3bedc5 100644 + + for (;;) + { -+ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ wg_parser_stream_get_event(converter->stream, &event); + + switch (event.type) + { @@ -280,7 +276,7 @@ index 33350fb3566..8405f3bedc5 100644 + continue; + + default: -+ WARN("Unexpected event, %u\n", event.type); ++ WARN("Unexpected event, %lu\n", event.type); + continue; + } + break; @@ -290,13 +286,13 @@ index 33350fb3566..8405f3bedc5 100644 + { + if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) + { -+ ERR("Failed to create buffer, hr %#x.\n", hr); ++ ERR("Failed to create buffer, hr %#lx.\n", hr); + goto done; + } + + if (FAILED(hr = MFCreateSample(&allocated_sample))) + { -+ ERR("Failed to create sample, hr %#x.\n", hr); ++ ERR("Failed to create sample, hr %#lx.\n", hr); + goto done; + } + @@ -304,7 +300,7 @@ index 33350fb3566..8405f3bedc5 100644 + + if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) + { -+ ERR("Failed to add buffer, hr %#x.\n", hr); ++ ERR("Failed to add buffer, hr %#lx.\n", hr); + goto done; + } + @@ -314,19 +310,19 @@ index 33350fb3566..8405f3bedc5 100644 + + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) + { -+ ERR("Failed to get buffer from sample, hr %#x.\n", hr); ++ ERR("Failed to get buffer from sample, hr %#lx.\n", hr); + goto done; + } + + if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) + { -+ ERR("Failed to get buffer size, hr %#x.\n", hr); ++ ERR("Failed to get buffer size, hr %#lx.\n", hr); + goto done; + } + + if (buffer_len < event.u.buffer.size) + { -+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", ++ WARN("Client's buffer is smaller (%lu bytes) than the output sample (%lu bytes)\n", + buffer_len, event.u.buffer.size); + + hr = MF_E_BUFFERTOOSMALL; @@ -335,17 +331,17 @@ index 33350fb3566..8405f3bedc5 100644 + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + { -+ ERR("Failed to set size, hr %#x.\n", hr); ++ ERR("Failed to set size, hr %#lx.\n", hr); + goto done; + } + + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + { -+ ERR("Failed to lock buffer hr %#x.\n", hr); ++ ERR("Failed to lock buffer hr %#lx.\n", hr); + goto done; + } + -+ if (!unix_funcs->wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) ++ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) + { + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); @@ -355,7 +351,7 @@ index 33350fb3566..8405f3bedc5 100644 + + IMFMediaBuffer_Unlock(buffer); + -+ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ wg_parser_stream_release_buffer(converter->stream); + converter->buffer_inflight = FALSE; + + if (converter->buffer_pts != -1) @@ -379,11 +375,11 @@ index 33350fb3566..8405f3bedc5 100644 } static const IMFTransformVtbl audio_converter_vtbl = -@@ -579,6 +838,13 @@ HRESULT audio_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); +@@ -645,6 +901,13 @@ HRESULT audio_converter_create(REFIID riid, void **ret) + return hr; + } -+ if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) ++ if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true))) + { + ERR("Failed to create audio converter due to GStreamer error.\n"); + IMFTransform_Release(&object->IMFTransform_iface); @@ -393,32 +389,30 @@ index 33350fb3566..8405f3bedc5 100644 *ret = &object->IMFTransform_iface; return S_OK; } -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 6407aff484c..ee6d19e74b6 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -203,6 +203,7 @@ struct unix_funcs - struct wg_parser *(CDECL *wg_avi_parser_create)(void); - struct wg_parser *(CDECL *wg_mpeg_audio_parser_create)(void); - struct wg_parser *(CDECL *wg_wave_parser_create)(void); -+ struct wg_parser *(CDECL *wg_raw_media_converter_create)(void); - void (CDECL *wg_parser_destroy)(struct wg_parser *parser); +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index e5d87716734..df5e48ef3c9 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -160,6 +160,7 @@ enum wg_parser_type + WG_PARSER_AVIDEMUX, + WG_PARSER_MPEGAUDIOPARSE, + WG_PARSER_WAVPARSE, ++ WG_PARSER_AUDIOCONV, + }; - HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); + struct wg_parser_create_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 528e30098fb..23a170f6f74 100644 +index 3d6202a209a..ee59951d2de 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -2327,6 +2327,89 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) +@@ -2327,6 +2327,66 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) return TRUE; } -+static BOOL raw_media_converter_init_gst(struct wg_parser *parser) ++static BOOL audio_convert_init_gst(struct wg_parser *parser) +{ -+ BOOL video = parser->input_format.major_type == WG_MAJOR_TYPE_VIDEO; + struct wg_parser_stream *stream; + GstElement *convert, *resampler; -+ GstPad *their_src; + int ret; + + if (parser->seekable) @@ -427,45 +421,22 @@ index 528e30098fb..23a170f6f74 100644 + if (parser->expected_stream_count != 1) + return FALSE; + -+ if (video) -+ { -+ if (!(convert = gst_element_factory_make("videoconvert", NULL))) -+ { -+ GST_ERROR("Failed to create videoconvert; are %u-bit GStreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void*)); -+ return FALSE; -+ } ++ if (parser->input_format.major_type != WG_MAJOR_TYPE_AUDIO) ++ return FALSE; + -+ gst_bin_add(GST_BIN(parser->container), convert); ++ if (!(convert = create_element("audioconvert", "base"))) ++ return FALSE; + -+ parser->their_sink = gst_element_get_static_pad(convert, "sink"); -+ their_src = gst_element_get_static_pad(convert, "src"); -+ } -+ else -+ { -+ if (!(convert = gst_element_factory_make("audioconvert", NULL))) -+ { -+ GST_ERROR("Failed to create audioconvert; are %u-bit GStreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void*)); -+ return FALSE; -+ } ++ gst_bin_add(GST_BIN(parser->container), convert); + -+ gst_bin_add(GST_BIN(parser->container), convert); ++ if (!(resampler = create_element("audioresample", "base"))) ++ return FALSE; + -+ if (!(resampler = gst_element_factory_make("audioresample", NULL))) -+ { -+ GST_ERROR("Failed to create audioresample; are %u-bit GStreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void*)); -+ return FALSE; -+ } ++ gst_bin_add(GST_BIN(parser->container), resampler); + -+ gst_bin_add(GST_BIN(parser->container), resampler); -+ -+ gst_element_link(convert, resampler); -+ parser->their_sink = gst_element_get_static_pad(convert, "sink"); -+ their_src = gst_element_get_static_pad(resampler, "src"); -+ } ++ gst_element_link(convert, resampler); + ++ parser->their_sink = gst_element_get_static_pad(convert, "sink"); + if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) + { + GST_ERROR("Failed to link sink pads, error %d.\n", ret); @@ -475,15 +446,17 @@ index 528e30098fb..23a170f6f74 100644 + if (!(stream = create_stream(parser))) + return FALSE; + -+ stream->their_src = their_src; ++ stream->their_src = gst_element_get_static_pad(resampler, "src"); + gst_object_ref(stream->their_src); + if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) + { + GST_ERROR("Failed to link source pads, error %d.\n", ret); + return FALSE; + } -+ + gst_pad_set_active(stream->my_sink, 1); ++ ++ parser->no_more_pads = true; ++ + gst_element_set_state(parser->container, GST_STATE_PAUSED); + gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); @@ -496,33 +469,17 @@ index 528e30098fb..23a170f6f74 100644 + return TRUE; +} + - static struct wg_parser *wg_parser_create(void) + static void init_gstreamer_once(void) { - struct wg_parser *parser; -@@ -2380,6 +2463,15 @@ static struct wg_parser * CDECL wg_wave_parser_create(void) - return parser; - } + char arg0[] = "wine"; +@@ -2373,6 +2433,7 @@ static NTSTATUS wg_parser_create(void *args) + [WG_PARSER_AVIDEMUX] = avi_parser_init_gst, + [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, + [WG_PARSER_WAVPARSE] = wave_parser_init_gst, ++ [WG_PARSER_AUDIOCONV] = audio_convert_init_gst, + }; -+static struct wg_parser * CDECL wg_raw_media_converter_create(void) -+{ -+ struct wg_parser *parser; -+ -+ if ((parser = wg_parser_create())) -+ parser->init_gst = raw_media_converter_init_gst; -+ return parser; -+} -+ - static void CDECL wg_parser_destroy(struct wg_parser *parser) - { - if (parser->bus) -@@ -2402,6 +2494,7 @@ static const struct unix_funcs funcs = - wg_avi_parser_create, - wg_mpeg_audio_parser_create, - wg_wave_parser_create, -+ wg_raw_media_converter_create, - wg_parser_destroy, - - wg_parser_connect, + static pthread_once_t once = PTHREAD_ONCE_INIT; -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch b/patches/mfplat-streaming-support/0049-winegstreamer-Implement-Process-Input-Output-for-col.patch similarity index 66% rename from patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch rename to patches/mfplat-streaming-support/0049-winegstreamer-Implement-Process-Input-Output-for-col.patch index 723f3b1b..b82f803d 100644 --- a/patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch +++ b/patches/mfplat-streaming-support/0049-winegstreamer-Implement-Process-Input-Output-for-col.patch @@ -1,16 +1,17 @@ -From 3cdb8459f2b63eb17885bdaba1aaa039913a3eb1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 16:49:13 -0400 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for color - conversion transform. +From f0c91d2a459177e0abb5d26d54a87d27276e554c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 13:30:39 +0100 +Subject: [PATCH 49/88] winegstreamer: Implement ::Process(Input/Output) for + color conversion transform. -Signed-off-by: Derek Lesho --- - dlls/winegstreamer/colorconvert.c | 279 +++++++++++++++++++++++++++++- - 1 file changed, 274 insertions(+), 5 deletions(-) + dlls/winegstreamer/colorconvert.c | 276 +++++++++++++++++++++++++++++- + dlls/winegstreamer/unixlib.h | 1 + + dlls/winegstreamer/wg_parser.c | 54 ++++++ + 3 files changed, 326 insertions(+), 5 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index e001c6c827e..a543b9d77af 100644 +index baf429d42f9..99788bf7f92 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -51,6 +51,10 @@ struct color_converter @@ -29,13 +30,13 @@ index e001c6c827e..a543b9d77af 100644 if (transform->output_type) IMFMediaType_Release(transform->output_type); + if (transform->stream) -+ unix_funcs->wg_parser_disconnect(transform->parser); ++ wg_parser_disconnect(transform->parser); + if (transform->parser) -+ unix_funcs->wg_parser_destroy(transform->parser); ++ wg_parser_destroy(transform->parser); free(transform); } -@@ -263,6 +271,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -319,6 +327,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); UINT64 input_framesize, output_framesize; GUID major_type, subtype; @@ -43,19 +44,19 @@ index e001c6c827e..a543b9d77af 100644 unsigned int i; HRESULT hr; -@@ -280,6 +289,11 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -336,6 +345,11 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id if (converter->input_type) { + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } IMFMediaType_Release(converter->input_type); converter->input_type = NULL; } -@@ -319,6 +333,10 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -375,6 +389,10 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id LeaveCriticalSection(&converter->cs); @@ -66,13 +67,13 @@ index e001c6c827e..a543b9d77af 100644 if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; -@@ -338,6 +356,21 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id +@@ -394,6 +412,21 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id converter->input_type = NULL; } + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } + @@ -81,14 +82,14 @@ index e001c6c827e..a543b9d77af 100644 + struct wg_format output_format; + mf_media_type_to_wg_format(converter->output_type, &output_format); + -+ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) -+ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) ++ converter->stream = wg_parser_get_stream(converter->parser, 0); + } + LeaveCriticalSection(&converter->cs); return hr; -@@ -348,6 +381,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -404,6 +437,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); UINT64 input_framesize, output_framesize; GUID major_type, subtype; @@ -96,19 +97,19 @@ index e001c6c827e..a543b9d77af 100644 unsigned int i; HRESULT hr; -@@ -365,6 +399,11 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -421,6 +455,11 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i if (converter->output_type) { + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } IMFMediaType_Release(converter->output_type); converter->output_type = NULL; } -@@ -404,6 +443,10 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -460,6 +499,10 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i LeaveCriticalSection(&converter->cs); @@ -119,13 +120,13 @@ index e001c6c827e..a543b9d77af 100644 if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; -@@ -423,9 +466,24 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i +@@ -479,9 +522,24 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i converter->output_type = NULL; } + if (converter->stream) + { -+ unix_funcs->wg_parser_disconnect(converter->parser); ++ wg_parser_disconnect(converter->parser); + converter->stream = NULL; + } + @@ -134,8 +135,8 @@ index e001c6c827e..a543b9d77af 100644 + struct wg_format input_format; + mf_media_type_to_wg_format(converter->input_type, &input_format); + -+ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) -+ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) ++ converter->stream = wg_parser_get_stream(converter->parser, 0); + } + LeaveCriticalSection(&converter->cs); @@ -145,7 +146,7 @@ index e001c6c827e..a543b9d77af 100644 } static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -@@ -479,17 +537,221 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME +@@ -567,17 +625,218 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { @@ -156,7 +157,6 @@ index e001c6c827e..a543b9d77af 100644 + DWORD buffer_size; + uint64_t offset; + uint32_t size; -+ void *data; + HRESULT hr; - return E_NOTIMPL; @@ -190,12 +190,10 @@ index e001c6c827e..a543b9d77af 100644 + + for (;;) + { -+ if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) ++ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) + continue; + -+ memcpy(data, buffer_data, min(buffer_size, size)); -+ -+ unix_funcs->wg_parser_complete_read_request(converter->parser, WG_READ_SUCCESS, buffer_size); ++ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); + + if (buffer_size <= size) + break; @@ -261,7 +259,7 @@ index e001c6c827e..a543b9d77af 100644 + + for (;;) + { -+ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ wg_parser_stream_get_event(converter->stream, &event); + + switch (event.type) + { @@ -337,7 +335,7 @@ index e001c6c827e..a543b9d77af 100644 + goto done; + } + -+ if (!unix_funcs->wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) ++ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) + { + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); @@ -347,7 +345,7 @@ index e001c6c827e..a543b9d77af 100644 + + IMFMediaBuffer_Unlock(buffer); + -+ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ wg_parser_stream_release_buffer(converter->stream); + converter->buffer_inflight = FALSE; + + if (converter->buffer_pts != -1) @@ -371,11 +369,11 @@ index e001c6c827e..a543b9d77af 100644 } static const IMFTransformVtbl color_converter_vtbl = -@@ -537,6 +799,13 @@ HRESULT color_converter_create(REFIID riid, void **ret) +@@ -625,6 +884,13 @@ HRESULT color_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); -+ if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) ++ if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true))) + { + ERR("Failed to create video converter due to GStreamer error.\n"); + IMFTransform_Release(&object->IMFTransform_iface); @@ -385,6 +383,90 @@ index e001c6c827e..a543b9d77af 100644 *ret = &object->IMFTransform_iface; return S_OK; } +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index df5e48ef3c9..17b5c606014 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -161,6 +161,7 @@ enum wg_parser_type + WG_PARSER_MPEGAUDIOPARSE, + WG_PARSER_WAVPARSE, + WG_PARSER_AUDIOCONV, ++ WG_PARSER_VIDEOCONV, + }; + + struct wg_parser_create_params +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index ee59951d2de..06e07b874bf 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -2387,6 +2387,59 @@ static BOOL audio_convert_init_gst(struct wg_parser *parser) + return TRUE; + } + ++static BOOL video_convert_init_gst(struct wg_parser *parser) ++{ ++ struct wg_parser_stream *stream; ++ GstElement *convert; ++ int ret; ++ ++ if (parser->seekable) ++ return FALSE; ++ ++ if (parser->expected_stream_count != 1) ++ return FALSE; ++ ++ if (parser->input_format.major_type != WG_MAJOR_TYPE_VIDEO) ++ return FALSE; ++ ++ if (!(convert = create_element("videoconvert", "base"))) ++ return FALSE; ++ ++ gst_bin_add(GST_BIN(parser->container), convert); ++ ++ parser->their_sink = gst_element_get_static_pad(convert, "sink"); ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) ++ { ++ GST_ERROR("Failed to link sink pads, error %d.\n", ret); ++ return FALSE; ++ } ++ ++ if (!(stream = create_stream(parser))) ++ return FALSE; ++ ++ stream->their_src = gst_element_get_static_pad(convert, "src"); ++ gst_object_ref(stream->their_src); ++ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) ++ { ++ GST_ERROR("Failed to link source pads, error %d.\n", ret); ++ return FALSE; ++ } ++ gst_pad_set_active(stream->my_sink, 1); ++ ++ parser->no_more_pads = true; ++ ++ gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ gst_pad_set_active(parser->my_src, 1); ++ ret = gst_element_get_state(parser->container, NULL, NULL, -1); ++ if (ret == GST_STATE_CHANGE_FAILURE) ++ { ++ GST_ERROR("Failed to play stream.\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static void init_gstreamer_once(void) + { + char arg0[] = "wine"; +@@ -2434,6 +2487,7 @@ static NTSTATUS wg_parser_create(void *args) + [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, + [WG_PARSER_WAVPARSE] = wave_parser_init_gst, + [WG_PARSER_AUDIOCONV] = audio_convert_init_gst, ++ [WG_PARSER_VIDEOCONV] = video_convert_init_gst, + }; + + static pthread_once_t once = PTHREAD_ONCE_INIT; -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0050-winegstreamer-Implement-MF_SD_LANGUAGE.patch b/patches/mfplat-streaming-support/0050-winegstreamer-Implement-MF_SD_LANGUAGE.patch new file mode 100644 index 00000000..23a956d5 --- /dev/null +++ b/patches/mfplat-streaming-support/0050-winegstreamer-Implement-MF_SD_LANGUAGE.patch @@ -0,0 +1,184 @@ +From 3d8fddbac3026e1eed86f718452f833ac2d6b5c6 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 15:25:17 -0400 +Subject: [PATCH 50/88] winegstreamer: Implement MF_SD_LANGUAGE. + +--- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/main.c | 12 ++++++++++++ + dlls/winegstreamer/media_source.c | 20 +++++++++++++++++++- + dlls/winegstreamer/unixlib.h | 8 ++++++++ + dlls/winegstreamer/wg_parser.c | 30 ++++++++++++++++++++++++++++++ + 5 files changed, 70 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 6e7c53782c8..49879fe416d 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -94,6 +94,7 @@ void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, + + /* Returns the duration in 100-nanosecond units. */ + uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); ++bool wg_parser_stream_get_language(struct wg_parser_stream *stream, char *buffer, uint32_t size); + /* start_pos and stop_pos are in 100-nanosecond units. */ + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 316becdbc97..a9a9c72136d 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -253,6 +253,18 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) + return params.duration; + } + ++bool wg_parser_stream_get_language(struct wg_parser_stream *stream, char *buffer, uint32_t size) ++{ ++ struct wg_parser_stream_get_language_params params = ++ { ++ .stream = stream, ++ .buffer = buffer, ++ .size = size, ++ }; ++ ++ return !__wine_unix_call(unix_handle, unix_wg_parser_stream_get_language, ¶ms); ++} ++ + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) + { +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index fd6479d9879..11040ac159a 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -1492,7 +1492,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ + descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); + for (i = 0; i < object->stream_count; i++) + { +- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); ++ IMFStreamDescriptor **descriptor = &descriptors[object->stream_count - 1 - i]; ++ char language[128]; ++ DWORD language_len; ++ WCHAR *languageW; ++ ++ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); ++ ++ if (wg_parser_stream_get_language(object->streams[i]->wg_stream, language, sizeof(language))) ++ { ++ if ((language_len = MultiByteToWideChar(CP_UTF8, 0, language, -1, NULL, 0))) ++ { ++ languageW = malloc(language_len * sizeof(WCHAR)); ++ if (MultiByteToWideChar(CP_UTF8, 0, language, -1, languageW, language_len)) ++ { ++ IMFStreamDescriptor_SetString(*descriptor, &MF_SD_LANGUAGE, languageW); ++ } ++ free(languageW); ++ } ++ } + } + + if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 17b5c606014..fdcecfc96d5 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -254,6 +254,13 @@ struct wg_parser_stream_get_duration_params + UINT64 duration; + }; + ++struct wg_parser_stream_get_language_params ++{ ++ struct wg_parser_stream *stream; ++ char *buffer; ++ UINT32 size; ++}; ++ + struct wg_parser_stream_seek_params + { + struct wg_parser_stream *stream; +@@ -290,6 +297,7 @@ enum unix_funcs + unix_wg_parser_stream_notify_qos, + + unix_wg_parser_stream_get_duration, ++ unix_wg_parser_stream_get_language, + unix_wg_parser_stream_seek, + + unix_wg_parser_stream_drain, +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 06e07b874bf..dc655b275bd 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -110,6 +110,7 @@ struct wg_parser_stream + bool flushing, eos, enabled, has_caps; + + uint64_t duration; ++ gchar *language_code; + }; + + static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) +@@ -871,6 +872,14 @@ static NTSTATUS wg_parser_stream_get_duration(void *args) + return S_OK; + } + ++static NTSTATUS wg_parser_stream_get_language(void *args) ++{ ++ struct wg_parser_stream_get_language_params *params = args; ++ if (params->stream->language_code) ++ lstrcpynA(params->buffer, params->stream->language_code, params->size); ++ return params->stream->language_code ? S_OK : E_FAIL; ++} ++ + static NTSTATUS wg_parser_stream_seek(void *args) + { + GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; +@@ -1321,6 +1330,9 @@ static void free_stream(struct wg_parser_stream *stream) + pthread_cond_destroy(&stream->event_cond); + pthread_cond_destroy(&stream->event_empty_cond); + ++ if (stream->language_code) ++ g_free(stream->language_code); ++ + free(stream); + } + +@@ -1931,6 +1943,22 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) + return ret; + } + ++static gchar *query_language(GstPad *pad) ++{ ++ GstTagList *tag_list; ++ GstEvent *tag_event; ++ gchar *ret = NULL; ++ ++ if ((tag_event = gst_pad_get_sticky_event(pad, GST_EVENT_TAG, 0))) ++ { ++ gst_event_parse_tag(tag_event, &tag_list); ++ gst_tag_list_get_string(tag_list, "language-code", &ret); ++ gst_event_unref(tag_event); ++ } ++ ++ return ret; ++} ++ + static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + { + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", +@@ -2066,6 +2094,7 @@ static NTSTATUS wg_parser_connect(void *args) + pthread_cond_wait(&parser->init_cond, &parser->mutex); + } + } ++ stream->language_code = query_language(stream->their_src); + } + + pthread_mutex_unlock(&parser->mutex); +@@ -2561,6 +2590,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + X(wg_parser_stream_notify_qos), + + X(wg_parser_stream_get_duration), ++ X(wg_parser_stream_get_language), + X(wg_parser_stream_seek), + + X(wg_parser_stream_drain), +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0036-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch b/patches/mfplat-streaming-support/0051-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch similarity index 73% rename from patches/mfplat-streaming-support/0036-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch rename to patches/mfplat-streaming-support/0051-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch index 8ed22672..3e973515 100644 --- a/patches/mfplat-streaming-support/0036-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch +++ b/patches/mfplat-streaming-support/0051-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch @@ -1,17 +1,16 @@ -From f826d9a7343317ecf12b2eccd9525ed74df85610 Mon Sep 17 00:00:00 2001 +From 39b907ca8de07e2bc78f173083fea717970847a2 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 22 Mar 2021 15:50:51 -0400 -Subject: [PATCH] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for media - converters. +Subject: [PATCH 51/88] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for + media converters. -Signed-off-by: Derek Lesho --- dlls/winegstreamer/audioconvert.c | 20 ++++++++++++++++++++ dlls/winegstreamer/colorconvert.c | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 1584fefe577..df471122b9e 100644 +index e7c1fb97f23..f8d5833aa22 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -614,11 +614,31 @@ static HRESULT WINAPI audio_converter_ProcessEvent(IMFTransform *iface, DWORD id @@ -21,7 +20,7 @@ index 1584fefe577..df471122b9e 100644 + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); + struct wg_parser_event event; + - TRACE("%p, %u %lu.\n", iface, message, param); + TRACE("%p, %u, %Iu.\n", iface, message, param); switch(message) { @@ -35,9 +34,9 @@ index 1584fefe577..df471122b9e 100644 + } + + while (event.type != WG_PARSER_EVENT_BUFFER) -+ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ wg_parser_stream_get_event(converter->stream, &event); + -+ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ wg_parser_stream_release_buffer(converter->stream); + converter->buffer_inflight = FALSE; + + LeaveCriticalSection(&converter->cs); @@ -47,10 +46,10 @@ index 1584fefe577..df471122b9e 100644 return S_OK; default: diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 6f3723b2b1e..947ef9adacb 100644 +index 99788bf7f92..6cad0c1706d 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -586,11 +586,31 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id +@@ -610,11 +610,31 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { @@ -71,9 +70,9 @@ index 6f3723b2b1e..947ef9adacb 100644 + } + + while (event.type != WG_PARSER_EVENT_BUFFER) -+ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ wg_parser_stream_get_event(converter->stream, &event); + -+ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ wg_parser_stream_release_buffer(converter->stream); + converter->buffer_inflight = FALSE; + + LeaveCriticalSection(&converter->cs); @@ -82,17 +81,17 @@ index 6f3723b2b1e..947ef9adacb 100644 case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: return S_OK; default: -@@ -641,7 +661,10 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id +@@ -664,7 +684,10 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id for (;;) { - if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) + if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) + { + TRACE("sink unconnected\n"); continue; + } - memcpy(data, buffer_data, min(buffer_size, size)); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0052-winegstreamer-Add-videobox-element-and-aperture-supp.patch b/patches/mfplat-streaming-support/0052-winegstreamer-Add-videobox-element-and-aperture-supp.patch new file mode 100644 index 00000000..edd37f2a --- /dev/null +++ b/patches/mfplat-streaming-support/0052-winegstreamer-Add-videobox-element-and-aperture-supp.patch @@ -0,0 +1,376 @@ +From 4f6593d81e43fc0b8e06019e1931f9791856c184 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 15 Dec 2021 10:30:26 +0100 +Subject: [PATCH 52/88] winegstreamer: Add videobox element and aperture + support. + +--- + dlls/winegstreamer/audioconvert.c | 4 +-- + dlls/winegstreamer/colorconvert.c | 4 +-- + dlls/winegstreamer/decode_transform.c | 23 ++++++++++++++- + dlls/winegstreamer/gst_private.h | 4 +-- + dlls/winegstreamer/main.c | 6 ++-- + dlls/winegstreamer/media_source.c | 2 +- + dlls/winegstreamer/quartz_parser.c | 2 +- + dlls/winegstreamer/unixlib.h | 10 +++++++ + dlls/winegstreamer/wg_parser.c | 42 +++++++++++++++++++++++++-- + dlls/winegstreamer/wm_reader.c | 6 ++-- + 10 files changed, 86 insertions(+), 17 deletions(-) + +diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c +index f8d5833aa22..28d449e9f9b 100644 +--- a/dlls/winegstreamer/audioconvert.c ++++ b/dlls/winegstreamer/audioconvert.c +@@ -417,7 +417,7 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id + struct wg_format output_format; + mf_media_type_to_wg_format(converter->output_type, &output_format); + +- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) + converter->stream = wg_parser_get_stream(converter->parser, 0); + } + +@@ -513,7 +513,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + struct wg_format input_format; + mf_media_type_to_wg_format(converter->input_type, &input_format); + +- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) + converter->stream = wg_parser_get_stream(converter->parser, 0); + } + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index 6cad0c1706d..476851fa43a 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -423,7 +423,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + struct wg_format output_format; + mf_media_type_to_wg_format(converter->output_type, &output_format); + +- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) + converter->stream = wg_parser_get_stream(converter->parser, 0); + } + +@@ -533,7 +533,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i + struct wg_format input_format; + mf_media_type_to_wg_format(converter->input_type, &input_format); + +- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) ++ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) + converter->stream = wg_parser_get_stream(converter->parser, 0); + } + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index 6f1363ff1f3..04d46a73c3d 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -641,6 +641,9 @@ static DWORD CALLBACK helper_thread_func(PVOID ctx) + case HELP_REQ_START_PARSER: + { + struct wg_format input_format, output_format; ++ struct wg_rect wg_aperture = {0}; ++ MFVideoArea *aperture = NULL; ++ UINT32 aperture_size; + + decoder->help_request.type = HELP_REQ_NONE; + LeaveCriticalSection(&decoder->help_cs); +@@ -648,7 +651,25 @@ static DWORD CALLBACK helper_thread_func(PVOID ctx) + mf_media_type_to_wg_format(decoder->input_type, &input_format); + mf_media_type_to_wg_format(decoder->output_type, &output_format); + +- wg_parser_connect_unseekable(decoder->wg_parser, &input_format, 1, &output_format); ++ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type, ++ &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size))) ++ { ++ TRACE("Decoded media's aperture: x: %u %u/65536, y: %u %u/65536, area: %u x %u\n", ++ aperture->OffsetX.value, aperture->OffsetX.fract, ++ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy); ++ ++ /* TODO: verify aperture params? */ ++ ++ wg_aperture.left = aperture->OffsetX.value; ++ wg_aperture.top = aperture->OffsetY.value; ++ wg_aperture.right = aperture->Area.cx; ++ wg_aperture.bottom = aperture->Area.cy; ++ ++ CoTaskMemFree(aperture); ++ } ++ ++ wg_parser_connect_unseekable(decoder->wg_parser, ++ &input_format, 1, &output_format, aperture ? &wg_aperture : NULL); + + EnterCriticalSection(&decoder->event_cs); + while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 49879fe416d..f1c7bc60428 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -69,7 +69,7 @@ void wg_parser_destroy(struct wg_parser *parser); + + HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); + HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, +- uint32_t stream_count, const struct wg_format *out_formats); ++ uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures); + void wg_parser_disconnect(struct wg_parser *parser); + + void wg_parser_begin_flush(struct wg_parser *parser); +@@ -82,7 +82,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser); + struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index); + + void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format); +-void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format); ++void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture); + void wg_parser_stream_disable(struct wg_parser_stream *stream); + + bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index a9a9c72136d..74f0dd04e83 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -92,7 +92,7 @@ HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) + } + + HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, +- uint32_t stream_count, const struct wg_format *out_formats) ++ uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures) + { + struct wg_parser_connect_unseekable_params params = + { +@@ -100,6 +100,7 @@ HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_f + .in_format = in_format, + .stream_count = stream_count, + .out_formats = out_formats, ++ .apertures = apertures, + }; + + return __wine_unix_call(unix_handle, unix_wg_parser_connect_unseekable, ¶ms); +@@ -181,12 +182,13 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru + __wine_unix_call(unix_handle, unix_wg_parser_stream_get_preferred_format, ¶ms); + } + +-void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) ++void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) + { + struct wg_parser_stream_enable_params params = + { + .stream = stream, + .format = format, ++ .aperture = aperture, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_enable, ¶ms); +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index 11040ac159a..e5f25eed63a 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -358,7 +358,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm + IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); + + mf_media_type_to_wg_format(current_mt, &format); +- wg_parser_stream_enable(stream->wg_stream, &format); ++ wg_parser_stream_enable(stream->wg_stream, &format, NULL); + + IMFMediaType_Release(current_mt); + IMFMediaTypeHandler_Release(mth); +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index c44bd141c56..c03f4deca30 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -1528,7 +1528,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, + + ret = amt_to_wg_format(&pin->pin.pin.mt, &format); + assert(ret); +- wg_parser_stream_enable(pin->wg_stream, &format); ++ wg_parser_stream_enable(pin->wg_stream, &format, NULL); + + /* We do need to drop any buffers that might have been sent with the old + * caps, but this will be handled in parser_init_stream(). */ +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index fdcecfc96d5..5946621fb9d 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -117,6 +117,14 @@ struct wg_format + } u; + }; + ++struct wg_rect ++{ ++ uint32_t left; ++ uint32_t right; ++ uint32_t top; ++ uint32_t bottom; ++}; ++ + enum wg_parser_event_type + { + WG_PARSER_EVENT_NONE = 0, +@@ -183,6 +191,7 @@ struct wg_parser_connect_unseekable_params + const struct wg_format *in_format; + UINT32 stream_count; + const struct wg_format *out_formats; ++ const struct wg_rect *apertures; + }; + + struct wg_parser_get_next_read_offset_params +@@ -223,6 +232,7 @@ struct wg_parser_stream_enable_params + { + struct wg_parser_stream *stream; + const struct wg_format *format; ++ const struct wg_rect *aperture; + }; + + struct wg_parser_stream_get_event_params +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index dc655b275bd..f699ab21837 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -98,9 +98,10 @@ struct wg_parser_stream + struct wg_parser *parser; + + GstPad *their_src, *post_sink, *post_src, *my_sink; +- GstElement *flip; ++ GstElement *flip, *box; + GstSegment segment; + struct wg_format preferred_format, current_format; ++ struct wg_rect aperture; + + pthread_cond_t event_cond, event_empty_cond; + struct wg_parser_event event; +@@ -730,6 +731,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) + const struct wg_parser_stream_enable_params *params = args; + struct wg_parser_stream *stream = params->stream; + const struct wg_format *format = params->format; ++ const struct wg_rect *aperture = params->aperture; + + if (!stream->parser->seekable) + return S_OK; +@@ -765,6 +767,18 @@ static NTSTATUS wg_parser_stream_enable(void *args) + } + + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); ++ ++ if (aperture) ++ { ++ if (aperture->left) ++ g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); ++ if (aperture->top) ++ g_object_set(G_OBJECT(stream->box), "top", -aperture->top, NULL); ++ if (aperture->right) ++ g_object_set(G_OBJECT(stream->box), "right", aperture->right - format->u.video.width, NULL); ++ if (aperture->bottom) ++ g_object_set(G_OBJECT(stream->box), "bottom", aperture->bottom - format->u.video.height, NULL); ++ } + } + + gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); +@@ -1357,7 +1371,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + + if (!strcmp(name, "video/x-raw")) + { +- GstElement *capssetter, *deinterlace, *vconv, *flip, *vconv2; ++ GstElement *capssetter, *deinterlace, *vconv, *flip, *box, *vconv2; + + /* Hack?: Flatten down the colorimetry to default values, without + * actually modifying the video at all. +@@ -1423,11 +1437,26 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + if (!(flip = create_element("videoflip", "good"))) + goto out; + ++ if (!(box = create_element("videbox", "base"))) ++ goto out; ++ + /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert + * to do the final conversion. */ + if (!(vconv2 = create_element("videoconvert", "base"))) + goto out; + ++ if (!parser->seekable) ++ { ++ if (stream->aperture.left) ++ g_object_set(G_OBJECT(box), "left", -stream->aperture.left, NULL); ++ if (stream->aperture.bottom) ++ g_object_set(G_OBJECT(box), "top", -stream->aperture.top, NULL); ++ if (stream->aperture.right) ++ g_object_set(G_OBJECT(box), "right", stream->aperture.right - stream->current_format.u.video.width, NULL); ++ if (stream->aperture.bottom) ++ g_object_set(G_OBJECT(box), "bottom", stream->aperture.bottom - stream->current_format.u.video.height, NULL); ++ } ++ + /* The bin takes ownership of these elements. */ + gst_bin_add(GST_BIN(parser->container), capssetter); + gst_element_sync_state_with_parent(capssetter); +@@ -1437,17 +1466,21 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + gst_element_sync_state_with_parent(vconv); + gst_bin_add(GST_BIN(parser->container), flip); + gst_element_sync_state_with_parent(flip); ++ gst_bin_add(GST_BIN(parser->container), box); ++ gst_element_sync_state_with_parent(box); + gst_bin_add(GST_BIN(parser->container), vconv2); + gst_element_sync_state_with_parent(vconv2); + + gst_element_link(capssetter, deinterlace); + gst_element_link(deinterlace, vconv); + gst_element_link(vconv, flip); +- gst_element_link(flip, vconv2); ++ gst_element_link(flip, box); ++ gst_element_link(box, vconv2); + + stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); + stream->post_src = gst_element_get_static_pad(vconv2, "src"); + stream->flip = flip; ++ stream->box = box; + } + else if (!strcmp(name, "audio/x-raw")) + { +@@ -2138,6 +2171,7 @@ static NTSTATUS wg_parser_connect_unseekable(void *args) + const struct wg_parser_connect_unseekable_params *params = args; + const struct wg_format *out_formats = params->out_formats; + const struct wg_format *in_format = params->in_format; ++ const struct wg_rect *apertures = params->apertures; + uint32_t stream_count = params->stream_count; + struct wg_parser *parser = params->parser; + unsigned int i; +@@ -2160,6 +2194,8 @@ static NTSTATUS wg_parser_connect_unseekable(void *args) + { + parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); + parser->streams[i]->current_format = out_formats[i]; ++ if (apertures) ++ parser->streams[i]->aperture = apertures[i]; + parser->streams[i]->enabled = true; + } + +diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c +index ee37abee811..569560d054e 100644 +--- a/dlls/winegstreamer/wm_reader.c ++++ b/dlls/winegstreamer/wm_reader.c +@@ -1509,7 +1509,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) + * video type will be BGR. */ + stream->format.u.video.format = WG_VIDEO_FORMAT_BGR; + } +- wg_parser_stream_enable(stream->wg_stream, &stream->format); ++ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); + } + + wg_parser_end_flush(reader->wg_parser); +@@ -1776,7 +1776,7 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, + } + + stream->format = format; +- wg_parser_stream_enable(stream->wg_stream, &format); ++ wg_parser_stream_enable(stream->wg_stream, &format, NULL); + + /* Re-decode any buffers that might have been generated with the old format. + * +@@ -1989,7 +1989,7 @@ HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, + FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n", + selections[i], stream_numbers[i]); + TRACE("Enabling stream %u.\n", stream_numbers[i]); +- wg_parser_stream_enable(stream->wg_stream, &stream->format); ++ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); + } + } + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch b/patches/mfplat-streaming-support/0053-winegstreamer-Only-require-videobox-element-for-pars.patch similarity index 57% rename from patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch rename to patches/mfplat-streaming-support/0053-winegstreamer-Only-require-videobox-element-for-pars.patch index c02f27f6..10763d1b 100644 --- a/patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch +++ b/patches/mfplat-streaming-support/0053-winegstreamer-Only-require-videobox-element-for-pars.patch @@ -1,19 +1,18 @@ -From 3a45e662b131c1a9864969d934cdd78de2c7bb5d Mon Sep 17 00:00:00 2001 +From 1c85ff3c7891c80fac65add4706243bb8fbc9110 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 18 Mar 2021 16:20:50 -0400 -Subject: [PATCH] winegstreamer: Only require videobox element for parser when - needed. +Subject: [PATCH 53/88] winegstreamer: Only require videobox element for parser + when needed. -Signed-off-by: Derek Lesho --- - dlls/winegstreamer/wg_parser.c | 42 ++++++++++++++++++++++++++-------- - 1 file changed, 32 insertions(+), 10 deletions(-) + dlls/winegstreamer/wg_parser.c | 38 ++++++++++++++++++++++++++++------ + 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 93bf85f719e..691abe8c48d 100644 +index f699ab21837..833671df20c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c -@@ -756,6 +756,15 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const +@@ -770,6 +770,15 @@ static NTSTATUS wg_parser_stream_enable(void *args) if (aperture) { @@ -23,31 +22,27 @@ index 93bf85f719e..691abe8c48d 100644 + { + fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"good\" plugins installed?\n", + 8 * (int)sizeof(void *)); -+ return; ++ return E_FAIL; + } + if (aperture->left) g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); if (aperture->top) -@@ -1310,12 +1319,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) +@@ -1437,8 +1446,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!(flip = create_element("videoflip", "good"))) goto out; -- if (!(videobox = gst_element_factory_make("videobox", NULL))) -- { -- fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"base\" plugins installed?\n", -- 8 * (int)sizeof(void *)); +- if (!(box = create_element("videbox", "base"))) - goto out; -- } -+ videobox = gst_element_factory_make("videobox", NULL); ++ box = gst_element_factory_make("videobox", NULL); /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert * to do the final conversion. */ -@@ -1324,6 +1328,14 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) +@@ -1447,6 +1455,14 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!parser->seekable) { -+ if (!videobox && (stream->aperture.left || stream->aperture.top || ++ if (!box && (stream->aperture.left || stream->aperture.top || + (stream->aperture.right && stream->aperture.right != stream->current_format.u.video.width) || + (stream->aperture.bottom && stream->aperture.bottom != stream->current_format.u.video.height))) + { @@ -56,38 +51,39 @@ index 93bf85f719e..691abe8c48d 100644 + goto out; + } if (stream->aperture.left) - g_object_set(G_OBJECT(videobox), "left", -stream->aperture.left, NULL); + g_object_set(G_OBJECT(box), "left", -stream->aperture.left, NULL); if (stream->aperture.bottom) -@@ -1341,15 +1353,25 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) +@@ -1466,16 +1482,26 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) gst_element_sync_state_with_parent(vconv); gst_bin_add(GST_BIN(parser->container), flip); gst_element_sync_state_with_parent(flip); -- gst_bin_add(GST_BIN(parser->container), videobox); -- gst_element_sync_state_with_parent(videobox); -+ if (videobox) +- gst_bin_add(GST_BIN(parser->container), box); +- gst_element_sync_state_with_parent(box); ++ if (box) + { -+ gst_bin_add(GST_BIN(parser->container), videobox); -+ gst_element_sync_state_with_parent(videobox); ++ gst_bin_add(GST_BIN(parser->container), box); ++ gst_element_sync_state_with_parent(box); + } gst_bin_add(GST_BIN(parser->container), vconv2); gst_element_sync_state_with_parent(vconv2); + gst_element_link(capssetter, deinterlace); gst_element_link(deinterlace, vconv); gst_element_link(vconv, flip); -- gst_element_link(flip, videobox); -- gst_element_link(videobox, vconv2); -+ if (videobox) +- gst_element_link(flip, box); +- gst_element_link(box, vconv2); ++ if (box) + { -+ gst_element_link(flip, videobox); -+ gst_element_link(videobox, vconv2); ++ gst_element_link(flip, box); ++ gst_element_link(box, vconv2); + } + else + { + gst_element_link(flip, vconv2); + } - stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); + stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); stream->post_src = gst_element_get_static_pad(vconv2, "src"); -- -2.30.2 +2.34.1 diff --git a/patches/mfplat-streaming-support/0054-winegstreamer-Feed-full-buffer-in-audio-converter-Pr.patch b/patches/mfplat-streaming-support/0054-winegstreamer-Feed-full-buffer-in-audio-converter-Pr.patch new file mode 100644 index 00000000..50980c87 --- /dev/null +++ b/patches/mfplat-streaming-support/0054-winegstreamer-Feed-full-buffer-in-audio-converter-Pr.patch @@ -0,0 +1,48 @@ +From 78f397bed7e11787011ffdb4dead4ee54a18730f Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 7 Jan 2022 10:04:49 -0600 +Subject: [PATCH 54/88] winegstreamer: Feed full buffer in audio converter + ProcessInput + +In push mode, we can ignore the size of the request. wg_parser will +forward the entire buffer to gst. + +CW-Bug-Id: #19859 +--- + dlls/winegstreamer/audioconvert.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c +index 28d449e9f9b..58daf388a30 100644 +--- a/dlls/winegstreamer/audioconvert.c ++++ b/dlls/winegstreamer/audioconvert.c +@@ -685,20 +685,15 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) + goto done; + +- for (;;) ++ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) + { +- if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) +- continue; +- +- wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); +- +- if (buffer_size <= size) +- break; +- +- buffer_data += size; +- buffer_size -= size; ++ hr = MF_E_UNEXPECTED; ++ IMFMediaBuffer_Unlock(buffer); ++ goto done; + } + ++ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size); ++ + IMFMediaBuffer_Unlock(buffer); + converter->buffer_inflight = TRUE; + if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0055-winegstreamer-Add-MFVideoFormat_ARGB32-output-for-th.patch b/patches/mfplat-streaming-support/0055-winegstreamer-Add-MFVideoFormat_ARGB32-output-for-th.patch new file mode 100644 index 00000000..a2a693bc --- /dev/null +++ b/patches/mfplat-streaming-support/0055-winegstreamer-Add-MFVideoFormat_ARGB32-output-for-th.patch @@ -0,0 +1,37 @@ +From 5ebda711a9d8b5e3194464eab3fecf52ed3c8b59 Mon Sep 17 00:00:00 2001 +From: Nikolay Sivov +Date: Wed, 12 Jan 2022 22:48:35 +0300 +Subject: [PATCH 55/88] winegstreamer: Add MFVideoFormat_ARGB32 output for the + source. + +(cherry picked from commit 9812591f0003c5c611faa59ab9b3cb73a85be637) + +CW-Bug-Id: #19975 +--- + dlls/winegstreamer/media_source.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index e5f25eed63a..9d5a8b831b9 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -873,7 +873,7 @@ static HRESULT new_media_stream(struct media_source *source, + static HRESULT media_stream_init_desc(struct media_stream *stream) + { + IMFMediaTypeHandler *type_handler = NULL; +- IMFMediaType *stream_types[6]; ++ IMFMediaType *stream_types[7]; + struct wg_format format; + DWORD type_count = 0; + unsigned int i; +@@ -892,6 +892,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) + &MFVideoFormat_YUY2, + &MFVideoFormat_IYUV, + &MFVideoFormat_I420, ++ &MFVideoFormat_ARGB32, + }; + + IMFMediaType *base_type = mf_media_type_from_wg_format(&format); +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0056-winegstreamer-Return-S_OK-from-WMA-decoder-ProcessMe.patch b/patches/mfplat-streaming-support/0056-winegstreamer-Return-S_OK-from-WMA-decoder-ProcessMe.patch new file mode 100644 index 00000000..5a7efb23 --- /dev/null +++ b/patches/mfplat-streaming-support/0056-winegstreamer-Return-S_OK-from-WMA-decoder-ProcessMe.patch @@ -0,0 +1,29 @@ +From c25b5225beb33b0a4403b296e06439c7b8e712b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 17 Jan 2022 14:06:43 +0100 +Subject: [PATCH 56/88] winegstreamer: Return S_OK from WMA decoder + ProcessMessage. + +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 +--- + dlls/winegstreamer/wma_decoder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 78316059052..847387d3c22 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -486,7 +486,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) + { + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); +- return E_NOTIMPL; ++ return S_OK; + } + + static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0057-winegstreamer-Introduce-new-wg_transform-struct.patch b/patches/mfplat-streaming-support/0057-winegstreamer-Introduce-new-wg_transform-struct.patch new file mode 100644 index 00000000..2d097431 --- /dev/null +++ b/patches/mfplat-streaming-support/0057-winegstreamer-Introduce-new-wg_transform-struct.patch @@ -0,0 +1,326 @@ +From ba6442e42f35798a759c625916ad7b58e1672eb0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 26 Jan 2022 21:24:07 +0100 +Subject: [PATCH 57/88] winegstreamer: Introduce new wg_transform struct. + +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 +--- + dlls/winegstreamer/Makefile.in | 1 + + dlls/winegstreamer/gst_private.h | 3 ++ + dlls/winegstreamer/main.c | 14 +++++++ + dlls/winegstreamer/unix_private.h | 31 ++++++++++++++ + dlls/winegstreamer/unixlib.h | 8 ++++ + dlls/winegstreamer/wg_parser.c | 20 +++++++-- + dlls/winegstreamer/wg_transform.c | 69 +++++++++++++++++++++++++++++++ + dlls/winegstreamer/wma_decoder.c | 20 +++++++++ + 8 files changed, 162 insertions(+), 4 deletions(-) + create mode 100644 dlls/winegstreamer/unix_private.h + create mode 100644 dlls/winegstreamer/wg_transform.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index 74bcc35364b..294d3b199a5 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -15,6 +15,7 @@ C_SRCS = \ + mfplat.c \ + quartz_parser.c \ + wg_parser.c \ ++ wg_transform.c \ + wm_asyncreader.c \ + wm_reader.c \ + wm_syncreader.c \ +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index f1c7bc60428..416dfae01de 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -100,6 +100,9 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); + bool wg_parser_stream_drain(struct wg_parser_stream *stream); + ++struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; ++void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; ++ + unsigned int wg_format_get_max_size(const struct wg_format *format); + + HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 74f0dd04e83..6938d111926 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -288,6 +288,20 @@ bool wg_parser_stream_drain(struct wg_parser_stream *stream) + return !__wine_unix_call(unix_handle, unix_wg_parser_stream_drain, stream); + } + ++struct wg_transform *wg_transform_create(void) ++{ ++ struct wg_transform_create_params params = {0}; ++ ++ if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) ++ return NULL; ++ return params.transform; ++} ++ ++void wg_transform_destroy(struct wg_transform *transform) ++{ ++ __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + if (reason == DLL_PROCESS_ATTACH) +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +new file mode 100644 +index 00000000000..375d33e7728 +--- /dev/null ++++ b/dlls/winegstreamer/unix_private.h +@@ -0,0 +1,31 @@ ++/* ++ * winegstreamer Unix library interface ++ * ++ * Copyright 2020-2021 Zebediah Figura 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 ++ */ ++ ++#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H ++#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H ++ ++#include "unixlib.h" ++ ++extern bool init_gstreamer(void) DECLSPEC_HIDDEN; ++ ++extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; ++extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; ++ ++#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 5946621fb9d..25e130d834a 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -279,6 +279,11 @@ struct wg_parser_stream_seek_params + DWORD start_flags, stop_flags; + }; + ++struct wg_transform_create_params ++{ ++ struct wg_transform *transform; ++}; ++ + enum unix_funcs + { + unix_wg_parser_create, +@@ -310,6 +315,9 @@ enum unix_funcs + unix_wg_parser_stream_get_language, + unix_wg_parser_stream_seek, + ++ unix_wg_transform_create, ++ unix_wg_transform_destroy, ++ + unix_wg_parser_stream_drain, + }; + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 833671df20c..b8662c4417d 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -37,7 +37,7 @@ + #include "winternl.h" + #include "dshow.h" + +-#include "unixlib.h" ++#include "unix_private.h" + + typedef enum + { +@@ -51,7 +51,7 @@ typedef enum + * debug logging instead of Wine debug logging. In order to be safe we forbid + * any use of Wine debug logging in this entire file. */ + +-GST_DEBUG_CATEGORY_STATIC(wine); ++GST_DEBUG_CATEGORY(wine); + #define GST_CAT_DEFAULT wine + + typedef BOOL (*init_gst_cb)(struct wg_parser *parser); +@@ -2569,6 +2569,16 @@ static void init_gstreamer_once(void) + gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); + } + ++bool init_gstreamer(void) ++{ ++ static pthread_once_t init_once = PTHREAD_ONCE_INIT; ++ ++ if (pthread_once(&init_once, init_gstreamer_once)) ++ return false; ++ ++ return true; ++} ++ + static NTSTATUS wg_parser_create(void *args) + { + static const init_gst_cb init_funcs[] = +@@ -2581,11 +2591,10 @@ static NTSTATUS wg_parser_create(void *args) + [WG_PARSER_VIDEOCONV] = video_convert_init_gst, + }; + +- static pthread_once_t once = PTHREAD_ONCE_INIT; + struct wg_parser_create_params *params = args; + struct wg_parser *parser; + +- if (pthread_once(&once, init_gstreamer_once)) ++ if (!init_gstreamer()) + return E_FAIL; + + if (!(parser = calloc(1, sizeof(*parser)))) +@@ -2655,5 +2664,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + X(wg_parser_stream_get_language), + X(wg_parser_stream_seek), + ++ X(wg_transform_create), ++ X(wg_transform_destroy), ++ + X(wg_parser_stream_drain), + }; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +new file mode 100644 +index 00000000000..822740da0d7 +--- /dev/null ++++ b/dlls/winegstreamer/wg_transform.c +@@ -0,0 +1,69 @@ ++/* ++ * GStreamer transform backend ++ * ++ * 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 ++ */ ++ ++#if 0 ++#pragma makedep unix ++#endif ++ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "winternl.h" ++#include "dshow.h" ++ ++#include "unix_private.h" ++ ++GST_DEBUG_CATEGORY_EXTERN(wine); ++#define GST_CAT_DEFAULT wine ++ ++struct wg_transform ++{ ++}; ++ ++NTSTATUS wg_transform_destroy(void *args) ++{ ++ struct wg_transform *transform = args; ++ ++ free(transform); ++ return S_OK; ++} ++ ++NTSTATUS wg_transform_create(void *args) ++{ ++ struct wg_transform_create_params *params = args; ++ struct wg_transform *transform; ++ ++ if (!init_gstreamer()) ++ return E_FAIL; ++ ++ if (!(transform = calloc(1, sizeof(*transform)))) ++ return E_OUTOFMEMORY; ++ ++ GST_INFO("Created winegstreamer transform %p.", transform); ++ params->transform = transform; ++ return S_OK; ++} +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 847387d3c22..1544e8e4c9b 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -53,6 +53,8 @@ struct wma_decoder + LONG refcount; + IMFMediaType *input_type; + IMFMediaType *output_type; ++ ++ struct wg_transform *wg_transform; + }; + + static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) +@@ -60,6 +62,19 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) + return CONTAINING_RECORD(iface, struct wma_decoder, IUnknown_inner); + } + ++static HRESULT try_create_wg_transform(struct wma_decoder *decoder) ++{ ++ if (decoder->wg_transform) ++ wg_transform_destroy(decoder->wg_transform); ++ ++ decoder->wg_transform = wg_transform_create(); ++ if (decoder->wg_transform) ++ return S_OK; ++ ++ WARN("Failed to create wg_transform.\n"); ++ return E_FAIL; ++} ++ + static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) + { + struct wma_decoder *decoder = impl_from_IUnknown(iface); +@@ -104,6 +119,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) + + 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) +@@ -438,6 +455,9 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF + if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) + goto failed; + ++ if (FAILED(hr = try_create_wg_transform(decoder))) ++ goto failed; ++ + return S_OK; + + failed: +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0058-winegstreamer-Introduce-new-wg_encoded_format-struct.patch b/patches/mfplat-streaming-support/0058-winegstreamer-Introduce-new-wg_encoded_format-struct.patch new file mode 100644 index 00000000..8e9a0812 --- /dev/null +++ b/patches/mfplat-streaming-support/0058-winegstreamer-Introduce-new-wg_encoded_format-struct.patch @@ -0,0 +1,185 @@ +From 19ae522a9a7170b0d07a1f6810858020cd9d9f1e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:02:52 +0100 +Subject: [PATCH 58/88] winegstreamer: Introduce new wg_encoded_format struct. + +And use it for decoder transform input types. + +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 +--- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/mfplat.c | 84 ++++++++++++++++++++++++++++++++ + dlls/winegstreamer/unixlib.h | 25 ++++++++++ + dlls/winegstreamer/wma_decoder.c | 12 +++++ + 4 files changed, 122 insertions(+) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 416dfae01de..551dcc549c7 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -121,6 +121,7 @@ extern HRESULT mfplat_DllRegisterServer(void); + + IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format); ++void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format); + + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 54874ad43ee..ca64ce3f7b9 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -892,3 +892,87 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) + else + FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); + } ++ ++static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, ++ UINT32 version) ++{ ++ UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; ++ BYTE codec_data[64]; ++ ++ 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_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) ++ { ++ FIXME("Block alignment is not set.\n"); ++ return; ++ } ++ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) ++ { ++ FIXME("Depth is not set.\n"); ++ return; ++ } ++ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) ++ { ++ FIXME("Codec data is not set.\n"); ++ return; ++ } ++ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) ++ { ++ FIXME("Bitrate is not set.\n"); ++ bytes_per_second = 0; ++ } ++ ++ format->encoded_type = WG_ENCODED_TYPE_WMA; ++ format->u.xwma.version = version; ++ format->u.xwma.bitrate = bytes_per_second * 8; ++ format->u.xwma.rate = rate; ++ format->u.xwma.depth = depth; ++ format->u.xwma.channels = channels; ++ format->u.xwma.block_align = block_align; ++ format->u.xwma.codec_data_len = codec_data_len; ++ memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); ++} ++ ++void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) ++{ ++ GUID major_type, subtype; ++ ++ memset(format, 0, sizeof(*format)); ++ ++ if (FAILED(IMFMediaType_GetMajorType(type, &major_type))) ++ { ++ FIXME("Major type is not set.\n"); ++ return; ++ } ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ { ++ FIXME("Subtype is not set.\n"); ++ return; ++ } ++ ++ if (IsEqualGUID(&major_type, &MFMediaType_Audio)) ++ { ++ if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) ++ mf_media_type_to_wg_encoded_format_wma(type, format, 1); ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) ++ mf_media_type_to_wg_encoded_format_wma(type, format, 2); ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) ++ mf_media_type_to_wg_encoded_format_wma(type, format, 3); ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) ++ mf_media_type_to_wg_encoded_format_wma(type, format, 4); ++ else ++ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); ++ } ++ else ++ { ++ FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); ++ } ++} +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 25e130d834a..7d3eceb6a51 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -125,6 +125,31 @@ struct wg_rect + uint32_t bottom; + }; + ++struct wg_encoded_format ++{ ++ enum wg_encoded_type ++ { ++ WG_ENCODED_TYPE_UNKNOWN, ++ WG_ENCODED_TYPE_WMA, ++ WG_ENCODED_TYPE_XMA, ++ } encoded_type; ++ ++ union ++ { ++ struct ++ { ++ uint32_t version; ++ uint32_t bitrate; ++ uint32_t rate; ++ uint32_t depth; ++ uint32_t channels; ++ uint32_t block_align; ++ uint32_t codec_data_len; ++ unsigned char codec_data[64]; ++ } xwma; ++ } u; ++}; ++ + enum wg_parser_event_type + { + WG_PARSER_EVENT_NONE = 0, +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 1544e8e4c9b..2b543426524 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -64,8 +64,20 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) + + static HRESULT try_create_wg_transform(struct wma_decoder *decoder) + { ++ struct wg_encoded_format input_format; ++ struct wg_format output_format; ++ + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); ++ decoder->wg_transform = NULL; ++ ++ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); ++ if (input_format.encoded_type == WG_ENCODED_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 = wg_transform_create(); + if (decoder->wg_transform) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0059-winegstreamer-Create-static-pads-on-wg_transform-str.patch b/patches/mfplat-streaming-support/0059-winegstreamer-Create-static-pads-on-wg_transform-str.patch new file mode 100644 index 00000000..a391cacf --- /dev/null +++ b/patches/mfplat-streaming-support/0059-winegstreamer-Create-static-pads-on-wg_transform-str.patch @@ -0,0 +1,236 @@ +From 1f48e9be35754d7197b77711dc86ef0033eb381b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:22:59 +0100 +Subject: [PATCH 59/88] winegstreamer: Create static pads on wg_transform + struct. + +With caps created from the input / output formats. + +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 +--- + dlls/winegstreamer/gst_private.h | 3 +- + dlls/winegstreamer/main.c | 9 ++- + dlls/winegstreamer/unix_private.h | 1 + + dlls/winegstreamer/unixlib.h | 2 + + dlls/winegstreamer/wg_parser.c | 2 +- + dlls/winegstreamer/wg_transform.c | 93 +++++++++++++++++++++++++++++++ + dlls/winegstreamer/wma_decoder.c | 2 +- + 7 files changed, 107 insertions(+), 5 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 551dcc549c7..6432ae37fc0 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -100,7 +100,8 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); + bool wg_parser_stream_drain(struct wg_parser_stream *stream); + +-struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; ++struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, ++ const struct wg_format *output_format) DECLSPEC_HIDDEN; + void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; + + unsigned int wg_format_get_max_size(const struct wg_format *format); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 6938d111926..d3e87973fdf 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -288,9 +288,14 @@ bool wg_parser_stream_drain(struct wg_parser_stream *stream) + return !__wine_unix_call(unix_handle, unix_wg_parser_stream_drain, stream); + } + +-struct wg_transform *wg_transform_create(void) ++struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, ++ const struct wg_format *output_format) + { +- struct wg_transform_create_params params = {0}; ++ struct wg_transform_create_params params = ++ { ++ .input_format = input_format, ++ .output_format = output_format, ++ }; + + if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) + return NULL; +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index 375d33e7728..38349eb5e8d 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -24,6 +24,7 @@ + #include "unixlib.h" + + extern bool init_gstreamer(void) DECLSPEC_HIDDEN; ++extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; + + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; + extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 7d3eceb6a51..51ffc5d3efe 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -307,6 +307,8 @@ struct wg_parser_stream_seek_params + struct wg_transform_create_params + { + struct wg_transform *transform; ++ const struct wg_encoded_format *input_format; ++ const struct wg_format *output_format; + }; + + enum unix_funcs +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index b8662c4417d..2970e2464a2 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -541,7 +541,7 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) + return caps; + } + +-static GstCaps *wg_format_to_caps(const struct wg_format *format) ++GstCaps *wg_format_to_caps(const struct wg_format *format) + { + switch (format->major_type) + { +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 822740da0d7..146cdd87ae7 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -42,12 +42,77 @@ GST_DEBUG_CATEGORY_EXTERN(wine); + + struct wg_transform + { ++ GstPad *my_src, *my_sink; + }; + ++static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) ++{ ++ GstBuffer *buffer; ++ GstCaps *caps; ++ ++ if (format->encoded_type == WG_ENCODED_TYPE_WMA) ++ caps = gst_caps_new_empty_simple("audio/x-wma"); ++ else ++ caps = gst_caps_new_empty_simple("audio/x-xma"); ++ ++ if (format->u.xwma.version) ++ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); ++ if (format->u.xwma.bitrate) ++ gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); ++ if (format->u.xwma.rate) ++ gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.xwma.rate, NULL); ++ if (format->u.xwma.depth) ++ gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.xwma.depth, NULL); ++ if (format->u.xwma.channels) ++ gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.xwma.channels, NULL); ++ if (format->u.xwma.block_align) ++ gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.xwma.block_align, NULL); ++ ++ if (format->u.xwma.codec_data_len) ++ { ++ buffer = gst_buffer_new_and_alloc(format->u.xwma.codec_data_len); ++ gst_buffer_fill(buffer, 0, format->u.xwma.codec_data, format->u.xwma.codec_data_len); ++ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); ++ gst_buffer_unref(buffer); ++ } ++ ++ return caps; ++} ++ ++static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) ++{ ++ switch (format->encoded_type) ++ { ++ case WG_ENCODED_TYPE_UNKNOWN: ++ return NULL; ++ case WG_ENCODED_TYPE_WMA: ++ case WG_ENCODED_TYPE_XMA: ++ return wg_format_to_caps_xwma(format); ++ } ++ assert(0); ++ return NULL; ++} ++ ++static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) ++{ ++ struct wg_transform *transform = gst_pad_get_element_private(pad); ++ ++ GST_INFO("transform %p, buffer %p.", transform, buffer); ++ ++ gst_buffer_unref(buffer); ++ ++ return GST_FLOW_OK; ++} ++ + NTSTATUS wg_transform_destroy(void *args) + { + struct wg_transform *transform = args; + ++ if (transform->my_sink) ++ g_object_unref(transform->my_sink); ++ if (transform->my_src) ++ g_object_unref(transform->my_src); ++ + free(transform); + return S_OK; + } +@@ -55,7 +120,11 @@ NTSTATUS wg_transform_destroy(void *args) + NTSTATUS wg_transform_create(void *args) + { + struct wg_transform_create_params *params = args; ++ struct wg_encoded_format input_format = *params->input_format; ++ struct wg_format output_format = *params->output_format; ++ GstCaps *src_caps, *sink_caps; + struct wg_transform *transform; ++ GstPadTemplate *template; + + if (!init_gstreamer()) + return E_FAIL; +@@ -63,7 +132,31 @@ NTSTATUS wg_transform_create(void *args) + if (!(transform = calloc(1, sizeof(*transform)))) + return E_OUTOFMEMORY; + ++ src_caps = wg_encoded_format_to_caps(&input_format); ++ assert(src_caps); ++ sink_caps = wg_format_to_caps(&output_format); ++ assert(sink_caps); ++ ++ template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); ++ assert(template); ++ transform->my_src = gst_pad_new_from_template(template, "src"); ++ g_object_unref(template); ++ assert(transform->my_src); ++ ++ template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); ++ assert(template); ++ transform->my_sink = gst_pad_new_from_template(template, "sink"); ++ g_object_unref(template); ++ assert(transform->my_sink); ++ ++ gst_pad_set_element_private(transform->my_sink, transform); ++ gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); ++ + GST_INFO("Created winegstreamer transform %p.", transform); + params->transform = transform; ++ ++ gst_caps_unref(src_caps); ++ gst_caps_unref(sink_caps); ++ + return S_OK; + } +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index 2b543426524..db6c8a677f6 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -79,7 +79,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + +- decoder->wg_transform = wg_transform_create(); ++ decoder->wg_transform = wg_transform_create(&input_format, &output_format); + if (decoder->wg_transform) + return S_OK; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0060-winegstreamer-Lookup-create-and-link-a-decoder-eleme.patch b/patches/mfplat-streaming-support/0060-winegstreamer-Lookup-create-and-link-a-decoder-eleme.patch new file mode 100644 index 00000000..96cfdb98 --- /dev/null +++ b/patches/mfplat-streaming-support/0060-winegstreamer-Lookup-create-and-link-a-decoder-eleme.patch @@ -0,0 +1,207 @@ +From 855ce2096c36de51d227cb07a88a73e51c34d3a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:24:27 +0100 +Subject: [PATCH 60/88] winegstreamer: Lookup, create and link a decoder + element. + +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 +--- + dlls/winegstreamer/wg_transform.c | 140 +++++++++++++++++++++++++++++- + 1 file changed, 138 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 146cdd87ae7..a436d8316dd 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -42,7 +42,9 @@ GST_DEBUG_CATEGORY_EXTERN(wine); + + struct wg_transform + { ++ GstElement *container; + GstPad *my_src, *my_sink; ++ GstPad *their_sink, *their_src; + }; + + static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) +@@ -108,6 +110,22 @@ NTSTATUS wg_transform_destroy(void *args) + { + struct wg_transform *transform = args; + ++ if (transform->container) ++ gst_element_set_state(transform->container, GST_STATE_NULL); ++ ++ if (transform->their_src && transform->my_sink) ++ gst_pad_unlink(transform->their_src, transform->my_sink); ++ if (transform->their_sink && transform->my_src) ++ gst_pad_unlink(transform->my_src, transform->their_sink); ++ ++ if (transform->their_sink) ++ g_object_unref(transform->their_sink); ++ if (transform->their_src) ++ g_object_unref(transform->their_src); ++ ++ if (transform->container) ++ g_object_unref(transform->container); ++ + if (transform->my_sink) + g_object_unref(transform->my_sink); + if (transform->my_src) +@@ -117,14 +135,85 @@ NTSTATUS wg_transform_destroy(void *args) + return S_OK; + } + ++static GstElement *try_create_transform(GstCaps *src_caps, GstCaps *sink_caps) ++{ ++ GstElement *element = NULL; ++ GList *tmp, *transforms; ++ gchar *type; ++ ++ transforms = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ANY, ++ GST_RANK_MARGINAL); ++ ++ tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); ++ gst_plugin_feature_list_free(transforms); ++ transforms = tmp; ++ ++ tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); ++ gst_plugin_feature_list_free(transforms); ++ transforms = tmp; ++ ++ transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); ++ for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) ++ { ++ type = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); ++ element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL); ++ if (!element) ++ GST_WARNING("Failed to create %s element.", type); ++ } ++ gst_plugin_feature_list_free(transforms); ++ ++ if (element) ++ GST_INFO("Created %s element %p.", type, element); ++ else ++ { ++ gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); ++ GST_WARNING("Failed to create transform matching caps %s / %s.", src_str, sink_str); ++ g_free(sink_str); ++ g_free(src_str); ++ } ++ ++ return element; ++} ++ ++static bool transform_append_element(struct wg_transform *transform, GstElement *element, ++ GstElement **first, GstElement **last) ++{ ++ gchar *name = gst_element_get_name(element); ++ ++ if (!gst_bin_add(GST_BIN(transform->container), element)) ++ { ++ GST_ERROR("Failed to add %s element to bin.", name); ++ g_free(name); ++ return false; ++ } ++ ++ if (*last && !gst_element_link(*last, element)) ++ { ++ GST_ERROR("Failed to link %s element.", name); ++ g_free(name); ++ return false; ++ } ++ ++ GST_INFO("Created %s element %p.", name, element); ++ g_free(name); ++ ++ if (!*first) ++ *first = element; ++ ++ *last = element; ++ return true; ++} ++ + NTSTATUS wg_transform_create(void *args) + { + struct wg_transform_create_params *params = args; + struct wg_encoded_format input_format = *params->input_format; + struct wg_format output_format = *params->output_format; +- GstCaps *src_caps, *sink_caps; ++ GstElement *first = NULL, *last = NULL, *element; + struct wg_transform *transform; ++ GstCaps *src_caps, *sink_caps; + GstPadTemplate *template; ++ int ret; + + if (!init_gstreamer()) + return E_FAIL; +@@ -137,6 +226,24 @@ NTSTATUS wg_transform_create(void *args) + sink_caps = wg_format_to_caps(&output_format); + assert(sink_caps); + ++ transform->container = gst_bin_new("wg_transform"); ++ assert(transform->container); ++ ++ if (!(element = try_create_transform(src_caps, sink_caps)) || ++ !transform_append_element(transform, element, &first, &last)) ++ goto failed; ++ ++ if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) ++ { ++ GST_ERROR("Failed to find target sink pad."); ++ goto failed; ++ } ++ if (!(transform->their_src = gst_element_get_static_pad(last, "src"))) ++ { ++ GST_ERROR("Failed to find target src pad."); ++ goto failed; ++ } ++ + template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + assert(template); + transform->my_src = gst_pad_new_from_template(template, "src"); +@@ -152,11 +259,40 @@ NTSTATUS wg_transform_create(void *args) + gst_pad_set_element_private(transform->my_sink, transform); + gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); + ++ if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) ++ { ++ GST_ERROR("Failed to link sink pads, error %d.", ret); ++ goto failed; ++ } ++ if ((ret = gst_pad_link(transform->their_src, transform->my_sink)) < 0) ++ { ++ GST_ERROR("Failed to link source pads, error %d.", ret); ++ goto failed; ++ } ++ ++ if (!(ret = gst_pad_set_active(transform->my_sink, 1))) ++ GST_WARNING("Failed to activate my_sink."); ++ if (!(ret = gst_pad_set_active(transform->my_src, 1))) ++ GST_WARNING("Failed to activate my_src."); ++ ++ gst_element_set_state(transform->container, GST_STATE_PAUSED); ++ ret = gst_element_get_state(transform->container, NULL, NULL, -1); ++ if (ret == GST_STATE_CHANGE_FAILURE) ++ { ++ GST_ERROR("Failed to play stream.\n"); ++ goto failed; ++ } ++ + GST_INFO("Created winegstreamer transform %p.", transform); + params->transform = transform; + ++failed: + gst_caps_unref(src_caps); + gst_caps_unref(sink_caps); + +- return S_OK; ++ if (params->transform) ++ return S_OK; ++ ++ wg_transform_destroy(transform); ++ return E_FAIL; + } +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0061-winegstreamer-Send-stream-start-and-caps-events-on-c.patch b/patches/mfplat-streaming-support/0061-winegstreamer-Send-stream-start-and-caps-events-on-c.patch new file mode 100644 index 00000000..67c5aed4 --- /dev/null +++ b/patches/mfplat-streaming-support/0061-winegstreamer-Send-stream-start-and-caps-events-on-c.patch @@ -0,0 +1,59 @@ +From 6cc21e8ca6164debd05e7a98b7c20cc65714518b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:25:20 +0100 +Subject: [PATCH 61/88] winegstreamer: Send stream-start and caps events on + creation. + +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 +--- + dlls/winegstreamer/wg_transform.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index a436d8316dd..d87b8cfa2c4 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -213,6 +213,7 @@ NTSTATUS wg_transform_create(void *args) + struct wg_transform *transform; + GstCaps *src_caps, *sink_caps; + GstPadTemplate *template; ++ GstSegment *segment; + int ret; + + if (!init_gstreamer()) +@@ -283,6 +284,30 @@ NTSTATUS wg_transform_create(void *args) + goto failed; + } + ++ if (!gst_pad_push_event(transform->my_src, gst_event_new_stream_start("stream"))) ++ { ++ GST_ERROR("Failed to send stream-start."); ++ goto failed; ++ } ++ ++ if (!gst_pad_push_event(transform->my_src, gst_event_new_caps(src_caps))) ++ { ++ GST_ERROR("Failed to set stream caps."); ++ goto failed; ++ } ++ ++ segment = gst_segment_new(); ++ gst_segment_init(segment, GST_FORMAT_TIME); ++ segment->start = 0; ++ segment->stop = -1; ++ ret = gst_pad_push_event(transform->my_src, gst_event_new_segment(segment)); ++ gst_segment_free(segment); ++ if (!ret) ++ { ++ GST_ERROR("Failed to start new segment."); ++ goto failed; ++ } ++ + GST_INFO("Created winegstreamer transform %p.", transform); + params->transform = transform; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0062-winegstreamer-Add-an-audioconverter-and-audioresampl.patch b/patches/mfplat-streaming-support/0062-winegstreamer-Add-an-audioconverter-and-audioresampl.patch new file mode 100644 index 00000000..98016f55 --- /dev/null +++ b/patches/mfplat-streaming-support/0062-winegstreamer-Add-an-audioconverter-and-audioresampl.patch @@ -0,0 +1,100 @@ +From b90b4207c326a3faf0e6ff5fb0649bd8a081fab7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:25:58 +0100 +Subject: [PATCH 62/88] winegstreamer: Add an audioconverter and audioresampler + elements. + +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 +--- + dlls/winegstreamer/unix_private.h | 1 + + dlls/winegstreamer/wg_parser.c | 2 +- + dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++-- + 3 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index 38349eb5e8d..e6b0f3636f7 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -24,6 +24,7 @@ + #include "unixlib.h" + + extern bool init_gstreamer(void) DECLSPEC_HIDDEN; ++extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; + extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; + + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 2970e2464a2..02bf639962f 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1280,7 +1280,7 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + } + } + +-static GstElement *create_element(const char *name, const char *plugin_set) ++GstElement *create_element(const char *name, const char *plugin_set) + { + GstElement *element; + +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index d87b8cfa2c4..d96923594e2 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -210,9 +210,10 @@ NTSTATUS wg_transform_create(void *args) + struct wg_encoded_format input_format = *params->input_format; + struct wg_format output_format = *params->output_format; + GstElement *first = NULL, *last = NULL, *element; ++ GstCaps *raw_caps, *src_caps, *sink_caps; + struct wg_transform *transform; +- GstCaps *src_caps, *sink_caps; + GstPadTemplate *template; ++ const gchar *media_type; + GstSegment *segment; + int ret; + +@@ -226,14 +227,31 @@ NTSTATUS wg_transform_create(void *args) + assert(src_caps); + sink_caps = wg_format_to_caps(&output_format); + assert(sink_caps); ++ media_type = gst_structure_get_name(gst_caps_get_structure(sink_caps, 0)); ++ raw_caps = gst_caps_new_empty_simple(media_type); ++ assert(raw_caps); + + transform->container = gst_bin_new("wg_transform"); + assert(transform->container); + +- if (!(element = try_create_transform(src_caps, sink_caps)) || ++ if (!(element = try_create_transform(src_caps, raw_caps)) || + !transform_append_element(transform, element, &first, &last)) + goto failed; + ++ switch (output_format.major_type) ++ { ++ case WG_MAJOR_TYPE_AUDIO: ++ if (!(element = create_element("audioconvert", "base")) || ++ !transform_append_element(transform, element, &first, &last)) ++ goto failed; ++ if (!(element = create_element("audioresample", "base")) || ++ !transform_append_element(transform, element, &first, &last)) ++ goto failed; ++ break; ++ default: ++ break; ++ } ++ + if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) + { + GST_ERROR("Failed to find target sink pad."); +@@ -312,6 +330,7 @@ NTSTATUS wg_transform_create(void *args) + params->transform = transform; + + failed: ++ gst_caps_unref(raw_caps); + gst_caps_unref(src_caps); + gst_caps_unref(sink_caps); + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0063-winegstreamer-Implement-WMA-decoder-ProcessInput.patch b/patches/mfplat-streaming-support/0063-winegstreamer-Implement-WMA-decoder-ProcessInput.patch new file mode 100644 index 00000000..41f3f4f3 --- /dev/null +++ b/patches/mfplat-streaming-support/0063-winegstreamer-Implement-WMA-decoder-ProcessInput.patch @@ -0,0 +1,249 @@ +From cd2746f22bdea18808282efbdfa6e599c5b7a5d7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:28:54 +0100 +Subject: [PATCH 63/88] winegstreamer: Implement WMA decoder ProcessInput. + +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 +--- + dlls/mf/tests/mf.c | 6 ----- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/main.c | 12 +++++++++ + dlls/winegstreamer/unix_private.h | 1 + + dlls/winegstreamer/unixlib.h | 9 +++++++ + dlls/winegstreamer/wg_parser.c | 2 ++ + dlls/winegstreamer/wg_transform.c | 22 ++++++++++++++++ + dlls/winegstreamer/wma_decoder.c | 43 +++++++++++++++++++++++++++++-- + 8 files changed, 88 insertions(+), 8 deletions(-) + +diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c +index 07f4c28052d..d78f0051714 100644 +--- a/dlls/mf/tests/mf.c ++++ b/dlls/mf/tests/mf.c +@@ -6207,25 +6207,20 @@ static void test_wma_decoder(void) + + sample = create_sample(wma_encoded_data, wma_block_size / 2); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == S_OK, "ProcessInput returned %#x\n", hr); + ret = IMFSample_Release(sample); + ok(ret == 0, "Release returned %u\n", ret); + sample = create_sample(wma_encoded_data + wma_block_size, wma_block_size - wma_block_size / 2); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == S_OK, "ProcessInput returned %#x\n", hr); + ret = IMFSample_Release(sample); + ok(ret == 0, "Release returned %u\n", ret); + sample = create_sample(wma_encoded_data, wma_block_size); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == S_OK, "ProcessInput returned %#x\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); + ret = IMFSample_Release(sample); +- todo_wine + ok(ret == 1, "Release returned %u\n", ret); + + /* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES +@@ -6248,7 +6243,6 @@ static void test_wma_decoder(void) + + sample = create_sample(wma_encoded_data, wma_block_size); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); + ret = IMFSample_Release(sample); + ok(ret == 0, "Release returned %u\n", ret); +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 6432ae37fc0..8c7e1795fea 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -103,6 +103,7 @@ bool wg_parser_stream_drain(struct wg_parser_stream *stream); + struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, + const struct wg_format *output_format) DECLSPEC_HIDDEN; + void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; ++HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; + + unsigned int wg_format_get_max_size(const struct wg_format *format); + +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index d3e87973fdf..cb21b54f7df 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -307,6 +307,18 @@ void wg_transform_destroy(struct wg_transform *transform) + __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); + } + ++HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) ++{ ++ struct wg_transform_push_data_params params = ++ { ++ .transform = transform, ++ .data = data, ++ .size = size, ++ }; ++ ++ return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + if (reason == DLL_PROCESS_ATTACH) +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index e6b0f3636f7..baa7f81926c 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -29,5 +29,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE + + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; + extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; ++extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; + + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 51ffc5d3efe..b361fea36d1 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -311,6 +311,13 @@ struct wg_transform_create_params + const struct wg_format *output_format; + }; + ++struct wg_transform_push_data_params ++{ ++ struct wg_transform *transform; ++ const void *data; ++ UINT32 size; ++}; ++ + enum unix_funcs + { + unix_wg_parser_create, +@@ -346,6 +353,8 @@ enum unix_funcs + unix_wg_transform_destroy, + + unix_wg_parser_stream_drain, ++ ++ unix_wg_transform_push_data, + }; + + #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 02bf639962f..a5dfa0cf7ee 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -2668,4 +2668,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + X(wg_transform_destroy), + + X(wg_parser_stream_drain), ++ ++ X(wg_transform_push_data), + }; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index d96923594e2..2137c4c8821 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -34,6 +34,7 @@ + + #include "winternl.h" + #include "dshow.h" ++#include "mferror.h" + + #include "unix_private.h" + +@@ -340,3 +341,24 @@ failed: + wg_transform_destroy(transform); + return E_FAIL; + } ++ ++NTSTATUS wg_transform_push_data(void *args) ++{ ++ struct wg_transform_push_data_params *params = args; ++ struct wg_transform *transform = params->transform; ++ GstBuffer *buffer; ++ GstFlowReturn ret; ++ ++ buffer = gst_buffer_new_and_alloc(params->size); ++ gst_buffer_fill(buffer, 0, params->data, params->size); ++ ++ ret = gst_pad_push(transform->my_src, buffer); ++ if (ret) ++ { ++ GST_ERROR("Failed to push buffer %d", ret); ++ return MF_E_NOTACCEPTING; ++ } ++ ++ GST_INFO("Pushed %u bytes", params->size); ++ return S_OK; ++} +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index db6c8a677f6..c9472bde019 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -54,6 +54,7 @@ struct wma_decoder + IMFMediaType *input_type; + IMFMediaType *output_type; + ++ IMFSample *input_sample; + struct wg_transform *wg_transform; + }; + +@@ -131,6 +132,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) + + if (!refcount) + { ++ if (decoder->input_sample) ++ IMFSample_Release(decoder->input_sample); + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) +@@ -523,8 +526,44 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ + + static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) + { +- FIXME("iface %p, id %lu, sample %p, flags %#lx stub!\n", iface, id, sample, flags); +- return E_NOTIMPL; ++ struct wma_decoder *decoder = impl_from_IMFTransform(iface); ++ IMFMediaBuffer *media_buffer; ++ MFT_INPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ BYTE *buffer; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %lu, sample %p, flags %#lx.\n", iface, id, sample, flags); ++ ++ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ if (decoder->input_sample) ++ return MF_E_NOTACCEPTING; ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_GetCurrentLength(media_buffer, &buffer_size))) ++ return hr; ++ ++ if (!(buffer_size = (buffer_size / info.cbSize) * info.cbSize)) ++ return S_OK; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, NULL))) ++ goto done; ++ ++ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) ++ IMFSample_AddRef((decoder->input_sample = sample)); ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; + } + + static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0064-winegstreamer-Implement-WMA-decoder-ProcessOutput.patch b/patches/mfplat-streaming-support/0064-winegstreamer-Implement-WMA-decoder-ProcessOutput.patch new file mode 100644 index 00000000..45b51603 --- /dev/null +++ b/patches/mfplat-streaming-support/0064-winegstreamer-Implement-WMA-decoder-ProcessOutput.patch @@ -0,0 +1,407 @@ +From 4c1eae2084677337da00722ed93e9b3032c8a6db Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:31:44 +0100 +Subject: [PATCH 64/88] winegstreamer: Implement WMA decoder ProcessOutput. + +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 +--- + dlls/mf/tests/mf.c | 19 ++------ + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/main.c | 11 +++++ + dlls/winegstreamer/unix_private.h | 1 + + dlls/winegstreamer/unixlib.h | 19 ++++++++ + dlls/winegstreamer/wg_parser.c | 1 + + dlls/winegstreamer/wg_transform.c | 76 ++++++++++++++++++++++++++++++- + dlls/winegstreamer/wma_decoder.c | 59 +++++++++++++++++++++++- + 8 files changed, 169 insertions(+), 18 deletions(-) + +diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c +index d78f0051714..4a81191bcf6 100644 +--- a/dlls/mf/tests/mf.c ++++ b/dlls/mf/tests/mf.c +@@ -6229,16 +6229,13 @@ static void test_wma_decoder(void) + status = 0xdeadbeef; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); +- todo_wine + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); + ok(output.dwStreamID == 0, "got dwStreamID %u\n", output.dwStreamID); + ok(!output.pSample, "got pSample %p\n", output.pSample); +- todo_wine + ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || + broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, + "got dwStatus %#x\n", output.dwStatus); + ok(!output.pEvents, "got pEvents %p\n", output.pEvents); +- todo_wine + ok(status == 0, "got status %#x\n", status); + + sample = create_sample(wma_encoded_data, wma_block_size); +@@ -6250,14 +6247,11 @@ static void test_wma_decoder(void) + status = 0xdeadbeef; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); +- todo_wine + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); + ok(!output.pSample, "got pSample %p\n", output.pSample); +- todo_wine + ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || + broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, + "got dwStatus %#x\n", output.dwStatus); +- todo_wine + ok(status == 0, "got status %#x\n", status); + + i = 1; +@@ -6291,7 +6285,6 @@ static void test_wma_decoder(void) + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + } + +- todo_wine + ok(hr == S_OK, "ProcessOutput returned %#x\n", hr); + ok(output.pSample == sample, "got pSample %p\n", output.pSample); + +@@ -6304,7 +6297,8 @@ static void test_wma_decoder(void) + "got dwStatus %#x\n", output.dwStatus); + ok(status == 0, "got status %#x\n", status); + if (output.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE || +- broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7))) ++ broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) || ++ !strcmp(winetest_platform, "wine")) + { + check_sample(sample, wma_decoded_data, sizeof(wma_decoded_data), NULL); + i += sizeof(wma_decoded_data); +@@ -6323,14 +6317,12 @@ static void test_wma_decoder(void) + output.pSample = sample; + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + } +- todo_wine +- ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i); ++ if (!strcmp(winetest_platform, "wine")) ok(i == 0x10000, "ProcessOutput produced %#x bytes\n", i); ++ else ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i); + +- todo_wine + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); + ok(output.pSample == sample, "got pSample %p\n", output.pSample); + ok(output.dwStatus == 0, "got dwStatus %#x\n", output.dwStatus); +- todo_wine + ok(status == 0, "got status %#x\n", status); + ret = IMFSample_Release(sample); + ok(ret == 0, "Release returned %u\n", ret); +@@ -6340,13 +6332,11 @@ static void test_wma_decoder(void) + memset(&output, 0, sizeof(output)); + output.pSample = sample; + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); +- todo_wine + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); + ok(output.pSample == sample, "got pSample %p\n", output.pSample); + ok(output.dwStatus == 0 || + broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) /* Win7 */, + "got dwStatus %#x\n", output.dwStatus); +- todo_wine + ok(status == 0, "got status %#x\n", status); + check_sample(sample, NULL, 0, NULL); + ret = IMFSample_Release(sample); +@@ -6354,7 +6344,6 @@ static void test_wma_decoder(void) + + sample = create_sample(wma_encoded_data, wma_block_size); + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); +- todo_wine + ok(hr == S_OK, "ProcessInput returned %#x\n", hr); + + ret = IMFTransform_Release(transform); +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 8c7e1795fea..af30e944865 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -104,6 +104,7 @@ struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_f + const struct wg_format *output_format) DECLSPEC_HIDDEN; + void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; + HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; ++HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) DECLSPEC_HIDDEN; + + unsigned int wg_format_get_max_size(const struct wg_format *format); + +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index cb21b54f7df..fd73bfc289a 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -319,6 +319,17 @@ HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, + return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); + } + ++HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) ++{ ++ struct wg_transform_read_data_params params = ++ { ++ .transform = transform, ++ .sample = sample, ++ }; ++ ++ return __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms); ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + if (reason == DLL_PROCESS_ATTACH) +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index baa7f81926c..1b055436ba5 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -30,5 +30,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; + extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; + extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; ++extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; + + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index b361fea36d1..0df245408ee 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -318,6 +318,24 @@ struct wg_transform_push_data_params + UINT32 size; + }; + ++enum wg_sample_flags ++{ ++ WG_SAMPLE_FLAG_INCOMPLETE = 1, ++}; ++ ++struct wg_sample ++{ ++ UINT32 flags; ++ BYTE *data; ++ UINT32 size; ++}; ++ ++struct wg_transform_read_data_params ++{ ++ struct wg_transform *transform; ++ struct wg_sample *sample; ++}; ++ + enum unix_funcs + { + unix_wg_parser_create, +@@ -355,6 +373,7 @@ enum unix_funcs + unix_wg_parser_stream_drain, + + unix_wg_transform_push_data, ++ unix_wg_transform_read_data, + }; + + #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index a5dfa0cf7ee..3217c78e864 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -2670,4 +2670,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = + X(wg_parser_stream_drain), + + X(wg_transform_push_data), ++ X(wg_transform_read_data), + }; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 2137c4c8821..1f8b35920b4 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -38,14 +38,24 @@ + + #include "unix_private.h" + ++#include "wine/list.h" ++ + GST_DEBUG_CATEGORY_EXTERN(wine); + #define GST_CAT_DEFAULT wine + ++struct wg_transform_sample ++{ ++ struct list entry; ++ GstSample *sample; ++}; ++ + struct wg_transform + { + GstElement *container; + GstPad *my_src, *my_sink; + GstPad *their_sink, *their_src; ++ pthread_mutex_t mutex; ++ struct list samples; + }; + + static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) +@@ -99,17 +109,29 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format + static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) + { + struct wg_transform *transform = gst_pad_get_element_private(pad); ++ struct wg_transform_sample *sample; + + GST_INFO("transform %p, buffer %p.", transform, buffer); + +- gst_buffer_unref(buffer); ++ if (!(sample = malloc(sizeof(*sample)))) ++ GST_ERROR("Failed to allocate transform sample entry"); ++ else ++ { ++ pthread_mutex_lock(&transform->mutex); ++ if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) ++ GST_ERROR("Failed to allocate transform sample"); ++ list_add_tail(&transform->samples, &sample->entry); ++ pthread_mutex_unlock(&transform->mutex); ++ } + ++ gst_buffer_unref(buffer); + return GST_FLOW_OK; + } + + NTSTATUS wg_transform_destroy(void *args) + { + struct wg_transform *transform = args; ++ struct wg_transform_sample *sample, *next; + + if (transform->container) + gst_element_set_state(transform->container, GST_STATE_NULL); +@@ -132,6 +154,13 @@ NTSTATUS wg_transform_destroy(void *args) + if (transform->my_src) + g_object_unref(transform->my_src); + ++ LIST_FOR_EACH_ENTRY_SAFE(sample, next, &transform->samples, struct wg_transform_sample, entry) ++ { ++ gst_sample_unref(sample->sample); ++ list_remove(&sample->entry); ++ free(sample); ++ } ++ + free(transform); + return S_OK; + } +@@ -224,6 +253,8 @@ NTSTATUS wg_transform_create(void *args) + if (!(transform = calloc(1, sizeof(*transform)))) + return E_OUTOFMEMORY; + ++ list_init(&transform->samples); ++ + src_caps = wg_encoded_format_to_caps(&input_format); + assert(src_caps); + sink_caps = wg_format_to_caps(&output_format); +@@ -362,3 +393,46 @@ NTSTATUS wg_transform_push_data(void *args) + GST_INFO("Pushed %u bytes", params->size); + return S_OK; + } ++ ++NTSTATUS wg_transform_read_data(void *args) ++{ ++ struct wg_transform_read_data_params *params = args; ++ struct wg_transform *transform = params->transform; ++ struct wg_sample *read_sample = params->sample; ++ struct wg_transform_sample *transform_sample; ++ GstBuffer *buffer; ++ struct list *head; ++ GstMapInfo info; ++ ++ pthread_mutex_lock(&transform->mutex); ++ if (!(head = list_head(&transform->samples))) ++ { ++ pthread_mutex_unlock(&transform->mutex); ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); ++ buffer = gst_sample_get_buffer(transform_sample->sample); ++ ++ gst_buffer_map(buffer, &info, GST_MAP_READ); ++ if (read_sample->size > info.size) ++ read_sample->size = info.size; ++ memcpy(read_sample->data, info.data, read_sample->size); ++ gst_buffer_unmap(buffer, &info); ++ ++ if (info.size > read_sample->size) ++ { ++ read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; ++ gst_buffer_resize(buffer, read_sample->size, -1); ++ } ++ else ++ { ++ gst_sample_unref(transform_sample->sample); ++ list_remove(&transform_sample->entry); ++ free(transform_sample); ++ } ++ pthread_mutex_unlock(&transform->mutex); ++ ++ GST_INFO("Read %u bytes, flags %#x", read_sample->size, read_sample->flags); ++ return S_OK; ++} +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index c9472bde019..cac345be269 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -569,8 +569,63 @@ done: + 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; ++ struct wma_decoder *decoder = impl_from_IMFTransform(iface); ++ struct wg_sample wg_sample = {0}; ++ IMFMediaBuffer *media_buffer; ++ MFT_OUTPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ HRESULT hr; ++ ++ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); ++ ++ if (count > 1) ++ { ++ FIXME("Not implemented count %lu\n", count); ++ return E_NOTIMPL; ++ } ++ ++ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ *status = 0; ++ samples[0].dwStatus = 0; ++ if (!samples[0].pSample) ++ { ++ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) ++ goto done; ++ wg_sample.size = buffer_size; ++ ++ if (wg_sample.size < info.cbSize) ++ hr = MF_E_BUFFERTOOSMALL; ++ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) ++ { ++ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) ++ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; ++ } ++ else ++ { ++ if (decoder->input_sample) ++ IMFSample_Release(decoder->input_sample); ++ decoder->input_sample = NULL; ++ wg_sample.size = 0; ++ } ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; + } + + static const IMFTransformVtbl transform_vtbl = +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0065-winegstreamer-Support-XMAudio2-input-format-in-WMA-d.patch b/patches/mfplat-streaming-support/0065-winegstreamer-Support-XMAudio2-input-format-in-WMA-d.patch new file mode 100644 index 00000000..0860c877 --- /dev/null +++ b/patches/mfplat-streaming-support/0065-winegstreamer-Support-XMAudio2-input-format-in-WMA-d.patch @@ -0,0 +1,116 @@ +From 39e3d198d51eab196cf884835fdedb02fee0861d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:32:39 +0100 +Subject: [PATCH 65/88] winegstreamer: 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: #19854 +--- + dlls/winegstreamer/mfplat.c | 18 +++++++++++------- + dlls/winegstreamer/wg_transform.c | 10 ++++++++-- + dlls/winegstreamer/wma_decoder.c | 3 +++ + 3 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index ca64ce3f7b9..5633331359d 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -29,6 +29,8 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + ++DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); ++ + struct video_processor + { + IMFTransform IMFTransform_iface; +@@ -893,8 +895,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) + FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); + } + +-static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, +- UINT32 version) ++static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct wg_encoded_format *format, ++ enum wg_encoded_type encoded_type, UINT32 version) + { + UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; + BYTE codec_data[64]; +@@ -930,7 +932,7 @@ static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg + bytes_per_second = 0; + } + +- format->encoded_type = WG_ENCODED_TYPE_WMA; ++ format->encoded_type = encoded_type; + format->u.xwma.version = version; + format->u.xwma.bitrate = bytes_per_second * 8; + format->u.xwma.rate = rate; +@@ -961,13 +963,15 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + { + if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) +- mf_media_type_to_wg_encoded_format_wma(type, format, 1); ++ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 1); + else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) +- mf_media_type_to_wg_encoded_format_wma(type, format, 2); ++ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 2); + else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) +- mf_media_type_to_wg_encoded_format_wma(type, format, 3); ++ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 3); + else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) +- mf_media_type_to_wg_encoded_format_wma(type, format, 4); ++ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) ++ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); + else + FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); + } +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 1f8b35920b4..256e77429a0 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -64,12 +64,18 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) + GstCaps *caps; + + if (format->encoded_type == WG_ENCODED_TYPE_WMA) ++ { + caps = gst_caps_new_empty_simple("audio/x-wma"); ++ if (format->u.xwma.version) ++ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); ++ } + else ++ { + caps = gst_caps_new_empty_simple("audio/x-xma"); ++ if (format->u.xwma.version) ++ gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.xwma.version, NULL); ++ } + +- if (format->u.xwma.version) +- gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); + if (format->u.xwma.bitrate) + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); + if (format->u.xwma.rate) +diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c +index cac345be269..d6ae7d93a39 100644 +--- a/dlls/winegstreamer/wma_decoder.c ++++ b/dlls/winegstreamer/wma_decoder.c +@@ -30,12 +30,15 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(wmadec); + ++DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); ++ + 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[] = + { +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0066-winegstreamer-Introduce-new-H264-decoder-transform-s.patch b/patches/mfplat-streaming-support/0066-winegstreamer-Introduce-new-H264-decoder-transform-s.patch new file mode 100644 index 00000000..a035d728 --- /dev/null +++ b/patches/mfplat-streaming-support/0066-winegstreamer-Introduce-new-H264-decoder-transform-s.patch @@ -0,0 +1,363 @@ +From e0fce42d02ca3c2975384f04729d7b67021fc8b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 18 Jan 2022 13:09:07 +0100 +Subject: [PATCH 66/88] winegstreamer: Introduce new H264 decoder transform + stub. + +As a remplacement for the previously added transform. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/Makefile.in | 1 + + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/h264_decoder.c | 279 ++++++++++++++++++++++++++++++ + dlls/winegstreamer/mfplat.c | 7 +- + 4 files changed, 282 insertions(+), 6 deletions(-) + create mode 100644 dlls/winegstreamer/h264_decoder.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index 294d3b199a5..c4f0f1cad2c 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -10,6 +10,7 @@ C_SRCS = \ + audioconvert.c \ + colorconvert.c \ + decode_transform.c \ ++ h264_decoder.c \ + main.c \ + media_source.c \ + mfplat.c \ +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index af30e944865..fa73fecb10d 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -128,6 +128,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo + + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); + ++HRESULT h264_decoder_create(REFIID riid, void **ret); + HRESULT audio_converter_create(REFIID riid, void **ret); + HRESULT color_converter_create(REFIID riid, void **ret); + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +new file mode 100644 +index 00000000000..5db72c55151 +--- /dev/null ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -0,0 +1,279 @@ ++/* 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 "wmcodecdsp.h" ++ ++#include "wine/debug.h" ++#include "wine/heap.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(mfplat); ++ ++struct h264_decoder ++{ ++ IMFTransform IMFTransform_iface; ++ LONG refcount; ++}; ++ ++static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) ++{ ++ return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_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 h264_decoder_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) ++ free(decoder); ++ ++ return refcount; ++} ++ ++static HRESULT WINAPI h264_decoder_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 stub!\n", ++ iface, input_minimum, input_maximum, output_minimum, output_maximum); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) ++{ ++ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 stub!\n", ++ iface, input_size, inputs, output_size, outputs); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_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 h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) ++{ ++ FIXME("iface %p, attributes %p stub!\n", iface, attributes); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, ++ IMFAttributes **attributes) ++{ ++ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) ++{ ++ FIXME("iface %p, id %#lx stub!\n", iface, id); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) ++{ ++ FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_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 h264_decoder_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 h264_decoder_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 h264_decoder_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 h264_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) ++{ ++ FIXME("iface %p, flags %p stub!\n", iface, flags); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) ++{ ++ FIXME("iface %p, lower %s, upper %s stub!\n", iface, ++ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) ++{ ++ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI h264_decoder_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 h264_decoder_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 h264_decoder_vtbl = ++{ ++ h264_decoder_QueryInterface, ++ h264_decoder_AddRef, ++ h264_decoder_Release, ++ h264_decoder_GetStreamLimits, ++ h264_decoder_GetStreamCount, ++ h264_decoder_GetStreamIDs, ++ h264_decoder_GetInputStreamInfo, ++ h264_decoder_GetOutputStreamInfo, ++ h264_decoder_GetAttributes, ++ h264_decoder_GetInputStreamAttributes, ++ h264_decoder_GetOutputStreamAttributes, ++ h264_decoder_DeleteInputStream, ++ h264_decoder_AddInputStreams, ++ h264_decoder_GetInputAvailableType, ++ h264_decoder_GetOutputAvailableType, ++ h264_decoder_SetInputType, ++ h264_decoder_SetOutputType, ++ h264_decoder_GetInputCurrentType, ++ h264_decoder_GetOutputCurrentType, ++ h264_decoder_GetInputStatus, ++ h264_decoder_GetOutputStatus, ++ h264_decoder_SetOutputBounds, ++ h264_decoder_ProcessEvent, ++ h264_decoder_ProcessMessage, ++ h264_decoder_ProcessInput, ++ h264_decoder_ProcessOutput, ++}; ++ ++HRESULT h264_decoder_create(REFIID riid, void **ret) ++{ ++ struct h264_decoder *decoder; ++ ++ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); ++ ++ if (!(decoder = calloc(1, sizeof(*decoder)))) ++ return E_OUTOFMEMORY; ++ ++ decoder->IMFTransform_iface.lpVtbl = &h264_decoder_vtbl; ++ decoder->refcount = 1; ++ ++ *ret = &decoder->IMFTransform_iface; ++ TRACE("Created decoder %p\n", *ret); ++ return S_OK; ++} +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 5633331359d..ca26c767125 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -400,11 +400,6 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a + + static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; + +-static HRESULT h264_decoder_create(REFIID riid, void **ret) +-{ +- return decode_transform_create(riid, ret, DECODER_TYPE_H264); +-} +- + static const struct class_object + { + const GUID *clsid; +@@ -549,7 +544,7 @@ mfts[] = + color_converter_supported_types, + }, + { +- &CLSID_MSAACDecMFT, ++ &CLSID_MSH264DecoderMFT, + &MFT_CATEGORY_VIDEO_DECODER, + h264_decoderW, + MFT_ENUM_FLAG_SYNCMFT, +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0067-winegstreamer-Return-S_OK-from-H264-decoder-GetAttri.patch b/patches/mfplat-streaming-support/0067-winegstreamer-Return-S_OK-from-H264-decoder-GetAttri.patch new file mode 100644 index 00000000..7bbb6fe3 --- /dev/null +++ b/patches/mfplat-streaming-support/0067-winegstreamer-Return-S_OK-from-H264-decoder-GetAttri.patch @@ -0,0 +1,37 @@ +From 30e5e0e405af8f99885727687dbcdfbda3e57f08 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 18 Jan 2022 13:33:36 +0100 +Subject: [PATCH 67/88] winegstreamer: Return S_OK from H264 decoder + GetAttributes. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 5db72c55151..f46d6d77f8e 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -120,7 +120,8 @@ static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWOR + static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) + { + FIXME("iface %p, attributes %p stub!\n", iface, attributes); +- return E_NOTIMPL; ++ ++ return MFCreateAttributes(attributes, 0); + } + + static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0068-winegstreamer-Return-S_OK-from-H264-decoder-ProcessM.patch b/patches/mfplat-streaming-support/0068-winegstreamer-Return-S_OK-from-H264-decoder-ProcessM.patch new file mode 100644 index 00000000..22e274e8 --- /dev/null +++ b/patches/mfplat-streaming-support/0068-winegstreamer-Return-S_OK-from-H264-decoder-ProcessM.patch @@ -0,0 +1,36 @@ +From ac5e4d49d48fb8b4f1070103c856f0b7363a7d03 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 18 Jan 2022 13:33:36 +0100 +Subject: [PATCH 68/88] winegstreamer: Return S_OK from H264 decoder + ProcessMessage. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index f46d6d77f8e..55f40ad7660 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -216,7 +216,7 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I + static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); +- return E_NOTIMPL; ++ return S_OK; + } + + static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0069-winegstreamer-Implement-H264-decoder-SetInputType.patch b/patches/mfplat-streaming-support/0069-winegstreamer-Implement-H264-decoder-SetInputType.patch new file mode 100644 index 00000000..6aab242b --- /dev/null +++ b/patches/mfplat-streaming-support/0069-winegstreamer-Implement-H264-decoder-SetInputType.patch @@ -0,0 +1,89 @@ +From 34491aae12bd533db2ceb8fdbfcbc0a1ccc54004 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:54:51 +0100 +Subject: [PATCH 69/88] winegstreamer: Implement H264 decoder SetInputType. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 37 +++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 55f40ad7660..e0634bedcaa 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -30,10 +30,16 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + ++static const GUID *h264_decoder_input_types[] = ++{ ++ &MFVideoFormat_H264, ++}; ++ + struct h264_decoder + { + IMFTransform IMFTransform_iface; + LONG refcount; ++ IMFMediaType *input_type; + }; + + static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +@@ -78,7 +84,11 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) ++ { ++ if (decoder->input_type) ++ IMFMediaType_Release(decoder->input_type); + free(decoder); ++ } + + return refcount; + } +@@ -166,8 +176,31 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D + + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ GUID major, subtype; ++ 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(h264_decoder_input_types); ++i) ++ if (IsEqualGUID(&subtype, h264_decoder_input_types[i])) ++ break; ++ if (i == ARRAY_SIZE(h264_decoder_input_types)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (decoder->input_type) ++ IMFMediaType_Release(decoder->input_type); ++ IMFMediaType_AddRef((decoder->input_type = type)); ++ ++ return S_OK; + } + + static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0070-winegstreamer-Implement-H264-decoder-GetOutputAvaila.patch b/patches/mfplat-streaming-support/0070-winegstreamer-Implement-H264-decoder-GetOutputAvaila.patch new file mode 100644 index 00000000..cdaf860b --- /dev/null +++ b/patches/mfplat-streaming-support/0070-winegstreamer-Implement-H264-decoder-GetOutputAvaila.patch @@ -0,0 +1,196 @@ +From 71e9a26475d40d5107b803cbc1c69dbff4a18b93 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:55:30 +0100 +Subject: [PATCH 70/88] winegstreamer: Implement H264 decoder + GetOutputAvailableType. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 141 +++++++++++++++++++++++++++++- + 1 file changed, 138 insertions(+), 3 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index e0634bedcaa..78bf317c36f 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -34,6 +34,14 @@ static const GUID *h264_decoder_input_types[] = + { + &MFVideoFormat_H264, + }; ++static const GUID *h264_decoder_output_types[] = ++{ ++ &MFVideoFormat_NV12, ++ &MFVideoFormat_YV12, ++ &MFVideoFormat_IYUV, ++ &MFVideoFormat_I420, ++ &MFVideoFormat_YUY2, ++}; + + struct h264_decoder + { +@@ -47,6 +55,103 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) + return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); + } + ++static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) ++{ ++ UINT32 value, width, height; ++ UINT64 value64; ++ GUID subtype; ++ HRESULT hr; ++ ++ if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64))) ++ { ++ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_SIZE, &value64))) ++ value64 = (UINT64)1920 << 32 | 1080; ++ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, value64))) ++ return hr; ++ } ++ width = value64 >> 32; ++ height = value64; ++ ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) ++ { ++ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_RATE, &value64))) ++ value64 = (UINT64)30000 << 32 | 1001; ++ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, value64))) ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) ++ { ++ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64))) ++ value64 = (UINT64)1 << 32 | 1; ++ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, value64))) ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) ++ { ++ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_SAMPLE_SIZE, &value))) ++ { ++ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) ++ value = width * height * 2; ++ else ++ value = width * height * 3 / 2; ++ } ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) ++ { ++ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_DEFAULT_STRIDE, &value))) ++ { ++ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) ++ value = width * 2; ++ else ++ value = width; ++ } ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL))) ++ { ++ if (!default_type || FAILED(hr = 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 = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) ++ { ++ if (!default_type || FAILED(hr = 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 = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL))) ++ { ++ if (!default_type || FAILED(hr = 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 = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) ++ { ++ if (!default_type || FAILED(hr = 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; ++ } ++ ++ return S_OK; ++} ++ + static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) + { + struct h264_decoder *decoder = impl_from_IMFTransform(iface); +@@ -170,8 +275,38 @@ static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DW + static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) + { +- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); +- return E_NOTIMPL; ++ 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); ++ ++ 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(media_type, NULL); ++ ++done: ++ if (SUCCEEDED(hr)) ++ IMFMediaType_AddRef((*type = media_type)); ++ ++ IMFMediaType_Release(media_type); ++ return hr; + } + + static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +@@ -184,7 +319,7 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, 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))) ++ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return E_INVALIDARG; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0071-winegstreamer-Implement-H264-decoder-GetInputAvailab.patch b/patches/mfplat-streaming-support/0071-winegstreamer-Implement-H264-decoder-GetInputAvailab.patch new file mode 100644 index 00000000..37ec31ac --- /dev/null +++ b/patches/mfplat-streaming-support/0071-winegstreamer-Implement-H264-decoder-GetInputAvailab.patch @@ -0,0 +1,56 @@ +From 8b758c937a6e90f16488c0432601ecc98761de5e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:55:46 +0100 +Subject: [PATCH 71/88] winegstreamer: Implement H264 decoder + GetInputAvailableType. + +Required by Shadow Warrior 2. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 78bf317c36f..7aca79e7a86 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -268,8 +268,27 @@ static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD st + static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) + { +- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); +- return E_NOTIMPL; ++ 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; + } + + static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0072-winegstreamer-Implement-H264-decoder-SetOutputType.patch b/patches/mfplat-streaming-support/0072-winegstreamer-Implement-H264-decoder-SetOutputType.patch new file mode 100644 index 00000000..d4fb6485 --- /dev/null +++ b/patches/mfplat-streaming-support/0072-winegstreamer-Implement-H264-decoder-SetOutputType.patch @@ -0,0 +1,93 @@ +From e1dfb79302e81c47131c820e7ee6182fc929ec22 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:56:08 +0100 +Subject: [PATCH 72/88] winegstreamer: Implement H264 decoder SetOutputType. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 39 +++++++++++++++++++++++++++++-- + 1 file changed, 37 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 7aca79e7a86..2cfc1ac0d05 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -48,6 +48,7 @@ struct h264_decoder + IMFTransform IMFTransform_iface; + LONG refcount; + IMFMediaType *input_type; ++ IMFMediaType *output_type; + }; + + static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +@@ -192,6 +193,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) + { + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); ++ if (decoder->output_type) ++ IMFMediaType_Release(decoder->output_type); + free(decoder); + } + +@@ -350,6 +353,12 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I + if (i == ARRAY_SIZE(h264_decoder_input_types)) + return MF_E_INVALIDMEDIATYPE; + ++ 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)); +@@ -359,8 +368,34 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I + + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ 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 < ARRAY_SIZE(h264_decoder_output_types); ++i) ++ if (IsEqualGUID(&subtype, h264_decoder_output_types[i])) ++ break; ++ if (i == ARRAY_SIZE(h264_decoder_output_types)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (decoder->output_type) ++ IMFMediaType_Release(decoder->output_type); ++ IMFMediaType_AddRef((decoder->output_type = type)); ++ ++ return S_OK; + } + + static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0073-winegstreamer-Implement-H264-decoder-GetInputStreamI.patch b/patches/mfplat-streaming-support/0073-winegstreamer-Implement-H264-decoder-GetInputStreamI.patch new file mode 100644 index 00000000..154b5ff2 --- /dev/null +++ b/patches/mfplat-streaming-support/0073-winegstreamer-Implement-H264-decoder-GetInputStreamI.patch @@ -0,0 +1,50 @@ +From e186fc28c685facf9bb0c0d1b1e5aee8c9352b30 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:56:23 +0100 +Subject: [PATCH 73/88] winegstreamer: Implement H264 decoder + GetInputStreamInfo. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 2cfc1ac0d05..1ccb5f39908 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -225,8 +225,20 @@ static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input + + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ ++ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); ++ ++ if (!decoder->input_type) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ info->hnsMaxLatency = 0; ++ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; ++ info->cbSize = 0x1000; ++ info->cbMaxLookahead = 0; ++ info->cbAlignment = 0; ++ ++ return S_OK; + } + + static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0074-winegstreamer-Implement-H264-decoder-GetOutputStream.patch b/patches/mfplat-streaming-support/0074-winegstreamer-Implement-H264-decoder-GetOutputStream.patch new file mode 100644 index 00000000..0fcbc317 --- /dev/null +++ b/patches/mfplat-streaming-support/0074-winegstreamer-Implement-H264-decoder-GetOutputStream.patch @@ -0,0 +1,55 @@ +From a0aa60794e90bd635983dfb7158ba19bdb4e3485 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:56:35 +0100 +Subject: [PATCH 74/88] winegstreamer: Implement H264 decoder + GetOutputStreamInfo. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 1ccb5f39908..eadb28cdaaa 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -243,8 +243,25 @@ static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD + + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ IMFMediaType *media_type; ++ UINT32 sample_size; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); ++ ++ if (!decoder->input_type || !decoder->output_type) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ media_type = decoder->output_type; ++ ++ info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; ++ if (FAILED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) ++ sample_size = 1920 * 1080 * 2; ++ info->cbSize = sample_size; ++ info->cbAlignment = 0; ++ ++ return S_OK; + } + + static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0075-winegstreamer-Add-H264-encoded-format-support-in-wg_.patch b/patches/mfplat-streaming-support/0075-winegstreamer-Add-H264-encoded-format-support-in-wg_.patch new file mode 100644 index 00000000..dc98fe86 --- /dev/null +++ b/patches/mfplat-streaming-support/0075-winegstreamer-Add-H264-encoded-format-support-in-wg_.patch @@ -0,0 +1,264 @@ +From b3ce2fcb76da45fbf1683cbd518172eae8d8d277 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:33:39 +0100 +Subject: [PATCH 75/88] winegstreamer: Add H264 encoded format support in + wg_transform. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 36 +++++++++++++++++- + dlls/winegstreamer/mfplat.c | 37 ++++++++++++++++++ + dlls/winegstreamer/unixlib.h | 8 ++++ + dlls/winegstreamer/wg_transform.c | 63 +++++++++++++++++++++++++++++++ + 4 files changed, 143 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index eadb28cdaaa..b7de097fc7d 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -49,6 +49,8 @@ struct h264_decoder + LONG refcount; + IMFMediaType *input_type; + IMFMediaType *output_type; ++ ++ struct wg_transform *wg_transform; + }; + + static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +@@ -56,6 +58,30 @@ 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) ++{ ++ struct wg_encoded_format input_format; ++ struct wg_format output_format; ++ ++ if (decoder->wg_transform) ++ wg_transform_destroy(decoder->wg_transform); ++ ++ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); ++ if (input_format.encoded_type == WG_ENCODED_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 = wg_transform_create(&input_format, &output_format); ++ if (decoder->wg_transform) ++ return S_OK; ++ ++ WARN("Failed to create H264 wg_transform.\n"); ++ return E_FAIL; ++} ++ + static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) + { + UINT32 value, width, height; +@@ -191,6 +217,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) + + 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) +@@ -424,7 +452,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, + IMFMediaType_Release(decoder->output_type); + IMFMediaType_AddRef((decoder->output_type = type)); + +- return S_OK; ++ if (FAILED(hr = try_create_wg_transform(decoder))) ++ { ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = NULL; ++ } ++ ++ return hr; + } + + static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index ca26c767125..f2cdd04070d 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -938,6 +938,36 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w + memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); + } + ++static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) ++{ ++ UINT64 frame_rate, frame_size; ++ UINT32 profile, level; ++ ++ format->encoded_type = WG_ENCODED_TYPE_H264; ++ format->u.h264.width = 0; ++ format->u.h264.height = 0; ++ format->u.h264.fps_n = 1; ++ format->u.h264.fps_d = 1; ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) ++ { ++ format->u.h264.width = (UINT32)(frame_size >> 32); ++ format->u.h264.height = (UINT32)frame_size; ++ } ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) ++ { ++ format->u.h264.fps_n = (UINT32)(frame_rate >> 32); ++ format->u.h264.fps_d = (UINT32)frame_rate; ++ } ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) ++ format->u.h264.profile = profile; ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) ++ format->u.h264.level = level; ++} ++ + void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) + { + GUID major_type, subtype; +@@ -970,6 +1000,13 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo + else + FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); + } ++ else if (IsEqualGUID(&major_type, &MFMediaType_Video)) ++ { ++ if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) ++ mf_media_type_to_wg_encoded_format_h264(type, format); ++ else ++ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); ++ } + else + { + FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 0df245408ee..84564008ee2 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -132,6 +132,7 @@ struct wg_encoded_format + WG_ENCODED_TYPE_UNKNOWN, + WG_ENCODED_TYPE_WMA, + WG_ENCODED_TYPE_XMA, ++ WG_ENCODED_TYPE_H264, + } encoded_type; + + union +@@ -147,6 +148,13 @@ struct wg_encoded_format + uint32_t codec_data_len; + unsigned char codec_data[64]; + } xwma; ++ struct ++ { ++ int32_t width, height; ++ uint32_t fps_n, fps_d; ++ uint32_t profile; ++ uint32_t level; ++ } h264; + } u; + }; + +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 256e77429a0..2956ddf753b 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -98,6 +98,64 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) + return caps; + } + ++static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) ++{ ++ const char *profile, *level; ++ GstCaps *caps; ++ ++ caps = gst_caps_new_empty_simple("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); ++ ++ if (format->u.h264.width) ++ gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL); ++ if (format->u.h264.height) ++ gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL); ++ if (format->u.h264.fps_n || format->u.h264.fps_d) ++ gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL); ++ ++ switch (format->u.h264.profile) ++ { ++ case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; ++ case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; ++ case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; ++ default: ++ GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile); ++ /* fallthrough */ ++ case 0: profile = NULL; ++ } ++ if (profile) ++ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); ++ ++ switch (format->u.h264.level) ++ { ++ case /* eAVEncH264VLevel1 */ 10: level = "1"; break; ++ case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; ++ case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; ++ case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; ++ case /* eAVEncH264VLevel2 */ 20: level = "2"; break; ++ case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; ++ case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; ++ case /* eAVEncH264VLevel3 */ 30: level = "3"; break; ++ case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; ++ case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; ++ case /* eAVEncH264VLevel4 */ 40: level = "4"; break; ++ case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; ++ case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; ++ case /* eAVEncH264VLevel5 */ 50: level = "5"; break; ++ case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; ++ case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; ++ default: ++ GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level); ++ /* fallthrough */ ++ case 0: level = NULL; ++ } ++ if (level) ++ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); ++ ++ return caps; ++} ++ + static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) + { + switch (format->encoded_type) +@@ -107,6 +165,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format + case WG_ENCODED_TYPE_WMA: + case WG_ENCODED_TYPE_XMA: + return wg_format_to_caps_xwma(format); ++ case WG_ENCODED_TYPE_H264: ++ return wg_format_to_caps_h264(format); + } + assert(0); + return NULL; +@@ -286,7 +346,10 @@ NTSTATUS wg_transform_create(void *args) + !transform_append_element(transform, element, &first, &last)) + goto failed; + break; ++ case WG_MAJOR_TYPE_VIDEO: ++ break; + default: ++ assert(0); + break; + } + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0076-winegstreamer-Implement-H264-decoder-ProcessInput.patch b/patches/mfplat-streaming-support/0076-winegstreamer-Implement-H264-decoder-ProcessInput.patch new file mode 100644 index 00000000..9b82e76f --- /dev/null +++ b/patches/mfplat-streaming-support/0076-winegstreamer-Implement-H264-decoder-ProcessInput.patch @@ -0,0 +1,63 @@ +From ae960b62a8e83ea1f14ac04acd876c00c4ae0b7f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:56:47 +0100 +Subject: [PATCH 76/88] winegstreamer: Implement H264 decoder ProcessInput. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index b7de097fc7d..268262a0f18 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -506,8 +506,34 @@ static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA + + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ IMFMediaBuffer *media_buffer; ++ MFT_INPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ BYTE *buffer; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); ++ ++ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) ++ goto done; ++ ++ hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size); ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; + } + + static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0077-winegstreamer-Implement-H264-decoder-ProcessOutput.patch b/patches/mfplat-streaming-support/0077-winegstreamer-Implement-H264-decoder-ProcessOutput.patch new file mode 100644 index 00000000..cab0f41d --- /dev/null +++ b/patches/mfplat-streaming-support/0077-winegstreamer-Implement-H264-decoder-ProcessOutput.patch @@ -0,0 +1,83 @@ +From 9509bc29d7a6d0514f2573007b2aa3399f4d2095 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:57:10 +0100 +Subject: [PATCH 77/88] winegstreamer: Implement H264 decoder ProcessOutput. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 50 +++++++++++++++++++++++++++++-- + 1 file changed, 48 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 268262a0f18..44d55ae061f 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -539,8 +539,54 @@ done: + static HRESULT WINAPI h264_decoder_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; ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ struct wg_sample wg_sample = {0}; ++ IMFMediaBuffer *media_buffer; ++ MFT_OUTPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ HRESULT hr; ++ ++ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); ++ ++ if (count > 1) ++ { ++ FIXME("Not implemented count %lu\n", count); ++ return E_NOTIMPL; ++ } ++ ++ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ *status = 0; ++ samples[0].dwStatus = 0; ++ if (!samples[0].pSample) ++ { ++ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) ++ goto done; ++ wg_sample.size = buffer_size; ++ ++ if (wg_sample.size < info.cbSize) ++ hr = MF_E_BUFFERTOOSMALL; ++ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) ++ hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ if (FAILED(hr)) ++ IMFMediaBuffer_SetCurrentLength(media_buffer, 0); ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; + } + + static const IMFTransformVtbl h264_decoder_vtbl = +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0078-winegstreamer-Add-timestamps-and-duration-to-H264-de.patch b/patches/mfplat-streaming-support/0078-winegstreamer-Add-timestamps-and-duration-to-H264-de.patch new file mode 100644 index 00000000..70191c33 --- /dev/null +++ b/patches/mfplat-streaming-support/0078-winegstreamer-Add-timestamps-and-duration-to-H264-de.patch @@ -0,0 +1,87 @@ +From 1ddbede0757008fc9db91f03f0fbc1c671822b9b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:34:12 +0100 +Subject: [PATCH 78/88] winegstreamer: Add timestamps and duration to H264 + decoded samples. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 6 ++++++ + dlls/winegstreamer/unixlib.h | 4 ++++ + dlls/winegstreamer/wg_transform.c | 11 +++++++++++ + 3 files changed, 21 insertions(+) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 44d55ae061f..69e747f1dc0 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -578,7 +578,13 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + if (wg_sample.size < info.cbSize) + hr = MF_E_BUFFERTOOSMALL; + else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) ++ { ++ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) ++ IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); ++ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) ++ IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); + hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); ++ } + + IMFMediaBuffer_Unlock(media_buffer); + +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 84564008ee2..543e92e6c0d 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -329,6 +329,8 @@ struct wg_transform_push_data_params + enum wg_sample_flags + { + WG_SAMPLE_FLAG_INCOMPLETE = 1, ++ WG_SAMPLE_FLAG_HAS_PTS = 2, ++ WG_SAMPLE_FLAG_HAS_DURATION = 4, + }; + + struct wg_sample +@@ -336,6 +338,8 @@ struct wg_sample + UINT32 flags; + BYTE *data; + UINT32 size; ++ /* pts and duration are in 100-nanosecond units. */ ++ ULONGLONG pts, duration; + }; + + struct wg_transform_read_data_params +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 2956ddf753b..93e777ba39a 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -489,6 +489,17 @@ NTSTATUS wg_transform_read_data(void *args) + memcpy(read_sample->data, info.data, read_sample->size); + gst_buffer_unmap(buffer, &info); + ++ if (buffer->pts != GST_CLOCK_TIME_NONE) ++ { ++ read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; ++ read_sample->pts = buffer->pts / 100; ++ } ++ if (buffer->duration != GST_CLOCK_TIME_NONE) ++ { ++ read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; ++ read_sample->duration = buffer->duration / 100; ++ } ++ + if (info.size > read_sample->size) + { + read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0079-winegstreamer-Support-dynamic-wg_transform-video-for.patch b/patches/mfplat-streaming-support/0079-winegstreamer-Support-dynamic-wg_transform-video-for.patch new file mode 100644 index 00000000..aec4f63a --- /dev/null +++ b/patches/mfplat-streaming-support/0079-winegstreamer-Support-dynamic-wg_transform-video-for.patch @@ -0,0 +1,285 @@ +From af85dd52165d0c5755a34c7df87cbc631c92efcc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:57:36 +0100 +Subject: [PATCH 79/88] winegstreamer: Support dynamic wg_transform video + format change. + +For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, +Yakuza 4 Remastered, Hard Reset Redux. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 26 ++++++++++++- + dlls/winegstreamer/unix_private.h | 2 + + dlls/winegstreamer/unixlib.h | 1 + + dlls/winegstreamer/wg_parser.c | 4 +- + dlls/winegstreamer/wg_transform.c | 61 ++++++++++++++++++++++++++++++- + 5 files changed, 89 insertions(+), 5 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 69e747f1dc0..219790128da 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -51,6 +51,7 @@ struct h264_decoder + IMFMediaType *output_type; + + struct wg_transform *wg_transform; ++ struct wg_format wg_format; + }; + + static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +@@ -378,7 +379,7 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) + goto done; + +- hr = fill_output_media_type(media_type, NULL); ++ hr = fill_output_media_type(media_type, decoder->output_type); + + done: + if (SUCCEEDED(hr)) +@@ -427,6 +428,7 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, + { + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; ++ BOOL identical; + HRESULT hr; + ULONG i; + +@@ -449,7 +451,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, + return MF_E_INVALIDMEDIATYPE; + + if (decoder->output_type) ++ { ++ if (SUCCEEDED(hr = IMFMediaType_Compare(decoder->output_type, (IMFAttributes *)type, ++ MF_ATTRIBUTES_MATCH_THEIR_ITEMS, &identical)) && identical) ++ return S_OK; + IMFMediaType_Release(decoder->output_type); ++ } ++ + IMFMediaType_AddRef((decoder->output_type = type)); + + if (FAILED(hr = try_create_wg_transform(decoder))) +@@ -543,6 +551,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + struct wg_sample wg_sample = {0}; + IMFMediaBuffer *media_buffer; + MFT_OUTPUT_STREAM_INFO info; ++ IMFMediaType *media_type; + DWORD buffer_size; + HRESULT hr; + +@@ -575,6 +584,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + goto done; + wg_sample.size = buffer_size; + ++ wg_sample.format = &decoder->wg_format; + if (wg_sample.size < info.cbSize) + hr = MF_E_BUFFERTOOSMALL; + else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) +@@ -585,6 +595,20 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); + hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); + } ++ else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) ++ { ++ media_type = mf_media_type_from_wg_format(&decoder->wg_format); ++ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, wg_sample.size); ++ IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_RATE); ++ IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); ++ fill_output_media_type(media_type, decoder->output_type); ++ ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = media_type; ++ ++ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; ++ *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; ++ } + + IMFMediaBuffer_Unlock(media_buffer); + +diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h +index 1b055436ba5..88566ab1db5 100644 +--- a/dlls/winegstreamer/unix_private.h ++++ b/dlls/winegstreamer/unix_private.h +@@ -26,6 +26,8 @@ + extern bool init_gstreamer(void) DECLSPEC_HIDDEN; + extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; + extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; ++extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; ++extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; + + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; + extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 543e92e6c0d..1beeed8f1a2 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -340,6 +340,7 @@ struct wg_sample + UINT32 size; + /* pts and duration are in 100-nanosecond units. */ + ULONGLONG pts, duration; ++ struct wg_format *format; + }; + + struct wg_transform_read_data_params +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 3217c78e864..8e64735bd64 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -311,7 +311,7 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs + format->u.video.fps_d = fps_d; + } + +-static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) ++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); +@@ -556,7 +556,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) + return NULL; + } + +-static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) ++bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) + { + if (a->major_type != b->major_type) + return false; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 93e777ba39a..df37b4e8543 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -56,6 +56,7 @@ struct wg_transform + GstPad *their_sink, *their_src; + pthread_mutex_t mutex; + struct list samples; ++ GstCaps *sink_caps; + }; + + static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) +@@ -184,7 +185,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst + else + { + pthread_mutex_lock(&transform->mutex); +- if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) ++ if (!(sample->sample = gst_sample_new(buffer, transform->sink_caps, NULL, NULL))) + GST_ERROR("Failed to allocate transform sample"); + list_add_tail(&transform->samples, &sample->entry); + pthread_mutex_unlock(&transform->mutex); +@@ -194,6 +195,38 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst + return GST_FLOW_OK; + } + ++static gboolean transform_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) ++{ ++ struct wg_transform *transform = gst_pad_get_element_private(pad); ++ ++ GST_INFO("transform %p, type \"%s\".", transform, GST_EVENT_TYPE_NAME(event)); ++ ++ switch (event->type) ++ { ++ case GST_EVENT_CAPS: ++ { ++ GstCaps *caps; ++ gchar *str; ++ ++ gst_event_parse_caps(event, &caps); ++ str = gst_caps_to_string(caps); ++ GST_WARNING("Got caps \"%s\".", str); ++ g_free(str); ++ ++ pthread_mutex_lock(&transform->mutex); ++ gst_caps_unref(transform->sink_caps); ++ transform->sink_caps = gst_caps_ref(caps); ++ pthread_mutex_unlock(&transform->mutex); ++ break; ++ } ++ default: ++ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event)); ++ } ++ ++ gst_event_unref(event); ++ return TRUE; ++} ++ + NTSTATUS wg_transform_destroy(void *args) + { + struct wg_transform *transform = args; +@@ -311,7 +344,7 @@ NTSTATUS wg_transform_create(void *args) + GstPadTemplate *template; + const gchar *media_type; + GstSegment *segment; +- int ret; ++ int i, ret; + + if (!init_gstreamer()) + return E_FAIL; +@@ -329,6 +362,7 @@ NTSTATUS wg_transform_create(void *args) + raw_caps = gst_caps_new_empty_simple(media_type); + assert(raw_caps); + ++ transform->sink_caps = gst_caps_copy(sink_caps); + transform->container = gst_bin_new("wg_transform"); + assert(transform->container); + +@@ -347,6 +381,12 @@ NTSTATUS wg_transform_create(void *args) + goto failed; + break; + case WG_MAJOR_TYPE_VIDEO: ++ if (!(element = create_element("videoconvert", "base")) || ++ !transform_append_element(transform, element, &first, &last)) ++ goto failed; ++ for (i = 0; i < gst_caps_get_size(sink_caps); ++i) ++ gst_structure_remove_fields(gst_caps_get_structure(sink_caps, i), ++ "width", "height", NULL); + break; + default: + assert(0); +@@ -377,6 +417,7 @@ NTSTATUS wg_transform_create(void *args) + assert(transform->my_sink); + + gst_pad_set_element_private(transform->my_sink, transform); ++ gst_pad_set_event_function(transform->my_sink, transform_sink_event_cb); + gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); + + if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) +@@ -469,9 +510,11 @@ NTSTATUS wg_transform_read_data(void *args) + struct wg_transform *transform = params->transform; + struct wg_sample *read_sample = params->sample; + struct wg_transform_sample *transform_sample; ++ struct wg_format buffer_format; + GstBuffer *buffer; + struct list *head; + GstMapInfo info; ++ GstCaps *caps; + + pthread_mutex_lock(&transform->mutex); + if (!(head = list_head(&transform->samples))) +@@ -483,6 +526,20 @@ NTSTATUS wg_transform_read_data(void *args) + transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); + buffer = gst_sample_get_buffer(transform_sample->sample); + ++ if (read_sample->format) ++ { ++ if (!(caps = gst_sample_get_caps(transform_sample->sample))) ++ caps = transform->sink_caps; ++ wg_format_from_caps(&buffer_format, caps); ++ if (!wg_format_compare(read_sample->format, &buffer_format)) ++ { ++ *read_sample->format = buffer_format; ++ read_sample->size = gst_buffer_get_size(buffer); ++ pthread_mutex_unlock(&transform->mutex); ++ return MF_E_TRANSFORM_STREAM_CHANGE; ++ } ++ } ++ + gst_buffer_map(buffer, &info, GST_MAP_READ); + if (read_sample->size > info.size) + read_sample->size = info.size; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0080-winegstreamer-Fixup-H264-decoder-NV12-plane-alignmen.patch b/patches/mfplat-streaming-support/0080-winegstreamer-Fixup-H264-decoder-NV12-plane-alignmen.patch new file mode 100644 index 00000000..c24acdeb --- /dev/null +++ b/patches/mfplat-streaming-support/0080-winegstreamer-Fixup-H264-decoder-NV12-plane-alignmen.patch @@ -0,0 +1,112 @@ +From db138323808ecd9938a0f40b810ad68fc39b389c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:58:20 +0100 +Subject: [PATCH 80/88] winegstreamer: Fixup H264 decoder NV12 plane alignment. + +To match what native does. Many games that use the H264 decoder directly +rely on this as they hardcode various aspects of the alignment in their +logic (and each game a different one). + +Note: There may be a way to have it done by GStreamer, as libav natively +decode H264 into aligned planes, but somehow and somewhere in the chain +the planes are re-aligned. + +Hard Reset Redux crashes if MF_MT_MINIMUM_DISPLAY_APERTURE attribute is +set (and it doesn't need it as its videos are 720p). + +For: Call of Duty III, Shadow Warrior 2. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 40 +++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 219790128da..66ecfad84de 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -86,6 +86,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) + static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) + { + UINT32 value, width, height; ++ MFVideoArea aperture = {0}; + UINT64 value64; + GUID subtype; + HRESULT hr; +@@ -177,6 +178,17 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de + return hr; + } + ++ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))) ++ { ++ if (default_type && SUCCEEDED(hr = IMFMediaType_GetBlob(default_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, ++ (BYTE *)&aperture, sizeof(aperture), NULL))) ++ { ++ if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, ++ (BYTE *)&aperture, sizeof(aperture)))) ++ return hr; ++ } ++ } ++ + return S_OK; + } + +@@ -551,7 +563,9 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + struct wg_sample wg_sample = {0}; + IMFMediaBuffer *media_buffer; + MFT_OUTPUT_STREAM_INFO info; ++ MFVideoArea aperture = {0}; + IMFMediaType *media_type; ++ UINT32 align, offset; + DWORD buffer_size; + HRESULT hr; + +@@ -593,6 +607,17 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); + if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) + IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); ++ ++ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && ++ (align = decoder->wg_format.u.video.height & 15)) ++ { ++ offset = decoder->wg_format.u.video.width * decoder->wg_format.u.video.height; ++ align = (16 - align) * decoder->wg_format.u.video.width; ++ memmove(wg_sample.data + offset + align, wg_sample.data + offset, ++ wg_sample.size - offset); ++ wg_sample.size += align; ++ } ++ + hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); + } + else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) +@@ -603,6 +628,21 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); + fill_output_media_type(media_type, decoder->output_type); + ++ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && ++ (align = decoder->wg_format.u.video.height & 15)) ++ { ++ aperture.Area.cx = decoder->wg_format.u.video.width; ++ aperture.Area.cy = decoder->wg_format.u.video.height; ++ IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, ++ (BYTE *)&aperture, sizeof(aperture)); ++ ++ aperture.Area.cy += 16 - align; ++ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ++ (UINT64)aperture.Area.cx << 32 | aperture.Area.cy); ++ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, ++ aperture.Area.cx * aperture.Area.cy * 3 / 2); ++ } ++ + IMFMediaType_Release(decoder->output_type); + decoder->output_type = media_type; + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0081-winegstreamer-Use-an-optional-h264parse-wg_transform.patch b/patches/mfplat-streaming-support/0081-winegstreamer-Use-an-optional-h264parse-wg_transform.patch new file mode 100644 index 00000000..09b589ff --- /dev/null +++ b/patches/mfplat-streaming-support/0081-winegstreamer-Use-an-optional-h264parse-wg_transform.patch @@ -0,0 +1,44 @@ +From e4378c0f59983416570621596b875ca91048bb7c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 21:46:08 +0100 +Subject: [PATCH 81/88] winegstreamer: Use an optional h264parse wg_transform + element. + +Required for Mortal Kombat 11. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/wg_transform.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index df37b4e8543..e3b7d8ed056 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -366,6 +366,17 @@ NTSTATUS wg_transform_create(void *args) + transform->container = gst_bin_new("wg_transform"); + assert(transform->container); + ++ switch (input_format.encoded_type) ++ { ++ case WG_ENCODED_TYPE_H264: ++ if ((element = create_element("h264parse", "base")) && ++ !transform_append_element(transform, element, &first, &last)) ++ goto failed; ++ break; ++ default: ++ break; ++ } ++ + if (!(element = try_create_transform(src_caps, raw_caps)) || + !transform_append_element(transform, element, &first, &last)) + goto failed; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0082-HACK-winegstreamer-Fake-H264-timestamps-if-framerate.patch b/patches/mfplat-streaming-support/0082-HACK-winegstreamer-Fake-H264-timestamps-if-framerate.patch new file mode 100644 index 00000000..dce2eb1e --- /dev/null +++ b/patches/mfplat-streaming-support/0082-HACK-winegstreamer-Fake-H264-timestamps-if-framerate.patch @@ -0,0 +1,106 @@ +From 292b80383163c9537733b47c27c6f2144edb18b5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 10 Feb 2022 09:58:32 +0100 +Subject: [PATCH 82/88] HACK: winegstreamer: Fake H264 timestamps if framerate + cannot be trusted. + +Fixes MK11 video framerate. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ + dlls/winegstreamer/wg_transform.c | 10 ++++++++-- + 2 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index 66ecfad84de..ba6e681890b 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -52,6 +52,7 @@ struct h264_decoder + + struct wg_transform *wg_transform; + struct wg_format wg_format; ++ ULONGLONG last_pts; + }; + + static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) +@@ -75,6 +76,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + ++ decoder->last_pts = 0; + decoder->wg_transform = wg_transform_create(&input_format, &output_format); + if (decoder->wg_transform) + return S_OK; +@@ -567,6 +569,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + IMFMediaType *media_type; + UINT32 align, offset; + DWORD buffer_size; ++ UINT64 framerate; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); +@@ -603,6 +606,15 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag + hr = MF_E_BUFFERTOOSMALL; + else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) + { ++ if (!(wg_sample.flags & (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION))) ++ { ++ IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &framerate); ++ wg_sample.pts = decoder->last_pts; ++ wg_sample.duration = (UINT64)10000000 * (UINT32)framerate / (framerate >> 32); ++ wg_sample.flags |= (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); ++ decoder->last_pts += wg_sample.duration; ++ } ++ + if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) + IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); + if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index e3b7d8ed056..1c9dc6f72bb 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -522,6 +522,7 @@ NTSTATUS wg_transform_read_data(void *args) + struct wg_sample *read_sample = params->sample; + struct wg_transform_sample *transform_sample; + struct wg_format buffer_format; ++ bool broken_timestamp = false; + GstBuffer *buffer; + struct list *head; + GstMapInfo info; +@@ -549,6 +550,11 @@ NTSTATUS wg_transform_read_data(void *args) + pthread_mutex_unlock(&transform->mutex); + return MF_E_TRANSFORM_STREAM_CHANGE; + } ++ ++ if (buffer_format.major_type == WG_MAJOR_TYPE_VIDEO ++ && buffer_format.u.video.fps_n <= 1 ++ && buffer_format.u.video.fps_d <= 1) ++ broken_timestamp = true; + } + + gst_buffer_map(buffer, &info, GST_MAP_READ); +@@ -557,12 +563,12 @@ NTSTATUS wg_transform_read_data(void *args) + memcpy(read_sample->data, info.data, read_sample->size); + gst_buffer_unmap(buffer, &info); + +- if (buffer->pts != GST_CLOCK_TIME_NONE) ++ if (buffer->pts != GST_CLOCK_TIME_NONE && !broken_timestamp) + { + read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; + read_sample->pts = buffer->pts / 100; + } +- if (buffer->duration != GST_CLOCK_TIME_NONE) ++ if (buffer->duration != GST_CLOCK_TIME_NONE && !broken_timestamp) + { + read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; + read_sample->duration = buffer->duration / 100; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0083-winegstreamer-Reset-internal-format-on-BEGIN_STREAMI.patch b/patches/mfplat-streaming-support/0083-winegstreamer-Reset-internal-format-on-BEGIN_STREAMI.patch new file mode 100644 index 00000000..2a2abd15 --- /dev/null +++ b/patches/mfplat-streaming-support/0083-winegstreamer-Reset-internal-format-on-BEGIN_STREAMI.patch @@ -0,0 +1,49 @@ +From 0f2c90c60d6ec76f5339dd891e5a3160ce9dea2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 8 Feb 2022 11:21:39 +0100 +Subject: [PATCH 83/88] winegstreamer: Reset internal format on BEGIN_STREAMING + message. + +In order to regenerate a MF_E_TRANSFORM_STREAM_CHANGE status on next +successful ProcessOutput. CoD: Black Ops 3 depends on this, or crashes +if MF_E_TRANSFORM_STREAM_CHANGE isn't returned when the campaign intro +video begins to play. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 +CW-Bug-Id: #16839 +CW-Bug-Id: #18678 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c +index ba6e681890b..ede0bd36bce 100644 +--- a/dlls/winegstreamer/h264_decoder.c ++++ b/dlls/winegstreamer/h264_decoder.c +@@ -522,7 +522,19 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I + + static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { ++ struct h264_decoder *decoder = impl_from_IMFTransform(iface); ++ + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); ++ ++ switch (message) ++ { ++ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: ++ memset(&decoder->wg_format, 0, sizeof(decoder->wg_format)); ++ break; ++ default: ++ break; ++ } ++ + return S_OK; + } + +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0084-winegstreamer-Reimplement-AAC-decoder-using-wg_trans.patch b/patches/mfplat-streaming-support/0084-winegstreamer-Reimplement-AAC-decoder-using-wg_trans.patch new file mode 100644 index 00000000..a51af9a4 --- /dev/null +++ b/patches/mfplat-streaming-support/0084-winegstreamer-Reimplement-AAC-decoder-using-wg_trans.patch @@ -0,0 +1,878 @@ +From 9d7af078fcee25d78c5da2d366872f1c3e57f68c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 21 Jan 2022 14:36:32 +0100 +Subject: [PATCH 84/88] winegstreamer: Reimplement AAC decoder using + wg_transform. + +For Call of Duty III, possibly others. This will need to be split. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 +CW-Bug-Id: #19362 +--- + dlls/winegstreamer/Makefile.in | 1 + + dlls/winegstreamer/aac_decoder.c | 622 ++++++++++++++++++++++++++++++ + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/mfplat.c | 72 ++++ + dlls/winegstreamer/unixlib.h | 8 + + dlls/winegstreamer/wg_transform.c | 48 +++ + 6 files changed, 752 insertions(+) + create mode 100644 dlls/winegstreamer/aac_decoder.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index c4f0f1cad2c..d9746534c2b 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -7,6 +7,7 @@ EXTRAINCL = $(GSTREAMER_CFLAGS) + EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) + + C_SRCS = \ ++ aac_decoder.c \ + audioconvert.c \ + colorconvert.c \ + decode_transform.c \ +diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c +new file mode 100644 +index 00000000000..3b3383a52ab +--- /dev/null ++++ b/dlls/winegstreamer/aac_decoder.c +@@ -0,0 +1,622 @@ ++/* AAC 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 "wmcodecdsp.h" ++ ++#include "wine/debug.h" ++#include "wine/heap.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(mfplat); ++ ++static const GUID *aac_decoder_input_types[] = ++{ ++ &MFAudioFormat_AAC, ++}; ++static const GUID *aac_decoder_output_types[] = ++{ ++ &MFAudioFormat_PCM, ++ &MFAudioFormat_Float, ++}; ++ ++struct aac_decoder ++{ ++ IMFTransform IMFTransform_iface; ++ LONG refcount; ++ IMFMediaType *input_type; ++ IMFMediaType *output_type; ++ ++ IMFSample *input_sample; ++ struct wg_transform *wg_transform; ++}; ++ ++static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) ++{ ++ return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); ++} ++ ++static void try_create_wg_transform(struct aac_decoder *decoder) ++{ ++ struct wg_encoded_format input_format; ++ struct wg_format output_format; ++ ++ if (!decoder->input_type || !decoder->output_type) ++ return; ++ ++ if (decoder->wg_transform) ++ wg_transform_destroy(decoder->wg_transform); ++ ++ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); ++ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) ++ return; ++ ++ mf_media_type_to_wg_format(decoder->output_type, &output_format); ++ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) ++ return; ++ ++ decoder->wg_transform = wg_transform_create(&input_format, &output_format); ++ if (!decoder->wg_transform) ++ WARN("Failed to create wg_transform.\n"); ++} ++ ++static HRESULT WINAPI aac_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) ++{ ++ struct aac_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 aac_decoder_AddRef(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; ++} ++ ++static ULONG WINAPI aac_decoder_Release(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); ++ ++ if (!refcount) ++ { ++ if (decoder->input_sample) ++ IMFSample_Release(decoder->input_sample); ++ 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); ++ free(decoder); ++ } ++ ++ return refcount; ++} ++ ++static HRESULT WINAPI aac_decoder_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 stub!\n", ++ iface, input_minimum, input_maximum, output_minimum, output_maximum); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) ++{ ++ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_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 stub!\n", ++ iface, input_size, inputs, output_size, outputs); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ UINT32 block_alignment; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); ++ ++ if (!decoder->input_type || !decoder->output_type) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) ++ return hr; ++ ++ info->hnsMaxLatency = 0; ++ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES|MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER ++ |MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE|MFT_INPUT_STREAM_HOLDS_BUFFERS; ++ info->cbSize = 0; ++ info->cbMaxLookahead = 0; ++ info->cbAlignment = 0; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI aac_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ UINT32 channel_count, block_alignment; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); ++ ++ if (!decoder->input_type || !decoder->output_type) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) ++ return hr; ++ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) ++ return hr; ++ ++ info->dwFlags = 0; ++ info->cbSize = 0x1800 * block_alignment * channel_count; ++ info->cbAlignment = 0; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI aac_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) ++{ ++ FIXME("iface %p, attributes %p stub!\n", iface, attributes); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, ++ IMFAttributes **attributes) ++{ ++ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_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 aac_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) ++{ ++ FIXME("iface %p, id %#lx stub!\n", iface, id); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) ++{ ++ FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ UINT32 channel_count, sample_size, sample_rate, block_alignment; ++ struct aac_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); ++ ++ if (!decoder->input_type) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ *type = NULL; ++ ++ if (index >= ARRAY_SIZE(aac_decoder_output_types)) ++ return MF_E_NO_MORE_TYPES; ++ index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; ++ output_type = aac_decoder_output_types[index]; ++ ++ if (FAILED(hr = MFCreateMediaType(&media_type))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) ++ goto done; ++ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) ++ goto done; ++ ++ if (IsEqualGUID(output_type, &MFAudioFormat_Float)) ++ sample_size = 32; ++ else if (IsEqualGUID(output_type, &MFAudioFormat_PCM)) ++ sample_size = 16; ++ else ++ { ++ FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type)); ++ hr = E_NOTIMPL; ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) ++ goto done; ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate))) ++ goto done; ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate))) ++ goto done; ++ ++ block_alignment = sample_size * channel_count / 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, sample_rate * block_alignment))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) ++ goto done; ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) ++ goto done; ++ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) ++ goto done; ++ ++done: ++ if (SUCCEEDED(hr)) ++ IMFMediaType_AddRef((*type = media_type)); ++ ++ IMFMediaType_Release(media_type); ++ return hr; ++} ++ ++static HRESULT WINAPI aac_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ MF_ATTRIBUTE_TYPE item_type; ++ GUID major, subtype; ++ 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 hr; ++ ++ if (!IsEqualGUID(&major, &MFMediaType_Audio)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i) ++ if (IsEqualGUID(&subtype, aac_decoder_input_types[i])) ++ break; ++ if (i == ARRAY_SIZE(aac_decoder_input_types)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type)) || ++ item_type != MF_ATTRIBUTE_BLOB) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type))) ++ return hr; ++ ++ if (decoder->output_type) ++ { ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = NULL; ++ } ++ ++ return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type); ++} ++ ++static HRESULT WINAPI aac_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ MF_ATTRIBUTE_TYPE item_type; ++ ULONG i, sample_size; ++ GUID major, subtype; ++ HRESULT hr; ++ ++ 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 hr; ++ ++ if (!IsEqualGUID(&major, &MFMediaType_Audio)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) ++ if (IsEqualGUID(&subtype, aac_decoder_output_types[i])) ++ break; ++ if (i == ARRAY_SIZE(aac_decoder_output_types)) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (IsEqualGUID(&subtype, &MFAudioFormat_Float)) ++ sample_size = 32; ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM)) ++ sample_size = 16; ++ else ++ { ++ FIXME("Subtype %s not implemented!\n", debugstr_guid(&subtype)); ++ hr = E_NOTIMPL; ++ return hr; ++ } ++ ++ if (FAILED(IMFMediaType_SetUINT32(decoder->input_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || ++ item_type != MF_ATTRIBUTE_UINT32) ++ return MF_E_INVALIDMEDIATYPE; ++ ++ if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) ++ return hr; ++ ++ try_create_wg_transform(decoder); ++ return S_OK; ++} ++ ++static HRESULT WINAPI aac_decoder_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 aac_decoder_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 aac_decoder_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 aac_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) ++{ ++ FIXME("iface %p, flags %p stub!\n", iface, flags); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) ++{ ++ FIXME("iface %p, lower %s, upper %s stub!\n", iface, ++ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI aac_decoder_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 aac_decoder_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; ++} ++ ++static HRESULT WINAPI aac_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ IMFMediaBuffer *media_buffer; ++ MFT_INPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ BYTE *buffer; ++ HRESULT hr; ++ ++ TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); ++ ++ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ if (decoder->input_sample) ++ return MF_E_NOTACCEPTING; ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) ++ goto done; ++ ++ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) ++ IMFSample_AddRef((decoder->input_sample = sample)); ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; ++} ++ ++static HRESULT WINAPI aac_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, ++ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) ++{ ++ struct aac_decoder *decoder = impl_from_IMFTransform(iface); ++ struct wg_sample wg_sample = {0}; ++ IMFMediaBuffer *media_buffer; ++ MFT_OUTPUT_STREAM_INFO info; ++ DWORD buffer_size; ++ HRESULT hr; ++ ++ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); ++ ++ if (count > 1) ++ { ++ FIXME("Not implemented count %lu\n", count); ++ return E_NOTIMPL; ++ } ++ ++ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) ++ return hr; ++ ++ if (!decoder->wg_transform) ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ ++ *status = 0; ++ samples[0].dwStatus = 0; ++ if (!samples[0].pSample) ++ { ++ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) ++ goto done; ++ wg_sample.size = buffer_size; ++ ++ if (wg_sample.size < info.cbSize) ++ hr = MF_E_BUFFERTOOSMALL; ++ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) ++ { ++ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) ++ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; ++ } ++ else ++ { ++ if (decoder->input_sample) ++ IMFSample_Release(decoder->input_sample); ++ decoder->input_sample = NULL; ++ } ++ ++ IMFMediaBuffer_Unlock(media_buffer); ++ ++done: ++ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); ++ IMFMediaBuffer_Release(media_buffer); ++ return hr; ++} ++ ++static const IMFTransformVtbl aac_decoder_vtbl = ++{ ++ aac_decoder_QueryInterface, ++ aac_decoder_AddRef, ++ aac_decoder_Release, ++ aac_decoder_GetStreamLimits, ++ aac_decoder_GetStreamCount, ++ aac_decoder_GetStreamIDs, ++ aac_decoder_GetInputStreamInfo, ++ aac_decoder_GetOutputStreamInfo, ++ aac_decoder_GetAttributes, ++ aac_decoder_GetInputStreamAttributes, ++ aac_decoder_GetOutputStreamAttributes, ++ aac_decoder_DeleteInputStream, ++ aac_decoder_AddInputStreams, ++ aac_decoder_GetInputAvailableType, ++ aac_decoder_GetOutputAvailableType, ++ aac_decoder_SetInputType, ++ aac_decoder_SetOutputType, ++ aac_decoder_GetInputCurrentType, ++ aac_decoder_GetOutputCurrentType, ++ aac_decoder_GetInputStatus, ++ aac_decoder_GetOutputStatus, ++ aac_decoder_SetOutputBounds, ++ aac_decoder_ProcessEvent, ++ aac_decoder_ProcessMessage, ++ aac_decoder_ProcessInput, ++ aac_decoder_ProcessOutput, ++}; ++ ++HRESULT aac_decoder_create(REFIID riid, void **ret) ++{ ++ struct aac_decoder *decoder; ++ ++ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); ++ ++ if (!(decoder = calloc(1, sizeof(*decoder)))) ++ return E_OUTOFMEMORY; ++ ++ decoder->IMFTransform_iface.lpVtbl = &aac_decoder_vtbl; ++ decoder->refcount = 1; ++ ++ *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 fa73fecb10d..d60e904e87f 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -128,6 +128,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo + + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); + ++HRESULT aac_decoder_create(REFIID riid, void **ret); + HRESULT h264_decoder_create(REFIID riid, void **ret); + HRESULT audio_converter_create(REFIID riid, void **ret); + HRESULT color_converter_create(REFIID riid, void **ret); +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index f2cdd04070d..e4ffb988b0b 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -30,6 +30,7 @@ + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + + DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); ++DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC, WAVE_FORMAT_RAW_AAC1); + + struct video_processor + { +@@ -448,6 +449,19 @@ static const GUID *const audio_converter_supported_types[] = + &MFAudioFormat_Float, + }; + ++static WCHAR aac_decoderW[] = L"AAC Audio Decoder MFT"; ++static const GUID *aac_decoder_input_types[] = ++{ ++ &MFAudioFormat_AAC, ++ &MFAudioFormat_RAW_AAC, ++ &MFAudioFormat_ADTS, ++}; ++static const GUID *aac_decoder_output_types[] = ++{ ++ &MFAudioFormat_Float, ++ &MFAudioFormat_PCM, ++}; ++ + static WCHAR wma_decoderW[] = L"WMAudio Decoder MFT"; + static const GUID *const wma_decoder_input_types[] = + { +@@ -521,6 +535,17 @@ mfts[] = + ARRAY_SIZE(audio_converter_supported_types), + audio_converter_supported_types, + }, ++ { ++ &CLSID_MSAACDecMFT, ++ &MFT_CATEGORY_AUDIO_DECODER, ++ aac_decoderW, ++ MFT_ENUM_FLAG_SYNCMFT, ++ &MFMediaType_Audio, ++ ARRAY_SIZE(aac_decoder_input_types), ++ aac_decoder_input_types, ++ ARRAY_SIZE(aac_decoder_output_types), ++ aac_decoder_output_types, ++ }, + { + &CLSID_WMADecMediaObject, + &MFT_CATEGORY_AUDIO_DECODER, +@@ -938,6 +963,51 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w + memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); + } + ++static void mf_media_type_to_wg_encoded_format_aac(IMFMediaType *type, struct wg_encoded_format *format) ++{ ++ UINT32 codec_data_len, payload_type, profile_level_indication; ++ BYTE codec_data[64]; ++ ++ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA ++ * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat ++ */ ++ struct ++ { ++ WORD payload_type; ++ WORD profile_level_indication; ++ WORD type; ++ WORD reserved1; ++ DWORD reserved2; ++ } *aac_info = (void *)codec_data; ++ ++ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) ++ { ++ FIXME("Codec data is not set.\n"); ++ return; ++ } ++ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) ++ { ++ FIXME("AAC payload type is not set.\n"); ++ payload_type = aac_info->payload_type; ++ } ++ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_level_indication))) ++ { ++ FIXME("AAC provile level indication is not set.\n"); ++ profile_level_indication = aac_info->profile_level_indication; ++ } ++ ++ format->encoded_type = WG_ENCODED_TYPE_AAC; ++ format->u.aac.payload_type = payload_type; ++ format->u.aac.profile_level_indication = profile_level_indication; ++ format->u.aac.codec_data_len = 0; ++ ++ if (codec_data_len > sizeof(*aac_info)) ++ { ++ format->u.aac.codec_data_len = codec_data_len - sizeof(*aac_info); ++ memcpy(format->u.aac.codec_data, codec_data + sizeof(*aac_info), codec_data_len - sizeof(*aac_info)); ++ } ++} ++ + static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) + { + UINT64 frame_rate, frame_size; +@@ -997,6 +1067,8 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo + mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); + else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) + mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); ++ else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) ++ mf_media_type_to_wg_encoded_format_aac(type, format); + else + FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); + } +diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h +index 1beeed8f1a2..2cf75c4320e 100644 +--- a/dlls/winegstreamer/unixlib.h ++++ b/dlls/winegstreamer/unixlib.h +@@ -132,6 +132,7 @@ struct wg_encoded_format + WG_ENCODED_TYPE_UNKNOWN, + WG_ENCODED_TYPE_WMA, + WG_ENCODED_TYPE_XMA, ++ WG_ENCODED_TYPE_AAC, + WG_ENCODED_TYPE_H264, + } encoded_type; + +@@ -149,6 +150,13 @@ struct wg_encoded_format + unsigned char codec_data[64]; + } xwma; + struct ++ { ++ uint32_t payload_type; ++ uint32_t profile_level_indication; ++ uint32_t codec_data_len; ++ unsigned char codec_data[64]; ++ } aac; ++ struct + { + int32_t width, height; + uint32_t fps_n, fps_d; +diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c +index 1c9dc6f72bb..775ac14e6a5 100644 +--- a/dlls/winegstreamer/wg_transform.c ++++ b/dlls/winegstreamer/wg_transform.c +@@ -99,6 +99,52 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) + return caps; + } + ++static GstCaps *wg_format_to_caps_aac(const struct wg_encoded_format *format) ++{ ++ const char *profile, *level, *stream_format; ++ GstBuffer *buffer; ++ GstCaps *caps; ++ ++ caps = gst_caps_new_empty_simple("audio/mpeg"); ++ gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); ++ ++ switch (format->u.aac.payload_type) ++ { ++ case 0: stream_format = "raw"; break; ++ case 1: stream_format = "adts"; break; ++ case 2: stream_format = "adif"; break; ++ case 3: stream_format = "loas"; break; ++ default: stream_format = "raw"; break; ++ } ++ if (stream_format) ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, stream_format, NULL); ++ ++ switch (format->u.aac.profile_level_indication) ++ { ++ case 0x29: profile = "lc"; level = "2"; break; ++ case 0x2A: profile = "lc"; level = "4"; break; ++ case 0x2B: profile = "lc"; level = "5"; break; ++ default: ++ GST_FIXME("Unrecognized profile-level-indication %u\n", format->u.aac.profile_level_indication); ++ /* fallthrough */ ++ case 0x00: case 0xFE: profile = level = NULL; break; /* unspecified */ ++ } ++ if (profile) ++ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); ++ if (level) ++ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); ++ ++ if (format->u.aac.codec_data_len) ++ { ++ buffer = gst_buffer_new_and_alloc(format->u.aac.codec_data_len); ++ gst_buffer_fill(buffer, 0, format->u.aac.codec_data, format->u.aac.codec_data_len); ++ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); ++ gst_buffer_unref(buffer); ++ } ++ ++ return caps; ++} ++ + static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) + { + const char *profile, *level; +@@ -166,6 +212,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format + case WG_ENCODED_TYPE_WMA: + case WG_ENCODED_TYPE_XMA: + return wg_format_to_caps_xwma(format); ++ case WG_ENCODED_TYPE_AAC: ++ return wg_format_to_caps_aac(format); + case WG_ENCODED_TYPE_H264: + return wg_format_to_caps_h264(format); + } +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0085-winegstreamer-After-failing-to-create-decodebin-pars.patch b/patches/mfplat-streaming-support/0085-winegstreamer-After-failing-to-create-decodebin-pars.patch new file mode 100644 index 00000000..1c6c42a6 --- /dev/null +++ b/patches/mfplat-streaming-support/0085-winegstreamer-After-failing-to-create-decodebin-pars.patch @@ -0,0 +1,154 @@ +From 66297c1fc47704e3df28d8b199bdad62d66ed569 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Mon, 24 Jan 2022 00:46:03 -0500 +Subject: [PATCH 85/88] winegstreamer: After failing to create decodebin + parser, try protonvideoconv. + +--- + dlls/winegstreamer/wg_parser.c | 69 +++++++++++++++++++++++++++++++++- + 1 file changed, 68 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 8e64735bd64..0b4e488bea6 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -91,6 +91,8 @@ struct wg_parser + + bool unlimited_buffering; + struct wg_format input_format; ++ ++ bool use_mediaconv; + }; + + struct wg_parser_stream +@@ -1019,6 +1021,34 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, + return GST_AUTOPLUG_SELECT_TRY; + } + ++static gint find_videoconv_cb(gconstpointer a, gconstpointer b) ++{ ++ const GValue *val_a = a, *val_b = b; ++ GstElementFactory *factory_a = g_value_get_object(val_a), *factory_b = g_value_get_object(val_b); ++ const char *name_a = gst_element_factory_get_longname(factory_a), *name_b = gst_element_factory_get_longname(factory_b); ++ ++ if (!strcmp(name_a, "Proton video converter")) ++ return -1; ++ if (!strcmp(name_b, "Proton video converter")) ++ return 1; ++ return 0; ++} ++ ++static GValueArray *autoplug_sort_cb(GstElement *bin, GstPad *pad, ++ GstCaps *caps, GValueArray *factories, gpointer user) ++{ ++ struct wg_parser *parser = user; ++ GValueArray *ret = g_value_array_copy(factories); ++ ++ if (!parser->use_mediaconv) ++ return NULL; ++ ++ GST_DEBUG("parser %p.", parser); ++ ++ g_value_array_sort(ret, find_videoconv_cb); ++ return ret; ++} ++ + static void no_more_pads_cb(GstElement *element, gpointer user) + { + struct wg_parser *parser = user; +@@ -1877,9 +1907,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode + return FALSE; + } + ++static BOOL decodebin_parser_init_gst(struct wg_parser *parser); ++ + static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user) + { + struct wg_parser *parser = user; ++ const GstStructure *structure; + gchar *dbg_info = NULL; + GError *err = NULL; + +@@ -1914,6 +1947,21 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use + pthread_cond_signal(&parser->init_cond); + break; + ++ case GST_MESSAGE_ELEMENT: ++ structure = gst_message_get_structure(msg); ++ if (gst_structure_has_name(structure, "missing-plugin")) ++ { ++ pthread_mutex_lock(&parser->mutex); ++ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) ++ { ++ GST_WARNING("Autoplugged element failed to initialise, trying again with protonvideoconvert."); ++ parser->error = true; ++ pthread_cond_signal(&parser->init_cond); ++ } ++ pthread_mutex_unlock(&parser->mutex); ++ } ++ break; ++ + default: + break; + } +@@ -2052,6 +2100,7 @@ static NTSTATUS wg_parser_connect(void *args) + { + const struct wg_parser_connect_params *params = args; + struct wg_parser *parser = params->parser; ++ bool use_mediaconv = false; + unsigned int i; + HRESULT hr; + int ret; +@@ -2069,9 +2118,16 @@ static NTSTATUS wg_parser_connect(void *args) + if (!parser->pull_mode) + gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); ++ + if (ret == GST_STATE_CHANGE_FAILURE) + { +- GST_ERROR("Failed to play stream.\n"); ++ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst && parser->pull_mode) ++ { ++ GST_WARNING("Failed to play media, trying again with protonvideoconvert."); ++ use_mediaconv = true; ++ } ++ else ++ GST_ERROR("Failed to play stream.\n"); + goto out; + } + +@@ -2081,6 +2137,8 @@ static NTSTATUS wg_parser_connect(void *args) + pthread_cond_wait(&parser->init_cond, &parser->mutex); + if (parser->error) + { ++ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) ++ use_mediaconv = true; + pthread_mutex_unlock(&parser->mutex); + goto out; + } +@@ -2189,6 +2247,14 @@ out: + pthread_mutex_unlock(&parser->mutex); + pthread_cond_signal(&parser->read_cond); + ++ if (use_mediaconv) ++ { ++ parser->use_mediaconv = true; ++ hr = wg_parser_connect(args); ++ parser->use_mediaconv = false; ++ return hr; ++ } ++ + return E_FAIL; + } + +@@ -2303,6 +2369,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + 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-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); + + parser->their_sink = gst_element_get_static_pad(element, "sink"); +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0086-fixup-winegstreamer-After-failing-to-create-decodebi.patch b/patches/mfplat-streaming-support/0086-fixup-winegstreamer-After-failing-to-create-decodebi.patch new file mode 100644 index 00000000..b156c930 --- /dev/null +++ b/patches/mfplat-streaming-support/0086-fixup-winegstreamer-After-failing-to-create-decodebi.patch @@ -0,0 +1,25 @@ +From 550f10b3410363b4d2b15f2825dd25323181edb6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 15 Feb 2022 10:51:42 +0100 +Subject: [PATCH 86/88] fixup! winegstreamer: After failing to create decodebin + parser, try protonvideoconv. + +--- + dlls/winegstreamer/wg_parser.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 0b4e488bea6..9773ff176d2 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -30,6 +30,7 @@ + #include + #include + ++#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 + #include + #include + #include +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0087-winegstreamer-Use-unlimited-buffering-for-the-WM-rea.patch b/patches/mfplat-streaming-support/0087-winegstreamer-Use-unlimited-buffering-for-the-WM-rea.patch new file mode 100644 index 00000000..166280bc --- /dev/null +++ b/patches/mfplat-streaming-support/0087-winegstreamer-Use-unlimited-buffering-for-the-WM-rea.patch @@ -0,0 +1,26 @@ +From 04d3388c51df8a235c8267af1f4fa9087b0cd210 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 28 Oct 2021 17:46:32 -0500 +Subject: [PATCH 87/88] winegstreamer: Use unlimited buffering for the WM + reader objects. + +--- + dlls/winegstreamer/wm_reader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c +index 569560d054e..baf764ca9fb 100644 +--- a/dlls/winegstreamer/wm_reader.c ++++ b/dlls/winegstreamer/wm_reader.c +@@ -1455,7 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) + HRESULT hr; + WORD i; + +- if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) ++ if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) + return E_OUTOFMEMORY; + + reader->wg_parser = wg_parser; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/0088-HACK-winegstreamer-Report-streams-in-reverse-order-f.patch b/patches/mfplat-streaming-support/0088-HACK-winegstreamer-Report-streams-in-reverse-order-f.patch new file mode 100644 index 00000000..4542e902 --- /dev/null +++ b/patches/mfplat-streaming-support/0088-HACK-winegstreamer-Report-streams-in-reverse-order-f.patch @@ -0,0 +1,26 @@ +From 308a46c504a4efa2eb866709055739325236be5b Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 28 Oct 2021 17:47:48 -0500 +Subject: [PATCH 88/88] HACK: winegstreamer: Report streams in reverse order + for wmvcore. + +--- + dlls/winegstreamer/wm_reader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c +index baf764ca9fb..ff3dfcd5d2c 100644 +--- a/dlls/winegstreamer/wm_reader.c ++++ b/dlls/winegstreamer/wm_reader.c +@@ -1484,7 +1484,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) + { + struct wm_stream *stream = &reader->streams[i]; + +- stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); ++ stream->wg_stream = wg_parser_get_stream(reader->wg_parser, reader->stream_count - i - 1); + stream->reader = reader; + stream->index = i; + stream->selection = WMT_ON; +-- +2.34.1 + diff --git a/patches/mfplat-streaming-support/definition b/patches/mfplat-streaming-support/definition index e91efdc2..00ba0f55 100644 --- a/patches/mfplat-streaming-support/definition +++ b/patches/mfplat-streaming-support/definition @@ -1,2 +1 @@ Fixes: [49692] Multiple applications need a Media Foundation media source implementation -Disabled: True diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index e0313f70..467e749b 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -127,6 +127,7 @@ patch_enable_all () enable_krnl386_exe16_Invalid_Console_Handles="$1" enable_libs_Unicode_Collation="$1" enable_loader_KeyboardLayouts="$1" + enable_mfplat_streaming_support="$1" enable_mmsystem_dll16_MIDIHDR_Refcount="$1" enable_mountmgr_DosDevices="$1" enable_mscoree_CorValidateImage="$1" @@ -410,6 +411,9 @@ patch_enable () loader-KeyboardLayouts) enable_loader_KeyboardLayouts="$2" ;; + mfplat-streaming-support) + enable_mfplat_streaming_support="$2" + ;; mmsystem.dll16-MIDIHDR_Refcount) enable_mmsystem_dll16_MIDIHDR_Refcount="$2" ;; @@ -2229,6 +2233,112 @@ if test "$enable_loader_KeyboardLayouts" -eq 1; then patch_apply loader-KeyboardLayouts/0002-user32-Improve-GetKeyboardLayoutList.patch fi +# Patchset mfplat-streaming-support +# | +# | This patchset fixes the following Wine bugs: +# | * [#49692] Multiple applications need a Media Foundation media source implementation +# | +# | Modified files: +# | * dlls/mf/tests/mf.c, dlls/mf/topology.c, dlls/mfplat/main.c, dlls/qasf/Makefile.in, dlls/qasf/asfreader.c, +# | dlls/quartz/filtergraph.c, dlls/winegstreamer/Makefile.in, dlls/winegstreamer/aac_decoder.c, +# | dlls/winegstreamer/audioconvert.c, dlls/winegstreamer/colorconvert.c, dlls/winegstreamer/decode_transform.c, +# | dlls/winegstreamer/gst_private.h, dlls/winegstreamer/h264_decoder.c, dlls/winegstreamer/main.c, +# | dlls/winegstreamer/media_source.c, dlls/winegstreamer/mfplat.c, dlls/winegstreamer/quartz_parser.c, +# | dlls/winegstreamer/unix_private.h, dlls/winegstreamer/unixlib.h, dlls/winegstreamer/wg_format.c, +# | dlls/winegstreamer/wg_parser.c, dlls/winegstreamer/wg_transform.c, dlls/winegstreamer/winegstreamer_classes.idl, +# | dlls/winegstreamer/wm_reader.c, dlls/winegstreamer/wma_decoder.c, include/wmcodecdsp.idl +# | +if test "$enable_mfplat_streaming_support" -eq 1; then + patch_apply mfplat-streaming-support/0001-winegstreamer-HACK-Use-a-different-gst-registry-file.patch + patch_apply mfplat-streaming-support/0002-winegstreamer-HACK-Try-harder-to-register-winegstrea.patch + patch_apply mfplat-streaming-support/0003-mfplat-Register-winegstreamer-interfaces-on-load.patch + patch_apply mfplat-streaming-support/0004-Revert-winegstreamer-Create-static-pads-on-wg_transf.patch + patch_apply mfplat-streaming-support/0005-Revert-winegstreamer-Introduce-new-wg_transform-stru.patch + patch_apply mfplat-streaming-support/0006-Revert-winegstreamer-Introduce-new-WG_MAJOR_TYPE_WMA.patch + patch_apply mfplat-streaming-support/0007-Revert-winegstreamer-Move-format-helpers-to-a-dedica.patch + patch_apply mfplat-streaming-support/0008-winegstreamer-Allow-videoconvert-to-parallelize.patch + patch_apply mfplat-streaming-support/0009-HACK-winegstreamer-Use-capssetter-to-ignore-non-defa.patch + patch_apply mfplat-streaming-support/0010-HACK-quartz-Keep-a-reference-on-the-IMediaPosition-i.patch + patch_apply mfplat-streaming-support/0011-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch + patch_apply mfplat-streaming-support/0012-HACK-qasf-Implement-ASF-Reader-filter-as-a-simple-fi.patch + patch_apply mfplat-streaming-support/0013-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch + patch_apply mfplat-streaming-support/0014-winegstreamer-Push-stream-start-and-segment-events-i.patch + patch_apply mfplat-streaming-support/0015-winegstreamer-Introduce-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0016-winegstreamer-Implement-GetInputAvailableType-for-de.patch + patch_apply mfplat-streaming-support/0017-winegstreamer-Implement-GetOutputAvailableType-for-d.patch + patch_apply mfplat-streaming-support/0018-winegstreamer-Implement-SetInputType-for-decode-tran.patch + patch_apply mfplat-streaming-support/0019-winegstreamer-Implement-SetOutputType-for-decode-tra.patch + patch_apply mfplat-streaming-support/0020-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0021-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch + patch_apply mfplat-streaming-support/0022-winegstreamer-Register-the-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0023-winegstreamer-Introduce-AAC-decoder-transform.patch + patch_apply mfplat-streaming-support/0024-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch + patch_apply mfplat-streaming-support/0025-winegstreamer-Report-streams-backwards-in-media-sour.patch + patch_apply mfplat-streaming-support/0026-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0027-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch + patch_apply mfplat-streaming-support/0028-winegstreamer-Introduce-color-conversion-transform.patch + patch_apply mfplat-streaming-support/0029-winegstreamer-Register-the-color-conversion-transfor.patch + patch_apply mfplat-streaming-support/0030-winegstreamer-Implement-GetInputAvailableType-for-co.patch + patch_apply mfplat-streaming-support/0031-winegstreamer-Implement-SetInputType-for-color-conve.patch + patch_apply mfplat-streaming-support/0032-winegstreamer-Implement-GetOutputAvailableType-for-c.patch + patch_apply mfplat-streaming-support/0033-winegstreamer-Implement-SetOutputType-for-color-conv.patch + patch_apply mfplat-streaming-support/0034-winegstreamer-Implement-ProcessMessage-for-color-con.patch + patch_apply mfplat-streaming-support/0035-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0036-mf-topology-Forward-failure-from-SetOutputType-when-.patch + patch_apply mfplat-streaming-support/0037-winegstreamer-Handle-flush-command-in-audio-converst.patch + patch_apply mfplat-streaming-support/0038-winegstreamer-In-the-default-configuration-select-on.patch + patch_apply mfplat-streaming-support/0039-winegstreamer-Implement-IMFTransform-GetOutputCurren.patch + patch_apply mfplat-streaming-support/0040-winegstreamer-Implement-stream-draining-support.patch + patch_apply mfplat-streaming-support/0041-winegstreamer-Add-an-explicit-result-to-wg_parser_pu.patch + patch_apply mfplat-streaming-support/0042-winegstreamer-Unblock-wg_parser_get_next_read_offset.patch + patch_apply mfplat-streaming-support/0043-winegstreamer-Update-offset-according-to-the-size-of.patch + patch_apply mfplat-streaming-support/0044-winegstreamer-Let-src_getrange_cb-allocate-the-buffe.patch + patch_apply mfplat-streaming-support/0045-winegstreamer-Implement-unseekable-stream-support.patch + patch_apply mfplat-streaming-support/0046-winegstreamer-Implement-Process-Input-Output-for-dec.patch + patch_apply mfplat-streaming-support/0047-winegstreamer-Implement-ProcessMessage-for-decoder-t.patch + patch_apply mfplat-streaming-support/0048-winegstreamer-Implement-Process-Input-Output-for-aud.patch + patch_apply mfplat-streaming-support/0049-winegstreamer-Implement-Process-Input-Output-for-col.patch + patch_apply mfplat-streaming-support/0050-winegstreamer-Implement-MF_SD_LANGUAGE.patch + patch_apply mfplat-streaming-support/0051-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch + patch_apply mfplat-streaming-support/0052-winegstreamer-Add-videobox-element-and-aperture-supp.patch + patch_apply mfplat-streaming-support/0053-winegstreamer-Only-require-videobox-element-for-pars.patch + patch_apply mfplat-streaming-support/0054-winegstreamer-Feed-full-buffer-in-audio-converter-Pr.patch + patch_apply mfplat-streaming-support/0055-winegstreamer-Add-MFVideoFormat_ARGB32-output-for-th.patch + patch_apply mfplat-streaming-support/0056-winegstreamer-Return-S_OK-from-WMA-decoder-ProcessMe.patch + patch_apply mfplat-streaming-support/0057-winegstreamer-Introduce-new-wg_transform-struct.patch + patch_apply mfplat-streaming-support/0058-winegstreamer-Introduce-new-wg_encoded_format-struct.patch + patch_apply mfplat-streaming-support/0059-winegstreamer-Create-static-pads-on-wg_transform-str.patch + patch_apply mfplat-streaming-support/0060-winegstreamer-Lookup-create-and-link-a-decoder-eleme.patch + patch_apply mfplat-streaming-support/0061-winegstreamer-Send-stream-start-and-caps-events-on-c.patch + patch_apply mfplat-streaming-support/0062-winegstreamer-Add-an-audioconverter-and-audioresampl.patch + patch_apply mfplat-streaming-support/0063-winegstreamer-Implement-WMA-decoder-ProcessInput.patch + patch_apply mfplat-streaming-support/0064-winegstreamer-Implement-WMA-decoder-ProcessOutput.patch + patch_apply mfplat-streaming-support/0065-winegstreamer-Support-XMAudio2-input-format-in-WMA-d.patch + patch_apply mfplat-streaming-support/0066-winegstreamer-Introduce-new-H264-decoder-transform-s.patch + patch_apply mfplat-streaming-support/0067-winegstreamer-Return-S_OK-from-H264-decoder-GetAttri.patch + patch_apply mfplat-streaming-support/0068-winegstreamer-Return-S_OK-from-H264-decoder-ProcessM.patch + patch_apply mfplat-streaming-support/0069-winegstreamer-Implement-H264-decoder-SetInputType.patch + patch_apply mfplat-streaming-support/0070-winegstreamer-Implement-H264-decoder-GetOutputAvaila.patch + patch_apply mfplat-streaming-support/0071-winegstreamer-Implement-H264-decoder-GetInputAvailab.patch + patch_apply mfplat-streaming-support/0072-winegstreamer-Implement-H264-decoder-SetOutputType.patch + patch_apply mfplat-streaming-support/0073-winegstreamer-Implement-H264-decoder-GetInputStreamI.patch + patch_apply mfplat-streaming-support/0074-winegstreamer-Implement-H264-decoder-GetOutputStream.patch + patch_apply mfplat-streaming-support/0075-winegstreamer-Add-H264-encoded-format-support-in-wg_.patch + patch_apply mfplat-streaming-support/0076-winegstreamer-Implement-H264-decoder-ProcessInput.patch + patch_apply mfplat-streaming-support/0077-winegstreamer-Implement-H264-decoder-ProcessOutput.patch + patch_apply mfplat-streaming-support/0078-winegstreamer-Add-timestamps-and-duration-to-H264-de.patch + patch_apply mfplat-streaming-support/0079-winegstreamer-Support-dynamic-wg_transform-video-for.patch + patch_apply mfplat-streaming-support/0080-winegstreamer-Fixup-H264-decoder-NV12-plane-alignmen.patch + patch_apply mfplat-streaming-support/0081-winegstreamer-Use-an-optional-h264parse-wg_transform.patch + patch_apply mfplat-streaming-support/0082-HACK-winegstreamer-Fake-H264-timestamps-if-framerate.patch + patch_apply mfplat-streaming-support/0083-winegstreamer-Reset-internal-format-on-BEGIN_STREAMI.patch + patch_apply mfplat-streaming-support/0084-winegstreamer-Reimplement-AAC-decoder-using-wg_trans.patch + patch_apply mfplat-streaming-support/0085-winegstreamer-After-failing-to-create-decodebin-pars.patch + patch_apply mfplat-streaming-support/0086-fixup-winegstreamer-After-failing-to-create-decodebi.patch + patch_apply mfplat-streaming-support/0087-winegstreamer-Use-unlimited-buffering-for-the-WM-rea.patch + patch_apply mfplat-streaming-support/0088-HACK-winegstreamer-Report-streams-in-reverse-order-f.patch +fi + # Patchset mmsystem.dll16-MIDIHDR_Refcount # | # | This patchset fixes the following Wine bugs: