Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/Makefile.in | 4 +- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 413 ++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 dlls/winegstreamer/media_source.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 2050a44b13..b00ce2586e 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -2,14 +2,16 @@ MODULE = winegstreamer.dll IMPORTS = strmiids uuid winmm msacm32 msvfw32 ole32 oleaut32 user32 gdi32 advapi32 mfplat mfuuid EXTRAINCL = $(GSTREAMER_CFLAGS) EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) -PARENTSRC = ../strmbase +PARENTSRC = ../strmbase ../mf
C_SRCS = \ dllfunc.c \ filter.c \ gst_cbs.c \ gstdemux.c \ + handler.c \ main.c \ + media_source.c \ mediatype.c \ mfplat.c \ pin.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 353ff0bbd5..8b11760740 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -47,4 +47,6 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN; extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; extern HRESULT mfplat_can_unload_now(void) DECLSPEC_HIDDEN;
+HRESULT container_stream_handler_construct(REFIID riid, void **obj, const char *demuxer_name); + #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c new file mode 100644 index 0000000000..dc5405b89e --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,413 @@ +#include "gst_private.h" +#include "handler.h" + +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION + +#include "mfapi.h" +#include "mferror.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +struct media_source +{ + IMFMediaSource IMFMediaSource_iface; + LONG ref; + IMFMediaEventQueue *event_queue; + enum + { + SOURCE_OPENING, + SOURCE_STOPPED, + SOURCE_PAUSED, + SOURCE_RUNNING, + SOURCE_SHUTDOWN, + } state; +}; + +/* source */ + +static inline struct media_source *impl_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 *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaSource) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &This->IMFMediaSource_iface; + } + else + { + FIXME("(%s, %p)\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%u\n", This, ref); + + return ref; +} + +static ULONG WINAPI media_source_Release(IMFMediaSource *iface) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%u\n", This, ref); + + if (!ref) + { + if (This->state != SOURCE_SHUTDOWN) + ERR("Application has freed media source without calling ::Shutdown\n"); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%#x, %p)\n", This, flags, event); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return IMFMediaEventQueue_GetEvent(This->event_queue, flags, event); +} + +static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%p, %p)\n", This, callback, state); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return IMFMediaEventQueue_BeginGetEvent(This->event_queue, callback, state); +} + +static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%p, %p)\n", This, result, event); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return IMFMediaEventQueue_EndGetEvent(This->event_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 *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%d, %s, %#x, %p)\n", This, event_type, debugstr_guid(ext_type), hr, value); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return IMFMediaEventQueue_QueueEventParamVar(This->event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + FIXME("(%p)->(%p): stub\n", This, characteristics); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + FIXME("(%p)->(%p): stub\n", This, descriptor); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, + const GUID *time_format, const PROPVARIANT *start_position) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + PROPVARIANT empty_var; + empty_var.vt = VT_EMPTY; + + FIXME("(%p)->(%p, %p, %p): stub\n", This, descriptor, time_format, start_position); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + FIXME("(%p): stub\n", This); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + FIXME("(%p): stub\n", This); + + if (This->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + return E_NOTIMPL; +} + +static HRESULT media_source_teardown(struct media_source *This) +{ + if (This->event_queue) + IMFMediaEventQueue_Release(This->event_queue); + + return S_OK; +} + +static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) +{ + struct media_source *This = impl_from_IMFMediaSource(iface); + + TRACE("(%p)\n", This); + + This->state = SOURCE_SHUTDOWN; + return media_source_teardown(This); +} + +static const IMFMediaSourceVtbl IMFMediaSource_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_constructor(IMFByteStream *bytestream, const char *demuxer_name, struct media_source **out_media_source) +{ + HRESULT hr; + int ret; + struct media_source *This = heap_alloc_zero(sizeof(*This)); + + if (!This) + return E_OUTOFMEMORY; + + This->state = SOURCE_OPENING; + + if (FAILED(hr = MFCreateEventQueue(&This->event_queue))) + goto fail; + + This->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; + This->ref = 1; + + *out_media_source = This; + return S_OK; + + fail: + WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); + + media_source_teardown(This); + heap_free(This); + return hr; +} + +/* IMFByteStreamHandler */ + +struct container_stream_handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + LONG refcount; + const char *demuxer_name; + struct handler handler; +}; + +static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI container_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFByteStreamHandler) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFByteStreamHandler_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI container_stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + + TRACE("%p, refcount %u.\n", handler, refcount); + + return refcount; +} + +static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&this->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + handler_destruct(&this->handler); + } + + return refcount; +} + +static HRESULT WINAPI container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); + return handler_begin_create_object(&this->handler, stream, url, flags, props, cancel_cookie, callback, state); +} + +static HRESULT WINAPI container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); + return handler_end_create_object(&this->handler, result, obj_type, object); +} + +static HRESULT WINAPI container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %p.\n", iface, cancel_cookie); + return handler_cancel_object_creation(&this->handler, cancel_cookie); +} + +static HRESULT WINAPI container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{ + FIXME("stub (%p %p)\n", iface, bytes); + return E_NOTIMPL; +} + +static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl = +{ + container_stream_handler_QueryInterface, + container_stream_handler_AddRef, + container_stream_handler_Release, + container_stream_handler_BeginCreateObject, + container_stream_handler_EndCreateObject, + container_stream_handler_CancelObjectCreation, + container_stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +static HRESULT container_stream_handler_create_object(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, + IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) +{ + TRACE("(%p %s %p %u %p %p %p)\n", handler, debugstr_w(url), stream, flags, props, out_object, out_obj_type); + + if (flags & MF_RESOLUTION_MEDIASOURCE) + { + HRESULT hr; + struct media_source *new_source; + struct container_stream_handler *This = CONTAINING_RECORD(handler, struct container_stream_handler, handler); + + if (FAILED(hr = media_source_constructor(stream, This->demuxer_name, &new_source))) + return hr; + + TRACE("->(%p)\n", new_source); + + *out_object = (IUnknown*)&new_source->IMFMediaSource_iface; + *out_obj_type = MF_OBJECT_MEDIASOURCE; + + return S_OK; + } + else + { + FIXME("flags = %08x\n", flags); + return E_NOTIMPL; + } +} + +HRESULT container_stream_handler_construct(REFIID riid, void **obj, const char *demuxer_name) +{ + struct container_stream_handler *this; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + this = heap_alloc_zero(sizeof(*this)); + if (!this) + return E_OUTOFMEMORY; + + handler_construct(&this->handler, container_stream_handler_create_object); + + this->demuxer_name = demuxer_name; + this->IMFByteStreamHandler_iface.lpVtbl = &container_stream_handler_vtbl; + this->refcount = 1; + + hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj); + IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface); + + return hr; +} \ No newline at end of file