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.
-- v2: mfmediaengine: Support video output in format R10G10B10A2. mfmediaengine/tests: Test format R10G10B10A2 in TransferVideoFrame().
From: Conor McCarthy cmccarthy@codeweavers.com
Windows supports this. Media engine apparently performs a format conversion, because the session engine does not support R10G10B10A2 output. --- dlls/mfmediaengine/tests/mfmediaengine.c | 20 ++++++++++++++------ dlls/mfmediaengine/tests/resource.rc | 4 ++++ dlls/mfmediaengine/tests/rgb32-10frame.bmp | Bin 0 -> 16438 bytes 3 files changed, 18 insertions(+), 6 deletions(-) create mode 100755 dlls/mfmediaengine/tests/rgb32-10frame.bmp
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index fbaeff50710..703e13e05e8 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1228,7 +1228,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: @@ -1266,7 +1267,7 @@ static struct test_transfer_notify *create_transfer_notify(void) return object; }
-static void test_TransferVideoFrame(void) +static void test_TransferVideoFrame(DXGI_FORMAT format, const WCHAR *expected_frame) { struct test_transfer_notify *notify; ID3D11Texture2D *texture = NULL, *rb_texture; @@ -1284,6 +1285,8 @@ static void test_TransferVideoFrame(void) BSTR url; LONGLONG pts;
+ winetest_push_context(format == DXGI_FORMAT_R10G10B10A2_UNORM ? "10-bit" : "8-bit"); + stream = load_resource(L"i420-64x64.avi", L"video/avi");
notify = create_transfer_notify(); @@ -1299,7 +1302,7 @@ static void test_TransferVideoFrame(void) 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_B8G8R8X8_UNORM, + create_media_engine(¬ify->IMFMediaEngineNotify_iface, manager, format, &IID_IMFMediaEngineEx, (void **)&media_engine);
IMFDXGIDeviceManager_Release(manager); @@ -1311,7 +1314,7 @@ static void test_TransferVideoFrame(void) desc.Width = 64; desc.Height = 64; desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; + desc.Format = format; desc.BindFlags = D3D11_BIND_RENDER_TARGET; desc.SampleDesc.Count = 1; hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); @@ -1366,7 +1369,9 @@ static void test_TransferVideoFrame(void) ok(!!map_desc.pData, "got pData %p\n", map_desc.pData); ok(map_desc.DepthPitch == 16384, "got DepthPitch %u\n", map_desc.DepthPitch); ok(map_desc.RowPitch == desc.Width * 4, "got RowPitch %u\n", map_desc.RowPitch); - res = check_rgb32_data(L"rgb32frame.bmp", map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect); + res = check_rgb32_data(expected_frame, map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect); + /* R10G10B10A2 equivalents in openGL and Vulkan are not binary compatible with R10G10B10A2 */ + todo_wine_if(format == DXGI_FORMAT_R10G10B10A2_UNORM) ok(res == 0, "Unexpected %lu%% diff\n", res); ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0);
@@ -1386,6 +1391,8 @@ done: ID3D11Device_Release(device);
IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); + + winetest_pop_context(); }
struct test_transform @@ -2712,7 +2719,8 @@ START_TEST(mfmediaengine) test_time_range(); test_SetSourceFromByteStream(); test_audio_configuration(); - test_TransferVideoFrame(); + test_TransferVideoFrame(DXGI_FORMAT_B8G8R8X8_UNORM, L"rgb32frame.bmp"); + test_TransferVideoFrame(DXGI_FORMAT_R10G10B10A2_UNORM, L"rgb32-10frame.bmp"); test_effect(); test_GetDuration(); test_GetSeekable(); diff --git a/dlls/mfmediaengine/tests/resource.rc b/dlls/mfmediaengine/tests/resource.rc index 960e5ffd73e..1b4db9df50c 100644 --- a/dlls/mfmediaengine/tests/resource.rc +++ b/dlls/mfmediaengine/tests/resource.rc @@ -31,3 +31,7 @@ i420-64x64.avi RCDATA i420-64x64.avi /* Generated from running the tests on Windows */ /* @makedep: rgb32frame.bmp */ rgb32frame.bmp RCDATA rgb32frame.bmp + +/* Generated from running the tests on Windows */ +/* @makedep: rgb32-10frame.bmp */ +rgb32-10frame.bmp RCDATA rgb32-10frame.bmp diff --git a/dlls/mfmediaengine/tests/rgb32-10frame.bmp b/dlls/mfmediaengine/tests/rgb32-10frame.bmp new file mode 100755 index 0000000000000000000000000000000000000000..c271b52ed9d390d1f082a24c48284e859c6e34ad GIT binary patch literal 16438 zcmZ?rHFID912YB&1`P%V1`rp785tD7;$Q&?3r?<Q|FLTnkA}f$8W>FjqiJ9?4UDFN z5tatpzwBB+g0WZok}V?|GcVlYHHt^WU^ESkrh(BkFq#HN)4+&I1FN!DX^rC1Fc?h( zqiJ9?4UDFN(KIl^(!jH2TB}Adc6}D6GNN%>u!`#_9u0%hG%%V5M$^D(8W>FjBPtE7 zTsh~~C>{-i(KIlc21e7sXc`zz10yUAsLs5#as*>n)yOL&8ZQmK;yQ{)!(cQGjHZFn sG%%V5M$^EEN&`!H{Jlo;Xc&y9fzdQDng&MGz-Ss6O#`E8VC19$0FQE02LJ#7
literal 0 HcmV?d00001
From: Conor McCarthy cmccarthy@codeweavers.com
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. --- dlls/mfmediaengine/main.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index aab5fd64aa2..9ed86cddf35 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -182,6 +182,7 @@ struct media_engine BYTE *buffer; UINT buffer_size; DXGI_FORMAT output_format; + BOOL uses_10bit;
struct { @@ -1188,6 +1189,21 @@ static HRESULT media_engine_create_video_renderer(struct media_engine *engine, I return E_FAIL; }
+ switch (output_format) + { + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + /* IMFMediaSession doesn't support output to these formats. Create an 8-bit + * output and ensure the sampled texture is copied via a pixel shader. + * TODO: to actually have 10 bits per channel we should use DXGI_FORMAT_P010. */ + output_format = DXGI_FORMAT_B8G8R8A8_UNORM; + engine->video_frame.uses_10bit = TRUE; + break; + default: + break; + } + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format))) { @@ -2722,7 +2738,9 @@ 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))) + if (!engine->device_manager + || engine->video_frame.uses_10bit + || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); }
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/main.c:
}
- switch (output_format)
- {
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R10G10B10A2_UINT:
/* IMFMediaSession doesn't support output to these formats. Create an 8-bit
* output and ensure the sampled texture is copied via a pixel shader.
* TODO: to actually have 10 bits per channel we should use DXGI_FORMAT_P010. */
output_format = DXGI_FORMAT_B8G8R8A8_UNORM;
engine->video_frame.uses_10bit = TRUE;
break;
default:
break;
- }
Do we actually need P010 format at some point, and why if we do? Why can't we simply use BGRA always and then copy to output format texture that user asked for? What does it mean that session doesn't support it? I don't think session really cares about what's in sample buffers. Calling this "uses_10bit" is too detailed, what it means really is "not-equal-to-output_format", right?
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/tests/mfmediaengine.c:
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);
- res = check_rgb32_data(L"rgb32frame.bmp", map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect);
- res = check_rgb32_data(expected_frame, map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect);
- /* R10G10B10A2 equivalents in openGL and Vulkan are not binary compatible with R10G10B10A2 */
- todo_wine_if(format == DXGI_FORMAT_R10G10B10A2_UNORM) ok(res == 0, "Unexpected %lu%% diff\n", res);
Does that mean it gets different "raw" data when accessed directly e.g. mapped, but rendering is still same and correct? This todo means we are not really testing this format on Wine.
I'm not sure we really need to compare full frame, same for existing rgb32frame.bmp resource. It should be enough to read back from output texture in a few locations, like d3d11/d2d tests do.
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/main.c:
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)))
if (!engine->device_manager
|| engine->video_frame.uses_10bit
|| FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture);
This should be cleaned up a bit now, with possible name change to uses_10bit field that I mentioned. Also existing transfer_to_d3d11 helpers are called too similar to understand what's happening.