mfplat: Add basic support for user queue object lifetime management.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
stable
Nikolay Sivov 2019-02-19 16:20:05 +03:00 committed by Alexandre Julliard
parent 3d463b8ff5
commit 1fb58ab2fb
5 changed files with 187 additions and 3 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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**);

View File

@ -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)