[PATCH 6/9] mfplat/allocator: Add initial implementation of sample allocator.
Nikolay Sivov
nsivov at codeweavers.com
Wed Feb 3 05:27:59 CST 2021
Signed-off-by: Nikolay Sivov <nsivov at 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);
--
2.30.0
More information about the wine-devel
mailing list