Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 2 +- dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/sample.c | 671 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/tests/mfplat.c | 5 +- 4 files changed, 677 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 7c252147679..85219c74dd5 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -20,10 +20,10 @@
#include "mfplat_private.h"
+#include "dxva2api.h" #include "initguid.h" #include "ks.h" #include "ksmedia.h" -#include "dxva2api.h"
#include "wine/debug.h"
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index f51c65c5b85..7d014e334c8 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -82,6 +82,7 @@ @ stdcall MFCreateVideoMediaTypeFromSubtype(ptr ptr) @ stub MFCreateVideoMediaTypeFromVideoInfoHeader2 @ stub MFCreateVideoMediaTypeFromVideoInfoHeader +@ stdcall MFCreateVideoSampleAllocatorEx(ptr ptr) @ stdcall MFCreateWaveFormatExFromMFMediaType(ptr ptr ptr long) @ stub MFDeserializeAttributesFromStream @ stub MFDeserializeEvent diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index bd67fb731fc..266bb6f0726 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -20,8 +20,13 @@
#include "mfplat_private.h" #include "rtworkq.h" +#include "d3d9.h" +#include "d3d11.h" +#include "initguid.h" +#include "dxva2api.h"
#include "wine/debug.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -50,6 +55,54 @@ struct sample LONG tracked_refcount; };
+struct sample_allocator +{ + IMFVideoSampleAllocatorEx IMFVideoSampleAllocatorEx_iface; + IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface; + IMFAsyncCallback tracking_callback; + LONG refcount; + + IMFVideoSampleAllocatorNotify *callback; + IDirect3DDeviceManager9 *d3d9_device_manager; + IMFDXGIDeviceManager *dxgi_device_manager; + + struct + { + unsigned int width; + unsigned int height; + D3DFORMAT d3d9_format; + DXGI_FORMAT dxgi_format; + unsigned int buffer_count; + } frame_desc; + + unsigned int free_sample_count; + unsigned int cold_sample_count; + struct list free_samples; + struct list used_samples; + CRITICAL_SECTION cs; +}; + +struct queued_sample +{ + struct list entry; + IMFSample *sample; +}; + +static struct sample_allocator *impl_from_IMFVideoSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorEx_iface); +} + +static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface); +} + +static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback); +} + static struct sample *impl_from_IMFSample(IMFSample *iface) { return CONTAINING_RECORD(iface, struct sample, IMFSample_iface); @@ -1005,3 +1058,621 @@ HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
return S_OK; } + +static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) || + IsEqualIID(riid, &IID_IMFVideoSampleAllocator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &allocator->IMFVideoSampleAllocatorEx_iface; + } + else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback)) + { + *obj = &allocator->IMFVideoSampleAllocatorCallback_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + ULONG refcount = InterlockedIncrement(&allocator->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static void sample_allocator_release_samples(struct sample_allocator *allocator) +{ + struct queued_sample *iter, *iter2; + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry) + { + list_remove(&iter->entry); + IMFSample_Release(iter->sample); + heap_free(iter); + } + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry) + { + list_remove(&iter->entry); + heap_free(iter); + } +} + +static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + ULONG refcount = InterlockedDecrement(&allocator->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); + if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); + sample_allocator_release_samples(allocator); + DeleteCriticalSection(&allocator->cs); + heap_free(allocator); + } + + return refcount; +} + +static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface, + IUnknown *manager) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + IDirect3DDeviceManager9 *d3d9_device_manager = NULL; + IMFDXGIDeviceManager *dxgi_device_manager = NULL; + HRESULT hr; + + TRACE("%p, %p.\n", iface, manager); + + if (manager) + { + if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager))) + { + hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager); + } + + if (FAILED(hr)) + return hr; + } + + EnterCriticalSection(&allocator->cs); + + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); + if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); + allocator->d3d9_device_manager = NULL; + allocator->dxgi_device_manager = NULL; + + if (dxgi_device_manager) + allocator->dxgi_device_manager = dxgi_device_manager; + else if (d3d9_device_manager) + allocator->d3d9_device_manager = d3d9_device_manager; + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + + TRACE("%p.\n", iface); + + EnterCriticalSection(&allocator->cs); + + sample_allocator_release_samples(allocator); + allocator->free_sample_count = 0; + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +struct surface_service +{ + IDirectXVideoProcessorService *dxva_service; + ID3D11Device *d3d11_device; + HANDLE hdevice; +}; + +static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service) +{ + HRESULT hr = S_OK; + + memset(service, 0, sizeof(*service)); + + if (allocator->d3d9_device_manager) + { + if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice))) + { + if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice, + &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service))) + { + WARN("Failed to get DXVA processor service, hr %#x.\n", hr); + IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice); + } + } + } + else if (allocator->dxgi_device_manager) + { + if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice))) + { + if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice, + &IID_ID3D11Device, (void **)&service->d3d11_device))) + { + WARN("Failed to get D3D11 device, hr %#x.\n", hr); + IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice); + } + } + } + + if (FAILED(hr)) + memset(service, 0, sizeof(*service)); + + return hr; +} + +static void sample_allocator_release_surface_service(struct sample_allocator *allocator, + struct surface_service *service) +{ + if (service->dxva_service) + IDirectXVideoProcessorService_Release(service->dxva_service); + if (service->d3d11_device) + ID3D11Device_Release(service->d3d11_device); + + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice); + else if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice); +} + +static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service, + IMFSample **sample) +{ + struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample)); + IMFTrackedSample *tracked_sample; + IMFMediaBuffer *buffer; + unsigned int i; + HRESULT hr; + + if (FAILED(hr = MFCreateTrackedSample(&tracked_sample))) + { + return hr; + } + + IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)sample); + IMFTrackedSample_Release(tracked_sample); + + for (i = 0; i < allocator->frame_desc.buffer_count; ++i) + { + if (service->dxva_service) + { + IDirect3DSurface9 *surface; + + if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width, + allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0, + DXVA2_VideoProcessorRenderTarget, &surface, NULL))) + { + hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer); + IDirect3DSurface9_Release(surface); + } + } + else if (service->d3d11_device) + { + D3D11_TEXTURE2D_DESC desc = { 0 }; + ID3D11Texture2D *texture; + + desc.Width = allocator->frame_desc.width; + desc.Height = allocator->frame_desc.height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = allocator->frame_desc.dxgi_format; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = 0; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + + if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture))) + { + hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); + ID3D11Texture2D_Release(texture); + } + } + else + { + hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height, + allocator->frame_desc.d3d9_format, FALSE, &buffer); + } + + if (SUCCEEDED(hr)) + { + hr = IMFSample_AddBuffer(*sample, buffer); + IMFMediaBuffer_Release(buffer); + } + } + + return hr; +} + +static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count, + unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type) +{ + struct surface_service service; + unsigned int i; + GUID major, subtype; + UINT64 frame_size; + IMFSample *sample; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (sample_count > max_sample_count) + return E_INVALIDARG; + + sample_count = max(1, sample_count); + max_sample_count = max(1, max_sample_count); + + if (attributes) + FIXME("Initialization attributes ignored.\n"); + + allocator->frame_desc.d3d9_format = subtype.Data1; + allocator->frame_desc.dxgi_format = MFMapDX9FormatToDXGIFormat(allocator->frame_desc.d3d9_format); + allocator->frame_desc.width = frame_size >> 32; + allocator->frame_desc.height = frame_size; + + if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service))) + return hr; + + sample_allocator_release_samples(allocator); + + for (i = 0; i < sample_count; ++i) + { + struct queued_sample *queued_sample; + + if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample))) + { + queued_sample = heap_alloc(sizeof(*queued_sample)); + queued_sample->sample = sample; + list_add_tail(&allocator->free_samples, &queued_sample->entry); + allocator->free_sample_count++; + } + } + allocator->cold_sample_count = max_sample_count - allocator->free_sample_count; + + sample_allocator_release_surface_service(allocator, &service); + + return hr; +} + +static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface, + DWORD sample_count, IMFMediaType *media_type) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + HRESULT hr; + + TRACE("%p, %u, %p.\n", iface, sample_count, media_type); + + if (!sample_count) + return E_INVALIDARG; + + EnterCriticalSection(&allocator->cs); + + hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type); + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample) +{ + IMFTrackedSample *tracked_sample; + HRESULT hr; + + if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample))) + { + hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL); + IMFTrackedSample_Release(tracked_sample); + } + + return hr; +} + +static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + IMFSample *sample; + HRESULT hr; + + TRACE("%p, %p.\n", iface, out); + + EnterCriticalSection(&allocator->cs); + + if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples)) + hr = MF_E_NOT_INITIALIZED; + else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count) + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + else if (!list_empty(&allocator->free_samples)) + { + struct list *head = list_head(&allocator->free_samples); + + sample = LIST_ENTRY(head, struct queued_sample, entry)->sample; + + if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample))) + { + list_remove(head); + list_add_tail(&allocator->used_samples, head); + allocator->free_sample_count--; + + /* Reference counter is not increased when sample is returned, so next release could trigger + tracking condition. This is balanced by incremented reference counter when sample is returned + back to the free list. */ + *out = sample; + } + } + else /* allocator->cold_sample_count != 0 */ + { + struct surface_service service; + + if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service))) + { + if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample))) + { + if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample))) + { + struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample)); + + queued_sample->sample = sample; + list_add_tail(&allocator->used_samples, &queued_sample->entry); + allocator->cold_sample_count--; + + *out = queued_sample->sample; + } + } + + sample_allocator_release_surface_service(allocator, &service); + } + } + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count, + DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + HRESULT hr; + + TRACE("%p, %u, %u, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type); + + EnterCriticalSection(&allocator->cs); + + hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type); + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl = +{ + sample_allocator_QueryInterface, + sample_allocator_AddRef, + sample_allocator_Release, + sample_allocator_SetDirectXManager, + sample_allocator_UninitializeSampleAllocator, + sample_allocator_InitializeSampleAllocator, + sample_allocator_AllocateSample, + sample_allocator_InitializeSampleAllocatorEx, +}; + +static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface, + REFIID riid, void **obj) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj); +} + +static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface, + IMFVideoSampleAllocatorNotify *callback) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + + TRACE("%p, %p.\n", iface, callback); + + EnterCriticalSection(&allocator->cs); + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + allocator->callback = callback; + if (allocator->callback) + IMFVideoSampleAllocatorNotify_AddRef(allocator->callback); + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface, + LONG *count) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_POINTER; + + EnterCriticalSection(&allocator->cs); + *count = allocator->free_sample_count; + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl = +{ + sample_allocator_callback_QueryInterface, + sample_allocator_callback_AddRef, + sample_allocator_callback_Release, + sample_allocator_callback_SetCallback, + sample_allocator_callback_GetFreeSampleCount, +}; + +static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface, + REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + struct queued_sample *iter; + IUnknown *object = NULL; + IMFSample *sample = NULL; + HRESULT hr; + + if (FAILED(IMFAsyncResult_GetObject(result, &object))) + return E_UNEXPECTED; + + hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample); + IUnknown_Release(object); + if (FAILED(hr)) + return E_UNEXPECTED; + + EnterCriticalSection(&allocator->cs); + + LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry) + { + if (sample == iter->sample) + { + list_remove(&iter->entry); + list_add_tail(&allocator->free_samples, &iter->entry); + IMFSample_AddRef(iter->sample); + allocator->free_sample_count++; + break; + } + } + + IMFSample_Release(sample); + + if (allocator->callback) + IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl = +{ + sample_allocator_tracking_callback_QueryInterface, + sample_allocator_tracking_callback_AddRef, + sample_allocator_tracking_callback_Release, + sample_allocator_tracking_callback_GetParameters, + sample_allocator_tracking_callback_Invoke, +}; + +/*********************************************************************** + * MFCreateVideoSampleAllocatorEx (mfplat.@) + */ +HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj) +{ + struct sample_allocator *object; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl; + object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl; + object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl; + object->refcount = 1; + object->frame_desc.buffer_count = 1; + list_init(&object->used_samples); + list_init(&object->free_samples); + InitializeCriticalSection(&object->cs); + + hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj); + IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface); + + return hr; +} diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d4a461a2df8..2e2610a3827 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6302,7 +6302,7 @@ static void test_sample_allocator(void)
if (!pMFCreateVideoSampleAllocatorEx) { - skip("MFCreateVideoSampleAllocatorEx() is not available.\n"); + win_skip("MFCreateVideoSampleAllocatorEx() is not available.\n"); return; }
@@ -6392,6 +6392,7 @@ static void test_sample_allocator(void)
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine ok(!count, "Unexpected count %d.\n", count);
check_interface(sample, &IID_IMFTrackedSample, TRUE); @@ -6500,9 +6501,11 @@ static void test_sample_allocator(void) IMFDXGIBuffer_Release(dxgi_buffer);
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); +todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaBuffer_Unlock(buffer); +todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMFSample_Release(sample);