[PATCH 3/4] mfplat: Use file url scheme as a fallback.

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


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/main.c         |  68 +++++++-----
 dlls/mfplat/tests/mfplat.c | 211 +++++++++++++++++++++++++------------
 2 files changed, 186 insertions(+), 93 deletions(-)

diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 83c8d34b92..803944d376 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -4956,12 +4956,46 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
     return hr;
 }
 
-static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSchemeHandler **handler)
+static HRESULT resolver_create_scheme_handler(const WCHAR *scheme, DWORD flags, IMFSchemeHandler **handler)
 {
     static const char schemehandlerspath[] = "Software\\Microsoft\\Windows Media Foundation\\SchemeHandlers";
     static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
+    unsigned int i;
+    HRESULT hr;
+
+    TRACE("%s, %#x, %p.\n", debugstr_w(scheme), flags, handler);
+
+    /* FIXME: check local handlers first */
+
+    for (i = 0; i < ARRAY_SIZE(hkey_roots); ++i)
+    {
+        HKEY hkey, hkey_handler;
+
+        hr = MF_E_UNSUPPORTED_SCHEME;
+
+        if (RegOpenKeyA(hkey_roots[i], schemehandlerspath, &hkey))
+            continue;
+
+        if (!RegOpenKeyW(hkey, scheme, &hkey_handler))
+        {
+            hr = resolver_create_registered_handler(hkey_handler, &IID_IMFSchemeHandler, (void **)handler);
+            RegCloseKey(hkey_handler);
+        }
+
+        RegCloseKey(hkey);
+
+        if (SUCCEEDED(hr))
+            break;
+    }
+
+    return hr;
+}
+
+static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSchemeHandler **handler)
+{
+    static const WCHAR fileschemeW[] = {'f','i','l','e',':',0};
     const WCHAR *ptr = url;
-    unsigned int len, i;
+    unsigned int len;
     WCHAR *scheme;
     HRESULT hr;
 
@@ -4985,9 +5019,12 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch
         ptr++;
     }
 
-    /* Schemes must end with a ':' */
+    /* Schemes must end with a ':', if not found try "file:" */
     if (ptr == url || *ptr != ':')
-        return MF_E_UNSUPPORTED_SCHEME;
+    {
+        url = fileschemeW;
+        ptr = fileschemeW + ARRAY_SIZE(fileschemeW) - 1;
+    }
 
     len = ptr - url;
     scheme = heap_alloc((len + 1) * sizeof(WCHAR));
@@ -4997,26 +5034,9 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch
     memcpy(scheme, url, len * sizeof(WCHAR));
     scheme[len] = 0;
 
-    /* FIXME: check local handlers first */
-
-    for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i)
-    {
-        HKEY hkey, hkey_handler;
-
-        if (RegOpenKeyA(hkey_roots[i], schemehandlerspath, &hkey))
-            continue;
-
-        if (!RegOpenKeyW(hkey, scheme, &hkey_handler))
-        {
-            hr = resolver_create_registered_handler(hkey_handler, &IID_IMFSchemeHandler, (void **)handler);
-            RegCloseKey(hkey_handler);
-        }
-
-        RegCloseKey(hkey);
-
-        if (SUCCEEDED(hr))
-            break;
-    }
+    hr = resolver_create_scheme_handler(scheme, flags, handler);
+    if (FAILED(hr) && url != fileschemeW)
+        hr = resolver_create_scheme_handler(fileschemeW, flags, handler);
 
     heap_free(scheme);
 
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index d2ae8f2a85..10c2fd1e21 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -63,6 +63,7 @@ static HRESULT (WINAPI *pMFAddPeriodicCallback)(MFPERIODICCALLBACK callback, IUn
 static HRESULT (WINAPI *pMFRemovePeriodicCallback)(DWORD key);
 
 static const WCHAR mp4file[] = {'t','e','s','t','.','m','p','4',0};
+static const WCHAR fileschemeW[] = {'f','i','l','e',':','/','/',0};
 
 static WCHAR *load_resource(const WCHAR *name)
 {
@@ -92,6 +93,48 @@ static WCHAR *load_resource(const WCHAR *name)
     return pathW;
 }
 
+struct test_callback
+{
+    IMFAsyncCallback IMFAsyncCallback_iface;
+    HANDLE event;
+};
+
+static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+    return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface);
+}
+
+static HRESULT WINAPI testcallback_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 testcallback_AddRef(IMFAsyncCallback *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+    ok(flags != NULL && queue != NULL, "Unexpected arguments.\n");
+    return E_NOTIMPL;
+}
+
+
 static BOOL check_clsid(CLSID *clsids, UINT32 count)
 {
     int i;
@@ -209,23 +252,61 @@ if(0)
     ok(ret == S_OK || broken(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)), "got %x\n", ret);
 }
 
+static HRESULT WINAPI test_create_from_url_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
+    IMFSourceResolver *resolver;
+    IUnknown *object, *object2;
+    MF_OBJECT_TYPE obj_type;
+    HRESULT hr;
+
+    ok(!!result, "Unexpected result object.\n");
+
+    resolver = (IMFSourceResolver *)IMFAsyncResult_GetStateNoAddRef(result);
+
+    hr = IMFSourceResolver_EndCreateObjectFromURL(resolver, result, &obj_type, &object);
+    ok(hr == S_OK, "Failed to create an object, hr %#x.\n", hr);
+
+    hr = IMFAsyncResult_GetObject(result, &object2);
+    ok(hr == S_OK, "Failed to get result object, hr %#x.\n", hr);
+    ok(object2 == object, "Unexpected object.\n");
+
+    IUnknown_Release(object);
+    IUnknown_Release(object2);
+
+    SetEvent(callback->event);
+
+    return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl test_create_from_url_callback_vtbl =
+{
+    testcallback_QueryInterface,
+    testcallback_AddRef,
+    testcallback_Release,
+    testcallback_GetParameters,
+    test_create_from_url_callback_Invoke,
+};
+
 static void test_source_resolver(void)
 {
+    static const WCHAR file_type[] = {'v','i','d','e','o','/','m','p','4',0};
+    struct test_callback callback = { { &test_create_from_url_callback_vtbl } };
     IMFSourceResolver *resolver, *resolver2;
-    IMFByteStream *bytestream;
     IMFAttributes *attributes;
     IMFMediaSource *mediasource;
     IMFPresentationDescriptor *descriptor;
     IMFMediaTypeHandler *handler;
     MF_OBJECT_TYPE obj_type;
     IMFStreamDescriptor *sd;
+    IUnknown *cancel_cookie;
+    IMFByteStream *stream;
+    WCHAR pathW[MAX_PATH];
     HRESULT hr;
     WCHAR *filename;
     BOOL selected;
     GUID guid;
 
-    static const WCHAR file_type[] = {'v','i','d','e','o','/','m','p','4',0};
-
     if (!pMFCreateSourceResolver)
     {
         win_skip("MFCreateSourceResolver() not found\n");
@@ -249,8 +330,7 @@ static void test_source_resolver(void)
 
     filename = load_resource(mp4file);
 
-    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST,
-                      MF_FILEFLAGS_NONE, filename, &bytestream);
+    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IMFSourceResolver_CreateObjectFromByteStream(
@@ -258,45 +338,38 @@ static void test_source_resolver(void)
         &obj_type, (IUnknown **)&mediasource);
     ok(hr == E_POINTER, "got 0x%08x\n", hr);
 
-    hr = IMFSourceResolver_CreateObjectFromByteStream(
-        resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
-        NULL, (IUnknown **)&mediasource);
+    hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
+            NULL, (IUnknown **)&mediasource);
     ok(hr == E_POINTER, "got 0x%08x\n", hr);
 
-    hr = IMFSourceResolver_CreateObjectFromByteStream(
-        resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
-        &obj_type, NULL);
+    hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
+            &obj_type, NULL);
     ok(hr == E_POINTER, "got 0x%08x\n", hr);
 
-    hr = IMFSourceResolver_CreateObjectFromByteStream(
-        resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
-        &obj_type, (IUnknown **)&mediasource);
+    hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
+            &obj_type, (IUnknown **)&mediasource);
     todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr);
     if (hr == S_OK) IMFMediaSource_Release(mediasource);
 
-    hr = IMFSourceResolver_CreateObjectFromByteStream(
-        resolver, bytestream, NULL, MF_RESOLUTION_BYTESTREAM, NULL,
-        &obj_type, (IUnknown **)&mediasource);
+    hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_BYTESTREAM, NULL,
+            &obj_type, (IUnknown **)&mediasource);
     todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr);
 
-    IMFByteStream_Release(bytestream);
+    IMFByteStream_Release(stream);
 
     /* We have to create a new bytestream here, because all following
      * calls to CreateObjectFromByteStream will fail. */
-    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST,
-                      MF_FILEFLAGS_NONE, filename, &bytestream);
+    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
-    hr = IUnknown_QueryInterface(bytestream, &IID_IMFAttributes,
-                                 (void **)&attributes);
+    hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes);
     ok(hr == S_OK, "got 0x%08x\n", hr);
     hr = IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, file_type);
     ok(hr == S_OK, "Failed to set string value, hr %#x.\n", hr);
     IMFAttributes_Release(attributes);
 
-    hr = IMFSourceResolver_CreateObjectFromByteStream(
-        resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
-        &obj_type, (IUnknown **)&mediasource);
+    hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
+            &obj_type, (IUnknown **)&mediasource);
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mediasource != NULL, "got %p\n", mediasource);
     ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type);
@@ -320,7 +393,42 @@ todo_wine
 
     IMFPresentationDescriptor_Release(descriptor);
     IMFMediaSource_Release(mediasource);
-    IMFByteStream_Release(bytestream);
+    IMFByteStream_Release(stream);
+
+    /* Create from URL. */
+    callback.event = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+    hr = IMFSourceResolver_CreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type,
+            (IUnknown **)&stream);
+todo_wine
+    ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr);
+    if (SUCCEEDED(hr))
+        IMFByteStream_Release(stream);
+
+    hr = IMFSourceResolver_BeginCreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL,
+            &cancel_cookie, &callback.IMFAsyncCallback_iface, (IUnknown *)resolver);
+todo_wine {
+    ok(hr == S_OK, "Create request failed, hr %#x.\n", hr);
+    ok(cancel_cookie != NULL, "Unexpected cancel object.\n");
+}
+    if (cancel_cookie)
+       IUnknown_Release(cancel_cookie);
+
+    if (SUCCEEDED(hr))
+        WaitForSingleObject(callback.event, INFINITE);
+
+    CloseHandle(callback.event);
+
+    /* With explicit scheme. */
+    lstrcpyW(pathW, fileschemeW);
+    lstrcatW(pathW, filename);
+
+    hr = IMFSourceResolver_CreateObjectFromURL(resolver, pathW, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type,
+            (IUnknown **)&stream);
+todo_wine
+    ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr);
+    if (SUCCEEDED(hr))
+        IMFByteStream_Release(stream);
 
     IMFSourceResolver_Release(resolver);
 
@@ -1131,10 +1239,10 @@ static void test_MFCreateMFByteStreamOnStream(void)
 
 static void test_file_stream(void)
 {
-    IMFByteStream *bytestream;
-    IMFByteStream *bytestream2;
+    IMFByteStream *bytestream, *bytestream2;
     IMFAttributes *attributes = NULL;
     MF_ATTRIBUTE_TYPE item_type;
+    WCHAR pathW[MAX_PATH];
     DWORD caps, count;
     WCHAR *filename;
     IUnknown *unk;
@@ -1245,6 +1353,12 @@ static void test_file_stream(void)
 
     IMFByteStream_Release(bytestream);
 
+    /* Explicit file: scheme */
+    lstrcpyW(pathW, fileschemeW);
+    lstrcatW(pathW, filename);
+    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, pathW, &bytestream);
+    ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
     hr = MFShutdown();
     ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
 
@@ -1524,47 +1638,6 @@ todo_wine
     IMFSample_Release(sample);
 }
 
-struct test_callback
-{
-    IMFAsyncCallback IMFAsyncCallback_iface;
-    HANDLE event;
-};
-
-static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
-{
-    return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface);
-}
-
-static HRESULT WINAPI testcallback_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 testcallback_AddRef(IMFAsyncCallback *iface)
-{
-    return 2;
-}
-
-static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface)
-{
-    return 1;
-}
-
-static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
-{
-    ok(flags != NULL && queue != NULL, "Unexpected arguments.\n");
-    return E_NOTIMPL;
-}
-
 static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
 {
     struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
-- 
2.20.1




More information about the wine-devel mailing list