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 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index af974441fbe..26b05bc0722 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6338,6 +6338,80 @@ static void test_h264_decoder(void) ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), {0}, }; + static const MFVideoArea actual_aperture = {.Area={78, 74}}; + static const media_type_desc actual_outputs[] = + { + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 80, 80), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 9600), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 80), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 80, 80), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 9600), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 80), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 80, 80), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 9600), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 80), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 80, 80), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 9600), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 80), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 80, 80), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 12800), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 160), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + }, + };
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_H264}; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; @@ -6602,6 +6676,33 @@ static void test_h264_decoder(void) ret = IMFSample_Release(output.pSample); ok(ret == 0, "Release returned %u\n", ret);
+ flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + memset(&output_info, 0xcd, sizeof(output_info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); + todo_wine + ok(hr == S_OK, "GetOutputStreamInfo returned %#x\n", hr); + todo_wine + ok(output_info.dwFlags == flags, "got dwFlags %#x\n", output_info.dwFlags); + todo_wine + ok(output_info.cbSize == 0x3200, "got cbSize %#x\n", output_info.cbSize); + todo_wine + ok(output_info.cbAlignment == 0, "got cbAlignment %#x\n", output_info.cbAlignment); + + i = -1; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type))) + { + winetest_push_context("out %u", i); + ok(hr == S_OK, "GetOutputAvailableType returned %#x\n", hr); + check_media_type(media_type, actual_outputs[i], -1); + ret = IMFMediaType_Release(media_type); + ok(ret == 0, "Release returned %u\n", ret); + winetest_pop_context(); + } + todo_wine + ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#x\n", hr); + todo_wine + ok(i == 5, "%u output media types\n", i); + ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %u\n", ret); ret = IMFSample_Release(sample);
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 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 60 ++++++++++++++++++++++++++++++++++-- dlls/mf/tests/nv12frame.bin | Bin 0 -> 9600 bytes dlls/mf/tests/resource.rc | 3 ++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 dlls/mf/tests/nv12frame.bin
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 26b05bc0722..b27f564153c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6415,18 +6415,22 @@ static void test_h264_decoder(void)
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_H264}; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; + const BYTE *h264_encoded_data, *nv12_frame_data; + ULONG h264_encoded_data_len, nv12_frame_len; MFT_OUTPUT_STREAM_INFO output_info; MFT_INPUT_STREAM_INFO input_info; MFT_OUTPUT_DATA_BUFFER output; - const BYTE *h264_encoded_data; - ULONG h264_encoded_data_len; + IMFMediaBuffer *media_buffer; + WCHAR output_path[MAX_PATH]; IMFMediaType *media_type; IMFTransform *transform; + DWORD status, length; ULONG i, ret, flags; + HANDLE output_file; IMFSample *sample; HRSRC resource; GUID class_id; - DWORD status; + BYTE *data; HRESULT hr;
hr = CoInitialize(NULL); @@ -6703,6 +6707,56 @@ static void test_h264_decoder(void) todo_wine ok(i == 5, "%u output media types\n", i);
+ /* and generate a new one as well in a temporary directory */ + GetTempPathW(ARRAY_SIZE(output_path), output_path); + lstrcatW(output_path, L"nv12frame.bin"); + output_file = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(output_file != INVALID_HANDLE_VALUE, "CreateFileW failed, error %u\n", GetLastError()); + + resource = FindResourceW(NULL, L"nv12frame.bin", (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %u\n", GetLastError()); + nv12_frame_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + nv12_frame_len = SizeofResource(GetModuleHandleW(NULL), resource); + ok(nv12_frame_len == 9600, "got frame length %u\n", nv12_frame_len); + + status = 0; + memset(&output, 0, sizeof(output)); + output.pSample = create_sample(NULL, output_info.cbSize); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine + ok(hr == S_OK, "ProcessOutput returned %#x\n", hr); + ok(output.dwStreamID == 0, "got dwStreamID %u\n", output.dwStreamID); + ok(!!output.pSample, "got pSample %p\n", output.pSample); + ok(output.dwStatus == 0, "got dwStatus %#x\n", output.dwStatus); + ok(!output.pEvents, "got pEvents %p\n", output.pEvents); + ok(status == 0, "got status %#x\n", status); + if (hr == S_OK) + { + /* Win8 and before pad the data with garbage instead of original + * buffer data, make sure it's consistent. */ + hr = IMFSample_ConvertToContiguousBuffer(output.pSample, &media_buffer); + ok(hr == S_OK, "ConvertToContiguousBuffer returned %#x\n", hr); + hr = IMFMediaBuffer_Lock(media_buffer, &data, NULL, &length); + ok(hr == S_OK, "Lock returned %#x\n", hr); + for (i = 0; i < 74; ++i) + { + memset(data + 80 * i + 78, 0xcd, 2); + memset(data + 80 * (80 + i) + 78, 0xcd, 2); + } + memset(data + 80 * 74, 0xcd, 6 * 80); + memset(data + 80 * 117, 0xcd, 3 * 80); + hr = IMFMediaBuffer_Unlock(media_buffer); + ok(hr == S_OK, "Unlock returned %#x\n", hr); + IMFMediaBuffer_Release(media_buffer); + + check_sample(output.pSample, nv12_frame_data, nv12_frame_len, output_file); + } + ret = IMFSample_Release(output.pSample); + ok(ret == 0, "Release returned %u\n", ret); + + trace("created %s\n", debugstr_w(output_path)); + CloseHandle(output_file); + ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %u\n", ret); ret = IMFSample_Release(sample); diff --git a/dlls/mf/tests/nv12frame.bin b/dlls/mf/tests/nv12frame.bin new file mode 100644 index 0000000000000000000000000000000000000000..9ceceb8fedbaace124ee5155566822fc2f441335 GIT binary patch literal 9600 zcmaF;8V)WYz$yfohyYm#5QqSpNZ{;QxM{CnBaFL*Fm4sXxQPhkvJl1vA{nPSY91sI zN5c=4Y(~=yD4UGt4`>-PTE2jah0*d9R4k0vAK+qPw7wjzFA)X8Xni?aUyioNK_$Xy z`+2ne3~M6Lw*8D`x&Q(omBa`^0eGrhxe7@XDaXD(dzLKoRt=bWf)I}o@Gn;Py?Xun z)!_FpQbY*|AV<|}6d49EfC?#qfxube^hMfBHDga-U81g)s8CRm`||8r6kQ~lC-+)) zX_BV!lGR#5ratAxP7f|5Ev3Y~wc;^{?>Nfs^P8}Gf19!VYtc0+mXw%x!R49V%Yc5P zJrY%3tAr9KCat=eM~Qh$j+xizWi7jKttD`p@YN%B31&%qDKYQnql(APGjH}8UP+NZ zF1>G6xl(pECFVJ0Zs<BwBJMNe;lWjsPY<2T-1sz!67!zxKREJ2we>}O%ZAks*7K&S zyU0~hV&0ST6SbG}p33){)bvf*C%-fLVC;QL%sZx{dO~%ha9qvg^!u~>3wM|-$zDK- zd5$|ub}zNI7t$7SHk+dQ;<nQHLz$GAx8Xw7#uHkT)Tc;J-#jVxSnrFa7iLppUdJR| zuasNo#L^31MYm-idb0P98*qG*?EI^E<BDYF)$@Iw4%4bPos5$>cI}dl7X{`ixCOND znALM)-MX{MNr$?OHpj>;3Z=w6wb1r#TjOg57b43xob}H0-ndX)g%a~lY<*lMkz8=f ze6M^_oPN#rOQ%<?q{KXtncB4__EYnFq|R9;7Cw^jTN87b67wcq-`=qz@8~%>uM}%3 z#d*u!o=KfQI|_z*2sFTfN2kCf7+fX*gL#r>N-%ip9t=);9`ykRKjb0c*|Tut8b-|n zh2d!Ufzr%qdV%DT(fk1^VPK`pX#RkdsH6E~q~?zu<uKR)tTAB_CbpxzGbK6@1`(o@ zXXNgHL4@dz^0Q|Vb@7gJL|qK4w@=+$x*j2l$c2+V5TeK|>YI1l2?qDOPfCN?wRHW` z^|vnF2EvoOw=Lebc=jZa%w!K3>`H;DM5WK3Jtm5Pi@lL$UmrujZHtj*aI;6vLxc?? X^j;qu4L?M<AhW2SUWR#h1H*d&)8J<o
literal 0 HcmV?d00001
diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 17adc3ed46c..5a2bf913672 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -25,3 +25,6 @@ wmadata.bin RCDATA wmadata.bin
/* @makedep: h264data.bin */ h264data.bin RCDATA h264data.bin + +/* @makedep: nv12frame.bin */ +nv12frame.bin RCDATA nv12frame.bin
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109200
Your paranoid android.
=== w1064_tsign (64 bit report) ===
mf: mf.c:6939: Test failed: ProcessOutput returned 0xc00d6d72
On 2/24/22 10:39, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109200
Your paranoid android.
=== w1064_tsign (64 bit report) ===
mf: mf.c:6939: Test failed: ProcessOutput returned 0xc00d6d72
I'll have a look at this failure, sadly the H264 transform seems to be asynchronous and the results aren't easily predictable.
On 2/24/22 12:47, Rémi Bernon wrote:
On 2/24/22 10:39, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109200
Your paranoid android.
=== w1064_tsign (64 bit report) ===
mf: mf.c:6939: Test failed: ProcessOutput returned 0xc00d6d72
I'll have a look at this failure, sadly the H264 transform seems to be asynchronous and the results aren't easily predictable.
In general if async mode is supported, it should be explicitly enabled. Does it really help if you sleep for a bit?
On 2/24/22 11:18, Nikolay Sivov wrote:
On 2/24/22 12:47, Rémi Bernon wrote:
On 2/24/22 10:39, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109200
Your paranoid android.
=== w1064_tsign (64 bit report) ===
mf: mf.c:6939: Test failed: ProcessOutput returned 0xc00d6d72
I'll have a look at this failure, sadly the H264 transform seems to be asynchronous and the results aren't easily predictable.
In general if async mode is supported, it should be explicitly enabled. Does it really help if you sleep for a bit?
Yes it helps, I didn't want to do that as it's always a bit dubious, and hoped that a robust loop should be enough, but maybe there's no other option.
It may not be truly async in the MF sense, but it definitely internally queues input samples and processes them asynchronously.
On 2/24/22 11:22, Rémi Bernon wrote:
On 2/24/22 11:18, Nikolay Sivov wrote:
On 2/24/22 12:47, Rémi Bernon wrote:
On 2/24/22 10:39, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109200
Your paranoid android.
=== w1064_tsign (64 bit report) ===
mf: mf.c:6939: Test failed: ProcessOutput returned 0xc00d6d72
I'll have a look at this failure, sadly the H264 transform seems to be asynchronous and the results aren't easily predictable.
In general if async mode is supported, it should be explicitly enabled. Does it really help if you sleep for a bit?
Yes it helps, I didn't want to do that as it's always a bit dubious, and hoped that a robust loop should be enough, but maybe there's no other option.
It may not be truly async in the MF sense, but it definitely internally queues input samples and processes them asynchronously.
I think there's also MF_LOW_LATENCY mode attributes which I believe helps too, I'll find a way.
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 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index b27f564153c..d520e38fea2 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6415,6 +6415,7 @@ static void test_h264_decoder(void)
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_H264}; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; + UINT32 input_id, output_id, input_count, output_count; const BYTE *h264_encoded_data, *nv12_frame_data; ULONG h264_encoded_data_len, nv12_frame_len; MFT_OUTPUT_STREAM_INFO output_info; @@ -6616,6 +6617,17 @@ static void test_h264_decoder(void) todo_wine ok(output_info.cbAlignment == 0, "got cbAlignment %#x\n", output_info.cbAlignment);
+ input_count = output_count = 0xdeadbeef; + hr = IMFTransform_GetStreamCount(transform, &input_count, &output_count); + todo_wine + ok(hr == S_OK, "GetStreamCount returned %#x\n", hr); + todo_wine + ok(input_count == 1, "got input_count %u\n", input_count); + todo_wine + ok(output_count == 1, "got output_count %u\n", output_count); + hr = IMFTransform_GetStreamIDs(transform, 1, &input_id, 1, &output_id); + ok(hr == E_NOTIMPL, "GetStreamIDs returned %#x\n", hr); + resource = FindResourceW(NULL, L"h264data.bin", (const WCHAR *)RT_RCDATA); ok(resource != 0, "FindResourceW failed, error %u\n", GetLastError()); h264_encoded_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource));
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 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 276 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 29 +- dlls/winegstreamer/winegstreamer_classes.idl | 6 + 5 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 dlls/winegstreamer/h264_decoder.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 0bcdb3eec65..3524cffb399 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -8,6 +8,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS)
C_SRCS = \ audioconvert.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 863bff91e4b..78d399489ec 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -126,6 +126,7 @@ void mf_destroy_wg_sample(struct wg_sample *wg_sample);
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);
struct wm_stream diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c new file mode 100644 index 00000000000..2fafaea4fff --- /dev/null +++ b/dlls/winegstreamer/h264_decoder.c @@ -0,0 +1,276 @@ +/* H264 Decoder Transform + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" + +#include "wine/debug.h" + +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 transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + free(decoder); + + return refcount; +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, + DWORD *inputs, DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", iface, + input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + FIXME("iface %p, attributes %p stub!\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, + IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + FIXME("iface %p, id %#lx stub!\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_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 transform_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 transform_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 transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + FIXME("iface %p, lower %I64d, upper %I64d stub!\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); + return E_NOTIMPL; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +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 = &transform_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 551bc1949e0..c9cc96d8d16 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -410,6 +410,7 @@ class_objects[] = { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, + { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, };
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -459,6 +460,21 @@ static const GUID *const wma_decoder_output_types[] = &MFAudioFormat_Float, };
+static WCHAR h264_decoderW[] = L"Microsoft H264 Video Decoder MFT"; +static const GUID *h264_decoder_input_types[] = +{ + &MFVideoFormat_H264, + &MFVideoFormat_H264_ES, +}; +static const GUID *h264_decoder_output_types[] = +{ + &MFVideoFormat_NV12, + &MFVideoFormat_YV12, + &MFVideoFormat_IYUV, + &MFVideoFormat_I420, + &MFVideoFormat_YUY2, +}; + static const struct mft { const GUID *clsid; @@ -495,13 +511,24 @@ mfts[] = ARRAY_SIZE(wma_decoder_output_types), wma_decoder_output_types, }, + { + &CLSID_MSH264DecoderMFT, + &MFT_CATEGORY_VIDEO_DECODER, + h264_decoderW, + MFT_ENUM_FLAG_SYNCMFT, + &MFMediaType_Video, + ARRAY_SIZE(h264_decoder_input_types), + h264_decoder_input_types, + ARRAY_SIZE(h264_decoder_output_types), + h264_decoder_output_types, + }, };
HRESULT mfplat_DllRegisterServer(void) { unsigned int i, j; HRESULT hr; - MFT_REGISTER_TYPE_INFO input_types[4], output_types[2]; + MFT_REGISTER_TYPE_INFO input_types[4], output_types[5];
for (i = 0; i < ARRAY_SIZE(mfts); i++) { diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 90dc1dc839b..347ee906a52 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -73,3 +73,9 @@ coclass WINEAudioConverter { } uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) ] coclass CWMADecMediaObject {}; + +[ + threading(both), + uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) +] +coclass CMSH264DecoderMFT {}
On 2/24/22 09:50, Rémi Bernon wrote:
+static WCHAR h264_decoderW[] = L"Microsoft H264 Video Decoder MFT"; +static const GUID *h264_decoder_input_types[] = +{
- &MFVideoFormat_H264,
- &MFVideoFormat_H264_ES,
+}; +static const GUID *h264_decoder_output_types[] = +{
- &MFVideoFormat_NV12,
- &MFVideoFormat_YV12,
- &MFVideoFormat_IYUV,
- &MFVideoFormat_I420,
- &MFVideoFormat_YUY2,
+};
As usual, looking at it *after* pressing the send button, I think this could use more const.
Anyway, I'm actually more interested by the tests, and this patch was to assert that they would pass with the stub too.
Adding the transform now will also cause some unfortunate regressions (because some games better handle its absence than a stub), which may not be ideal for next release.