Nikolay Sivov : mfplat: Better handle source resolution when content type is not specified for the stream.

Alexandre Julliard julliard at winehq.org
Thu Feb 10 16:10:29 CST 2022


Module: wine
Branch: master
Commit: 3a8bdf8bdc211ae8e8d38500d7a88fad1aef0d7d
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=3a8bdf8bdc211ae8e8d38500d7a88fad1aef0d7d

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Thu Feb 10 11:21:28 2022 +0300

mfplat: Better handle source resolution when content type is not specified for the stream.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mfplat/main.c | 190 +++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 154 insertions(+), 36 deletions(-)

diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 7a1f10dac24..72dd0915447 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -6159,40 +6159,15 @@ static HRESULT resolver_create_registered_handler(HKEY hkey, REFIID riid, void *
     return hr;
 }
 
-static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags,
-        IMFByteStreamHandler **handler)
+static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD flags, const WCHAR *mime,
+        const WCHAR *extension, IMFByteStreamHandler **handler)
 {
     static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
-    WCHAR *mimeW = NULL, *urlW = NULL;
-    IMFAttributes *attributes;
-    const WCHAR *url_ext;
     HRESULT hr = E_FAIL;
     unsigned int i, j;
-    UINT32 length;
 
     *handler = NULL;
 
-    /* MIME type */
-    if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
-    {
-        IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length);
-        if (!url)
-        {
-            IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &urlW, &length);
-            url = urlW;
-        }
-        IMFAttributes_Release(attributes);
-    }
-
-    /* Extension */
-    url_ext = url ? wcsrchr(url, '.') : NULL;
-
-    if (!url_ext && !mimeW)
-    {
-        CoTaskMemFree(urlW);
-        return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
-    }
-
     if (!(flags & MF_RESOLUTION_DISABLE_LOCAL_PLUGINS))
     {
         struct local_handler *local_handler;
@@ -6201,8 +6176,8 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
 
         LIST_FOR_EACH_ENTRY(local_handler, &local_bytestream_handlers, struct local_handler, entry)
         {
-            if ((mimeW && !lstrcmpiW(mimeW, local_handler->u.bytestream.mime))
-                    || (url_ext && !lstrcmpiW(url_ext, local_handler->u.bytestream.extension)))
+            if ((mime && !lstrcmpiW(mime, local_handler->u.bytestream.mime))
+                    || (extension && !lstrcmpiW(extension, local_handler->u.bytestream.extension)))
             {
                 if (SUCCEEDED(hr = IMFActivate_ActivateObject(local_handler->activate, &IID_IMFByteStreamHandler,
                         (void **)handler)))
@@ -6213,16 +6188,12 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
         LeaveCriticalSection(&local_handlers_section);
 
         if (*handler)
-        {
-            CoTaskMemFree(mimeW);
-            CoTaskMemFree(urlW);
             return hr;
-        }
     }
 
     for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i)
     {
-        const WCHAR *namesW[2] = { mimeW, url_ext };
+        const WCHAR *namesW[2] = { mime, extension };
         HKEY hkey, hkey_handler;
 
         if (RegOpenKeyW(hkey_roots[i], L"Software\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", &hkey))
@@ -6249,14 +6220,161 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
             break;
     }
 
+    return hr;
+}
+
+static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR const **url)
+{
+    static const unsigned char asfmagic[]  = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
+    static const unsigned char wavmagic[]  = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
+    static const unsigned char wavmask[]   = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+    static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
+    static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00};
+    static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
+    static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00};
+    static const unsigned char mp4mask[]   = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
+    static const struct stream_content_url_hint
+    {
+        const unsigned char *magic;
+        const WCHAR *url;
+        const unsigned char *mask;
+    }
+    url_hints[] =
+    {
+        { asfmagic,  L".asf" },
+        { wavmagic,  L".wav", wavmask },
+        { isommagic, L".mp4", mp4mask },
+        { mp42magic, L".mp4", mp4mask },
+        { mp4_magic, L".mp4", mp4mask },
+        { mp4vmagic, L".m4v", mp4mask },
+    };
+    unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)];
+    IMFAttributes *attributes;
+    DWORD length = 0, caps = 0;
+    unsigned int i, j;
+    QWORD position;
+    HRESULT hr;
+
+    *url = NULL;
+
+    if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
+    {
+        UINT32 string_length = 0;
+        IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &string_length);
+        IMFAttributes_Release(attributes);
+
+        if (string_length)
+            return S_OK;
+    }
+
+    if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
+        return hr;
+
+    if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
+        return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
+
+    if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
+        return hr;
+
+    hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
+    IMFByteStream_SetCurrentPosition(stream, position);
     if (FAILED(hr))
+        return hr;
+
+    if (length < sizeof(buffer))
+        return S_OK;
+
+    for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
+    {
+        memcpy(pattern, buffer, sizeof(buffer));
+        if (url_hints[i].mask)
+        {
+            unsigned int *mask = (unsigned int *)url_hints[i].mask;
+            unsigned int *data = (unsigned int *)pattern;
+
+            for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
+                data[j] &= mask[j];
+
+        }
+        if (!memcmp(pattern, url_hints[i].magic, sizeof(pattern)))
+        {
+            *url = url_hints[i].url;
+            break;
+        }
+    }
+
+    if (*url)
+        TRACE("Content type guessed as %s from %s.\n", debugstr_w(*url), debugstr_an((char *)buffer, length));
+    else
+        WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
+
+    return S_OK;
+}
+
+static HRESULT resolver_create_gstreamer_handler(IMFByteStreamHandler **handler)
+{
+    static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
+    return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler);
+}
+
+static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags,
+        IMFByteStreamHandler **handler)
+{
+    WCHAR *mimeW = NULL, *urlW = NULL;
+    IMFAttributes *attributes;
+    const WCHAR *url_ext;
+    HRESULT hr = E_FAIL;
+    UINT32 length;
+
+    *handler = NULL;
+
+    /* MIME type */
+    if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
     {
-        static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
-        hr = CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler);
+        IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length);
+        if (!url)
+        {
+            IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &urlW, &length);
+            url = urlW;
+        }
+        IMFAttributes_Release(attributes);
+    }
+
+    /* Extension */
+    url_ext = url ? wcsrchr(url, '.') : NULL;
+
+    /* If content type was provided by the caller, it's tried first. Otherwise an attempt to deduce
+       content type from the content itself is made.
+
+       TODO: wine specific fallback to predefined handler could be replaced by normally registering
+       this handler for all possible types.
+     */
+
+    if (url_ext || mimeW)
+    {
+        hr = resolver_create_bytestream_handler(stream, flags, mimeW, url_ext, handler);
+
+        if (FAILED(hr))
+            hr = resolver_create_gstreamer_handler(handler);
     }
 
     CoTaskMemFree(mimeW);
     CoTaskMemFree(urlW);
+
+    if (SUCCEEDED(hr))
+        return hr;
+
+    if (!(flags & MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE))
+        return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
+
+    if (FAILED(hr = resolver_get_bytestream_url_hint(stream, &url_ext)))
+        return hr;
+
+    hr = resolver_create_bytestream_handler(stream, flags, NULL, url_ext, handler);
+
+    if (FAILED(hr))
+        hr = resolver_create_gstreamer_handler(handler);
+
     return hr;
 }
 




More information about the wine-cvs mailing list