mfplat: Implement periodic callbacks.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
fb78d19881
commit
b22b28e231
|
@ -15,7 +15,7 @@
|
||||||
@ stub GetAMSubtypeFromD3DFormat
|
@ stub GetAMSubtypeFromD3DFormat
|
||||||
@ stub GetD3DFormatFromMFSubtype
|
@ stub GetD3DFormatFromMFSubtype
|
||||||
@ stub LFGetGlobalPool
|
@ stub LFGetGlobalPool
|
||||||
@ stub MFAddPeriodicCallback
|
@ stdcall MFAddPeriodicCallback(ptr ptr ptr)
|
||||||
@ stdcall MFAllocateWorkQueue(ptr)
|
@ stdcall MFAllocateWorkQueue(ptr)
|
||||||
@ stdcall MFAllocateWorkQueueEx(long ptr)
|
@ stdcall MFAllocateWorkQueueEx(long ptr)
|
||||||
@ stub MFAppendCollection
|
@ stub MFAppendCollection
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
@ stub MFGetSockaddrFromNumericName
|
@ stub MFGetSockaddrFromNumericName
|
||||||
@ stub MFGetStrideForBitmapInfoHeader
|
@ stub MFGetStrideForBitmapInfoHeader
|
||||||
@ stdcall MFGetSystemTime()
|
@ stdcall MFGetSystemTime()
|
||||||
@ stub MFGetTimerPeriodicity
|
@ stdcall MFGetTimerPeriodicity(ptr)
|
||||||
@ stub MFGetUncompressedVideoFormat
|
@ stub MFGetUncompressedVideoFormat
|
||||||
@ stub MFGetWorkQueueMMCSSClass
|
@ stub MFGetWorkQueueMMCSSClass
|
||||||
@ stub MFGetWorkQueueMMCSSTaskId
|
@ stub MFGetWorkQueueMMCSSTaskId
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
@ stdcall MFPutWorkItem(long ptr ptr)
|
@ stdcall MFPutWorkItem(long ptr ptr)
|
||||||
@ stdcall MFPutWorkItemEx(long ptr)
|
@ stdcall MFPutWorkItemEx(long ptr)
|
||||||
@ stub MFRecordError
|
@ stub MFRecordError
|
||||||
@ stub MFRemovePeriodicCallback
|
@ stdcall MFRemovePeriodicCallback(long)
|
||||||
@ stdcall MFScheduleWorkItem(ptr ptr int64 ptr)
|
@ stdcall MFScheduleWorkItem(ptr ptr int64 ptr)
|
||||||
@ stdcall MFScheduleWorkItemEx(ptr int64 ptr)
|
@ stdcall MFScheduleWorkItemEx(ptr int64 ptr)
|
||||||
@ stub MFSerializeAttributesToStream
|
@ stub MFSerializeAttributesToStream
|
||||||
|
|
|
@ -39,9 +39,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
|
||||||
|
|
||||||
static LONG next_item_key;
|
static LONG next_item_key;
|
||||||
|
|
||||||
|
static MFWORKITEM_KEY get_item_key(DWORD mask, DWORD key)
|
||||||
|
{
|
||||||
|
return ((MFWORKITEM_KEY)mask << 32) | key;
|
||||||
|
}
|
||||||
|
|
||||||
static MFWORKITEM_KEY generate_item_key(DWORD mask)
|
static MFWORKITEM_KEY generate_item_key(DWORD mask)
|
||||||
{
|
{
|
||||||
return ((MFWORKITEM_KEY)mask << 32) | InterlockedIncrement(&next_item_key);
|
return get_item_key(mask, InterlockedIncrement(&next_item_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct work_item
|
struct work_item
|
||||||
|
@ -315,9 +320,10 @@ void shutdown_system_queues(void)
|
||||||
LeaveCriticalSection(&queues_section);
|
LeaveCriticalSection(&queues_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void grab_work_item(struct work_item *item)
|
static struct work_item *grab_work_item(struct work_item *item)
|
||||||
{
|
{
|
||||||
InterlockedIncrement(&item->refcount);
|
InterlockedIncrement(&item->refcount);
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CALLBACK standard_queue_worker(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
|
static void CALLBACK standard_queue_worker(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
|
||||||
|
@ -442,6 +448,15 @@ static void CALLBACK scheduled_item_cancelable_callback(TP_CALLBACK_INSTANCE *in
|
||||||
release_work_item(item);
|
release_work_item(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CALLBACK periodic_item_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_TIMER *timer)
|
||||||
|
{
|
||||||
|
struct work_item *item = grab_work_item(context);
|
||||||
|
|
||||||
|
invoke_async_callback(item->result);
|
||||||
|
|
||||||
|
release_work_item(item);
|
||||||
|
}
|
||||||
|
|
||||||
static void queue_mark_item_pending(DWORD mask, struct work_item *item, MFWORKITEM_KEY *key)
|
static void queue_mark_item_pending(DWORD mask, struct work_item *item, MFWORKITEM_KEY *key)
|
||||||
{
|
{
|
||||||
*key = generate_item_key(mask);
|
*key = generate_item_key(mask);
|
||||||
|
@ -478,7 +493,8 @@ static HRESULT queue_submit_wait(struct queue *queue, HANDLE event, LONG priorit
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT queue_submit_timer(struct queue *queue, IMFAsyncResult *result, INT64 timeout, MFWORKITEM_KEY *key)
|
static HRESULT queue_submit_timer(struct queue *queue, IMFAsyncResult *result, INT64 timeout, DWORD period,
|
||||||
|
MFWORKITEM_KEY *key)
|
||||||
{
|
{
|
||||||
PTP_TIMER_CALLBACK callback;
|
PTP_TIMER_CALLBACK callback;
|
||||||
struct work_item *item;
|
struct work_item *item;
|
||||||
|
@ -491,17 +507,19 @@ static HRESULT queue_submit_timer(struct queue *queue, IMFAsyncResult *result, I
|
||||||
if (key)
|
if (key)
|
||||||
{
|
{
|
||||||
queue_mark_item_pending(SCHEDULED_ITEM_KEY_MASK, item, key);
|
queue_mark_item_pending(SCHEDULED_ITEM_KEY_MASK, item, key);
|
||||||
callback = scheduled_item_cancelable_callback;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (period)
|
||||||
|
callback = periodic_item_callback;
|
||||||
else
|
else
|
||||||
callback = scheduled_item_callback;
|
callback = key ? scheduled_item_cancelable_callback : scheduled_item_callback;
|
||||||
|
|
||||||
t.QuadPart = timeout * 1000 * 10;
|
t.QuadPart = timeout * 1000 * 10;
|
||||||
filetime.dwLowDateTime = t.u.LowPart;
|
filetime.dwLowDateTime = t.u.LowPart;
|
||||||
filetime.dwHighDateTime = t.u.HighPart;
|
filetime.dwHighDateTime = t.u.HighPart;
|
||||||
|
|
||||||
item->u.timer_object = CreateThreadpoolTimer(callback, item, &queue->env);
|
item->u.timer_object = CreateThreadpoolTimer(callback, item, &queue->env);
|
||||||
SetThreadpoolTimer(item->u.timer_object, &filetime, 0, 0);
|
SetThreadpoolTimer(item->u.timer_object, &filetime, period, 0);
|
||||||
|
|
||||||
TRACE("dispatched %p.\n", result);
|
TRACE("dispatched %p.\n", result);
|
||||||
|
|
||||||
|
@ -842,7 +860,7 @@ static HRESULT schedule_work_item(IMFAsyncResult *result, INT64 timeout, MFWORKI
|
||||||
|
|
||||||
TRACE("%p, %s, %p.\n", result, wine_dbgstr_longlong(timeout), key);
|
TRACE("%p, %s, %p.\n", result, wine_dbgstr_longlong(timeout), key);
|
||||||
|
|
||||||
hr = queue_submit_timer(queue, result, timeout, key);
|
hr = queue_submit_timer(queue, result, timeout, 0, key);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -912,3 +930,165 @@ HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key)
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD get_timer_period(void)
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* MFGetTimerPeriodicity (mfplat.@)
|
||||||
|
*/
|
||||||
|
HRESULT WINAPI MFGetTimerPeriodicity(DWORD *period)
|
||||||
|
{
|
||||||
|
TRACE("%p.\n", period);
|
||||||
|
|
||||||
|
*period = get_timer_period();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct periodic_callback
|
||||||
|
{
|
||||||
|
IMFAsyncCallback IMFAsyncCallback_iface;
|
||||||
|
LONG refcount;
|
||||||
|
MFPERIODICCALLBACK callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct periodic_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
|
||||||
|
{
|
||||||
|
return CONTAINING_RECORD(iface, struct periodic_callback, IMFAsyncCallback_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI periodic_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
||||||
|
{
|
||||||
|
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
||||||
|
IsEqualIID(riid, &IID_IUnknown))
|
||||||
|
{
|
||||||
|
*obj = iface;
|
||||||
|
IMFAsyncCallback_AddRef(iface);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
*obj = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI periodic_callback_AddRef(IMFAsyncCallback *iface)
|
||||||
|
{
|
||||||
|
struct periodic_callback *callback = impl_from_IMFAsyncCallback(iface);
|
||||||
|
ULONG refcount = InterlockedIncrement(&callback->refcount);
|
||||||
|
|
||||||
|
TRACE("%p, %u.\n", iface, refcount);
|
||||||
|
|
||||||
|
return refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI periodic_callback_Release(IMFAsyncCallback *iface)
|
||||||
|
{
|
||||||
|
struct periodic_callback *callback = impl_from_IMFAsyncCallback(iface);
|
||||||
|
ULONG refcount = InterlockedDecrement(&callback->refcount);
|
||||||
|
|
||||||
|
TRACE("%p, %u.\n", iface, refcount);
|
||||||
|
|
||||||
|
if (!refcount)
|
||||||
|
heap_free(callback);
|
||||||
|
|
||||||
|
return refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI periodic_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI periodic_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||||
|
{
|
||||||
|
struct periodic_callback *callback = impl_from_IMFAsyncCallback(iface);
|
||||||
|
IUnknown *context = NULL;
|
||||||
|
|
||||||
|
IMFAsyncResult_GetObject(result, &context);
|
||||||
|
|
||||||
|
callback->callback(context);
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
IUnknown_Release(context);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const IMFAsyncCallbackVtbl periodic_callback_vtbl =
|
||||||
|
{
|
||||||
|
periodic_callback_QueryInterface,
|
||||||
|
periodic_callback_AddRef,
|
||||||
|
periodic_callback_Release,
|
||||||
|
periodic_callback_GetParameters,
|
||||||
|
periodic_callback_Invoke,
|
||||||
|
};
|
||||||
|
|
||||||
|
static HRESULT create_periodic_callback_obj(MFPERIODICCALLBACK callback, IMFAsyncCallback **out)
|
||||||
|
{
|
||||||
|
struct periodic_callback *object;
|
||||||
|
|
||||||
|
object = heap_alloc(sizeof(*object));
|
||||||
|
if (!object)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
object->IMFAsyncCallback_iface.lpVtbl = &periodic_callback_vtbl;
|
||||||
|
object->refcount = 1;
|
||||||
|
object->callback = callback;
|
||||||
|
|
||||||
|
*out = &object->IMFAsyncCallback_iface;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* MFAddPeriodicCallback (mfplat.@)
|
||||||
|
*/
|
||||||
|
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key)
|
||||||
|
{
|
||||||
|
IMFAsyncCallback *periodic_callback;
|
||||||
|
MFWORKITEM_KEY workitem_key;
|
||||||
|
IMFAsyncResult *result;
|
||||||
|
struct queue *queue;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("%p, %p, %p.\n", callback, context, key);
|
||||||
|
|
||||||
|
if (FAILED(hr = grab_queue(MFASYNC_CALLBACK_QUEUE_TIMER, &queue)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (FAILED(hr = create_periodic_callback_obj(callback, &periodic_callback)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = create_async_result(context, periodic_callback, NULL, &result);
|
||||||
|
IMFAsyncCallback_Release(periodic_callback);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = queue_submit_timer(queue, result, 0, get_timer_period(), key ? &workitem_key : NULL);
|
||||||
|
|
||||||
|
IMFAsyncResult_Release(result);
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
*key = workitem_key;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* MFRemovePeriodicCallback (mfplat.@)
|
||||||
|
*/
|
||||||
|
HRESULT WINAPI MFRemovePeriodicCallback(DWORD key)
|
||||||
|
{
|
||||||
|
struct queue *queue;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("%#x.\n", key);
|
||||||
|
|
||||||
|
if (FAILED(hr = grab_queue(MFASYNC_CALLBACK_QUEUE_TIMER, &queue)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return queue_cancel_item(queue, get_item_key(SCHEDULED_ITEM_KEY_MASK, key));
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ static void* (WINAPI *pMFHeapAlloc)(SIZE_T size, ULONG flags, char *file, int
|
||||||
static void (WINAPI *pMFHeapFree)(void *p);
|
static void (WINAPI *pMFHeapFree)(void *p);
|
||||||
static HRESULT (WINAPI *pMFPutWaitingWorkItem)(HANDLE event, LONG priority, IMFAsyncResult *result, MFWORKITEM_KEY *key);
|
static HRESULT (WINAPI *pMFPutWaitingWorkItem)(HANDLE event, LONG priority, IMFAsyncResult *result, MFWORKITEM_KEY *key);
|
||||||
static HRESULT (WINAPI *pMFAllocateSerialWorkQueue)(DWORD queue, DWORD *serial_queue);
|
static HRESULT (WINAPI *pMFAllocateSerialWorkQueue)(DWORD queue, DWORD *serial_queue);
|
||||||
|
static HRESULT (WINAPI *pMFAddPeriodicCallback)(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
|
||||||
|
static HRESULT (WINAPI *pMFRemovePeriodicCallback)(DWORD key);
|
||||||
|
|
||||||
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
|
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
|
||||||
|
|
||||||
|
@ -314,6 +316,7 @@ static void init_functions(void)
|
||||||
HMODULE mod = GetModuleHandleA("mfplat.dll");
|
HMODULE mod = GetModuleHandleA("mfplat.dll");
|
||||||
|
|
||||||
#define X(f) p##f = (void*)GetProcAddress(mod, #f)
|
#define X(f) p##f = (void*)GetProcAddress(mod, #f)
|
||||||
|
X(MFAddPeriodicCallback);
|
||||||
X(MFAllocateSerialWorkQueue);
|
X(MFAllocateSerialWorkQueue);
|
||||||
X(MFCopyImage);
|
X(MFCopyImage);
|
||||||
X(MFCreateSourceResolver);
|
X(MFCreateSourceResolver);
|
||||||
|
@ -322,6 +325,7 @@ static void init_functions(void)
|
||||||
X(MFHeapAlloc);
|
X(MFHeapAlloc);
|
||||||
X(MFHeapFree);
|
X(MFHeapFree);
|
||||||
X(MFPutWaitingWorkItem);
|
X(MFPutWaitingWorkItem);
|
||||||
|
X(MFRemovePeriodicCallback);
|
||||||
#undef X
|
#undef X
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,6 +1203,49 @@ static void test_serial_queue(void)
|
||||||
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LONG periodic_counter;
|
||||||
|
static void CALLBACK periodic_callback(IUnknown *context)
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&periodic_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_periodic_callback(void)
|
||||||
|
{
|
||||||
|
DWORD period, key;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||||
|
ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
period = 0;
|
||||||
|
hr = MFGetTimerPeriodicity(&period);
|
||||||
|
ok(hr == S_OK, "Failed to get timer perdiod, hr %#x.\n", hr);
|
||||||
|
ok(period == 10, "Unexpected period %u.\n", period);
|
||||||
|
|
||||||
|
if (!pMFAddPeriodicCallback)
|
||||||
|
{
|
||||||
|
win_skip("Periodic callbacks are not supported.\n");
|
||||||
|
MFShutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(periodic_counter == 0, "Unexpected counter value %u.\n", periodic_counter);
|
||||||
|
|
||||||
|
hr = pMFAddPeriodicCallback(periodic_callback, NULL, &key);
|
||||||
|
ok(hr == S_OK, "Failed to add periodic callback, hr %#x.\n", hr);
|
||||||
|
ok(key != 0, "Unexpected key %#x.\n", key);
|
||||||
|
|
||||||
|
Sleep(10 * period);
|
||||||
|
|
||||||
|
hr = pMFRemovePeriodicCallback(key);
|
||||||
|
ok(hr == S_OK, "Failed to remove callback, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
ok(periodic_counter > 0, "Unexpected counter value %u.\n", periodic_counter);
|
||||||
|
|
||||||
|
hr = MFShutdown();
|
||||||
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(mfplat)
|
START_TEST(mfplat)
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(NULL);
|
||||||
|
@ -1222,6 +1269,7 @@ START_TEST(mfplat)
|
||||||
test_MFHeapAlloc();
|
test_MFHeapAlloc();
|
||||||
test_scheduled_items();
|
test_scheduled_items();
|
||||||
test_serial_queue();
|
test_serial_queue();
|
||||||
|
test_periodic_callback();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,9 @@ typedef enum
|
||||||
MF_MULTITHREADED_WORKQUEUE,
|
MF_MULTITHREADED_WORKQUEUE,
|
||||||
} MFASYNC_WORKQUEUE_TYPE;
|
} MFASYNC_WORKQUEUE_TYPE;
|
||||||
|
|
||||||
|
typedef void (CALLBACK *MFPERIODICCALLBACK)(IUnknown *context);
|
||||||
|
|
||||||
|
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
|
||||||
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
|
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
|
||||||
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
|
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
|
||||||
HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
|
HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
|
||||||
|
@ -131,6 +134,7 @@ HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags
|
||||||
HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWSTR name,
|
HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWSTR name,
|
||||||
UINT32 flags, UINT32 cinput, const MFT_REGISTER_TYPE_INFO *input_types,
|
UINT32 flags, UINT32 cinput, const MFT_REGISTER_TYPE_INFO *input_types,
|
||||||
UINT32 coutput, const MFT_REGISTER_TYPE_INFO* output_types);
|
UINT32 coutput, const MFT_REGISTER_TYPE_INFO* output_types);
|
||||||
|
HRESULT WINAPI MFRemovePeriodicCallback(DWORD key);
|
||||||
HRESULT WINAPI MFShutdown(void);
|
HRESULT WINAPI MFShutdown(void);
|
||||||
HRESULT WINAPI MFStartup(ULONG version, DWORD flags);
|
HRESULT WINAPI MFStartup(ULONG version, DWORD flags);
|
||||||
HRESULT WINAPI MFUnlockPlatform(void);
|
HRESULT WINAPI MFUnlockPlatform(void);
|
||||||
|
|
Loading…
Reference in New Issue