Nikolay Sivov : mfplat: Add basic support for user queue object lifetime management.
Alexandre Julliard
julliard at winehq.org
Tue Feb 19 15:29:34 CST 2019
Module: wine
Branch: master
Commit: 1fb58ab2fb08498b68d753de5456d2a1a0d6cb59
URL: https://source.winehq.org/git/wine.git/?a=commit;h=1fb58ab2fb08498b68d753de5456d2a1a0d6cb59
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue Feb 19 16:20:05 2019 +0300
mfplat: Add basic support for user queue object lifetime management.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/mfplat/mfplat.spec | 6 +-
dlls/mfplat/queue.c | 139 +++++++++++++++++++++++++++++++++++++++++++++
dlls/mfplat/tests/mfplat.c | 40 +++++++++++++
include/mfapi.h | 3 +
include/mferror.h | 2 +
5 files changed, 187 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 9813789..8f5ee77 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -16,7 +16,7 @@
@ stub GetD3DFormatFromMFSubtype
@ stub LFGetGlobalPool
@ stub MFAddPeriodicCallback
-@ stub MFAllocateWorkQueue
+@ stdcall MFAllocateWorkQueue(ptr)
@ stub MFAllocateWorkQueueEx
@ stub MFAppendCollection
@ stub MFAverageTimePerFrameToFrameRate
@@ -119,7 +119,7 @@
@ stub MFInvokeCallback
@ stub MFJoinIoPort
@ stdcall MFLockPlatform()
-@ stub MFLockWorkQueue
+@ stdcall MFLockWorkQueue(long)
@ stub MFPutWorkItem
@ stub MFPutWorkItemEx
@ stub MFRecordError
@@ -147,7 +147,7 @@
@ stub MFTraceFuncEnter
@ stub MFUnblockThread
@ stdcall MFUnlockPlatform()
-@ stub MFUnlockWorkQueue
+@ stdcall MFUnlockWorkQueue(long)
@ stub MFUnwrapMediaType
@ stub MFValidateMediaTypeSize
@ stub MFWrapMediaType
diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c
index 32c7a6c..65f111b 100644
--- a/dlls/mfplat/queue.c
+++ b/dlls/mfplat/queue.c
@@ -21,12 +21,121 @@
#define COBJMACROS
#include "mfapi.h"
+#include "mferror.h"
#include "wine/debug.h"
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+#define FIRST_USER_QUEUE_HANDLE 5
+#define MAX_USER_QUEUE_HANDLES 124
+
+struct queue
+{
+ void *obj;
+ LONG refcount;
+ WORD generation;
+};
+
+static struct queue user_queues[MAX_USER_QUEUE_HANDLES];
+static struct queue *next_free_user_queue;
+static struct queue *next_unused_user_queue = user_queues;
+static WORD queue_generation;
+
+static CRITICAL_SECTION user_queues_section;
+static CRITICAL_SECTION_DEBUG user_queues_critsect_debug =
+{
+ 0, 0, &user_queues_section,
+ { &user_queues_critsect_debug.ProcessLocksList, &user_queues_critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": user_queues_section") }
+};
+static CRITICAL_SECTION user_queues_section = { &user_queues_critsect_debug, -1, 0, 0, 0, 0 };
+
+static struct queue *get_queue_obj(DWORD handle)
+{
+ unsigned int idx = HIWORD(handle) - FIRST_USER_QUEUE_HANDLE;
+
+ if (idx < MAX_USER_QUEUE_HANDLES && user_queues[idx].refcount)
+ {
+ if (LOWORD(handle) == user_queues[idx].generation)
+ return &user_queues[idx];
+ }
+
+ return NULL;
+}
+
+static HRESULT alloc_user_queue(DWORD *queue)
+{
+ struct queue *entry;
+ unsigned int idx;
+
+ EnterCriticalSection(&user_queues_section);
+
+ entry = next_free_user_queue;
+ if (entry)
+ next_free_user_queue = entry->obj;
+ else if (next_unused_user_queue < user_queues + MAX_USER_QUEUE_HANDLES)
+ entry = next_unused_user_queue++;
+ else
+ {
+ LeaveCriticalSection(&user_queues_section);
+ return E_OUTOFMEMORY;
+ }
+
+ entry->refcount = 1;
+ entry->obj = NULL;
+ if (++queue_generation == 0xffff) queue_generation = 1;
+ entry->generation = queue_generation;
+ idx = entry - user_queues + FIRST_USER_QUEUE_HANDLE;
+ *queue = (idx << 16) | entry->generation;
+ LeaveCriticalSection(&user_queues_section);
+
+ return S_OK;
+}
+
+static HRESULT lock_user_queue(DWORD queue)
+{
+ HRESULT hr = MF_E_INVALID_WORKQUEUE;
+ struct queue *entry;
+
+ if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK))
+ return S_OK;
+
+ EnterCriticalSection(&user_queues_section);
+ entry = get_queue_obj(queue);
+ if (entry && entry->refcount)
+ {
+ entry->refcount++;
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&user_queues_section);
+ return hr;
+}
+
+static HRESULT unlock_user_queue(DWORD queue)
+{
+ HRESULT hr = MF_E_INVALID_WORKQUEUE;
+ struct queue *entry;
+
+ if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK))
+ return S_OK;
+
+ EnterCriticalSection(&user_queues_section);
+ entry = get_queue_obj(queue);
+ if (entry && entry->refcount)
+ {
+ if (--entry->refcount == 0)
+ {
+ entry->obj = next_free_user_queue;
+ next_free_user_queue = entry;
+ }
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&user_queues_section);
+ return hr;
+}
+
struct async_result
{
MFASYNCRESULT result;
@@ -192,3 +301,33 @@ HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback,
return S_OK;
}
+
+/***********************************************************************
+ * MFAllocateWorkQueue (mfplat.@)
+ */
+HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue)
+{
+ TRACE("%p.\n", queue);
+
+ return alloc_user_queue(queue);
+}
+
+/***********************************************************************
+ * MFLockWorkQueue (mfplat.@)
+ */
+HRESULT WINAPI MFLockWorkQueue(DWORD queue)
+{
+ TRACE("%#x.\n", queue);
+
+ return lock_user_queue(queue);
+}
+
+/***********************************************************************
+ * MFUnlockWorkQueue (mfplat.@)
+ */
+HRESULT WINAPI MFUnlockWorkQueue(DWORD queue)
+{
+ TRACE("%#x.\n", queue);
+
+ return unlock_user_queue(queue);
+}
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 7d202bc..8b06e23 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -838,6 +838,45 @@ static void test_startup(void)
ok(hr == S_OK, "Failed to shutdown, hr %#x.\n", hr);
}
+static void test_allocate_queue(void)
+{
+ DWORD queue, queue2;
+ HRESULT hr;
+
+ hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+ ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
+
+ hr = MFAllocateWorkQueue(&queue);
+ ok(hr == S_OK, "Failed to allocate a queue, hr %#x.\n", hr);
+ ok(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK, "Unexpected queue id.\n");
+
+ hr = MFUnlockWorkQueue(queue);
+ ok(hr == S_OK, "Failed to unlock the queue, hr %#x.\n", hr);
+
+ hr = MFUnlockWorkQueue(queue);
+ ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
+ hr = MFAllocateWorkQueue(&queue2);
+ ok(hr == S_OK, "Failed to allocate a queue, hr %#x.\n", hr);
+ ok(queue2 & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK, "Unexpected queue id.\n");
+
+ hr = MFUnlockWorkQueue(queue2);
+ ok(hr == S_OK, "Failed to unlock the queue, hr %#x.\n", hr);
+
+ /* Unlock in system queue range. */
+ hr = MFUnlockWorkQueue(MFASYNC_CALLBACK_QUEUE_STANDARD);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = MFUnlockWorkQueue(MFASYNC_CALLBACK_QUEUE_UNDEFINED);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = MFUnlockWorkQueue(0x20);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = MFShutdown();
+ ok(hr == S_OK, "Failed to shutdown, hr %#x.\n", hr);
+}
+
START_TEST(mfplat)
{
CoInitialize(NULL);
@@ -855,6 +894,7 @@ START_TEST(mfplat)
test_MFCreateMemoryBuffer();
test_source_resolver();
test_MFCreateAsyncResult();
+ test_allocate_queue();
CoUninitialize();
}
diff --git a/include/mfapi.h b/include/mfapi.h
index 1575cc3..d70a300 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -80,6 +80,7 @@ DEFINE_GUID(MFMediaType_Video, 0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0
typedef unsigned __int64 MFWORKITEM_KEY;
+HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines);
HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size);
@@ -99,6 +100,7 @@ HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *inpu
HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate,
UINT32 *pcount);
+HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result);
HRESULT WINAPI MFLockPlatform(void);
HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags, UINT32 cinput,
MFT_REGISTER_TYPE_INFO *input_types, UINT32 coutput,
@@ -109,6 +111,7 @@ HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWST
HRESULT WINAPI MFShutdown(void);
HRESULT WINAPI MFStartup(ULONG version, DWORD flags);
HRESULT WINAPI MFUnlockPlatform(void);
+HRESULT WINAPI MFUnlockWorkQueue(DWORD queue);
HRESULT WINAPI MFTUnregister(CLSID clsid);
HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory);
HRESULT WINAPI MFGetPluginControl(IMFPluginControl**);
diff --git a/include/mferror.h b/include/mferror.h
index 1f5ae98..53024ca 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -65,6 +65,8 @@
#define MF_E_INVALID_POSITION _HRESULT_TYPEDEF_(0xc00d36e5)
#define MF_E_ATTRIBUTENOTFOUND _HRESULT_TYPEDEF_(0xc00d36e6)
#define MF_E_PROPERTY_TYPE_NOT_ALLOWED _HRESULT_TYPEDEF_(0xc00d36e7)
+#define MF_E_INVALID_WORKQUEUE _HRESULT_TYPEDEF_(0xc00d36ff)
+#define MF_E_SHUTDOWN _HRESULT_TYPEDEF_(0xc00d3e85)
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
#define MF_E_TOPO_CANNOT_FIND_DECRYPTOR _HRESULT_TYPEDEF_(0xc00d5211)
More information about the wine-cvs
mailing list