This format is used for video output with a depth of 10 bits per channel. Decoding at 10-bit quality is not currently supported, but this patch makes video playable.
-- v5: mfmediaengine: Retry topology resolution if necessary with video output type B8G8R8A8_UNORM. mfmediaengine: Resolve the topology before setting it on the session object. mfmediaengine: Introduce a create_video_media_type_from_fourcc() helper function. mfmediaengine: Call OnVideoStreamTick() if a sample is not available. mfmediaengine: Call media_engine_render_d3d11 if stretch/scale is needed. mfmediaengine: Round the source box coordinates in media_engine_transfer_d3d11(). mfmediaengine: Rename media_engine_transfer_to_d3d11_texture() helper function. mfmediaengine/tests: Test output to format R10G10B10A2 from H.264.
From: Conor McCarthy cmccarthy@codeweavers.com
Windows supports this. Media engine apparently performs a format conversion, because the session engine topology loader cannot resolve output to R10G10B10A2. --- dlls/mfmediaengine/tests/i420-64x64.mp4 | Bin 0 -> 4200 bytes dlls/mfmediaengine/tests/mfmediaengine.c | 152 ++++++++++++++++++++++- dlls/mfmediaengine/tests/resource.rc | 6 + 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 dlls/mfmediaengine/tests/i420-64x64.mp4
diff --git a/dlls/mfmediaengine/tests/i420-64x64.mp4 b/dlls/mfmediaengine/tests/i420-64x64.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..82c203ce95ed87f4844af2d460b9cdfa80c63a04 GIT binary patch literal 4200 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�=_8z?~oUifg{Bw^6`5%AIWqL|x>Y2UG(>ojR<hy>sU-wtGtB++XMeg{XbZgVf zryd(0@9TcCH(j%~RJH5Ywl%9NgLHFt%<*kAnI05*?dq{jtA&;qS<GFYdF0s2l3QoH zZfy)cJ@>@TLW|ivnHo|lH#a9cDrrvJyf$P~<Fd1}%}j*U3J&wA6z3Ekmz=QSQ>D#3 zADNGzEBD;XiI~r0aPY{jIfXMPz*!UT*H^^<_>pV(@5B7Z54ZgOeW<>_?TP!7D|?FX zznp)5`>|4W@yVfcf<1SiGdJt|DddS3h791e&p0nB%PHRBfT9#AJby56y*I(}(u5Kf zvF9)Uf2+6u{{MEr_C9f;r-f&O^8EQDg~Q~xt#mwnFIkr_R!TF&uZdA**Xi#+#8-S} zxBQaImnBfP!~XE(UF@|bdEc(stld&_t?<*kvrpe`d=%rJnlo?LlX+gZ_e?!$U7hzj zH+$`7zpS%Xw@sd{xjbuQ?A*;|WxW?~nRoBlo}3daySOkr?bf#3)oHi3Rd?^G*4|XD z-CJ?Hw=iP1>9n({n<I0sMQTbyp_oskVan0TxTzzFZXyIwT;=n5sAz8c!%II(>~MsH zU;=V@G9FNr1_j{XA3nD;-&l#YH66WV-hZ}kZQ9zPiaB0;KL%I5-)}X+b9>7Mjuwd@ zag%@KZT*%R60~t8lcW6VPdV#u23*>)XH&Dx3AxRW<gVYDn}1#2|Hpaf59h@{`isBn z`+wj1f6V*8pZ9-1U;KXV|9$SqU@*1PEqqF9rQ3ZF5k4j2jhHoS-@&O*CF26YguEmK zf;mtEtR#5@NG+SbAcVo%cQAQ_dB)wvWxcn|Gwv?=^8^V#i+nl{iVi^mT;S=v$n9`# zP~AAGRG2Zy+Mmvggc^!Lo#{WiP&iZi__O_Co5NPx_^HPISh=_S{#*~0+lL~MBLK#h zVPIh0lbfGk#=yXklUtUN0+WEy%r6)i7}^*Z89)dk1R@zh1QJH$J0MA6VKOr?F!h!c zC1x`)FvOH(gY9HSQU^1w4M_~bgvmg7XpUlF0NV>9K$w9+B{ij_n1O*oCN-zH1gZsO zLK_1E`z45nm{@aDG7~}V_1qM&JD|!yRH*?21OJlHBOo?|ZbnK@5tzlmzyNAJ!`L7? z4Ah$TNX$#gNd>84+>o1@m&U-rAX1hKHWXwjNF4~Pq(J0kQi@VRYCvKjd7jdu90dlj zmlz9*OOkRJ7#P+RmlVSy1f*sTr~?7g08s~J!6*j?2L=xY1~3MRF^Zxzd=zprlRzzf zkQ5Y4{Qu9uzyRu&I5Va&aQ%PCAex@Sz_sRPi&_iF?+nZ<8*DtLWiT?ZWxT9V*XjQI z;|EBqNK#1=G(gY&W?%qe28rSlaA1SvL2hMXU|@a;3WMU3Vo)TfZz$q2Qeh-U;x z2-xrZOBg^sCWu~*;*#QIkVc3YILeryeuvQ@^HhpUimRaNKorRC00ssI9waPNT#}p* zl4M|D0NH84z`$~wfr0%x0|Qeep2P^U2c#_)L_jek$WpLtpaNhDEC^<S2}l|QGeHEd z#2CxKzykI;0|Vnl+=+3G3j>1)1GdCioL`y;vH*sI^GowmkP>4JG%*SkLlPrQ9We>f z0h$o&&=O)^Zh;9X*MQ7Ic$<kq03-l%Dgy(9S!!_#IO3Tb8X8m?m>5_Z8XCkML_taz zzc4T`KB;GIXlP&+5(s<Bz}C>vzz7OzMACw)VPL>WTCCt8V_?9RJV34iVUSrM3}S=S zAtw)31_nld1_s783=E7e3=E8p3=E7NpmG8=i7@vtFt9vlU|@gDz`!6?oL-OuGOQ>+ z2b49zW`nbjOmR|r0mxHO8IU4YXd+E2O(_9|Q&es$m<B0RL@r5kQ!<MZ3kpCcg5<zh jHxp7^sje)^2c=lqlti#*kinq7Oq!X2o}rnZp@9Ja0WO$@
literal 0 HcmV?d00001
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index fbaeff50710..8ea7a69b158 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -164,6 +164,17 @@ static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data return compare_rgb32(data, &length, &size, rect, expect_data); }
+#define check_r10g10b10a2_diff(a, b, c, d, e, f, g) check_r10g10b10a2_diff_(__LINE__, a, b, c, d, e, f, g) +static void check_r10g10b10a2_diff_(int line, const D3D11_MAPPED_SUBRESOURCE *map_desc, + UINT x, UINT y, int r, int g, int b, UINT max_diff) +{ + UINT got = ((UINT *)map_desc->pData)[x + map_desc->RowPitch / 4u * y]; + UINT diff = abs(r - (int)(got & 0x3ff)) + + abs(g - (int)((got >> 10) & 0x3ff)) + + abs(b - (int)((got >> 20) & 0x3ff)); + ok(diff <= max_diff, "got diff %u at (%u, %u)\n", diff, x, y); +} + static void init_functions(void) { HMODULE mod; @@ -1228,7 +1239,8 @@ static HRESULT WINAPI test_transfer_notify_EventNotify(IMFMediaEngineNotify *ifa break;
case MF_MEDIA_ENGINE_EVENT_ERROR: - ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE), "Unexpected error %#lx\n", param2); + ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE || param2 == MF_E_INVALIDMEDIATYPE), + "Unexpected error %#lx\n", param2); notify->error = param2; /* fallthrough */ case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY: @@ -1357,6 +1369,7 @@ static void test_TransferVideoFrame(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ID3D11Device_GetImmediateContext(device, &context); + ID3D11DeviceContext_CopySubresourceRegion(context, (ID3D11Resource *)rb_texture, 0, 0, 0, 0, (ID3D11Resource *)texture, 0, NULL);
@@ -1388,6 +1401,142 @@ done: IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); }
+static void test_TransferVideoFrame_10bit(void) +{ + ID3D11Texture2D *texture = NULL, *rb_texture; + IMFMediaEngineEx *media_engine = NULL; + struct test_transfer_notify *notify; + D3D11_MAPPED_SUBRESOURCE map_desc; + IMFDXGIDeviceManager *manager; + ID3D11DeviceContext *context; + D3D11_TEXTURE2D_DESC desc; + IMFByteStream *stream; + ID3D11Device *device; + RECT dst_rect; + LONGLONG pts; + UINT token; + HRESULT hr; + DWORD res; + BSTR url; + + /* Windows does not support R10G10B10A2 output from raw video, but does at least for h264 */ + stream = load_resource(L"i420-64x64.mp4", L"video/mp4"); + + notify = create_transfer_notify(); + + if (!(device = create_d3d11_device())) + { + skip("Failed to create a D3D11 device, skipping tests.\n"); + goto done; + } + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)device, token); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + create_media_engine(¬ify->IMFMediaEngineNotify_iface, manager, DXGI_FORMAT_R10G10B10A2_UNORM, + &IID_IMFMediaEngineEx, (void **)&media_engine); + + IMFDXGIDeviceManager_Release(manager); + + if (!(notify->media_engine = media_engine)) + goto done; + + memset(&desc, 0, sizeof(desc)); + desc.Width = 64; + desc.Height = 64; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; + desc.BindFlags = D3D11_BIND_RENDER_TARGET; + desc.SampleDesc.Count = 1; + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + url = SysAllocString(L"i420-64x64.mp4"); + hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SysFreeString(url); + IMFByteStream_Release(stream); + + res = WaitForSingleObject(notify->frame_ready_event, 5000); + ok(!res, "Unexpected res %#lx.\n", res); + + if (FAILED(notify->error)) + { + win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error); + goto done; + } + + res = 0; + hr = IMFMediaEngineEx_GetNumberOfStreams(media_engine, &res); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(res == 2, "Unexpected stream count %lu.\n", res); + + /* FIXME: Wine first video frame is often full of garbage, wait for another update */ + res = WaitForSingleObject(notify->ready_event, 500); + /* It's also missing the MF_MEDIA_ENGINE_EVENT_TIMEUPDATE notifications */ + todo_wine + ok(!res, "Unexpected res %#lx.\n", res); + + SetRect(&dst_rect, 0, 0, desc.Width, desc.Height); + IMFMediaEngineEx_OnVideoStreamTick(notify->media_engine, &pts); + hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ID3D11Texture2D_GetDesc(texture, &desc); + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &rb_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ID3D11Device_GetImmediateContext(device, &context); + + ID3D11DeviceContext_CopySubresourceRegion(context, (ID3D11Resource *)rb_texture, + 0, 0, 0, 0, (ID3D11Resource *)texture, 0, NULL); + + memset(&map_desc, 0, sizeof(map_desc)); + hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)rb_texture, 0, D3D11_MAP_READ, 0, &map_desc); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!map_desc.pData, "got pData %p\n", map_desc.pData); + ok(map_desc.DepthPitch == 16384, "got DepthPitch %u\n", map_desc.DepthPitch); + ok(map_desc.RowPitch == desc.Width * 4, "got RowPitch %u\n", map_desc.RowPitch); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 5, 0x3ff, 0x3ff, 0x3ff, 24); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 14, 0x3fa, 0x3ff, 0x4, 31); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 23, 0x5, 0x3ff, 0x3ff, 25); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 32, 0x1, 0x3ff, 0x6, 27); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 41, 0x3fd, 0, 0x3f7, 10); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 50, 0x3fd, 0, 0, 10); + todo_wine + check_r10g10b10a2_diff(&map_desc, 32, 59, 0x2, 0, 0x3ff, 10); + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0); + + ID3D11DeviceContext_Release(context); + ID3D11Texture2D_Release(rb_texture); + +done: + if (media_engine) + { + IMFMediaEngineEx_Shutdown(media_engine); + IMFMediaEngineEx_Release(media_engine); + } + + if (texture) + ID3D11Texture2D_Release(texture); + if (device) + ID3D11Device_Release(device); + + IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); +} + struct test_transform { IMFTransform IMFTransform_iface; @@ -2713,6 +2862,7 @@ START_TEST(mfmediaengine) test_SetSourceFromByteStream(); test_audio_configuration(); test_TransferVideoFrame(); + test_TransferVideoFrame_10bit(); test_effect(); test_GetDuration(); test_GetSeekable(); diff --git a/dlls/mfmediaengine/tests/resource.rc b/dlls/mfmediaengine/tests/resource.rc index 960e5ffd73e..1b311e50937 100644 --- a/dlls/mfmediaengine/tests/resource.rc +++ b/dlls/mfmediaengine/tests/resource.rc @@ -28,6 +28,12 @@ /* @makedep: i420-64x64.avi */ i420-64x64.avi RCDATA i420-64x64.avi
+/* Generated with: + * ffmpeg -i i420-64x64.avi -c:v libx264 -preset slow -crf 17 i420-64x64.mp4 + */ +/* @makedep: i420-64x64.mp4 */ +i420-64x64.mp4 RCDATA i420-64x64.mp4 + /* Generated from running the tests on Windows */ /* @makedep: rgb32frame.bmp */ rgb32frame.bmp RCDATA rgb32frame.bmp
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfmediaengine/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index aab5fd64aa2..dd239962bae 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2557,7 +2557,7 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te return hr; }
-static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture, +static HRESULT media_engine_render_d3d11(struct media_engine *engine, ID3D11Texture2D *texture, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; @@ -2723,7 +2723,7 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture))) { if (!engine->device_manager || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) - hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); + hr = media_engine_render_d3d11(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); } else
From: Conor McCarthy cmccarthy@codeweavers.com
Accurate checking for scaled/stretched transfer depends upon this. --- dlls/mfmediaengine/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index dd239962bae..8624b8867ca 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2527,11 +2527,11 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te ID3D11Texture2D_GetDesc(src_texture, &src_desc); ID3D11Texture2D_GetDesc(dst_texture, &dst_desc);
- src_box.left = src_rect->left * src_desc.Width; - src_box.top = src_rect->top * src_desc.Height; + src_box.left = src_rect->left * src_desc.Width + 0.5f; + src_box.top = src_rect->top * src_desc.Height + 0.5f; src_box.front = 0; - src_box.right = src_rect->right * src_desc.Width; - src_box.bottom = src_rect->bottom * src_desc.Height; + src_box.right = src_rect->right * src_desc.Width + 0.5f; + src_box.bottom = src_rect->bottom * src_desc.Height + 0.5f; src_box.back = 1;
if (dst_rect->left + src_box.right - src_box.left > dst_desc.Width ||
From: Conor McCarthy cmccarthy@codeweavers.com
The need to call media_engine_render_d3d11 becomes fully known in media_engine_transfer_d3d11(), so it makes sense to call it only from there.
Both of these functions call media_engine_lock_d3d_device() and therefore the null check of device_manager has no effect, so this commit removes it.
This change reveals a failure in test_effect() which previously was silent (nothing is transferred but no error was returned). --- dlls/mfmediaengine/main.c | 25 +++++++++++++++++++++--- dlls/mfmediaengine/tests/mfmediaengine.c | 1 + 2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 8624b8867ca..3594a52bb6e 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2495,6 +2495,20 @@ static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D return hr; }
+static BOOL transfer_needs_render_pipeline(const D3D11_TEXTURE2D_DESC *src_desc, const D3D11_TEXTURE2D_DESC *dst_desc, + const D3D11_BOX *src_box, const RECT *dst_rect) +{ + if (dst_rect->right && dst_rect->bottom + && (dst_rect->right - dst_rect->left != src_box->right - src_box->left + || dst_rect->bottom - dst_rect->top != src_box->bottom - src_box->top)) + return TRUE; + + return FALSE; +} + +static HRESULT media_engine_render_d3d11(struct media_engine *engine, ID3D11Texture2D *texture, + const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color); + static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Texture2D *dst_texture, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { @@ -2522,7 +2536,7 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te hr = get_d3d11_resource_from_sample(sample, &src_texture, &subresource); IMFSample_Release(sample); if (FAILED(hr)) - return hr; + return media_engine_render_d3d11(engine, dst_texture, src_rect, dst_rect, color);
ID3D11Texture2D_GetDesc(src_texture, &src_desc); ID3D11Texture2D_GetDesc(dst_texture, &dst_desc); @@ -2541,6 +2555,12 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te return MF_E_UNEXPECTED; }
+ if (transfer_needs_render_pipeline(&src_desc, &dst_desc, &src_box, dst_rect)) + { + ID3D11Texture2D_Release(src_texture); + return media_engine_render_d3d11(engine, dst_texture, src_rect, dst_rect, color); + } + if (FAILED(hr = media_engine_lock_d3d_device(engine, &device))) { ID3D11Texture2D_Release(src_texture); @@ -2722,8 +2742,7 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I
if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture))) { - if (!engine->device_manager || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) - hr = media_engine_render_d3d11(engine, texture, src_rect, dst_rect, color); + hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); } else diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 8ea7a69b158..288c7e6ae23 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -2018,6 +2018,7 @@ static void test_effect(void)
SetRect(&dst_rect, 0, 0, desc.Width, desc.Height); hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
count = test_transform_get_sample_count(video_effect);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfmediaengine/main.c | 9 ++++++++- dlls/mfmediaengine/tests/mfmediaengine.c | 1 - 2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 3594a52bb6e..be6c3f86ed6 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2522,6 +2522,7 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te ID3D11Device *device; IMFSample *sample; UINT subresource; + LONGLONG pts; HRESULT hr;
if (!src_rect) @@ -2532,7 +2533,13 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te color = &color_default;
if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) - return MF_E_UNEXPECTED; + { + /* The app does not need to call OnVideoStreamTick() before transferring + * a frame, but we need it to get the current sample. */ + IMFMediaEngineEx_OnVideoStreamTick(&engine->IMFMediaEngineEx_iface, &pts); + if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) + return MF_E_UNEXPECTED; + } hr = get_d3d11_resource_from_sample(sample, &src_texture, &subresource); IMFSample_Release(sample); if (FAILED(hr)) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 288c7e6ae23..8ea7a69b158 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -2018,7 +2018,6 @@ static void test_effect(void)
SetRect(&dst_rect, 0, 0, desc.Width, desc.Height); hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
count = test_transform_get_sample_count(video_effect);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfmediaengine/main.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index be6c3f86ed6..a12106d1a1d 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -71,6 +71,22 @@ static double mftime_to_seconds(MFTIME time) return (double)time / 10000000.0; }
+static HRESULT create_video_media_type_from_fourcc(IMFMediaType **media_type, UINT32 fourcc) +{ + GUID subtype; + HRESULT hr; + + if (FAILED(hr = MFCreateMediaType(media_type))) + return hr; + + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); + subtype.Data1 = fourcc; + IMFMediaType_SetGUID(*media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + IMFMediaType_SetGUID(*media_type, &MF_MT_SUBTYPE, &subtype); + + return hr; +} + enum media_engine_mode { MEDIA_ENGINE_INVALID, @@ -1175,9 +1191,8 @@ static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, I
static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node) { + UINT32 output_format, fourcc; IMFMediaType *media_type; - UINT32 output_format; - GUID subtype; HRESULT hr;
*node = NULL; @@ -1188,19 +1203,15 @@ static HRESULT media_engine_create_video_renderer(struct media_engine *engine, I return E_FAIL; }
- memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); - if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format))) + if (!(fourcc = MFMapDXGIFormatToDX9Format(output_format))) { WARN("Unrecognized output format %#x.\n", output_format); return E_FAIL; }
- if (FAILED(hr = MFCreateMediaType(&media_type))) + if (FAILED(hr = create_video_media_type_from_fourcc(&media_type, fourcc))) return hr;
- IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); - IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype); - hr = create_video_frame_sink(media_type, (IUnknown *)engine->device_manager, &engine->sink_events, &engine->presentation.frame_sink); IMFMediaType_Release(media_type); if (FAILED(hr))
From: Conor McCarthy cmccarthy@codeweavers.com
Allows resolution failure to be handled locally. --- dlls/mfmediaengine/main.c | 41 ++++++++++++++++++------ dlls/mfmediaengine/tests/mfmediaengine.c | 3 +- 2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index a12106d1a1d..607c587aab5 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -1164,27 +1164,41 @@ static HRESULT media_engine_create_effects(struct effect *effects, size_t count, static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; - IMFActivate *sar_activate; + IMFStreamSink *stream_sink; + IMFAttributes *attributes; + IMFMediaSink *media_sink; HRESULT hr;
*node = NULL;
- if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate))) + if (FAILED(hr = MFCreateAttributes(&attributes, 2))) return hr;
/* Configuration attributes keys differ between Engine and SAR. */ if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category))) - IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category); + IMFAttributes_SetUINT32(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category); if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role))) - IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role); + IMFAttributes_SetUINT32(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role); + hr = MFCreateAudioRenderer(attributes, &media_sink); + IMFAttributes_Release(attributes); + + if (FAILED(hr)) + return hr;
if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node))) { - IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate); - IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + if (FAILED(hr = IMFMediaSink_GetStreamSinkByIndex(media_sink, 0, &stream_sink))) + hr = IMFMediaSink_AddStreamSink(media_sink, 0, NULL, &stream_sink); + + if (SUCCEEDED(hr)) + { + IMFTopologyNode_SetObject(*node, (IUnknown *)stream_sink); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + IMFStreamSink_Release(stream_sink); + } }
- IMFActivate_Release(sar_activate); + IMFMediaSink_Release(media_sink);
return hr; } @@ -1273,9 +1287,10 @@ static void media_engine_clear_effects(struct effects *effects) static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; + IMFTopology *topology, *resolved_topology = NULL; IMFPresentationDescriptor *pd; + IMFTopoLoader *topo_loader; DWORD stream_count = 0, i; - IMFTopology *topology; UINT64 duration; HRESULT hr;
@@ -1410,12 +1425,20 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE); IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK, TRUE);
+ if (SUCCEEDED(hr) && SUCCEEDED(hr = MFCreateTopoLoader(&topo_loader))) + { + hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL); + IMFTopoLoader_Release(topo_loader); + } if (SUCCEEDED(hr)) - hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology); + hr = IMFMediaSession_SetTopology(engine->session, + MFSESSION_SETTOPOLOGY_IMMEDIATE | MFSESSION_SETTOPOLOGY_NORESOLUTION, resolved_topology); }
if (topology) IMFTopology_Release(topology); + if (resolved_topology) + IMFTopology_Release(resolved_topology);
if (sd_video) IMFStreamDescriptor_Release(sd_video); diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 8ea7a69b158..9e0d5e16fb9 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1239,6 +1239,7 @@ static HRESULT WINAPI test_transfer_notify_EventNotify(IMFMediaEngineNotify *ifa break;
case MF_MEDIA_ENGINE_EVENT_ERROR: + todo_wine_if(param2 == MF_E_NO_MORE_TYPES) ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE || param2 == MF_E_INVALIDMEDIATYPE), "Unexpected error %#lx\n", param2); notify->error = param2; @@ -1464,7 +1465,7 @@ static void test_TransferVideoFrame_10bit(void)
if (FAILED(notify->error)) { - win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error); + skip("Media engine reported error %#lx, skipping tests.\n", notify->error); goto done; }
From: Conor McCarthy cmccarthy@codeweavers.com
Output frames will be transferred via render if the destination texture format differs. --- dlls/mfmediaengine/main.c | 62 +++++++++++++++++++++++- dlls/mfmediaengine/mediaengine_private.h | 1 + dlls/mfmediaengine/tests/mfmediaengine.c | 10 +--- dlls/mfmediaengine/video_frame_sink.c | 10 ++++ 4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 607c587aab5..9d25473ae87 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -1291,6 +1291,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi IMFPresentationDescriptor *pd; IMFTopoLoader *topo_loader; DWORD stream_count = 0, i; + IMFMediaType *media_type; UINT64 duration; HRESULT hr;
@@ -1427,7 +1428,15 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
if (SUCCEEDED(hr) && SUCCEEDED(hr = MFCreateTopoLoader(&topo_loader))) { - hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL); + if (FAILED(hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL)) + && svr_node && SUCCEEDED(hr = create_video_media_type_from_fourcc(&media_type, + MFMapDXGIFormatToDX9Format(DXGI_FORMAT_B8G8R8A8_UNORM)))) + { + video_frame_sink_set_media_type(engine->presentation.frame_sink, media_type); + IMFMediaType_Release(media_type); + engine->video_frame.output_format = DXGI_FORMAT_B8G8R8A8_UNORM; + hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL); + } IMFTopoLoader_Release(topo_loader); } if (SUCCEEDED(hr)) @@ -2529,6 +2538,53 @@ static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D return hr; }
+static DXGI_FORMAT dxgi_format_get_typeless_format(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return DXGI_FORMAT_R32G32B32A32_TYPELESS; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_TYPELESS; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + return DXGI_FORMAT_R10G10B10A2_TYPELESS; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_TYPELESS; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return DXGI_FORMAT_B8G8R8A8_TYPELESS; + + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return DXGI_FORMAT_B8G8R8X8_TYPELESS; + + default: + WARN("Unhandled format %#x.\n", format); + return format; + } +} + static BOOL transfer_needs_render_pipeline(const D3D11_TEXTURE2D_DESC *src_desc, const D3D11_TEXTURE2D_DESC *dst_desc, const D3D11_BOX *src_box, const RECT *dst_rect) { @@ -2537,7 +2593,9 @@ static BOOL transfer_needs_render_pipeline(const D3D11_TEXTURE2D_DESC *src_desc, || dst_rect->bottom - dst_rect->top != src_box->bottom - src_box->top)) return TRUE;
- return FALSE; + /* If block-compressed formats were to show up in the dst then we + * would need to also check copy-to-BC and byte count compatibility. */ + return dxgi_format_get_typeless_format(src_desc->Format) != dxgi_format_get_typeless_format(dst_desc->Format); }
static HRESULT media_engine_render_d3d11(struct media_engine *engine, ID3D11Texture2D *texture, diff --git a/dlls/mfmediaengine/mediaengine_private.h b/dlls/mfmediaengine/mediaengine_private.h index 3b280a6d1ee..095deb93147 100644 --- a/dlls/mfmediaengine/mediaengine_private.h +++ b/dlls/mfmediaengine/mediaengine_private.h @@ -22,6 +22,7 @@ struct video_frame_sink;
HRESULT create_video_frame_sink(IMFMediaType *media_type, IUnknown *device_manager, IMFAsyncCallback *events_callback, struct video_frame_sink **sink); +void video_frame_sink_set_media_type(struct video_frame_sink *sink, IMFMediaType *media_type); HRESULT video_frame_sink_query_iface(struct video_frame_sink *object, REFIID riid, void **obj); ULONG video_frame_sink_release(struct video_frame_sink *sink); int video_frame_sink_get_sample(struct video_frame_sink *sink, IMFSample **sample); diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 9e0d5e16fb9..ea26024289a 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1239,7 +1239,6 @@ static HRESULT WINAPI test_transfer_notify_EventNotify(IMFMediaEngineNotify *ifa break;
case MF_MEDIA_ENGINE_EVENT_ERROR: - todo_wine_if(param2 == MF_E_NO_MORE_TYPES) ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE || param2 == MF_E_INVALIDMEDIATYPE), "Unexpected error %#lx\n", param2); notify->error = param2; @@ -1465,7 +1464,7 @@ static void test_TransferVideoFrame_10bit(void)
if (FAILED(notify->error)) { - skip("Media engine reported error %#lx, skipping tests.\n", notify->error); + win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error); goto done; }
@@ -1504,19 +1503,12 @@ static void test_TransferVideoFrame_10bit(void) ok(!!map_desc.pData, "got pData %p\n", map_desc.pData); ok(map_desc.DepthPitch == 16384, "got DepthPitch %u\n", map_desc.DepthPitch); ok(map_desc.RowPitch == desc.Width * 4, "got RowPitch %u\n", map_desc.RowPitch); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 5, 0x3ff, 0x3ff, 0x3ff, 24); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 14, 0x3fa, 0x3ff, 0x4, 31); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 23, 0x5, 0x3ff, 0x3ff, 25); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 32, 0x1, 0x3ff, 0x6, 27); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 41, 0x3fd, 0, 0x3f7, 10); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 50, 0x3fd, 0, 0, 10); - todo_wine check_r10g10b10a2_diff(&map_desc, 32, 59, 0x2, 0, 0x3ff, 10); ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0);
diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index f710466fed4..76e88b84e4b 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -1214,6 +1214,16 @@ failed: return hr; }
+void video_frame_sink_set_media_type(struct video_frame_sink *sink, IMFMediaType *media_type) +{ + IMFMediaType_Release(sink->media_type); + IMFMediaType_Release(sink->current_media_type); + sink->media_type = media_type; + IMFMediaType_AddRef(sink->media_type); + sink->current_media_type = media_type; + IMFMediaType_AddRef(sink->current_media_type); +} + HRESULT video_frame_sink_query_iface(struct video_frame_sink *sink, REFIID riid, void **obj) { return IMFStreamSink_QueryInterface(&sink->IMFStreamSink_iface, riid, obj);
Setting this to draft because more tests are needed, and `test_SetCurrentTime()` crashes because the audio output type is never set. The session engine skips setting it if `MFSESSION_SETTOPOLOGY_NORESOLUTION` is used. I will find out if the loader or session should set it or if it must be done in mfmediaengine.
I made frame transfer go via the renderer if the sizes don't match, but we have no tests to show exactly what should happen there.
The topology is resolved in mfmediaengine, and if it fails, Load() is called again after setting the output to B8G8R8A8_UNORM.