Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 75 +++++++++++++++++++++++++++++++------- dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/tests/mfplat.c | 15 ++++++++ 3 files changed, 77 insertions(+), 14 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 4082f9e2ac..b0db0db922 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -48,13 +48,22 @@ static LONG platform_lock; struct local_handler { struct list entry; - WCHAR *scheme; + union + { + WCHAR *scheme; + struct + { + WCHAR *extension; + WCHAR *mime; + } bytestream; + } u; IMFActivate *activate; };
static CRITICAL_SECTION local_handlers_section = { NULL, -1, 0, 0, 0, 0 };
static struct list local_scheme_handlers = LIST_INIT(local_scheme_handlers); +static struct list local_bytestream_handlers = LIST_INIT(local_bytestream_handlers);
struct system_clock { @@ -7154,21 +7163,25 @@ static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl = async_create_file_callback_Invoke, };
-static WCHAR *heap_strdupW(const WCHAR *str) +static HRESULT heap_strdupW(const WCHAR *str, WCHAR **dest) { - WCHAR *ret = NULL; + HRESULT hr = S_OK;
if (str) { unsigned int size;
size = (strlenW(str) + 1) * sizeof(WCHAR); - ret = heap_alloc(size); - if (ret) - memcpy(ret, str, size); + *dest = heap_alloc(size); + if (*dest) + memcpy(*dest, str, size); + else + hr = E_OUTOFMEMORY; } + else + *dest = NULL;
- return ret; + return hr; }
/*********************************************************************** @@ -7202,12 +7215,8 @@ HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMOD async->access_mode = access_mode; async->open_mode = open_mode; async->flags = flags; - async->path = heap_strdupW(path); - if (!async->path) - { - hr = E_OUTOFMEMORY; + if (FAILED(hr = heap_strdupW(path, &async->path))) goto failed; - }
hr = MFCreateAsyncResult(NULL, &async->IMFAsyncCallback_iface, (IUnknown *)caller, &item); if (FAILED(hr)) @@ -7301,6 +7310,7 @@ HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie) HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *activate) { struct local_handler *handler; + HRESULT hr;
TRACE("%s, %p.\n", debugstr_w(scheme), activate);
@@ -7310,10 +7320,10 @@ HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *ac if (!(handler = heap_alloc(sizeof(*handler)))) return E_OUTOFMEMORY;
- if (!(handler->scheme = heap_strdupW(scheme))) + if (FAILED(hr = heap_strdupW(scheme, &handler->u.scheme))) { heap_free(handler); - return E_OUTOFMEMORY; + return hr; } handler->activate = activate; IMFActivate_AddRef(handler->activate); @@ -7324,3 +7334,40 @@ HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *ac
return S_OK; } + +/*********************************************************************** + * MFRegisterLocalByteStreamHandler (mfplat.@) + */ +HRESULT WINAPI MFRegisterLocalByteStreamHandler(const WCHAR *extension, const WCHAR *mime, IMFActivate *activate) +{ + struct local_handler *handler; + HRESULT hr; + + TRACE("%s, %s, %p.\n", debugstr_w(extension), debugstr_w(mime), activate); + + if ((!extension && !mime) || !activate) + return E_INVALIDARG; + + if (!(handler = heap_alloc_zero(sizeof(*handler)))) + return E_OUTOFMEMORY; + + hr = heap_strdupW(extension, &handler->u.bytestream.extension); + if (SUCCEEDED(hr)) + hr = heap_strdupW(mime, &handler->u.bytestream.mime); + + if (FAILED(hr)) + goto failed; + + EnterCriticalSection(&local_handlers_section); + list_add_head(&local_bytestream_handlers, &handler->entry); + LeaveCriticalSection(&local_handlers_section); + + return hr; + +failed: + heap_free(handler->u.bytestream.extension); + heap_free(handler->u.bytestream.mime); + heap_free(handler); + + return hr; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 2dfa92f202..1ae0927f51 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -128,6 +128,7 @@ @ stdcall MFPutWorkItemEx(long ptr) @ stdcall MFPutWorkItemEx2(long long ptr) @ stub MFRecordError +@ stdcall MFRegisterLocalByteStreamHandler(wstr wstr ptr) @ stdcall MFRegisterLocalSchemeHandler(wstr ptr) @ stdcall MFRemovePeriodicCallback(long) @ stdcall MFScheduleWorkItem(ptr ptr int64 ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index ab651c54f2..e63efc154b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3591,6 +3591,21 @@ static void test_local_handlers(void)
hr = pMFRegisterLocalSchemeHandler(localW, &local_activate); ok(hr == S_OK, "Failed to register scheme handler, hr %#x.\n", hr); + + hr = pMFRegisterLocalByteStreamHandler(NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = pMFRegisterLocalByteStreamHandler(NULL, NULL, &local_activate); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = pMFRegisterLocalByteStreamHandler(NULL, localW, &local_activate); + ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr); + + hr = pMFRegisterLocalByteStreamHandler(localW, NULL, &local_activate); + ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr); + + hr = pMFRegisterLocalByteStreamHandler(localW, localW, &local_activate); + ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr); }
START_TEST(mfplat)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index b0db0db922..cf313d7a21 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -5093,12 +5093,34 @@ static HRESULT resolver_create_scheme_handler(const WCHAR *scheme, DWORD flags, { static const char schemehandlerspath[] = "Software\Microsoft\Windows Media Foundation\SchemeHandlers"; static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; + HRESULT hr = MF_E_UNSUPPORTED_SCHEME; unsigned int i; - HRESULT hr;
TRACE("%s, %#x, %p.\n", debugstr_w(scheme), flags, handler);
- /* FIXME: check local handlers first */ + *handler = NULL; + + if (!(flags & MF_RESOLUTION_DISABLE_LOCAL_PLUGINS)) + { + struct local_handler *local_handler; + + EnterCriticalSection(&local_handlers_section); + + LIST_FOR_EACH_ENTRY(local_handler, &local_scheme_handlers, struct local_handler, entry) + { + if (!lstrcmpiW(scheme, local_handler->u.scheme)) + { + if (SUCCEEDED(hr = IMFActivate_ActivateObject(local_handler->activate, &IID_IMFSchemeHandler, + (void **)handler))) + break; + } + } + + LeaveCriticalSection(&local_handlers_section); + + if (*handler) + return hr; + }
for (i = 0; i < ARRAY_SIZE(hkey_roots); ++i) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=53504
Your paranoid android.
=== debian9 (64 bit WoW report) ===
mfplat: mfplat.c:2866: Test failed: Unexpected refcount 1. Unhandled exception: page fault on read access to 0x00000009 in 32-bit code (0x7ed8a0e2).
Report errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index cf313d7a21..f2157b5f2c 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -5032,9 +5032,9 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA IMFAttributes *attributes; const WCHAR *url_ext; WCHAR *mimeW = NULL; + HRESULT hr = E_FAIL; unsigned int i, j; UINT32 length; - HRESULT hr;
*handler = NULL;
@@ -5054,7 +5054,28 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA return MF_E_UNSUPPORTED_BYTESTREAM_TYPE; }
- /* FIXME: check local handlers first */ + if (!(flags & MF_RESOLUTION_DISABLE_LOCAL_PLUGINS)) + { + struct local_handler *local_handler; + + EnterCriticalSection(&local_handlers_section); + + 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 (SUCCEEDED(hr = IMFActivate_ActivateObject(local_handler->activate, &IID_IMFByteStreamHandler, + (void **)handler))) + break; + } + } + + LeaveCriticalSection(&local_handlers_section); + + if (*handler) + return hr; + }
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 42 ++++++++++++++++++++++++++++++++++------- include/mfidl.idl | 17 +++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 9cf94654e5..7bc566f542 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -66,6 +66,7 @@ struct sample_grabber_stream LONG refcount; struct sample_grabber *sink; IMFMediaEventQueue *event_queue; + IMFAttributes *sample_attributes; enum sink_state state; struct list items; IUnknown *cancel_key; @@ -79,6 +80,7 @@ struct sample_grabber IMFMediaEventGenerator IMFMediaEventGenerator_iface; LONG refcount; IMFSampleGrabberSinkCallback *callback; + IMFSampleGrabberSinkCallback2 *callback2; IMFMediaType *media_type; BOOL is_shut_down; struct sample_grabber_stream *stream; @@ -90,6 +92,11 @@ struct sample_grabber CRITICAL_SECTION cs; };
+static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink) +{ + return sink->callback2 ? (IMFSampleGrabberSinkCallback *)sink->callback2 : sink->callback; +} + struct sample_grabber_activate_context { IMFMediaType *media_type; @@ -209,6 +216,8 @@ static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface) IMFMediaEventQueue_Shutdown(stream->event_queue); IMFMediaEventQueue_Release(stream->event_queue); } + if (stream->sample_attributes) + IMFAttributes_Release(stream->sample_attributes); LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &stream->items, struct scheduled_item, entry) { stream_release_pending_item(item); @@ -333,8 +342,16 @@ static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFS
if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size))) { - hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time, - sample_duration, data, size); + if (grabber->callback2) + { + hr = IMFSample_CopyAllItems(sample, grabber->stream->sample_attributes); + if (SUCCEEDED(hr)) + hr = IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber->callback2, &major_type, flags, + sample_time, sample_duration, data, size, grabber->stream->sample_attributes); + } + else + hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time, + sample_duration, data, size); IMFMediaBuffer_Unlock(buffer); }
@@ -814,7 +831,10 @@ static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
if (!refcount) { - IMFSampleGrabberSinkCallback_Release(grabber->callback); + if (grabber->callback) + IMFSampleGrabberSinkCallback_Release(grabber->callback); + if (grabber->callback2) + IMFSampleGrabberSinkCallback2_Release(grabber->callback2); IMFMediaType_Release(grabber->media_type); if (grabber->event_queue) { @@ -941,7 +961,8 @@ static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *ifa
EnterCriticalSection(&grabber->cs);
- if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(grabber->callback, clock))) + if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber), + clock))) { if (grabber->clock) { @@ -1008,7 +1029,7 @@ static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
EnterCriticalSection(&grabber->cs); grabber->is_shut_down = TRUE; - if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(grabber->callback))) + if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber)))) { IMFMediaSink_Release(&grabber->stream->sink->IMFMediaSink_iface); EnterCriticalSection(&grabber->stream->cs); @@ -1246,6 +1267,9 @@ static HRESULT sample_grabber_create_stream(struct sample_grabber *sink, struct if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto failed;
+ if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0))) + goto failed; + *stream = object;
return S_OK; @@ -1277,8 +1301,12 @@ static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *use object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl; object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl; object->refcount = 1; - object->callback = context->callback; - IMFSampleGrabberSinkCallback_AddRef(object->callback); + if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2, + (void **)&object->callback2))) + { + object->callback = context->callback; + IMFSampleGrabberSinkCallback_AddRef(object->callback); + } object->media_type = context->media_type; IMFMediaType_AddRef(object->media_type); IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock); diff --git a/include/mfidl.idl b/include/mfidl.idl index 4968bf9aa7..66a84771a7 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -549,6 +549,23 @@ interface IMFSampleGrabberSinkCallback : IMFClockStateSink HRESULT OnShutdown(); }
+[ + object, + uuid(ca86aa50-c46e-429e-ab27-16d6ac6844cb), + local +] +interface IMFSampleGrabberSinkCallback2 : IMFSampleGrabberSinkCallback +{ + HRESULT OnProcessSampleEx( + [in] REFGUID major_type, + [in] DWORD sample_flags, + [in] LONGLONG sample_time, + [in] LONGLONG sample_duration, + [in] const BYTE *buffer, + [in] DWORD sample_size, + [in] IMFAttributes *attributes); +} + cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);") cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" ) cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 7bc566f542..af9666c86c 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -1127,7 +1127,7 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *
sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
- return S_OK; + return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset); }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) @@ -1138,14 +1138,16 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *i
sample_grabber_set_state(grabber, SINK_STATE_STOPPED);
- return S_OK; + return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime); }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) { + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(systime));
- return S_OK; + return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime); }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) @@ -1156,14 +1158,16 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
- return S_OK; + return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber), systime); }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) { - FIXME("%p, %s, %f.\n", iface, wine_dbgstr_longlong(systime), rate); + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
- return E_NOTIMPL; + TRACE("%p, %s, %f.\n", iface, wine_dbgstr_longlong(systime), rate); + + return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate); }
static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)