-- v6: 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 scale/letterbox is needed. mfmediaengine: Call media_engine_render_d3d11 from media_engine_transfer_d3d11(). mfmediaengine: Rename media_engine_transfer_to_d3d11_texture() helper function. mfmediaengine/tests: Test TransferVideoFrame() scale/letterbox. 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 | 153 ++++++++++++++++++++++- dlls/mfmediaengine/tests/resource.rc | 6 + 3 files changed, 158 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..49bc9dde755 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -164,6 +164,19 @@ 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)); + UINT a = got >> 30; + ok_(__FILE__, line)(diff <= max_diff, "got diff %u at (%u, %u)\n", diff, x, y); + ok_(__FILE__, line)(a == 3, "got alpha %u at (%u, %u)\n", a, x, y); +} + static void init_functions(void) { HMODULE mod; @@ -1228,7 +1241,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: @@ -1388,6 +1402,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 +2863,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/tests/mfmediaengine.c | 95 ++++++++++++++++++++++++ 1 file changed, 95 insertions(+)
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 49bc9dde755..51b472535b5 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -177,6 +177,17 @@ static void check_r10g10b10a2_diff_(int line, const D3D11_MAPPED_SUBRESOURCE *ma ok_(__FILE__, line)(a == 3, "got alpha %u at (%u, %u)\n", a, x, y); }
+#define check_bgr_diff(a, b, c, d, e, f, g) check_bgr_diff_(__LINE__, a, b, c, d, e, f, g) +static void check_bgr_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(b - (int)(got & 0xff)) + + abs(g - (int)((got >> 8) & 0xff)) + + abs(r - (int)((got >> 16) & 0xff)); + ok_(__FILE__, line)(diff <= max_diff, "got diff %u at (%u, %u)\n", diff, x, y); +} + static void init_functions(void) { HMODULE mod; @@ -1298,6 +1309,8 @@ static void test_TransferVideoFrame(void) BSTR url; LONGLONG pts;
+ static const MFARGB border = {0x3f, 0x7f, 0x1f, 0xff}; + stream = load_resource(L"i420-64x64.avi", L"video/avi");
notify = create_transfer_notify(); @@ -1384,6 +1397,88 @@ static void test_TransferVideoFrame(void) ok(res == 0, "Unexpected %lu%% diff\n", res); ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0);
+ ID3D11Texture2D_Release(texture); + memset(&desc, 0, sizeof(desc)); + desc.Width = 32; + desc.Height = 32; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8X8_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); + + SetRect(&dst_rect, 0, 0, desc.Width, desc.Height); + hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + 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); + /* scaled down */ + check_bgr_diff(&map_desc, 16, 2, 0xff, 0xff, 0xff, 6); + check_bgr_diff(&map_desc, 16, 7, 0xff, 0xff, 0, 8); + check_bgr_diff(&map_desc, 16, 11, 0x1, 0xff, 0xff, 6); + check_bgr_diff(&map_desc, 16, 16, 0x0, 0xff, 0x1, 6); + check_bgr_diff(&map_desc, 16, 20, 0xff, 0, 0xfe, 4); + check_bgr_diff(&map_desc, 16, 25, 0xfe, 0, 0, 1); + check_bgr_diff(&map_desc, 16, 29, 0x0, 0, 0xff, 2); + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0); + + ID3D11Texture2D_Release(texture); + memset(&desc, 0, sizeof(desc)); + desc.Width = 80; + desc.Height = 96; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8X8_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); + + ID3D11Texture2D_Release(rb_texture); + 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); + + SetRect(&dst_rect, 0, 0, desc.Width, desc.Height); + hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, &border); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + 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); + /* letterbox with border colour above/below */ + todo_wine + check_bgr_diff(&map_desc, 40, 7, 0x1f, 0x7f, 0x3f, 0); + todo_wine + check_bgr_diff(&map_desc, 40, 14, 0xff, 0xff, 0xff, 6); + todo_wine + check_bgr_diff(&map_desc, 40, 25, 0xff, 0xff, 0, 8); + todo_wine + check_bgr_diff(&map_desc, 40, 37, 0x1, 0xff, 0xff, 6); + todo_wine + check_bgr_diff(&map_desc, 40, 48, 0x0, 0xff, 0x1, 6); + todo_wine + check_bgr_diff(&map_desc, 40, 59, 0xff, 0, 0xfe, 4); + todo_wine + check_bgr_diff(&map_desc, 40, 71, 0xfe, 0, 0, 1); + todo_wine + check_bgr_diff(&map_desc, 40, 82, 0x0, 0, 0xff, 2); + todo_wine + check_bgr_diff(&map_desc, 40, 88, 0x1f, 0x7f, 0x3f, 0); + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0); + ID3D11DeviceContext_Release(context); ID3D11Texture2D_Release(rb_texture);
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
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(), 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 | 10 ++++++---- dlls/mfmediaengine/tests/mfmediaengine.c | 1 + 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index dd239962bae..dc6857a38ca 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2495,6 +2495,9 @@ static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D return hr; }
+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 +2525,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); @@ -2538,7 +2541,7 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te dst_rect->top + src_box.bottom - src_box.top > dst_desc.Height) { ID3D11Texture2D_Release(src_texture); - return MF_E_UNEXPECTED; + return media_engine_render_d3d11(engine, dst_texture, src_rect, dst_rect, color); }
if (FAILED(hr = media_engine_lock_d3d_device(engine, &device))) @@ -2722,8 +2725,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 51b472535b5..1757abeee35 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -2114,6 +2114,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
The existing code only checks if the rect fits within the destination texture for compatibility with CopySubresourceRegion(). --- dlls/mfmediaengine/main.c | 29 ++++++++++++++++++------ dlls/mfmediaengine/tests/mfmediaengine.c | 9 -------- 2 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index dc6857a38ca..bb4ae5d61a3 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2495,6 +2495,17 @@ static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D return hr; }
+static BOOL transfer_needs_render_pipeline(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);
@@ -2513,10 +2524,16 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te UINT subresource; HRESULT hr;
+ ID3D11Texture2D_GetDesc(dst_texture, &dst_desc); + if (!src_rect) src_rect = &src_rect_default; if (!dst_rect) + { dst_rect = &dst_rect_default; + dst_rect_default.right = dst_desc.Width; + dst_rect_default.bottom = dst_desc.Height; + } if (!color) color = &color_default;
@@ -2528,17 +2545,15 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te 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);
- 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 || - dst_rect->top + src_box.bottom - src_box.top > dst_desc.Height) + if (transfer_needs_render_pipeline(&dst_desc, &src_box, dst_rect)) { ID3D11Texture2D_Release(src_texture); return media_engine_render_d3d11(engine, dst_texture, src_rect, dst_rect, color); diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 1757abeee35..d98d482e4a0 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1459,23 +1459,14 @@ static void test_TransferVideoFrame(void) hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)rb_texture, 0, D3D11_MAP_READ, 0, &map_desc); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); /* letterbox with border colour above/below */ - todo_wine check_bgr_diff(&map_desc, 40, 7, 0x1f, 0x7f, 0x3f, 0); - todo_wine check_bgr_diff(&map_desc, 40, 14, 0xff, 0xff, 0xff, 6); - todo_wine check_bgr_diff(&map_desc, 40, 25, 0xff, 0xff, 0, 8); - todo_wine check_bgr_diff(&map_desc, 40, 37, 0x1, 0xff, 0xff, 6); - todo_wine check_bgr_diff(&map_desc, 40, 48, 0x0, 0xff, 0x1, 6); - todo_wine check_bgr_diff(&map_desc, 40, 59, 0xff, 0, 0xfe, 4); - todo_wine check_bgr_diff(&map_desc, 40, 71, 0xfe, 0, 0, 1); - todo_wine check_bgr_diff(&map_desc, 40, 82, 0x0, 0, 0xff, 2); - todo_wine check_bgr_diff(&map_desc, 40, 88, 0x1f, 0x7f, 0x3f, 0); ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0);
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 bb4ae5d61a3..b621b66dacd 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;
ID3D11Texture2D_GetDesc(dst_texture, &dst_desc); @@ -2538,7 +2539,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 d98d482e4a0..108065bf1d7 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -2105,7 +2105,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 b621b66dacd..ac2421ec2eb 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 | 127 +++++++++++++++++++++-- dlls/mfmediaengine/tests/mfmediaengine.c | 3 +- 2 files changed, 120 insertions(+), 10 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index ac2421ec2eb..2bd814de856 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; } @@ -1270,12 +1284,84 @@ static void media_engine_clear_effects(struct effects *effects) memset(effects, 0, sizeof(*effects)); }
+static HRESULT sar_node_set_media_type(IMFTopologyNode *sar_node) +{ + IMFMediaTypeHandler *handler; + MF_TOPOLOGY_TYPE node_type; + IMFStreamSink *stream_sink; + IMFTopologyNode *up_node; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFTransform *transform; + DWORD up_output; + HRESULT hr; + + if (FAILED(hr = IMFTopologyNode_GetInput(sar_node, 0, &up_node, &up_output))) + return hr; + if (FAILED(hr = IMFTopologyNode_GetNodeType(up_node, &node_type))) + { + IMFTopologyNode_Release(up_node); + return hr; + } + + switch (node_type) + { + case MF_TOPOLOGY_SOURCESTREAM_NODE: + if (SUCCEEDED(hr = IMFTopologyNode_GetUnknown(up_node, &MF_TOPONODE_STREAM_DESCRIPTOR, + &IID_IMFStreamDescriptor, (void **)&sd))) + { + hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler); + IMFStreamDescriptor_Release(sd); + if (SUCCEEDED(hr)) + { + hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type); + IMFMediaTypeHandler_Release(handler); + } + } + break; + case MF_TOPOLOGY_TRANSFORM_NODE: + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(up_node, (IUnknown **)&transform))) + { + hr = IMFTransform_GetOutputCurrentType(transform, up_output, &media_type); + IMFTransform_Release(transform); + } + break; + default: + WARN("Unhandled node type %u.\n", node_type); + hr = MF_E_UNEXPECTED; + break; + } + + if (FAILED(hr)) + { + IMFTopologyNode_Release(up_node); + return hr; + } + + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(sar_node, (IUnknown **)&stream_sink))) + { + hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); + IMFStreamSink_Release(stream_sink); + if (SUCCEEDED(hr)) + { + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type); + IMFMediaTypeHandler_Release(handler); + } + } + + IMFMediaType_Release(media_type); + IMFTopologyNode_Release(up_node); + return hr; +} + 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; + TOPOID sar_node_id; UINT64 duration; HRESULT hr;
@@ -1372,6 +1458,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_effects(engine->audio_effects.effects, engine->audio_effects.count, audio_src, sar_node, topology))) WARN("Failed to create audio effect nodes, hr %#lx.\n", hr); + IMFTopologyNode_GetTopoNodeID(sar_node, &sar_node_id); }
if (sar_node) @@ -1410,12 +1497,34 @@ 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);
+ /* MESessionTopologySet is not sent until the session is started, which would + * complicate things if loading failed, so the topology is resolved here. The session + * engine does not set types on the sinks when NORESOLUTION is specified. Video type + * is set explicitly, but audio type must be taken from the sink's upstream node. */ + if (SUCCEEDED(hr) && SUCCEEDED(hr = MFCreateTopoLoader(&topo_loader))) + { + hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL); + IMFTopoLoader_Release(topo_loader); + + if (FAILED(hr)) + WARN("Failed to load topology, hr %#lx.\n", hr); + } 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 (SUCCEEDED(hr) && SUCCEEDED(hr = IMFTopology_GetNodeByID(resolved_topology, sar_node_id, &sar_node))) + { + hr = sar_node_set_media_type(sar_node); + IMFTopologyNode_Release(sar_node); + } + } }
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 108065bf1d7..b9c5207df58 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1252,6 +1252,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; @@ -1551,7 +1552,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 | 66 ++++++++++++++++++++++-- dlls/mfmediaengine/mediaengine_private.h | 1 + dlls/mfmediaengine/tests/mfmediaengine.c | 10 +--- dlls/mfmediaengine/video_frame_sink.c | 10 ++++ 4 files changed, 74 insertions(+), 13 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 2bd814de856..0f08cbf3264 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -1361,6 +1361,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; TOPOID sar_node_id; UINT64 duration; HRESULT hr; @@ -1503,7 +1504,15 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi * is set explicitly, but audio type must be taken from the sink's upstream node. */ 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 (FAILED(hr)) @@ -2615,7 +2624,54 @@ static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D return hr; }
-static BOOL transfer_needs_render_pipeline(const D3D11_TEXTURE2D_DESC *dst_desc, +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) { if (dst_rect->right && dst_rect->bottom @@ -2623,7 +2679,9 @@ static BOOL transfer_needs_render_pipeline(const D3D11_TEXTURE2D_DESC *dst_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, @@ -2680,7 +2738,7 @@ static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Te src_box.bottom = src_rect->bottom * src_desc.Height + 0.5f; src_box.back = 1;
- if (transfer_needs_render_pipeline(&dst_desc, &src_box, dst_rect)) + 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); 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 b9c5207df58..22ebb499be1 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1252,7 +1252,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; @@ -1552,7 +1551,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; }
@@ -1591,19 +1590,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);
The topology loader doesn't set types on the sink, nor does the session engine if `MFSESSION_SETTOPOLOGY_NORESOLUTION` is specified, and tests already exist for this. Setting the audio sink type is quite involved, but I see no other option.
I cleaned things up and added tests for scale down and letterbox.