From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/Makefile.in | 2 +- dlls/mf/main.c | 2 + dlls/mf/mf.idl | 6 +++ dlls/mf/mf.rgs | 8 ++++ dlls/mf/mf_private.h | 1 + dlls/mf/scheme_handler.c | 84 +++++++++++++++++++++++++++++++++++----- dlls/mf/tests/mf.c | 4 +- 7 files changed, 93 insertions(+), 14 deletions(-)
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 870ca7cbcba..b400f19b3a5 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -1,6 +1,6 @@ MODULE = mf.dll IMPORTLIB = mf -IMPORTS = advapi32 mfplat ole32 uuid mfuuid strmiids +IMPORTS = advapi32 mfplat ole32 uuid mfuuid strmiids urlmon DELAYIMPORTS = evr user32
EXTRADLLFLAGS = -Wb,--prefer-native diff --git a/dlls/mf/main.c b/dlls/mf/main.c index b25a47d78c0..92558a86b30 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -549,6 +549,7 @@ static const IClassFactoryVtbl class_factory_vtbl = };
static struct class_factory file_scheme_handler_factory = { { &class_factory_vtbl }, file_scheme_handler_construct }; +static struct class_factory urlmon_scheme_handler_factory = { { &class_factory_vtbl }, urlmon_scheme_handler_construct };
static const struct class_object { @@ -558,6 +559,7 @@ static const struct class_object class_objects[] = { { &CLSID_FileSchemePlugin, &file_scheme_handler_factory.IClassFactory_iface }, + { &CLSID_UrlmonSchemePlugin, &urlmon_scheme_handler_factory.IClassFactory_iface }, };
/******************************************************************************* diff --git a/dlls/mf/mf.idl b/dlls/mf/mf.idl index 289a521b4f2..4f5ef36c965 100644 --- a/dlls/mf/mf.idl +++ b/dlls/mf/mf.idl @@ -24,3 +24,9 @@ uuid(477ec299-1421-4bdd-971f-7ccb933f21ad) ] coclass FileSchemePlugin { } + +[ + threading(both), + uuid(9ec4b4f9-3029-45ad-947b-344de2a249e2) +] +coclass UrlmonSchemePlugin {} diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs index f127df76321..f06576baccb 100644 --- a/dlls/mf/mf.rgs +++ b/dlls/mf/mf.rgs @@ -12,6 +12,14 @@ HKLM { val '{477ec299-1421-4bdd-971f-7ccb933f21ad}' = s 'File Scheme Handler' } + 'http:' + { + val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler' + } + 'https:' + { + val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler' + } } } } diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 90ad8eaf8b7..bbfadaee5d8 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -114,6 +114,7 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v) }
extern HRESULT file_scheme_handler_construct(REFIID riid, void **obj); +extern HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj);
extern BOOL mf_is_sample_copier_transform(IMFTransform *transform); extern BOOL mf_is_sar_sink(IMFMediaSink *sink); diff --git a/dlls/mf/scheme_handler.c b/dlls/mf/scheme_handler.c index 9f23ffcc76c..b2b9abbe5ac 100644 --- a/dlls/mf/scheme_handler.c +++ b/dlls/mf/scheme_handler.c @@ -32,6 +32,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+typedef HRESULT (*resolve_cb)(const WCHAR *url, DWORD flags, IMFByteStream **out); + struct scheme_handler_result { struct list entry; @@ -48,6 +50,7 @@ struct scheme_handler IMFSourceResolver *resolver; struct list results; CRITICAL_SECTION cs; + resolve_cb resolve; };
static struct scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) @@ -374,7 +377,6 @@ static HRESULT scheme_handler_get_resolver(struct scheme_handler *handler, IMFSo
static HRESULT WINAPI scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { - static const WCHAR schemeW[] = {'f','i','l','e',':','/','/'}; struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface); struct scheme_handler_result *handler_result; MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; @@ -383,7 +385,6 @@ static HRESULT WINAPI scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IM IMFSourceResolver *resolver; IMFAsyncResult *caller; IMFByteStream *stream; - const WCHAR *url; HRESULT hr;
caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); @@ -396,14 +397,7 @@ static HRESULT WINAPI scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IM
context = impl_from_IUnknown(context_object);
- /* Strip from scheme, MFCreateFile() won't be expecting it. */ - url = context->url; - if (!wcsnicmp(context->url, schemeW, ARRAY_SIZE(schemeW))) - url += ARRAY_SIZE(schemeW); - - hr = MFCreateFile(context->flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, - MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, url, &stream); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr = handler->resolve(context->url, context->flags, &stream))) { if (context->flags & MF_RESOLUTION_MEDIASOURCE) { @@ -458,6 +452,14 @@ static const IMFAsyncCallbackVtbl scheme_handler_callback_vtbl = scheme_handler_callback_Invoke, };
+static HRESULT file_scheme_handler_resolve(const WCHAR *url, DWORD flags, IMFByteStream **out) +{ + if (!wcsnicmp(url, L"file://", 7)) + url += 7; + return MFCreateFile(flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, + MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, url, out); +} + HRESULT file_scheme_handler_construct(REFIID riid, void **obj) { struct scheme_handler *handler; @@ -473,6 +475,68 @@ HRESULT file_scheme_handler_construct(REFIID riid, void **obj) handler->refcount = 1; list_init(&handler->results); InitializeCriticalSection(&handler->cs); + handler->resolve = file_scheme_handler_resolve; + + hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); + IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); + + return hr; +} + +static HRESULT urlmon_scheme_handler_resolve(const WCHAR *url, DWORD flags, IMFByteStream **out) +{ + IStream *stream; + HRESULT hr; + + if (flags & MF_RESOLUTION_WRITE) + return E_INVALIDARG; + + if (FAILED(hr = URLOpenBlockingStreamW(NULL, url, &stream, 0, NULL))) + { + WARN("Failed to open url %s, hr %#lx\n", debugstr_w(url), hr); + return hr; + } + + if (FAILED(hr = MFCreateMFByteStreamOnStream(stream, out))) + WARN("Failed to create IMFByteStream from IStream, hr %#lx\n", hr); + else + { + IMFAttributes *attributes; + + if (FAILED(IMFByteStream_QueryInterface(*out, &IID_IMFAttributes, (void **)&attributes))) + WARN("Failed to get IMFAttributes interface\n"); + else + { + if (FAILED(IMFAttributes_DeleteItem(attributes, &MF_BYTESTREAM_ORIGIN_NAME))) + WARN("Failed to delete MF_BYTESTREAM_ORIGIN_NAME attribute\n"); + if (FAILED(IMFAttributes_SetString(attributes, &MF_BYTESTREAM_EFFECTIVE_URL, url))) + WARN("Failed to set MF_BYTESTREAM_EFFECTIVE_URL attribute\n"); + if (FAILED(IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, L"application/octet-stream"))) + WARN("Failed to set MF_BYTESTREAM_CONTENT_TYPE attribute\n"); + IMFAttributes_Release(attributes); + } + } + + IStream_Release(stream); + return hr; +} + +HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj) +{ + struct scheme_handler *handler; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(handler = calloc(1, sizeof(*handler)))) + return E_OUTOFMEMORY; + + handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl; + handler->IMFAsyncCallback_iface.lpVtbl = &scheme_handler_callback_vtbl; + handler->refcount = 1; + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); + handler->resolve = urlmon_scheme_handler_resolve;
hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 41e943757e2..1c5ac065b84 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6472,7 +6472,7 @@ static void test_scheme_resolvers(void) for (i = 0; i < ARRAY_SIZE(urls); i++) { hr = IMFSourceResolver_CreateObjectFromURL(resolver, urls[i], MF_RESOLUTION_BYTESTREAM, NULL, &type, &object); - todo_wine + todo_wine_if(i >= 2) ok(hr == S_OK, "got hr %#lx\n", hr); if (hr != S_OK) continue; @@ -6485,7 +6485,6 @@ static void test_scheme_resolvers(void) PropVariantInit(&propvar); hr = IMFAttributes_GetItem(attributes, &MF_BYTESTREAM_EFFECTIVE_URL, &propvar); ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Win7 */, "got hr %#lx\n", hr); - todo_wine ok(broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Win7 */ || !wcscmp(expect_urls[2 * i + 0], propvar.pwszVal) || !wcscmp(expect_urls[2 * i + 1], propvar.pwszVal), @@ -6494,7 +6493,6 @@ static void test_scheme_resolvers(void) ok(hr == S_OK, "got hr %#lx\n", hr);
hr = IMFAttributes_GetItem(attributes, &MF_BYTESTREAM_CONTENT_TYPE, NULL); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); hr = IMFAttributes_GetItem(attributes, &MF_BYTESTREAM_LAST_MODIFIED_TIME, NULL); todo_wine