From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 107 ++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index fe6f8cea256..86095119d19 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -23,13 +23,116 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
-static HRESULT byte_stream_plugin_create(IUnknown *outer, REFIID riid, void **out) +struct byte_stream_handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + LONG refcount; +}; + +static struct byte_stream_handler *byte_stream_handler_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct byte_stream_handler, IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI byte_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **out) { - FIXME("outer %p, riid %s, out %p stub!.\n", outer, debugstr_guid(riid), out); + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + + TRACE("handler %p, riid %s, out %p\n", handler, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMFByteStreamHandler)) + { + IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); + *out = &handler->IMFByteStreamHandler_iface; + return S_OK; + } + + WARN("Unsupported %s\n", debugstr_guid(riid)); *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI byte_stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + TRACE("handler %p, refcount %ld\n", handler, refcount); + return refcount; +} + +static ULONG WINAPI byte_stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + TRACE("handler %p, refcount %ld\n", handler, refcount); + if (!refcount) + free(handler); + return refcount; +} + +static HRESULT WINAPI byte_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + FIXME("handler %p, stream %p, url %s, flags %#lx, props %p, cookie %p, callback %p, state %p stub!\n", handler, stream, debugstr_w(url), + flags, props, cookie, callback, state); + return E_NOTIMPL; +} + +static HRESULT WINAPI byte_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *type, IUnknown **object) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + FIXME("handler %p, result %p, type %p, object %p stub!\n", handler, result, type, object); + return E_NOTIMPL; +} + +static HRESULT WINAPI byte_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + FIXME("handler %p, cookie %p, stub!\n", handler, cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI byte_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{ + struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); + FIXME("handler %p, bytes %p, stub!\n", handler, bytes); return E_NOTIMPL; }
+static const IMFByteStreamHandlerVtbl byte_stream_handler_vtbl = +{ + byte_stream_handler_QueryInterface, + byte_stream_handler_AddRef, + byte_stream_handler_Release, + byte_stream_handler_BeginCreateObject, + byte_stream_handler_EndCreateObject, + byte_stream_handler_CancelObjectCreation, + byte_stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +static HRESULT byte_stream_plugin_create(IUnknown *outer, REFIID riid, void **out) +{ + struct byte_stream_handler *handler; + HRESULT hr; + + TRACE("outer %p, riid %s, out %p\n", outer, debugstr_guid(riid), out); + + if (outer) + return CLASS_E_NOAGGREGATION; + if (!(handler = calloc(1, sizeof(*handler)))) + return E_OUTOFMEMORY; + handler->IMFByteStreamHandler_iface.lpVtbl = &byte_stream_handler_vtbl; + handler->refcount = 1; + TRACE("created %p\n", handler); + + hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, out); + IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); + return hr; +} + static BOOL use_gst_byte_stream_handler(void) { BOOL result;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 217 ++++++++++++++++++++++++++++++- dlls/mfsrcsnk/mfsrcsnk_private.h | 35 +++++ 2 files changed, 247 insertions(+), 5 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 86095119d19..8b6a015073f 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -18,11 +18,185 @@
#include "mfsrcsnk_private.h"
+#include "wine/list.h" #include "wine/debug.h" #include "wine/winedmo.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct media_source +{ + IMFMediaSource IMFMediaSource_iface; + LONG refcount; + + IMFMediaEventQueue *queue; + IMFByteStream *stream; +}; + +static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + + TRACE("source %p, riid %s, out %p\n", source, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IMFMediaSource)) + { + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + *out = &source->IMFMediaSource_iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + ULONG refcount = InterlockedIncrement(&source->refcount); + TRACE("source %p, refcount %ld\n", source, refcount); + return refcount; +} + +static ULONG WINAPI media_source_Release(IMFMediaSource *iface) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + ULONG refcount = InterlockedDecrement(&source->refcount); + + TRACE("source %p, refcount %ld\n", source, refcount); + + if (!refcount) + { + IMFMediaEventQueue_Release(source->queue); + free(source); + } + + return refcount; +} + +static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + TRACE("source %p, flags %#lx, event %p\n", source, flags, event); + return IMFMediaEventQueue_GetEvent(source->queue, flags, event); +} + +static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + TRACE("source %p, callback %p, state %p\n", source, callback, state); + return IMFMediaEventQueue_BeginGetEvent(source->queue, callback, state); +} + +static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + TRACE("source %p, result %p, event %p\n", source, result, event); + return IMFMediaEventQueue_EndGetEvent(source->queue, result, event); +} + +static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + TRACE("source %p, event_type %#lx, ext_type %s, hr %#lx, value %p\n", source, event_type, + debugstr_guid(ext_type), hr, debugstr_propvar(value)); + return IMFMediaEventQueue_QueueEventParamVar(source->queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p, characteristics %p\n", source, characteristics); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p, descriptor %p, stub!\n", source, descriptor); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, const GUID *format, + const PROPVARIANT *position) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p, descriptor %p, format %s, position %s, stub!\n", source, descriptor, + debugstr_guid(format), debugstr_propvar(position)); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p, stub!\n", source); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p, stub!\n", source); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) +{ + struct media_source *source = media_source_from_IMFMediaSource(iface); + FIXME("source %p\n", source); + return E_NOTIMPL; +} + +static const IMFMediaSourceVtbl media_source_vtbl = +{ + media_source_QueryInterface, + media_source_AddRef, + media_source_Release, + media_source_GetEvent, + media_source_BeginGetEvent, + media_source_EndGetEvent, + media_source_QueueEvent, + media_source_GetCharacteristics, + media_source_CreatePresentationDescriptor, + media_source_Start, + media_source_Stop, + media_source_Pause, + media_source_Shutdown, +}; + +static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFMediaSource **out) +{ + struct media_source *source; + HRESULT hr; + + TRACE("url %s, stream %p, out %p\n", debugstr_w(url), stream, out); + + if (!(source = calloc(1, sizeof(*source)))) + return E_OUTOFMEMORY; + source->IMFMediaSource_iface.lpVtbl = &media_source_vtbl; + source->refcount = 1; + + if (FAILED(hr = MFCreateEventQueue(&source->queue))) + { + free(source); + return hr; + } + + *out = &source->IMFMediaSource_iface; + TRACE("created source %p\n", source); + return S_OK; +} + struct byte_stream_handler { IMFByteStreamHandler IMFByteStreamHandler_iface; @@ -75,17 +249,50 @@ static HRESULT WINAPI byte_stream_handler_BeginCreateObject(IMFByteStreamHandler IPropertyStore *props, IUnknown **cookie, IMFAsyncCallback *callback, IUnknown *state) { struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); - FIXME("handler %p, stream %p, url %s, flags %#lx, props %p, cookie %p, callback %p, state %p stub!\n", handler, stream, debugstr_w(url), - flags, props, cookie, callback, state); - return E_NOTIMPL; + IMFAsyncResult *result; + IMFMediaSource *source; + HRESULT hr; + + TRACE("handler %p, stream %p, url %s, flags %#lx, props %p, cookie %p, callback %p, state %p\n", + handler, stream, debugstr_w(url), flags, props, cookie, callback, state); + + if (cookie) + *cookie = NULL; + if (!stream) + return E_INVALIDARG; + if (flags != MF_RESOLUTION_MEDIASOURCE) + FIXME("Unimplemented flags %#lx\n", flags); + + if (FAILED(hr = media_source_create(url, stream, &source))) + return hr; + if (SUCCEEDED(hr = MFCreateAsyncResult((IUnknown *)source, callback, state, &result))) + { + hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, result); + IMFAsyncResult_Release(result); + } + IMFMediaSource_Release(source); + + return hr; }
static HRESULT WINAPI byte_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, MF_OBJECT_TYPE *type, IUnknown **object) { struct byte_stream_handler *handler = byte_stream_handler_from_IMFByteStreamHandler(iface); - FIXME("handler %p, result %p, type %p, object %p stub!\n", handler, result, type, object); - return E_NOTIMPL; + HRESULT hr; + + TRACE("handler %p, result %p, type %p, object %p\n", handler, result, type, object); + + *object = NULL; + *type = MF_OBJECT_INVALID; + + if (SUCCEEDED(hr = IMFAsyncResult_GetStatus(result))) + { + hr = IMFAsyncResult_GetObject(result, object); + *type = MF_OBJECT_MEDIASOURCE; + } + + return hr; }
static HRESULT WINAPI byte_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie) diff --git a/dlls/mfsrcsnk/mfsrcsnk_private.h b/dlls/mfsrcsnk/mfsrcsnk_private.h index 6d4ef560d5b..1f0e027f358 100644 --- a/dlls/mfsrcsnk/mfsrcsnk_private.h +++ b/dlls/mfsrcsnk/mfsrcsnk_private.h @@ -20,6 +20,7 @@
#include "mfapi.h" #include "mfidl.h" +#include "mfapi.h" #include "mferror.h"
#include "wine/mfinternal.h" @@ -91,3 +92,37 @@ static inline const char *debugstr_time(LONGLONG time)
return wine_dbg_sprintf("%s", rev); } + +static inline const char *debugstr_propvar(const PROPVARIANT *v) +{ + if (!v) + return "(null)"; + + switch (v->vt) + { + case VT_EMPTY: + return wine_dbg_sprintf("%p {VT_EMPTY}", v); + case VT_NULL: + return wine_dbg_sprintf("%p {VT_NULL}", v); + case VT_UI4: + return wine_dbg_sprintf("%p {VT_UI4: %ld}", v, v->ulVal); + case VT_UI8: + return wine_dbg_sprintf("%p {VT_UI8: %s}", v, wine_dbgstr_longlong(v->uhVal.QuadPart)); + case VT_I8: + return wine_dbg_sprintf("%p {VT_I8: %s}", v, wine_dbgstr_longlong(v->hVal.QuadPart)); + case VT_R4: + return wine_dbg_sprintf("%p {VT_R4: %.8e}", v, v->fltVal); + case VT_R8: + return wine_dbg_sprintf("%p {VT_R8: %lf}", v, v->dblVal); + case VT_CLSID: + return wine_dbg_sprintf("%p {VT_CLSID: %s}", v, debugstr_guid(v->puuid)); + case VT_LPWSTR: + return wine_dbg_sprintf("%p {VT_LPWSTR: %s}", v, wine_dbgstr_w(v->pwszVal)); + case VT_VECTOR | VT_UI1: + return wine_dbg_sprintf("%p {VT_VECTOR|VT_UI1: %p}", v, v->caub.pElems); + case VT_UNKNOWN: + return wine_dbg_sprintf("%p {VT_UNKNOWN: %p}", v, v->punkVal); + default: + return wine_dbg_sprintf("%p {vt %#x}", v, v->vt); + } +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 8b6a015073f..1329787c546 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -29,8 +29,15 @@ struct media_source IMFMediaSource IMFMediaSource_iface; LONG refcount;
+ CRITICAL_SECTION cs; IMFMediaEventQueue *queue; IMFByteStream *stream; + + enum + { + SOURCE_STOPPED, + SOURCE_SHUTDOWN, + } state; };
static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *iface) @@ -75,7 +82,14 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
if (!refcount) { + IMFMediaSource_Shutdown(iface); + IMFMediaEventQueue_Release(source->queue); + IMFByteStream_Release(source->stream); + + source->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&source->cs); + free(source); }
@@ -153,8 +167,24 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = media_source_from_IMFMediaSource(iface); - FIXME("source %p\n", source); - return E_NOTIMPL; + + TRACE("source %p\n", source); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + { + LeaveCriticalSection(&source->cs); + return MF_E_SHUTDOWN; + } + source->state = SOURCE_SHUTDOWN; + + IMFMediaEventQueue_Shutdown(source->queue); + IMFByteStream_Close(source->stream); + + LeaveCriticalSection(&source->cs); + + return S_OK; }
static const IMFMediaSourceVtbl media_source_vtbl = @@ -192,6 +222,11 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM return hr; }
+ IMFByteStream_AddRef((source->stream = stream)); + + InitializeCriticalSectionEx(&source->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); + source->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + *out = &source->IMFMediaSource_iface; TRACE("created source %p\n", source); return S_OK;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 1329787c546..0a61913585c 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -130,8 +130,21 @@ static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventT static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) { struct media_source *source = media_source_from_IMFMediaSource(iface); - FIXME("source %p, characteristics %p\n", source, characteristics); - return E_NOTIMPL; + HRESULT hr; + + TRACE("source %p, characteristics %p\n", source, characteristics); + + EnterCriticalSection(&source->cs); + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + { + *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; + hr = S_OK; + } + LeaveCriticalSection(&source->cs); + + return hr; }
static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) @@ -287,6 +300,7 @@ static HRESULT WINAPI byte_stream_handler_BeginCreateObject(IMFByteStreamHandler IMFAsyncResult *result; IMFMediaSource *source; HRESULT hr; + DWORD caps;
TRACE("handler %p, stream %p, url %s, flags %#lx, props %p, cookie %p, callback %p, state %p\n", handler, stream, debugstr_w(url), flags, props, cookie, callback, state); @@ -298,6 +312,14 @@ static HRESULT WINAPI byte_stream_handler_BeginCreateObject(IMFByteStreamHandler if (flags != MF_RESOLUTION_MEDIASOURCE) FIXME("Unimplemented flags %#lx\n", flags);
+ if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps))) + return hr; + if (!(caps & MFBYTESTREAM_IS_SEEKABLE)) + { + FIXME("Non-seekable bytestreams not supported\n"); + return MF_E_BYTESTREAM_NOT_SEEKABLE; + } + if (FAILED(hr = media_source_create(url, stream, &source))) return hr; if (SUCCEEDED(hr = MFCreateAsyncResult((IUnknown *)source, callback, state, &result)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 0a61913585c..4f3d422405b 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -27,6 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); struct media_source { IMFMediaSource IMFMediaSource_iface; + IMFGetService IMFGetService_iface; LONG refcount;
CRITICAL_SECTION cs; @@ -45,6 +46,49 @@ static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *ifa return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); }
+static struct media_source *media_source_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); +} + +static HRESULT WINAPI media_source_IMFGetService_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct media_source *source = media_source_from_IMFGetService(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_IMFGetService_AddRef(IMFGetService *iface) +{ + struct media_source *source = media_source_from_IMFGetService(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_IMFGetService_Release(IMFGetService *iface) +{ + struct media_source *source = media_source_from_IMFGetService(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_IMFGetService_GetService(IMFGetService *iface, REFGUID service, + REFIID riid, void **obj) +{ + struct media_source *source = media_source_from_IMFGetService(iface); + + TRACE("source %p, service %s, riid %s, obj %p\n", source, debugstr_guid(service), debugstr_guid(riid), obj); + + FIXME("Unsupported service %s / riid %s\n", debugstr_guid(service), debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static const IMFGetServiceVtbl media_source_IMFGetService_vtbl = +{ + media_source_IMFGetService_QueryInterface, + media_source_IMFGetService_AddRef, + media_source_IMFGetService_Release, + media_source_IMFGetService_GetService, +}; + static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { struct media_source *source = media_source_from_IMFMediaSource(iface); @@ -60,6 +104,13 @@ static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID return S_OK; }
+ if (IsEqualIID(riid, &IID_IMFGetService)) + { + IMFGetService_AddRef(&source->IMFGetService_iface); + *out = &source->IMFGetService_iface; + return S_OK; + } + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); *out = NULL; return E_NOINTERFACE; @@ -227,6 +278,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM if (!(source = calloc(1, sizeof(*source)))) return E_OUTOFMEMORY; source->IMFMediaSource_iface.lpVtbl = &media_source_vtbl; + source->IMFGetService_iface.lpVtbl = &media_source_IMFGetService_vtbl; source->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&source->queue)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 4f3d422405b..3ba43f37ae6 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -28,6 +28,7 @@ struct media_source { IMFMediaSource IMFMediaSource_iface; IMFGetService IMFGetService_iface; + IMFRateSupport IMFRateSupport_iface; LONG refcount;
CRITICAL_SECTION cs; @@ -76,6 +77,16 @@ static HRESULT WINAPI media_source_IMFGetService_GetService(IMFGetService *iface
TRACE("source %p, service %s, riid %s, obj %p\n", source, debugstr_guid(service), debugstr_guid(riid), obj);
+ if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFRateSupport)) + { + IMFRateSupport_AddRef(&source->IMFRateSupport_iface); + *obj = &source->IMFRateSupport_iface; + return S_OK; + } + } + FIXME("Unsupported service %s / riid %s\n", debugstr_guid(service), debugstr_guid(riid)); *obj = NULL; return E_NOINTERFACE; @@ -89,6 +100,66 @@ static const IMFGetServiceVtbl media_source_IMFGetService_vtbl = media_source_IMFGetService_GetService, };
+static struct media_source *media_source_from_IMFRateSupport(IMFRateSupport *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface); +} + +static HRESULT WINAPI media_source_IMFRateSupport_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_IMFRateSupport_AddRef(IMFRateSupport *iface) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_IMFRateSupport_Release(IMFRateSupport *iface) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_IMFRateSupport_GetSlowestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + TRACE("source %p, direction %d, thin %d, rate %p\n", source, direction, thin, rate); + *rate = 0.0f; + return S_OK; +} + +static HRESULT WINAPI media_source_IMFRateSupport_GetFastestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + TRACE("source %p, direction %d, thin %d, rate %p\n", source, direction, thin, rate); + *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f; + return S_OK; +} + +static HRESULT WINAPI media_source_IMFRateSupport_IsRateSupported(IMFRateSupport *iface, BOOL thin, + float rate, float *nearest_rate) +{ + struct media_source *source = media_source_from_IMFRateSupport(iface); + TRACE("source %p, thin %d, rate %f, nearest_rate %p\n", source, thin, rate, nearest_rate); + if (nearest_rate) *nearest_rate = rate; + return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE; +} + +static const IMFRateSupportVtbl media_source_IMFRateSupport_vtbl = +{ + media_source_IMFRateSupport_QueryInterface, + media_source_IMFRateSupport_AddRef, + media_source_IMFRateSupport_Release, + media_source_IMFRateSupport_GetSlowestRate, + media_source_IMFRateSupport_GetFastestRate, + media_source_IMFRateSupport_IsRateSupported, +}; + static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { struct media_source *source = media_source_from_IMFMediaSource(iface); @@ -279,6 +350,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM return E_OUTOFMEMORY; source->IMFMediaSource_iface.lpVtbl = &media_source_vtbl; source->IMFGetService_iface.lpVtbl = &media_source_IMFGetService_vtbl; + source->IMFRateSupport_iface.lpVtbl = &media_source_IMFRateSupport_vtbl; source->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&source->queue)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 3ba43f37ae6..95430a21d6b 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -29,11 +29,13 @@ struct media_source IMFMediaSource IMFMediaSource_iface; IMFGetService IMFGetService_iface; IMFRateSupport IMFRateSupport_iface; + IMFRateControl IMFRateControl_iface; LONG refcount;
CRITICAL_SECTION cs; IMFMediaEventQueue *queue; IMFByteStream *stream; + float rate;
enum { @@ -85,6 +87,12 @@ static HRESULT WINAPI media_source_IMFGetService_GetService(IMFGetService *iface *obj = &source->IMFRateSupport_iface; return S_OK; } + if (IsEqualIID(riid, &IID_IMFRateControl)) + { + IMFRateControl_AddRef(&source->IMFRateControl_iface); + *obj = &source->IMFRateControl_iface; + return S_OK; + } }
FIXME("Unsupported service %s / riid %s\n", debugstr_guid(service), debugstr_guid(riid)); @@ -160,6 +168,76 @@ static const IMFRateSupportVtbl media_source_IMFRateSupport_vtbl = media_source_IMFRateSupport_IsRateSupported, };
+static struct media_source *media_source_from_IMFRateControl(IMFRateControl *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface); +} + +static HRESULT WINAPI media_source_IMFRateControl_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj) +{ + struct media_source *source = media_source_from_IMFRateControl(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_IMFRateControl_AddRef(IMFRateControl *iface) +{ + struct media_source *source = media_source_from_IMFRateControl(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_IMFRateControl_Release(IMFRateControl *iface) +{ + struct media_source *source = media_source_from_IMFRateControl(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_IMFRateControl_SetRate(IMFRateControl *iface, BOOL thin, float rate) +{ + struct media_source *source = media_source_from_IMFRateControl(iface); + HRESULT hr; + + FIXME("source %p, thin %d, rate %f, stub!\n", source, thin, rate); + + if (rate < 0.0f) + return MF_E_REVERSE_UNSUPPORTED; + if (thin) + return MF_E_THINNING_UNSUPPORTED; + + if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) + return hr; + + EnterCriticalSection(&source->cs); + source->rate = rate; + LeaveCriticalSection(&source->cs); + + return IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); +} + +static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) +{ + struct media_source *source = media_source_from_IMFRateControl(iface); + + TRACE("source %p, thin %p, rate %p\n", source, thin, rate); + + if (thin) + *thin = FALSE; + + EnterCriticalSection(&source->cs); + *rate = source->rate; + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +static const IMFRateControlVtbl media_source_IMFRateControl_vtbl = +{ + media_source_IMFRateControl_QueryInterface, + media_source_IMFRateControl_AddRef, + media_source_IMFRateControl_Release, + media_source_IMFRateControl_SetRate, + media_source_IMFRateControl_GetRate, +}; + static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { struct media_source *source = media_source_from_IMFMediaSource(iface); @@ -351,6 +429,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM source->IMFMediaSource_iface.lpVtbl = &media_source_vtbl; source->IMFGetService_iface.lpVtbl = &media_source_IMFGetService_vtbl; source->IMFRateSupport_iface.lpVtbl = &media_source_IMFRateSupport_vtbl; + source->IMFRateControl_iface.lpVtbl = &media_source_IMFRateControl_vtbl; source->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&source->queue))) @@ -361,6 +440,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM
IMFByteStream_AddRef((source->stream = stream));
+ source->rate = 1.0f; InitializeCriticalSectionEx(&source->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); source->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");