Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 395fde421d..7d202bc2e5 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -319,12 +319,6 @@ static void test_MFCreateMediaType(void) HRESULT hr; IMFMediaType *mediatype;
- hr = MFStartup(MAKELONG( MF_API_VERSION, 0xdead ), MFSTARTUP_FULL); - ok(hr == MF_E_BAD_STARTUP_VERSION, "got 0x%08x\n", hr); - - hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); - ok(hr == S_OK, "got 0x%08x\n", hr); - if(0) { /* Crash on Windows Vista/7 */ @@ -339,8 +333,6 @@ if(0) todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
IMFMediaType_Release(mediatype); - - MFShutdown(); }
static void test_MFCreateMediaEvent(void) @@ -832,12 +824,27 @@ static void test_MFCreateAsyncResult(void) ok(!refcount, "Unexpected refcount %u\n.", refcount); }
+static void test_startup(void) +{ + HRESULT hr; + + hr = MFStartup(MAKELONG(MF_API_VERSION, 0xdead), MFSTARTUP_FULL); + ok(hr == MF_E_BAD_STARTUP_VERSION, "Unexpected hr %#x.\n", hr); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shutdown, hr %#x.\n", hr); +} + START_TEST(mfplat) { CoInitialize(NULL);
init_functions();
+ test_startup(); test_register(); test_MFCreateMediaType(); test_MFCreateMediaEvent();
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 23 +++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 4 ++-- dlls/mfplat/queue.c | 4 ++++ 3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 7e1736cc16..94d5ab0f48 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -38,6 +38,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+static LONG platform_lock; + static const WCHAR transform_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\', 'T','r','a','n','s','f','o','r','m','s',0}; static const WCHAR categories_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\', @@ -450,6 +452,27 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) HRESULT WINAPI MFShutdown(void) { FIXME("(): stub\n"); + + return S_OK; +} + +/*********************************************************************** + * MFLockPlatform (mfplat.@) + */ +HRESULT WINAPI MFLockPlatform(void) +{ + InterlockedIncrement(&platform_lock); + + return S_OK; +} + +/*********************************************************************** + * MFUnlockPlatform (mfplat.@) + */ +HRESULT WINAPI MFUnlockPlatform(void) +{ + InterlockedDecrement(&platform_lock); + return S_OK; }
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index b4e6c77aae..9813789fa6 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -118,7 +118,7 @@ @ stub MFInitVideoFormat_RGB @ stub MFInvokeCallback @ stub MFJoinIoPort -@ stub MFLockPlatform +@ stdcall MFLockPlatform() @ stub MFLockWorkQueue @ stub MFPutWorkItem @ stub MFPutWorkItemEx @@ -146,7 +146,7 @@ @ stub MFTraceError @ stub MFTraceFuncEnter @ stub MFUnblockThread -@ stub MFUnlockPlatform +@ stdcall MFUnlockPlatform() @ stub MFUnlockWorkQueue @ stub MFUnwrapMediaType @ stub MFValidateMediaTypeSize diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c index 762af248f0..32c7a6c31e 100644 --- a/dlls/mfplat/queue.c +++ b/dlls/mfplat/queue.c @@ -83,6 +83,8 @@ static ULONG WINAPI async_result_Release(IMFAsyncResult *iface) if (result->state) IUnknown_Release(result->state); heap_free(result); + + MFUnlockPlatform(); }
return refcount; @@ -172,6 +174,8 @@ HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, if (!result) return E_OUTOFMEMORY;
+ MFLockPlatform(); + result->result.AsyncResult.lpVtbl = &async_result_vtbl; result->refcount = 1; result->object = object;
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)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 15 +++++++++++++-- dlls/mfplat/tests/mfplat.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 94d5ab0f48..21240dfbeb 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -476,10 +476,21 @@ HRESULT WINAPI MFUnlockPlatform(void) return S_OK; }
+/*********************************************************************** + * MFCopyImage (mfplat.@) + */ HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines) { - FIXME("(%p, %d, %p, %d, %d, %d) stub\n", dest, deststride, src, srcstride, width, lines); - return E_NOTIMPL; + TRACE("(%p, %d, %p, %d, %u, %u)\n", dest, deststride, src, srcstride, width, lines); + + while (lines--) + { + memcpy(dest, src, width); + dest += deststride; + src += srcstride; + } + + return S_OK; }
typedef struct _mfattributes diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 8b06e23375..7d319b480d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -877,6 +877,40 @@ static void test_allocate_queue(void) ok(hr == S_OK, "Failed to shutdown, hr %#x.\n", hr); }
+static void test_MFCopyImage(void) +{ + BYTE dest[16], src[16]; + HRESULT hr; + + memset(dest, 0xaa, sizeof(dest)); + memset(src, 0x11, sizeof(src)); + + hr = MFCopyImage(dest, 8, src, 8, 4, 1); + ok(hr == S_OK, "Failed to copy image %#x.\n", hr); + ok(!memcmp(dest, src, 4) && dest[4] == 0xaa, "Unexpected buffer contents.\n"); + + memset(dest, 0xaa, sizeof(dest)); + memset(src, 0x11, sizeof(src)); + + hr = MFCopyImage(dest, 8, src, 8, 16, 1); + ok(hr == S_OK, "Failed to copy image %#x.\n", hr); + ok(!memcmp(dest, src, 16), "Unexpected buffer contents.\n"); + + memset(dest, 0xaa, sizeof(dest)); + memset(src, 0x11, sizeof(src)); + + hr = MFCopyImage(dest, 8, src, 8, 8, 2); + ok(hr == S_OK, "Failed to copy image %#x.\n", hr); + ok(!memcmp(dest, src, 16), "Unexpected buffer contents.\n"); + + memset(dest, 0xaa, sizeof(dest)); + memset(src, 0x11, sizeof(src)); + + hr = MFCopyImage(dest, 8, src, 8, 8, 0); + ok(hr == S_OK, "Failed to copy image %#x.\n", hr); + ok(dest[0] == 0xaa, "Unexpected buffer contents.\n"); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -895,6 +929,7 @@ START_TEST(mfplat) test_source_resolver(); test_MFCreateAsyncResult(); test_allocate_queue(); + test_MFCopyImage();
CoUninitialize(); }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=47846
Your paranoid android.
=== wxppro (32 bit report) ===
mfplat: mfplat: Timeout
=== wvistau64 (32 bit report) ===
mfplat: mfplat: Timeout
=== wvistau64_zh_CN (32 bit report) ===
mfplat: mfplat: Timeout
=== wvistau64_fr (32 bit report) ===
mfplat: mfplat: Timeout
=== wvistau64_he (32 bit report) ===
mfplat: mfplat: Timeout
=== w7u (32 bit report) ===
mfplat: mfplat.c:911: Test failed: Unexpected buffer contents.
=== w7pro64 (32 bit report) ===
mfplat: mfplat.c:911: Test failed: Unexpected buffer contents.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout