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