diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 77ac299c918..8271454b0f9 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -70,6 +70,13 @@ static void _expect_ref(IUnknown *obj, ULONG ref, int line) ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d.\n", rc, ref); } +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) { @@ -124,6 +131,9 @@ static HRESULT (WINAPI *pMFCreateMediaBufferFromMediaType)(IMFMediaType *media_t static HRESULT (WINAPI *pMFCreateDXSurfaceBuffer)(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer); static HRESULT (WINAPI *pMFCreateTrackedSample)(IMFTrackedSample **sample); static DWORD (WINAPI *pMFMapDXGIFormatToDX9Format)(DXGI_FORMAT dxgi_format); +static HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **allocator); +static HRESULT (WINAPI *pMFCreateDXGISurfaceBuffer)(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottomup, + IMFMediaBuffer **buffer); static HWND create_window(void) { @@ -450,7 +460,7 @@ static const IMFAsyncCallbackVtbl events_callback_vtbl = static BOOL get_event(IMFMediaEventGenerator *generator, MediaEventType expected_event_type, PROPVARIANT *value) { - struct test_callback callback = { 0 }; + struct test_callback callback = {{ 0 }}; MediaEventType event_type; BOOL ret = FALSE; HRESULT hr; @@ -780,12 +790,14 @@ static void init_functions(void) X(MFCopyImage); X(MFCreate2DMediaBuffer); X(MFCreateDXGIDeviceManager); + X(MFCreateDXGISurfaceBuffer); X(MFCreateDXSurfaceBuffer); X(MFCreateSourceResolver); X(MFCreateMediaBufferFromMediaType); X(MFCreateMFByteStreamOnStream); X(MFCreateTrackedSample); X(MFCreateTransformActivate); + X(MFCreateVideoSampleAllocatorEx); X(MFGetPlaneSize); X(MFGetStrideForBitmapInfoHeader); X(MFMapDXGIFormatToDX9Format); @@ -5246,6 +5258,7 @@ static void test_MFCreate2DMediaBuffer(void) ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr); check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMF2DBuffer, TRUE); /* Full backing buffer size, with 64 bytes per row alignment. */ hr = IMFMediaBuffer_GetMaxLength(buffer, &max_length); @@ -6025,6 +6038,386 @@ static void test_MFMapDXGIFormatToDX9Format(void) } } +static HRESULT WINAPI test_notify_callback_QueryInterface(IMFVideoSampleAllocatorNotify *iface, + REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFVideoSampleAllocatorNotify_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_notify_callback_AddRef(IMFVideoSampleAllocatorNotify *iface) +{ + return 2; +} + +static ULONG WINAPI test_notify_callback_Release(IMFVideoSampleAllocatorNotify *iface) +{ + return 1; +} + +static HRESULT WINAPI test_notify_callback_NotifyRelease(IMFVideoSampleAllocatorNotify *iface) +{ + return E_NOTIMPL; +} + +static const IMFVideoSampleAllocatorNotifyVtbl test_notify_callback_vtbl = +{ + test_notify_callback_QueryInterface, + test_notify_callback_AddRef, + test_notify_callback_Release, + test_notify_callback_NotifyRelease, +}; + +static IMFMediaType * create_video_type(const GUID *subtype) +{ + IMFMediaType *video_type; + HRESULT hr; + + hr = MFCreateMediaType(&video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(video_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(video_type, &MF_MT_SUBTYPE, subtype); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + return video_type; +} + +static ID3D11Device *create_d3d11_device(void) +{ + static const D3D_FEATURE_LEVEL default_feature_level[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + const D3D_FEATURE_LEVEL *feature_level; + unsigned int feature_level_count; + ID3D11Device *device; + + feature_level = default_feature_level; + feature_level_count = ARRAY_SIZE(default_feature_level); + + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, + feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, + feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, + feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + + return NULL; +} + +static void test_dxgi_surface_buffer(void) +{ + IMFDXGIBuffer *dxgi_buffer; + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D *texture; + IMFMediaBuffer *buffer; + ID3D11Device *device; + UINT index, size; + IUnknown *obj; + HRESULT hr; + BYTE *data; + + if (!pMFCreateDXGISurfaceBuffer) + { + skip("MFCreateDXGISurfaceBuffer() is not available.\n"); + return; + } + + device = create_d3d11_device(); + + memset(&desc, 0, sizeof(desc)); + desc.Width = 64; + desc.Height = 64; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); + ok(hr == S_OK, "Failed to create a texture, hr %#x.\n", hr); + + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); + ok(hr == S_OK || broken(hr == MF_E_INVALIDMEDIATYPE) /* Win8 */, "Failed to create a buffer, hr %#x.\n", hr); + + if (FAILED(hr)) + { + ID3D11Texture2D_Release(texture); + ID3D11Device_Release(device); + return; + } + + check_interface(buffer, &IID_IMF2DBuffer, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, TRUE); + check_interface(buffer, &IID_IMFGetService, FALSE); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); + + EXPECT_REF(texture, 2); + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&obj); + ok(hr == S_OK, "Failed to get resource, hr %#x.\n", hr); + EXPECT_REF(texture, 3); + ok(obj == (IUnknown *)texture, "Unexpected resource pointer.\n"); + IUnknown_Release(obj); + + hr = IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, &index); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(index == 0, "Unexpected subresource index.\n"); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, (void *)device); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = ID3D11Texture2D_GetPrivateData(texture, &IID_IMFDXGIBuffer, &size, &data); + ok(hr == DXGI_ERROR_NOT_FOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, &IID_ID3D11Device, (void **)&obj); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(obj == (IUnknown *)device, "Unexpected pointer.\n"); + IUnknown_Release(obj); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, &IID_IUnknown, (void **)&obj); + ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#x.\n", hr); + + IMFDXGIBuffer_Release(dxgi_buffer); + + IMFMediaBuffer_Release(buffer); + + ID3D11Texture2D_Release(texture); + + ID3D11Device_Release(device); +} + +static void test_sample_allocator(void) +{ + IMFVideoSampleAllocatorNotify test_notify = { &test_notify_callback_vtbl }; + IMFVideoSampleAllocatorCallback *allocator_cb; + IMFVideoSampleAllocatorEx *allocatorex; + IMFMediaType *media_type, *video_type; + IMFVideoSampleAllocator *allocator; + IMFDXGIDeviceManager *manager; + IMFSample *sample, *sample2; + IMFMediaBuffer *buffer; + ID3D11Device *device; + LONG refcount, count; + unsigned int token; + IUnknown *unk; + HRESULT hr; + BYTE *data; + + if (!pMFCreateVideoSampleAllocatorEx) + { + skip("MFCreateVideoSampleAllocatorEx() is not available.\n"); + return; + } + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + check_interface(unk, &IID_IMFVideoSampleAllocator, TRUE); + check_interface(unk, &IID_IMFVideoSampleAllocatorEx, TRUE); + check_interface(unk, &IID_IMFVideoSampleAllocatorCallback, TRUE); + + IUnknown_Release(unk); + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocator, (void **)&allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_QueryInterface(allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&allocator_cb); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, &test_notify); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + count = 10; + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!count, "Unexpected count %d.\n", count); + + hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_SetDirectXManager(allocator, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 2, media_type); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + video_type = create_video_type(&MFVideoFormat_RGB32); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 2, video_type); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + /* Frame size is required. */ + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64) 320 << 32 | 240); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 0, video_type); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 1, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = 0; + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(count == 1, "Unexpected count %d.\n", count); + + sample = NULL; + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + refcount = get_refcount(sample); + + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!count, "Unexpected count %d.\n", count); + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample2); + ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "Unexpected hr %#x.\n", hr); + + /* Reinitialize with active sample. */ + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 2, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(refcount == get_refcount(sample), "Unexpected refcount %u.\n", get_refcount(sample)); + + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!count, "Unexpected count %d.\n", count); + + check_interface(sample, &IID_IMFTrackedSample, TRUE); + check_interface(sample, &IID_IMFDesiredSample, FALSE); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + check_interface(buffer, &IID_IMF2DBuffer, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); + + IMFVideoSampleAllocatorCallback_Release(allocator_cb); + IMFVideoSampleAllocator_Release(allocator); + + /* IMFVideoSampleAllocatorEx */ + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&allocatorex); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorEx_QueryInterface(allocatorex, &IID_IMFVideoSampleAllocatorCallback, (void **)&allocator_cb); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 1, 0, NULL, video_type); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 0, 0, NULL, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = 0; + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(count == 1, "Unexpected count %d.\n", count); + + hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample2); + ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "Unexpected hr %#x.\n", hr); + + IMFSample_Release(sample); + + IMFVideoSampleAllocatorCallback_Release(allocator_cb); + IMFVideoSampleAllocatorEx_Release(allocatorex); + + /* Using device manager */ + if (!(device = create_d3d11_device())) + { + skip("Failed to create a D3D11 device, skipping tests.\n"); + return; + } + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "Failed to create device manager, hr %#x.\n", hr); + + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)device, token); + ok(hr == S_OK, "Failed to set a device, hr %#x.\n", hr); + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocator, (void **)&allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_SetDirectXManager(allocator, (IUnknown *)manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 0, video_type); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 1, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + check_interface(buffer, &IID_IMF2DBuffer, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, TRUE); + check_interface(buffer, &IID_IMFGetService, FALSE); + + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFSample_Release(sample); + + IMFVideoSampleAllocator_Release(allocator); + + IMFMediaType_Release(media_type); + IMFDXGIDeviceManager_Release(manager); + ID3D11Device_Release(device); +} + START_TEST(mfplat) { char **argv; @@ -6085,6 +6478,8 @@ START_TEST(mfplat) test_MFCreateTrackedSample(); test_MFFrameRateToAverageTimePerFrame(); test_MFMapDXGIFormatToDX9Format(); + test_dxgi_surface_buffer(); + test_sample_allocator(); CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 77875486e54..7bac3e21fa9 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -510,6 +510,8 @@ HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **result); HRESULT WINAPI MFCreateCollection(IMFCollection **collection); HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager); +HRESULT WINAPI MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottomup, + IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue); HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, @@ -522,6 +524,7 @@ HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size); HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateVideoMediaTypeFromSubtype(const GUID *subtype, IMFVideoMediaType **media_type); +HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **allocator); HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *type, WAVEFORMATEX **format, UINT32 *size, UINT32 flags); HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream); diff --git a/include/mfobjects.idl b/include/mfobjects.idl index ee49be35af0..b2d0e5d06ec 100644 --- a/include/mfobjects.idl +++ b/include/mfobjects.idl @@ -167,6 +167,34 @@ interface IMF2DBuffer2 : IMF2DBuffer HRESULT Copy2DTo([in] IMF2DBuffer2 *dest_buffer); } +[ + object, + uuid(e7174cfa-1c9e-48b1-8866-626226bfc258), + local +] +interface IMFDXGIBuffer : IUnknown +{ + HRESULT GetResource( + [in] REFIID riid, + [out] void **object + ); + + HRESULT GetSubresourceIndex( + [out] UINT *index + ); + + HRESULT GetUnknown( + [in] REFIID guid, + [in] REFIID riid, + [out] void **object + ); + + HRESULT SetUnknown( + [in] REFIID guid, + [in] IUnknown *data + ); +} + [ object, uuid(44ae0fa8-ea31-4109-8d2e-4cae4997c555),