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>
This commit is contained in:
parent
3d463b8ff5
commit
1fb58ab2fb
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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**);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue