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:
parent
9e948c47f6
commit
75def3a11e
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue