[PATCH 1/4] mfplat: Implement async file stream creation API.

Nikolay Sivov nsivov at codeweavers.com
Thu May 2 09:09:07 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/main.c         | 257 +++++++++++++++++++++++++++++++++++++
 dlls/mfplat/mfplat.spec    |   6 +-
 dlls/mfplat/tests/mfplat.c |  67 ++++++++++
 include/mfapi.h            |   4 +
 4 files changed, 331 insertions(+), 3 deletions(-)

diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 05ee1070af..83c8d34b92 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -6713,3 +6713,260 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
 
     return S_OK;
 }
+
+struct async_create_file
+{
+    IMFAsyncCallback IMFAsyncCallback_iface;
+    LONG refcount;
+    MF_FILE_ACCESSMODE access_mode;
+    MF_FILE_OPENMODE open_mode;
+    MF_FILE_FLAGS flags;
+    WCHAR *path;
+};
+
+struct async_create_file_result
+{
+    struct list entry;
+    IMFAsyncResult *result;
+    IMFByteStream *stream;
+};
+
+static struct list async_create_file_results = LIST_INIT(async_create_file_results);
+static CRITICAL_SECTION async_create_file_cs = { NULL, -1, 0, 0, 0, 0 };
+
+static struct async_create_file *impl_from_create_file_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+    return CONTAINING_RECORD(iface, struct async_create_file, IMFAsyncCallback_iface);
+}
+
+static HRESULT WINAPI async_create_file_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 async_create_file_callback_AddRef(IMFAsyncCallback *iface)
+{
+    struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
+    ULONG refcount = InterlockedIncrement(&async->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI async_create_file_callback_Release(IMFAsyncCallback *iface)
+{
+    struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
+    ULONG refcount = InterlockedDecrement(&async->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        heap_free(async->path);
+        heap_free(async);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI async_create_file_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
+    IMFAsyncResult *caller;
+    IMFByteStream *stream;
+    HRESULT hr;
+
+    caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
+
+    hr = MFCreateFile(async->access_mode, async->open_mode, async->flags, async->path, &stream);
+    if (SUCCEEDED(hr))
+    {
+        struct async_create_file_result *result_item;
+
+        result_item = heap_alloc(sizeof(*result_item));
+        if (result_item)
+        {
+            result_item->result = caller;
+            IMFAsyncResult_AddRef(caller);
+            result_item->stream = stream;
+            IMFByteStream_AddRef(stream);
+
+            EnterCriticalSection(&async_create_file_cs);
+            list_add_tail(&async_create_file_results, &result_item->entry);
+            LeaveCriticalSection(&async_create_file_cs);
+        }
+
+        IMFByteStream_Release(stream);
+    }
+    else
+        IMFAsyncResult_SetStatus(caller, hr);
+
+    MFInvokeCallback(caller);
+
+    return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl =
+{
+    async_create_file_callback_QueryInterface,
+    async_create_file_callback_AddRef,
+    async_create_file_callback_Release,
+    async_create_file_callback_GetParameters,
+    async_create_file_callback_Invoke,
+};
+
+static WCHAR *heap_strdupW(const WCHAR *str)
+{
+    WCHAR *ret = NULL;
+
+    if (str)
+    {
+        unsigned int size;
+
+        size = (strlenW(str) + 1) * sizeof(WCHAR);
+        ret = heap_alloc(size);
+        if (ret)
+            memcpy(ret, str, size);
+    }
+
+    return ret;
+}
+
+/***********************************************************************
+ *      MFBeginCreateFile (mfplat.@)
+ */
+HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags,
+        const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie)
+{
+    struct async_create_file *async = NULL;
+    IMFAsyncResult *caller, *item = NULL;
+    HRESULT hr;
+
+    TRACE("%#x, %#x, %#x, %s, %p, %p, %p.\n", access_mode, open_mode, flags, debugstr_w(path), callback, state,
+            cancel_cookie);
+
+    if (cancel_cookie)
+        *cancel_cookie = NULL;
+
+    if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
+        return hr;
+
+    async = heap_alloc(sizeof(*async));
+    if (!async)
+    {
+        hr = E_OUTOFMEMORY;
+        goto failed;
+    }
+
+    async->IMFAsyncCallback_iface.lpVtbl = &async_create_file_callback_vtbl;
+    async->refcount = 1;
+    async->access_mode = access_mode;
+    async->open_mode = open_mode;
+    async->flags = flags;
+    async->path = heap_strdupW(path);
+    if (!async->path)
+    {
+        hr = E_OUTOFMEMORY;
+        goto failed;
+    }
+
+    hr = MFCreateAsyncResult(NULL, &async->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
+    if (FAILED(hr))
+        goto failed;
+
+    if (cancel_cookie)
+    {
+        *cancel_cookie = (IUnknown *)caller;
+        IUnknown_AddRef(*cancel_cookie);
+    }
+
+    hr = MFInvokeCallback(item);
+
+failed:
+    if (async)
+        IMFAsyncCallback_Release(&async->IMFAsyncCallback_iface);
+    if (item)
+        IMFAsyncResult_Release(item);
+    if (caller)
+        IMFAsyncResult_Release(caller);
+
+    return hr;
+}
+
+static HRESULT async_create_file_pull_result(IUnknown *unk, IMFByteStream **stream)
+{
+    struct async_create_file_result *item;
+    HRESULT hr = MF_E_UNEXPECTED;
+    IMFAsyncResult *result;
+
+    *stream = NULL;
+
+    if (FAILED(IUnknown_QueryInterface(unk, &IID_IMFAsyncResult, (void **)&result)))
+        return hr;
+
+    EnterCriticalSection(&async_create_file_cs);
+
+    LIST_FOR_EACH_ENTRY(item, &async_create_file_results, struct async_create_file_result, entry)
+    {
+        if (result == item->result)
+        {
+            *stream = item->stream;
+            IMFAsyncResult_Release(item->result);
+            list_remove(&item->entry);
+            heap_free(item);
+            break;
+        }
+    }
+
+    LeaveCriticalSection(&async_create_file_cs);
+
+    if (*stream)
+        hr = IMFAsyncResult_GetStatus(result);
+
+    IMFAsyncResult_Release(result);
+
+    return hr;
+}
+
+/***********************************************************************
+ *      MFEndCreateFile (mfplat.@)
+ */
+HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream)
+{
+    TRACE("%p, %p.\n", result, stream);
+
+    return async_create_file_pull_result((IUnknown *)result, stream);
+}
+
+/***********************************************************************
+ *      MFCancelCreateFile (mfplat.@)
+ */
+HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie)
+{
+    IMFByteStream *stream = NULL;
+    HRESULT hr;
+
+    TRACE("%p.\n", cancel_cookie);
+
+    hr = async_create_file_pull_result(cancel_cookie, &stream);
+
+    if (stream)
+        IMFByteStream_Release(stream);
+
+    return hr;
+}
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 7823ac0d9e..3ebbdbdd4b 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -20,14 +20,14 @@
 @ stdcall MFAllocateWorkQueueEx(long ptr)
 @ stub MFAppendCollection
 @ stub MFAverageTimePerFrameToFrameRate
-@ stub MFBeginCreateFile
+@ stdcall MFBeginCreateFile(long long long wstr ptr ptr ptr)
 @ stub MFBeginGetHostByName
 @ stub MFBeginRegisterWorkQueueWithMMCSS
 @ stub MFBeginUnregisterWorkQueueWithMMCSS
 @ stub MFBlockThread
 @ stub MFCalculateBitmapImageSize
 @ stdcall MFCalculateImageSize(ptr long long ptr)
-@ stub MFCancelCreateFile
+@ stdcall MFCancelCreateFile(ptr)
 @ stdcall MFCancelWorkItem(int64)
 @ stdcall MFCompareFullToPartialMediaType(ptr ptr)
 @ stub MFCompareSockaddrAddresses
@@ -79,7 +79,7 @@
 @ stub MFDeserializeEvent
 @ stub MFDeserializeMediaTypeFromStream
 @ stub MFDeserializePresentationDescriptor
-@ stub MFEndCreateFile
+@ stdcall MFEndCreateFile(ptr ptr)
 @ stub MFEndGetHostByName
 @ stub MFEndRegisterWorkQueueWithMMCSS
 @ stub MFEndUnregisterWorkQueueWithMMCSS
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index b349c51af3..d2ae8f2a85 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -2886,6 +2886,72 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void)
     IMFMediaType_Release(mediatype);
 }
 
+static HRESULT WINAPI test_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
+    IMFByteStream *stream;
+    IUnknown *object;
+    HRESULT hr;
+
+    ok(!!result, "Unexpected result object.\n");
+
+    ok((IUnknown *)iface == IMFAsyncResult_GetStateNoAddRef(result), "Unexpected result state.\n");
+
+    hr = IMFAsyncResult_GetObject(result, &object);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = MFEndCreateFile(result, &stream);
+    ok(hr == S_OK, "Failed to get file stream, hr %#x.\n", hr);
+    IMFByteStream_Release(stream);
+
+    SetEvent(callback->event);
+
+    return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl test_create_file_callback_vtbl =
+{
+    testcallback_QueryInterface,
+    testcallback_AddRef,
+    testcallback_Release,
+    testcallback_GetParameters,
+    test_create_file_callback_Invoke,
+};
+
+static void test_async_create_file(void)
+{
+    struct test_callback callback = { { &test_create_file_callback_vtbl } };
+    WCHAR pathW[MAX_PATH], fileW[MAX_PATH];
+    IUnknown *cancel_cookie;
+    HRESULT hr;
+    BOOL ret;
+
+    hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+    ok(hr == S_OK, "Fail to start up, hr %#x.\n", hr);
+
+    callback.event = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
+    GetTempFileNameW(pathW, NULL, 0, fileW);
+
+    hr = MFBeginCreateFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, fileW,
+            &callback.IMFAsyncCallback_iface, (IUnknown *)&callback.IMFAsyncCallback_iface, &cancel_cookie);
+    ok(hr == S_OK, "Async create request failed, hr %#x.\n", hr);
+    ok(cancel_cookie != NULL, "Unexpected cancellation object.\n");
+
+    WaitForSingleObject(callback.event, INFINITE);
+
+    IUnknown_Release(cancel_cookie);
+
+    CloseHandle(callback.event);
+
+    hr = MFShutdown();
+    ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+
+    ret = DeleteFileW(fileW);
+    ok(ret, "Failed to delete test file.\n");
+}
+
 START_TEST(mfplat)
 {
     CoInitialize(NULL);
@@ -2920,6 +2986,7 @@ START_TEST(mfplat)
     test_attributes_serialization();
     test_wrapped_media_type();
     test_MFCreateWaveFormatExFromMFMediaType();
+    test_async_create_file();
 
     CoUninitialize();
 }
diff --git a/include/mfapi.h b/include/mfapi.h
index cee9d403c4..d172db147a 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -353,7 +353,10 @@ typedef enum _MFWaveFormatExConvertFlags
 HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
 HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
 HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
+HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags,
+        const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie);
 HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size);
+HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie);
 HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
 BOOL    WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaType *partial_type);
 HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines);
@@ -370,6 +373,7 @@ HRESULT WINAPI MFCreateMediaType(IMFMediaType **type);
 HRESULT WINAPI MFCreateSample(IMFSample **sample);
 HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer);
 HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *type, WAVEFORMATEX **format, UINT32 *size, UINT32 flags);
+HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream);
 void *  WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type);
 void    WINAPI MFHeapFree(void *ptr);
 HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size);
-- 
2.20.1




More information about the wine-devel mailing list