Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- 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 9813789fa6..8f5ee77406 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 32c7a6c31e..65f111ba41 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 7d202bc2e5..8b06e23375 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 1575cc3d97..d70a300a3c 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 1f5ae98382..53024caed1 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)