[v2 PATCH 2/2] evr: Implement sample allocator.
Nikolay Sivov
nsivov at codeweavers.com
Tue Oct 27 12:50:20 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v2: fixed mf/tests failure.
dlls/evr/sample.c | 284 +++++++++++++++++++++++++++++++++++++++++--
dlls/evr/tests/evr.c | 23 ++--
dlls/mf/tests/mf.c | 1 -
3 files changed, 283 insertions(+), 25 deletions(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c
index f5189443307..b65cc45a662 100644
--- a/dlls/evr/sample.c
+++ b/dlls/evr/sample.c
@@ -26,6 +26,7 @@
#include "wine/debug.h"
#include "wine/heap.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(evr);
@@ -106,14 +107,23 @@ struct sample_allocator
{
IMFVideoSampleAllocator IMFVideoSampleAllocator_iface;
IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface;
+ IMFAsyncCallback tracking_callback;
LONG refcount;
IMFVideoSampleAllocatorNotify *callback;
- unsigned int free_samples;
IDirect3DDeviceManager9 *device_manager;
+ unsigned int free_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_IMFVideoSampleAllocator(IMFVideoSampleAllocator *iface)
{
return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocator_iface);
@@ -124,6 +134,11 @@ static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVid
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 HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocator *iface, REFIID riid, void **obj)
{
struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
@@ -160,6 +175,25 @@ static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocator *iface)
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);
+ IMFSample_Release(iter->sample);
+ heap_free(iter);
+ }
+}
+
static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocator *iface)
{
struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
@@ -173,6 +207,7 @@ static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocator *iface)
IMFVideoSampleAllocatorNotify_Release(allocator->callback);
if (allocator->device_manager)
IDirect3DDeviceManager9_Release(allocator->device_manager);
+ sample_allocator_release_samples(allocator);
DeleteCriticalSection(&allocator->cs);
heap_free(allocator);
}
@@ -208,24 +243,176 @@ static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocator
static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocator *iface)
{
- FIXME("%p.\n", iface);
+ struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
- return E_NOTIMPL;
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&allocator->cs);
+
+ sample_allocator_release_samples(allocator);
+ allocator->free_sample_count = 0;
+
+ LeaveCriticalSection(&allocator->cs);
+
+ return S_OK;
+}
+
+static HRESULT sample_allocator_create_samples(struct sample_allocator *allocator, unsigned int sample_count,
+ IMFMediaType *media_type)
+{
+ IDirectXVideoProcessorService *service = NULL;
+ unsigned int i, width, height;
+ IDirect3DSurface9 *surface;
+ HANDLE hdevice = NULL;
+ GUID major, subtype;
+ UINT64 frame_size;
+ IMFSample *sample;
+ D3DFORMAT format;
+ HRESULT hr;
+
+ if (FAILED(IMFMediaType_GetMajorType(media_type, &major)))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (!IsEqualGUID(&major, &MFMediaType_Video))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (FAILED(IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDMEDIATYPE;
+
+ format = subtype.Data1;
+ height = frame_size;
+ width = frame_size >> 32;
+
+ if (allocator->device_manager)
+ {
+ if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->device_manager, &hdevice)))
+ {
+ hr = IDirect3DDeviceManager9_GetVideoService(allocator->device_manager, hdevice,
+ &IID_IDirectXVideoProcessorService, (void **)&service);
+ }
+
+ if (FAILED(hr))
+ {
+ WARN("Failed to get processor service, %#x.\n", hr);
+ return hr;
+ }
+ }
+
+ sample_allocator_release_samples(allocator);
+
+ for (i = 0; i < sample_count; ++i)
+ {
+ struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample));
+
+ if (service)
+ {
+ if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service, width, height, 0, format,
+ D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
+ {
+ hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample);
+ IDirect3DSurface9_Release(surface);
+ }
+ }
+ else
+ {
+ IMFMediaBuffer *buffer;
+
+ if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample)))
+ {
+ if (SUCCEEDED(hr = MFCreate2DMediaBuffer(width, height, format, FALSE, &buffer)))
+ {
+ hr = IMFSample_AddBuffer(sample, buffer);
+ IMFMediaBuffer_Release(buffer);
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ WARN("Unable to allocate %u samples.\n", sample_count);
+ sample_allocator_release_samples(allocator);
+ break;
+ }
+
+ queued_sample = heap_alloc(sizeof(*queued_sample));
+ queued_sample->sample = sample;
+ list_add_tail(&allocator->free_samples, &queued_sample->entry);
+ allocator->free_sample_count++;
+ }
+
+ if (service)
+ IDirectXVideoProcessorService_Release(service);
+
+ if (allocator->device_manager)
+ IDirect3DDeviceManager9_CloseDeviceHandle(allocator->device_manager, hdevice);
+
+ return hr;
}
static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocator *iface,
DWORD sample_count, IMFMediaType *media_type)
{
- FIXME("%p, %u, %p.\n", iface, sample_count, media_type);
+ struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %u, %p.\n", iface, sample_count, media_type);
+
+ if (!sample_count)
+ sample_count = 1;
+
+ EnterCriticalSection(&allocator->cs);
+
+ hr = sample_allocator_create_samples(allocator, sample_count, media_type);
+
+ LeaveCriticalSection(&allocator->cs);
+
+ return hr;
}
-static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocator *iface, IMFSample **sample)
+static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocator *iface, IMFSample **out)
{
- FIXME("%p, %p.\n", iface, sample);
+ struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
+ IMFTrackedSample *tracked_sample;
+ IMFSample *sample;
+ HRESULT hr;
- return E_NOTIMPL;
+ 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))
+ hr = MF_E_SAMPLEALLOCATOR_EMPTY;
+ else
+ {
+ struct list *head = list_head(&allocator->free_samples);
+
+ sample = LIST_ENTRY(head, struct queued_sample, entry)->sample;
+
+ if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
+ {
+ hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
+ IMFTrackedSample_Release(tracked_sample);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ list_remove(head);
+ list_add_tail(&allocator->used_samples, head);
+ allocator->free_sample_count--;
+
+ *out = sample;
+ IMFSample_AddRef(*out);
+ }
+ }
+
+ LeaveCriticalSection(&allocator->cs);
+
+ return hr;
}
static const IMFVideoSampleAllocatorVtbl sample_allocator_vtbl =
@@ -285,7 +472,7 @@ static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampl
EnterCriticalSection(&allocator->cs);
if (count)
- *count = allocator->free_samples;
+ *count = allocator->free_sample_count;
LeaveCriticalSection(&allocator->cs);
return S_OK;
@@ -300,6 +487,77 @@ static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl
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 IMFVideoSampleAllocator_AddRef(&allocator->IMFVideoSampleAllocator_iface);
+}
+
+static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
+{
+ struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
+ return IMFVideoSampleAllocator_Release(&allocator->IMFVideoSampleAllocator_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 *sample = NULL;
+
+ EnterCriticalSection(&allocator->cs);
+
+ IMFAsyncResult_GetObject(result, (IUnknown **)&sample);
+
+ LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
+ {
+ if (sample == (IUnknown *)iter->sample)
+ {
+ list_remove(&iter->entry);
+ list_add_tail(&allocator->free_samples, &iter->entry);
+ allocator->free_sample_count++;
+ break;
+ }
+ }
+
+ IUnknown_Release(sample);
+
+ 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,
+};
+
HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj)
{
struct sample_allocator *object;
@@ -312,7 +570,10 @@ HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj)
object->IMFVideoSampleAllocator_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;
+ list_init(&object->used_samples);
+ list_init(&object->free_samples);
InitializeCriticalSection(&object->cs);
hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj);
@@ -369,8 +630,7 @@ static ULONG WINAPI video_sample_Release(IMFSample *iface)
HRESULT hr;
IMFSample_LockStore(sample->sample);
- refcount = InterlockedDecrement(&sample->refcount);
- if (sample->tracked_result && sample->tracked_refcount == refcount)
+ if (sample->tracked_result && sample->tracked_refcount == (sample->refcount - 1))
{
/* Call could fail if queue system is not initialized, it's not critical. */
if (FAILED(hr = MFInvokeCallback(sample->tracked_result)))
@@ -381,6 +641,8 @@ static ULONG WINAPI video_sample_Release(IMFSample *iface)
}
IMFSample_UnlockStore(sample->sample);
+ refcount = InterlockedDecrement(&sample->refcount);
+
TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c
index 8c82ae34f8d..fbcf798157e 100644
--- a/dlls/evr/tests/evr.c
+++ b/dlls/evr/tests/evr.c
@@ -1338,13 +1338,14 @@ static void test_MFCreateVideoSampleAllocator(void)
ok(!count, "Unexpected count %d.\n", count);
hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(allocator);
-todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample);
-todo_wine
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);
@@ -1356,42 +1357,34 @@ todo_wine
video_type = create_video_type(&MFVideoFormat_RGB32);
hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 2, video_type);
-todo_wine
ok(hr == MF_E_INVALIDMEDIATYPE, "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);
-todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-todo_wine
ok(count == 1, "Unexpected count %d.\n", count);
sample = NULL;
hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample);
-todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
- if (SUCCEEDED(hr))
- ok(get_refcount(sample) == 3, "Unexpected refcount %u.\n", get_refcount(sample));
+ ok(get_refcount(sample) == 3, "Unexpected refcount %u.\n", get_refcount(sample));
hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample2);
-todo_wine
ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "Unexpected hr %#x.\n", hr);
/* Reinitialize with active sample. */
hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 4, video_type);
-todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
- if (sample)
- ok(get_refcount(sample) == 3, "Unexpected refcount %u.\n", get_refcount(sample));
+todo_wine
+ ok(get_refcount(sample) == 3, "Unexpected refcount %u.\n", get_refcount(sample));
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-todo_wine
ok(count == 4, "Unexpected count %d.\n", count);
if (sample)
@@ -1418,6 +1411,10 @@ todo_wine
IMFGetService_Release(gs);
}
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&unk);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ IUnknown_Release(unk);
+
IMFMediaBuffer_Release(buffer);
IMFSample_Release(sample);
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index b110c0ec9ef..8c49a483f74 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -3381,7 +3381,6 @@ static void test_evr(void)
ok(!sample_count, "Unexpected sample count %d.\n", sample_count);
hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample);
-todo_wine
ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
IMFVideoSampleAllocatorCallback_Release(allocator_callback);
--
2.28.0
More information about the wine-devel
mailing list