-- v5: mfreadwrite/reader: Pass the device manager to the stream transforms. winegstreamer/video_processor: Implement D3D awareness. mf/tests: Test video processor D3D11 awareness. mfreadwrite/tests: Add some source reader D3D11 awareness tests.
From: Rémi Bernon rbernon@codeweavers.com
(cherry picked from commit 40e2e9cf2ef68d40d09be12cb2eca267b05cc739) --- dlls/mfreadwrite/tests/Makefile.in | 2 +- dlls/mfreadwrite/tests/mfplat.c | 342 +++++++++++++++++++++++++++-- 2 files changed, 324 insertions(+), 20 deletions(-)
diff --git a/dlls/mfreadwrite/tests/Makefile.in b/dlls/mfreadwrite/tests/Makefile.in index 3bdab217148..c6262c01009 100644 --- a/dlls/mfreadwrite/tests/Makefile.in +++ b/dlls/mfreadwrite/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfreadwrite.dll -IMPORTS = ole32 user32 d3d9 dxva2 mfplat mf mfreadwrite mfuuid propsys +IMPORTS = ole32 user32 d3d11 d3d9 dxva2 mfplat mf mfreadwrite mfuuid propsys
SOURCES = \ mfplat.c \ diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index b70d0587072..d0f9c689390 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -42,6 +42,7 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "initguid.h" #include "d3d9.h" #include "dxva2api.h" +#include "d3d11_4.h" #include "evr.h"
#include "wine/test.h" @@ -199,6 +200,7 @@ static IDirect3DDevice9 *create_d3d9_device(IDirect3D9 *d3d9, HWND focus_window) }
static HRESULT (WINAPI *pMFCreateMFByteStreamOnStream)(IStream *stream, IMFByteStream **bytestream); +static HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager);
static void init_functions(void) { @@ -206,6 +208,7 @@ static void init_functions(void)
#define X(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return; X(MFCreateMFByteStreamOnStream); + X(MFCreateDXGIDeviceManager); #undef X }
@@ -2296,9 +2299,11 @@ skip_tests: }
static BOOL test_decoder_d3d_aware; +static BOOL test_decoder_d3d11_aware; static BOOL test_decoder_got_d3d_manager; static BOOL test_decoder_allocate_samples; -static IDirect3DDeviceManager9 *expect_d3d_manager; +static IDirect3DDeviceManager9 *expect_d3d9_manager; +static IMFDXGIDeviceManager *expect_dxgi_manager;
struct test_decoder { @@ -2564,20 +2569,35 @@ static HRESULT WINAPI test_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA return S_OK;
case MFT_MESSAGE_SET_D3D_MANAGER: - ok(test_decoder_d3d_aware, "Unexpected call.\n"); - if (param) + ok(test_decoder_d3d_aware || test_decoder_d3d11_aware, "Unexpected call.\n"); + if (!param) + return S_OK; + + if (test_decoder_d3d_aware) { IDirect3DDeviceManager9 *manager; HRESULT hr;
hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&manager); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(manager == expect_d3d_manager, "got manager %p\n", manager); + ok(manager == expect_d3d9_manager, "got manager %p\n", manager); IDirect3DDeviceManager9_Release(manager);
test_decoder_got_d3d_manager = TRUE; } - return test_decoder_d3d_aware ? S_OK : E_NOTIMPL; + if (test_decoder_d3d11_aware) + { + IMFDXGIDeviceManager *manager; + HRESULT hr; + + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IMFDXGIDeviceManager, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == expect_dxgi_manager, "got manager %p\n", manager); + IMFDXGIDeviceManager_Release(manager); + + test_decoder_got_d3d_manager = TRUE; + } + return S_OK;
default: ok(0, "Unexpected call.\n"); @@ -2712,13 +2732,21 @@ static HRESULT WINAPI test_mft_factory_CreateInstance(IClassFactory *iface, IUnk decoder->IMFTransform_iface.lpVtbl = &test_decoder_vtbl; decoder->refcount = 1;
- if (test_decoder_d3d_aware) + if (test_decoder_d3d_aware || test_decoder_d3d11_aware) { hr = MFCreateAttributes(&decoder->attributes, 1); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + if (test_decoder_d3d_aware) + { hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, 1); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } + if (test_decoder_d3d11_aware) + { + hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + }
*obj = &decoder->IMFTransform_iface; return S_OK; @@ -2901,7 +2929,7 @@ skip_tests: ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
-static void test_source_reader_transforms_d3d(void) +static void test_source_reader_transforms_d3d9(void) { static const struct attribute_desc test_stream_type_desc[] = { @@ -2966,8 +2994,11 @@ static void test_source_reader_transforms_d3d(void) if (!(d3d9_device = create_d3d9_device(d3d9, window))) { skip("Failed to create a D3D9 device, skipping tests.\n"); - goto done; + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; } + IDirect3D9_Release(d3d9);
test_decoder_d3d_aware = TRUE;
@@ -2984,9 +3015,11 @@ static void test_source_reader_transforms_d3d(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDevice9_Release(d3d9_device); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)d3d9_manager); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - expect_d3d_manager = d3d9_manager; + expect_d3d9_manager = d3d9_manager;
/* test d3d aware decoder that doesn't allocate buffers */ @@ -3016,7 +3049,6 @@ static void test_source_reader_transforms_d3d(void) IMFSourceReader_Release(reader); goto skip_tests; } - IMFSourceReaderEx_Release(reader_ex);
hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3046,10 +3078,8 @@ static void test_source_reader_transforms_d3d(void) IMFMediaType_Release(media_type);
- hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* video processor transform is not D3D9 aware on more recent Windows */
- /* video processor transform is not D3D aware */ hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); @@ -3057,6 +3087,19 @@ static void test_source_reader_transforms_d3d(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 1, "got %u.\n", value); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); IMFAttributes_Release(attributes); IMFTransform_Release(video_processor);
@@ -3070,7 +3113,6 @@ static void test_source_reader_transforms_d3d(void) ok(value == 1, "got %u\n", value); IMFAttributes_Release(attributes);
- IMFSourceReaderEx_Release(reader_ex);
fail_request_sample = FALSE; test_decoder_set_next_output(test_decoder, S_OK); @@ -3096,7 +3138,33 @@ static void test_source_reader_transforms_d3d(void)
fail_request_sample = TRUE;
+ + /* video processor output stream attributes are left empty in D3D9 mode */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 6, "got %u.\n", value); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + IMFTransform_Release(test_decoder); + IMFSourceReaderEx_Release(reader_ex); IMFSourceReader_Release(reader);
@@ -3182,13 +3250,248 @@ skip_tests: ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IDirect3DDeviceManager9_Release(d3d9_manager); - IDirect3DDevice9_Release(d3d9_device); - -done: - IDirect3D9_Release(d3d9); DestroyWindow(window);
+ test_decoder_got_d3d_manager = FALSE; test_decoder_d3d_aware = FALSE; + expect_d3d9_manager = NULL; +} + +static void test_source_reader_transforms_d3d11(void) +{ + static const struct attribute_desc test_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_TEST), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + {0}, + }; + static const struct attribute_desc rgb32_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + {0}, + }; + static const struct attribute_desc rgb32_expect_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), + {0}, + }; + const MFT_REGISTER_TYPE_INFO output_info[] = + { + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + }; + const MFT_REGISTER_TYPE_INFO input_info[] = + { + {MFMediaType_Video, MFVideoFormat_TEST}, + }; + IClassFactory factory = {.lpVtbl = &test_mft_factory_vtbl}; + IMFTransform *test_decoder, *video_processor; + IMFStreamDescriptor *video_stream; + ID3D11Multithread *multithread; + IMFDXGIDeviceManager *manager; + IMFSourceReaderEx *reader_ex; + IMFAttributes *attributes; + IMFMediaType *media_type; + IMFSourceReader *reader; + IMFMediaBuffer *buffer; + IMFMediaSource *source; + UINT32 value, token; + ID3D11Device *d3d11; + LONGLONG timestamp; + DWORD index, flags; + IMFSample *sample; + HRESULT hr; + + if (!pMFCreateDXGIDeviceManager) + { + win_skip("MFCreateDXGIDeviceManager() is not available, skipping tests.\n"); + return; + } + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + return; + } + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + + test_decoder_d3d11_aware = TRUE; + + hr = MFTRegisterLocal(&factory, &MFT_CATEGORY_VIDEO_DECODER, L"Test Decoder", 0, + ARRAY_SIZE(input_info), input_info, ARRAY_SIZE(output_info), output_info); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + expect_dxgi_manager = manager; + + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, test_stream_type_desc, -1); + hr = MFCreateStreamDescriptor(0, 1, &media_type, &video_stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + source = create_test_source(&video_stream, 1); + ok(!!source, "Failed to create test source.\n"); + IMFStreamDescriptor_Release(video_stream); + + hr = MFCreateSourceReaderFromMediaSource(source, attributes, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + IMFMediaSource_Release(source); + + /* skip tests on Win7 which misses IMFSourceReaderEx */ + hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win7 */, "Unexpected hr %#lx.\n", hr); + if (broken(hr == E_NOINTERFACE)) + { + win_skip("missing IMFSourceReaderEx interface, skipping tests on Win7\n"); + IMFSourceReader_Release(reader); + goto skip_tests; + } + + hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSourceReader_GetNativeMediaType(reader, 0, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, test_stream_type_desc, -1); + IMFMediaType_Release(media_type); + ok(!test_decoder_got_d3d_manager, "d3d manager received\n"); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(media_type, rgb32_stream_type_desc, -1); + hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_media_type(media_type, rgb32_expect_desc, -1); + IMFMediaType_Release(media_type); + + + /* video processor output stream attributes are still empty */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_GetCount(attributes, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, NULL, &test_decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(test_decoder->lpVtbl == &test_decoder_vtbl, "got unexpected transform\n"); + + fail_request_sample = FALSE; + test_decoder_set_next_output(test_decoder, S_OK); + + sample = (void *)0xdeadbeef; + index = flags = timestamp = 0xdeadbeef; + hr = IMFSourceReader_ReadSample(reader, 0, 0, &index, &flags, ×tamp, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "got %lu.\n", index); + ok(flags == 0, "got %lu.\n", flags); + ok(timestamp == 0, "got %I64d.\n", timestamp); + ok(sample != (void *)0xdeadbeef, "got %p.\n", sample); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, FALSE); + check_interface(buffer, &IID_IMFDXGIBuffer, TRUE); + IMFMediaBuffer_Release(buffer); + + IMFSample_Release(sample); + + fail_request_sample = TRUE; + + + /* video processor output stream attributes are now set with some defaults */ + + hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, NULL, &video_processor); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(video_processor->lpVtbl != &test_decoder_vtbl, "got unexpected transform\n"); + + hr = IMFTransform_GetAttributes(video_processor, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 6, "got %u.\n", value); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &value); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(value == 1024, "got %u.\n", value); + IMFAttributes_Release(attributes); + + IMFTransform_Release(video_processor); + + + IMFSourceReaderEx_Release(reader_ex); + IMFSourceReader_Release(reader); + IMFTransform_Release(test_decoder); + + +skip_tests: + hr = MFTUnregisterLocal(&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFDXGIDeviceManager_Release(manager); + + test_decoder_got_d3d_manager = FALSE; + test_decoder_d3d11_aware = FALSE; + expect_dxgi_manager = NULL; }
START_TEST(mfplat) @@ -3209,7 +3512,8 @@ START_TEST(mfplat) test_source_reader_transforms(TRUE, FALSE); test_source_reader_transforms(FALSE, TRUE); test_source_reader_transform_stream_change(); - test_source_reader_transforms_d3d(); + test_source_reader_transforms_d3d9(); + test_source_reader_transforms_d3d11(); test_reader_d3d9(); test_sink_writer_create(); test_sink_writer_mp4();
From: Rémi Bernon rbernon@codeweavers.com
(cherry picked from commit 5ac048b2bc7c67d7c00b49c023f18b6eba96c571) --- dlls/mf/tests/mf.c | 2 + dlls/mf/tests/mf_test.h | 1 + dlls/mf/tests/transform.c | 309 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 5959905a278..8ba199557a1 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -80,6 +80,7 @@ extern GUID DMOVideoFormat_RGB32; HRESULT (WINAPI *pMFCreateSampleCopierMFT)(IMFTransform **copier); HRESULT (WINAPI *pMFGetTopoNodeCurrentType)(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager); +HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **obj); BOOL has_video_processor;
static BOOL is_vista(void) @@ -5727,6 +5728,7 @@ void init_functions(void)
mod = GetModuleHandleA("mfplat.dll"); X(MFCreateDXGIDeviceManager); + X(MFCreateVideoSampleAllocatorEx); #undef X
hr = CoInitialize(NULL); diff --git a/dlls/mf/tests/mf_test.h b/dlls/mf/tests/mf_test.h index 324815e3e8b..b3247ba00cc 100644 --- a/dlls/mf/tests/mf_test.h +++ b/dlls/mf/tests/mf_test.h @@ -33,6 +33,7 @@ extern HRESULT (WINAPI *pMFCreateSampleCopierMFT)(IMFTransform **copier); extern HRESULT (WINAPI *pMFGetTopoNodeCurrentType)(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); extern HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager); +extern HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **obj);
extern BOOL has_video_processor; void init_functions(void); diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 300a22094fb..8bb51cc790c 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7343,6 +7343,7 @@ static void test_video_processor(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MFT_SUPPORT_3DVIDEO, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D11_AWARE, 1, .todo = TRUE), /* ATTR_UINT32(MF_SA_D3D_AWARE, 1), only on W7 */ {0}, }; @@ -8785,6 +8786,8 @@ failed: IMFDXGIDeviceManager_Release(manager); if (transform) IMFTransform_Release(transform); + + MFShutdown(); CoUninitialize(); }
@@ -8981,6 +8984,310 @@ static void test_iv50_decoder(void) IMFCollection_Release(collection); }
+static void test_video_processor_with_dxgi_manager(void) +{ + static const unsigned int set_width = 82, set_height = 84, aligned_width = 96, aligned_height = 96; + const struct attribute_desc output_sample_attributes[] = + { + {0}, + }; + const struct buffer_desc output_buffer_desc_rgb32 = + { + .length = aligned_width * aligned_height * 4, + .compare = compare_rgb32, .compare_rect = {.right = set_width, .bottom = set_height}, + .dump = dump_rgb32, .size = {.cx = aligned_width, .cy = aligned_height}, + }; + const struct sample_desc output_sample_desc_rgb32 = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 0, + .buffer_count = 1, .buffers = &output_buffer_desc_rgb32, + }; + + IMFVideoSampleAllocator *allocator = NULL; + IMFDXGIDeviceManager *manager = NULL; + IMFTrackedSample *tracked_sample; + IMFTransform *transform = NULL; + ID3D11Multithread *multithread; + MFT_OUTPUT_DATA_BUFFER output; + IMFCollection *output_samples; + MFT_OUTPUT_STREAM_INFO info; + IMFDXGIBuffer *dxgi_buffer; + const BYTE *nv12frame_data; + D3D11_TEXTURE2D_DESC desc; + ULONG nv12frame_data_len; + IMFSample *input_sample; + IMFMediaBuffer *buffer; + IMFAttributes *attribs; + ID3D11Texture2D *tex2d; + IMF2DBuffer2 *buffer2d; + ID3D11Device *d3d11; + IMFMediaType *type; + DWORD status, val; + ULONG i, length; + UINT32 value; + BYTE *data; + HRESULT hr; + UINT token; + DWORD ret; + + if (!pMFCreateDXGIDeviceManager || !pMFCreateVideoSampleAllocatorEx) + { + win_skip("MFCreateDXGIDeviceManager / MFCreateVideoSampleAllocatorEx are not available, skipping tests.\n"); + return; + } + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + return; + } + + hr = MFStartup(MF_VERSION, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocator, (void **)&allocator); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFVideoSampleAllocator_SetDirectXManager(allocator, (IUnknown *)manager); + ok(hr == S_OK, "got %#lx\n", hr); + + if (FAILED(hr = CoCreateInstance(&CLSID_VideoProcessorMFT, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)transform); + todo_wine ok(hr == E_NOINTERFACE, "got %#lx\n", hr); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got %#lx\n", hr); + if (hr == E_NOINTERFACE) + { + win_skip("No hardware video decoding support.\n"); + goto failed; + } + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + if (broken(!(info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)) /* w8 / w1064v1507 */) + { + win_skip("missing video processor sample allocator support.\n"); + goto failed; + } + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_NV12); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 4, type); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_Release(type); + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, (UINT64)96 << 32 | 96); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_Release(type); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + + /* native wants a dxgi buffer on input */ + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &input_sample); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFSample_GetBufferByIndex(input_sample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + memcpy(data, nv12frame_data, nv12frame_data_len); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaBuffer_Release(buffer); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + todo_wine ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + if (!output.pSample) goto skip_tests; + + hr = IMFTransform_GetAttributes(transform, &attribs); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFAttributes_GetUINT32(attribs, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFAttributes_Release(attribs); + + hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &attribs); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFAttributes_GetCount(attribs, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(value == 0, "got %u.\n", value); + IMFAttributes_Release(attribs); + + + hr = IMFSample_QueryInterface(output.pSample, &IID_IMFTrackedSample, (void **)&tracked_sample); + ok(hr == S_OK, "got %#lx\n", hr); + IMFTrackedSample_Release(tracked_sample); + + hr = IMFSample_GetBufferCount(output.pSample, &val); + ok(hr == S_OK, "got %#lx\n", hr); + ok(val == 1, "got %lu.\n", val); + hr = IMFSample_GetBufferByIndex(output.pSample, 0, &buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&buffer2d); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&tex2d); + ok(hr == S_OK, "got %#lx\n", hr); + memset(&desc, 0xcc, sizeof(desc)); + ID3D11Texture2D_GetDesc(tex2d, &desc); + ok(desc.Format == DXGI_FORMAT_B8G8R8X8_UNORM, "got %#x.\n", desc.Format); + ok(!desc.Usage, "got %u.\n", desc.Usage); + ok(desc.BindFlags == (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), "got %#x.\n", desc.BindFlags); + ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags); + ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags); + ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels); + ok(desc.Width == aligned_width, "got %u.\n", desc.Width); + ok(desc.Height == aligned_height, "got %u.\n", desc.Height); + + ID3D11Texture2D_Release(tex2d); + IMFDXGIBuffer_Release(dxgi_buffer); + IMF2DBuffer2_Release(buffer2d); + IMFMediaBuffer_Release(buffer); + + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); + ok(ret <= 5, "got %lu%% diff\n", ret); + + for (i = 0; i < 9; i++) + { + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output.pSample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + IMFSample_Release(output.pSample); + } + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "got %#lx\n", hr); + + IMFCollection_Release(output_samples); + + status = 0; + memset(&output, 0, sizeof(output)); + hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!output.pEvents, "got events\n"); + ok(!!output.pSample, "got no sample\n"); + ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); + ok(status == 0, "got %#lx\n", status); + IMFSample_Release(output.pSample); + +skip_tests: + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + memset(&info, 0xcc, sizeof(info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + + + hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(allocator); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + + IMFSample_Release(input_sample); + +failed: + if (allocator) + IMFVideoSampleAllocator_Release(allocator); + if (manager) + IMFDXGIDeviceManager_Release(manager); + if (transform) + IMFTransform_Release(transform); + + MFShutdown(); + CoUninitialize(); +} + START_TEST(transform) { init_functions(); @@ -9010,4 +9317,6 @@ START_TEST(transform)
test_h264_with_dxgi_manager(); test_h264_decoder_concat_streams(); + + test_video_processor_with_dxgi_manager(); }
From: Rémi Bernon rbernon@codeweavers.com
(cherry picked from commit 4216c6aab8d2bc09f042c38ec9366384a9294038) --- dlls/mf/tests/transform.c | 21 ++-- dlls/mfreadwrite/tests/mfplat.c | 6 +- dlls/winegstreamer/video_processor.c | 171 +++++++++++++++++++++++++-- 3 files changed, 177 insertions(+), 21 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 8bb51cc790c..8b066a9f702 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7343,7 +7343,7 @@ static void test_video_processor(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MFT_SUPPORT_3DVIDEO, 1, .todo = TRUE), - ATTR_UINT32(MF_SA_D3D11_AWARE, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D11_AWARE, 1), /* ATTR_UINT32(MF_SA_D3D_AWARE, 1), only on W7 */ {0}, }; @@ -9089,7 +9089,7 @@ static void test_video_processor_with_dxgi_manager(void) win_skip("missing video processor sample allocator support.\n"); goto failed; } - todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags);
hr = MFCreateMediaType(&type); ok(hr == S_OK, "got %#lx\n", hr); @@ -9120,7 +9120,7 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr);
load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); /* skip BMP header and RGB data from the dump */ @@ -9152,18 +9152,17 @@ static void test_video_processor_with_dxgi_manager(void)
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags); + ok(info.dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, "got %#lx.\n", info.dwFlags);
status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); - todo_wine ok(!!output.pSample, "got no sample\n"); + ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); - if (!output.pSample) goto skip_tests;
hr = IMFTransform_GetAttributes(transform, &attribs); ok(hr == S_OK, "got %#lx\n", hr); @@ -9220,6 +9219,7 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample);
ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); + todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 5, "got %lu%% diff\n", ret);
for (i = 0; i < 9; i++) @@ -9254,14 +9254,17 @@ static void test_video_processor_with_dxgi_manager(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + /* FIXME: Wine sample release happens entirely asynchronously */ + flaky_wine_if(hr == MF_E_SAMPLEALLOCATOR_EMPTY) ok(hr == S_OK, "got %#lx\n", hr); ok(!output.pEvents, "got events\n"); + flaky_wine_if(hr == MF_E_SAMPLEALLOCATOR_EMPTY) ok(!!output.pSample, "got no sample\n"); ok(output.dwStatus == 0, "got %#lx\n", output.dwStatus); ok(status == 0, "got %#lx\n", status); - IMFSample_Release(output.pSample); + if (output.pSample) + IMFSample_Release(output.pSample);
-skip_tests: hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0); ok(hr == S_OK, "got %#lx\n", hr);
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index d0f9c689390..624ee2d90a8 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3086,11 +3086,11 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFTransform_GetAttributes(video_processor, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value); + todo_wine /* Wine exposes MF_SA_D3D_AWARE on the video processor, as Win7 */ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); - value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 1, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 1, "got %u.\n", value); hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); IMFAttributes_Release(attributes); diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index cce077ae63b..eeb252a5c1c 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -83,6 +83,12 @@ struct video_processor
wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; + + IUnknown *device_manager; + IMFVideoSampleAllocatorEx *allocator; + + IMFTransform *copier; + IMFMediaBuffer *copier_buffer; };
static HRESULT try_create_wg_transform(struct video_processor *impl) @@ -108,6 +114,82 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) return S_OK; }
+static HRESULT video_processor_init_allocator(struct video_processor *processor) +{ + IMFVideoSampleAllocatorEx *allocator; + UINT32 count; + HRESULT hr; + + if (processor->allocator) + return S_OK; + + if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&allocator))) + return hr; + if (FAILED(IMFAttributes_GetUINT32(processor->attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &count))) + count = 2; + if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(allocator, processor->device_manager)) + || FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocator, count, max(count + 2, 11), + processor->output_attributes, processor->output_type))) + { + IMFVideoSampleAllocatorEx_Release(allocator); + return hr; + } + + processor->allocator = allocator; + return S_OK; +} + +static HRESULT video_processor_uninit_allocator(struct video_processor *processor) +{ + HRESULT hr; + + if (!processor->allocator) + return S_OK; + + if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(processor->allocator))) + hr = IMFVideoSampleAllocatorEx_SetDirectXManager(processor->allocator, NULL); + IMFVideoSampleAllocatorEx_Release(processor->allocator); + processor->allocator = NULL; + + return hr; +} + +static HRESULT video_processor_init_copier(struct video_processor *processor, const MFT_OUTPUT_STREAM_INFO *info) +{ + IMFTransform *copier; + HRESULT hr; + + if (processor->copier) + return S_OK; + + if (FAILED(hr = MFCreateSampleCopierMFT(&copier))) + return hr; + + if (SUCCEEDED(hr = IMFTransform_SetInputType(copier, 0, processor->output_type, 0)) + && SUCCEEDED(hr = IMFTransform_SetOutputType(copier, 0, processor->output_type, 0)) + && SUCCEEDED(hr = MFCreateMemoryBuffer(info->cbSize, &processor->copier_buffer))) + processor->copier = copier; + else + IMFTransform_Release(copier); + + return hr; +} + +static void video_processor_uninit_copier(struct video_processor *processor) +{ + if (processor->copier) + { + IMFTransform_Release(processor->copier); + processor->copier = NULL; + } + + if (processor->copier_buffer) + { + IMFMediaBuffer_Release(processor->copier_buffer); + processor->copier_buffer = NULL; + } +} + static struct video_processor *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_processor, IMFTransform_iface); @@ -151,6 +233,10 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface)
if (!refcount) { + video_processor_uninit_allocator(impl); + video_processor_uninit_copier(impl); + if (impl->device_manager) + IUnknown_Release(impl->device_manager); if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); if (impl->input_type) @@ -223,7 +309,7 @@ static HRESULT WINAPI video_processor_GetAttributes(IMFTransform *iface, IMFAttr { struct video_processor *impl = impl_from_IMFTransform(iface);
- FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); + TRACE("iface %p, attributes %p\n", iface, attributes);
if (!attributes) return E_POINTER; @@ -242,7 +328,7 @@ static HRESULT WINAPI video_processor_GetOutputStreamAttributes(IMFTransform *if { struct video_processor *impl = impl_from_IMFTransform(iface);
- FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes); + TRACE("iface %p, id %#lx, attributes %p\n", iface, id, attributes);
if (!attributes) return E_POINTER; @@ -438,6 +524,10 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK;
+ if (FAILED(hr = video_processor_uninit_allocator(impl))) + return hr; + video_processor_uninit_copier(impl); + if (impl->output_type) IMFMediaType_Release(impl->output_type); IMFMediaType_AddRef((impl->output_type = type)); @@ -538,8 +628,34 @@ static HRESULT WINAPI video_processor_ProcessEvent(IMFTransform *iface, DWORD id
static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); - return S_OK; + struct video_processor *processor = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); + + switch (message) + { + case MFT_MESSAGE_SET_D3D_MANAGER: + if (FAILED(hr = video_processor_uninit_allocator(processor))) + return hr; + video_processor_uninit_copier(processor); + + if (processor->device_manager) + { + processor->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + IUnknown_Release(processor->device_manager); + } + if ((processor->device_manager = (IUnknown *)param)) + { + IUnknown_AddRef(processor->device_manager); + processor->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + } + return S_OK; + + default: + FIXME("Ignoring message %#x.\n", message); + return S_OK; + } }
static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) @@ -559,6 +675,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f { struct video_processor *impl = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; + IMFSample *output_sample; HRESULT hr;
TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -570,16 +687,47 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f return MF_E_TRANSFORM_TYPE_NOT_SET;
samples->dwStatus = 0; - if (!samples->pSample) - return E_INVALIDARG; - if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) return hr;
- if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, + if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + if (FAILED(hr = MFCreateSample(&output_sample))) + return hr; + if (FAILED(hr = video_processor_init_allocator(impl))) + goto done; + if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(impl->allocator, &samples->pSample))) + goto done; + + if (FAILED(hr = video_processor_init_copier(impl, &info))) + goto done; + if (FAILED(hr = IMFSample_AddBuffer(output_sample, impl->copier_buffer))) + goto done; + } + else + { + if (!(output_sample = samples->pSample)) + return E_INVALIDARG; + IMFSample_AddRef(output_sample); + } + + if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, NULL, &samples->dwStatus))) - wg_sample_queue_flush(impl->wg_sample_queue, false); + goto done; + wg_sample_queue_flush(impl->wg_sample_queue, false);
+ if (impl->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + MFT_OUTPUT_DATA_BUFFER output = {.pSample = samples->pSample}; + DWORD status; + HRESULT hr; + + if (SUCCEEDED(hr = IMFTransform_ProcessInput(impl->copier, 0, output_sample, 0))) + hr = IMFTransform_ProcessOutput(impl->copier, 0, 1, &output, &status); + } + +done: + IMFSample_Release(output_sample); return hr; }
@@ -654,6 +802,11 @@ HRESULT video_processor_create(REFIID riid, void **ret)
if (FAILED(hr = MFCreateAttributes(&impl->attributes, 0))) goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(impl->attributes, &MF_SA_D3D11_AWARE, TRUE))) + goto failed; + /* native only has MF_SA_D3D_AWARE on Win7, but it is useful to have in mfreadwrite */ + if (FAILED(hr = IMFAttributes_SetUINT32(impl->attributes, &MF_SA_D3D_AWARE, TRUE))) + goto failed; if (FAILED(hr = MFCreateAttributes(&impl->output_attributes, 0))) goto failed; if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue)))
From: Rémi Bernon rbernon@codeweavers.com
(cherry picked from commit 34acb8163b18493a54aa1e4cd4773f4755a42a60) --- dlls/mfreadwrite/reader.c | 59 +++++++++++++++++++++++++++++++++ dlls/mfreadwrite/tests/mfplat.c | 17 +++++----- 2 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index ab8c3993570..d2d40eda11e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -79,6 +79,7 @@ struct transform_entry UINT32 pending_flags; GUID category; BOOL hidden; + BOOL attributes_initialized; };
struct media_stream @@ -816,6 +817,35 @@ static HRESULT transform_entry_update_input_type(struct transform_entry *entry, return hr; }
+static void transform_entry_initialize_attributes(struct source_reader *reader, struct transform_entry *entry) +{ + IMFAttributes *attributes; + + if (SUCCEEDED(IMFTransform_GetAttributes(entry->transform, &attributes))) + { + if (FAILED(IMFAttributes_GetItem(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, NULL))) + IMFAttributes_SetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, 6); + + IMFAttributes_Release(attributes); + } + + if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(entry->transform, 0, &attributes))) + { + UINT32 shared, shared_without_mutex, bind_flags; + + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED, shared); + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, shared_without_mutex); + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_D3D11_BIND_FLAGS, &bind_flags))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, bind_flags); + else if ((reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER) && FAILED(IMFAttributes_GetItem(attributes, &MF_SA_D3D11_BINDFLAGS, NULL))) + IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, 1024); + + IMFAttributes_Release(attributes); + } +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { @@ -828,6 +858,12 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader if ((ptr = list_next(&stream->transforms, &entry->entry))) next = LIST_ENTRY(ptr, struct transform_entry, entry);
+ if (!entry->attributes_initialized) + { + transform_entry_initialize_attributes(reader, entry); + entry->attributes_initialized = TRUE; + } + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) return hr; stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); @@ -2011,10 +2047,33 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL
for (i = 0; i < count; i++) { + IMFAttributes *attributes; IMFMediaType *media_type;
if (FAILED(hr = IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) continue; + + if (!reader->device_manager || FAILED(IMFTransform_GetAttributes(transform, &attributes))) + entry->attributes_initialized = TRUE; + else + { + UINT32 d3d_aware = FALSE; + + if (reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER) + { + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &d3d_aware)) && d3d_aware) + IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager); + } + else if (reader->flags & SOURCE_READER_D3D9_DEVICE_MANAGER) + { + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware) && d3d_aware)) + IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager); + } + + entry->attributes_initialized = !d3d_aware; + IMFAttributes_Release(attributes); + } + if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 624ee2d90a8..65cd94748ac 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3070,7 +3070,7 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); - todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n");
hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3147,10 +3147,9 @@ static void test_source_reader_transforms_d3d9(void)
hr = IMFTransform_GetAttributes(video_processor, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 6, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 6, "got %u.\n", value); IMFAttributes_Release(attributes);
hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); @@ -3204,7 +3203,7 @@ static void test_source_reader_transforms_d3d9(void) hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); - todo_wine ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n"); + ok(!!test_decoder_got_d3d_manager, "d3d manager not received\n");
hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); @@ -3463,16 +3462,16 @@ static void test_source_reader_transforms_d3d11(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 6, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 6, "got %u.\n", value); IMFAttributes_Release(attributes);
hr = IMFTransform_GetOutputStreamAttributes(video_processor, 0, &attributes); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); value = 0xdeadbeef; hr = IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(value == 1024, "got %u.\n", value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value == 1024, "got %u.\n", value); IMFAttributes_Release(attributes);
IMFTransform_Release(video_processor);
Rebased on top of the latest upstream changes.