mfplat: Use file url scheme as a fallback.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2019-05-02 17:09:09 +03:00 committed by Alexandre Julliard
parent 9e948c47f6
commit 75def3a11e
2 changed files with 186 additions and 93 deletions

View File

@ -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);

View File

@ -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);