[PATCH v3 2/5] winegstreamer: Add stub bytestream handler.
Zebediah Figura
z.figura12 at gmail.com
Fri Aug 28 10:19:46 CDT 2020
On 8/27/20 1:22 PM, Derek Lesho wrote:
> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
> ---
> dlls/winegstreamer/Makefile.in | 1 +
> dlls/winegstreamer/gst_private.h | 2 +
> dlls/winegstreamer/media_source.c | 457 +++++++++++++++++++
> dlls/winegstreamer/mfplat.c | 9 +
> dlls/winegstreamer/winegstreamer.rgs | 32 ++
> dlls/winegstreamer/winegstreamer_classes.idl | 7 +
> include/mfidl.idl | 1 +
> 7 files changed, 509 insertions(+)
> create mode 100644 dlls/winegstreamer/media_source.c
>
> diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
> index 337c1086e6b..e578d194f7f 100644
> --- a/dlls/winegstreamer/Makefile.in
> +++ b/dlls/winegstreamer/Makefile.in
> @@ -10,6 +10,7 @@ C_SRCS = \
> gst_cbs.c \
> gstdemux.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 e6fb841fc87..b44e75a8a5b 100644
> --- a/dlls/winegstreamer/gst_private.h
> +++ b/dlls/winegstreamer/gst_private.h
> @@ -54,4 +54,6 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
>
> extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
>
> +HRESULT container_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
> +
> #endif /* __GST_PRIVATE_INCLUDED__ */
> diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
> new file mode 100644
> index 00000000000..801d058f6b8
> --- /dev/null
> +++ b/dlls/winegstreamer/media_source.c
> @@ -0,0 +1,457 @@
> +#include "gst_private.h"
> +
> +#include <stdarg.h>
> +
> +#define COBJMACROS
> +#define NONAMELESSUNION
> +
> +#include "mfapi.h"
> +#include "mferror.h"
> +#include "mfidl.h"
> +
> +#include "wine/debug.h"
> +#include "wine/heap.h"
> +#include "wine/list.h"
> +
> +WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
> +
> +/* IMFByteStreamHandler */
I'm not sure what comments like this are doing. It's already clear that
struct container_stream_handler exposes IMFByteStreamHandler.
> +
> +struct container_stream_handler_result
> +{
> + struct list entry;
> + IMFAsyncResult *result;
> + MF_OBJECT_TYPE obj_type;
> + IUnknown *object;
> +};
> +
> +struct container_stream_handler
> +{
> + IMFByteStreamHandler IMFByteStreamHandler_iface;
> + IMFAsyncCallback IMFAsyncCallback_iface;
> + LONG refcount;
> + struct list results;
> + CRITICAL_SECTION cs;
> +};
Why "container"?
> +
> +static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
> +{
> + return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface);
> +}
> +
> +static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
> +{
> + return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_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 *handler = impl_from_IMFByteStreamHandler(iface);
> + ULONG refcount = InterlockedDecrement(&handler->refcount);
> + struct container_stream_handler_result *result, *next;
> +
> + TRACE("%p, refcount %u.\n", iface, refcount);
> +
> + if (!refcount)
> + {
> + LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_stream_handler_result, entry)
> + {
> + list_remove(&result->entry);
> + IMFAsyncResult_Release(result->result);
> + if (result->object)
> + IUnknown_Release(result->object);
> + heap_free(result);
> + }
> + DeleteCriticalSection(&handler->cs);
> + heap_free(handler);
> + }
> +
> + return refcount;
> +}
> +
> +struct create_object_context
> +{
> + IUnknown IUnknown_iface;
> + LONG refcount;
> +
> + IPropertyStore *props;
> + IMFByteStream *stream;
> + WCHAR *url;
> + DWORD flags;
> +};
> +
> +static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
> +{
> + return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
> +}
> +
> +static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
> +{
> + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
> +
> + if (IsEqualIID(riid, &IID_IUnknown))
> + {
> + *obj = iface;
> + IUnknown_AddRef(iface);
> + return S_OK;
> + }
> +
> + WARN("Unsupported %s.\n", debugstr_guid(riid));
> + *obj = NULL;
> + return E_NOINTERFACE;
> +}
> +
> +static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
> +{
> + struct create_object_context *context = impl_from_IUnknown(iface);
> + ULONG refcount = InterlockedIncrement(&context->refcount);
> +
> + TRACE("%p, refcount %u.\n", iface, refcount);
> +
> + return refcount;
> +}
> +
> +static ULONG WINAPI create_object_context_Release(IUnknown *iface)
> +{
> + struct create_object_context *context = impl_from_IUnknown(iface);
> + ULONG refcount = InterlockedDecrement(&context->refcount);
> +
> + TRACE("%p, refcount %u.\n", iface, refcount);
> +
> + if (!refcount)
> + {
> + if (context->props)
> + IPropertyStore_Release(context->props);
> + if (context->stream)
> + IMFByteStream_Release(context->stream);
> + if (context->url)
> + heap_free(context->url);
> + heap_free(context);
> + }
> +
> + return refcount;
> +}
> +
> +static const IUnknownVtbl create_object_context_vtbl =
> +{
> + create_object_context_QueryInterface,
> + create_object_context_AddRef,
> + create_object_context_Release,
> +};
> +
> +static WCHAR *heap_strdupW(const WCHAR *str)
> +{
> + WCHAR *ret = NULL;
> +
> + if (str)
> + {
> + unsigned int size;
> +
> + size = (lstrlenW(str) + 1) * sizeof(WCHAR);
> + ret = heap_alloc(size);
> + if (ret)
> + memcpy(ret, str, size);
> + }
> +
> + return ret;
> +}
> +
> +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);
> + struct create_object_context *context;
> + IMFAsyncResult *caller, *item;
> + HRESULT hr;
> +
> + TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
> +
> + if (cancel_cookie)
> + *cancel_cookie = NULL;
> +
> + if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
> + return hr;
> +
> + context = heap_alloc(sizeof(*context));
> + if (!context)
> + {
> + IMFAsyncResult_Release(caller);
> + return E_OUTOFMEMORY;
> + }
> +
> + context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
> + context->refcount = 1;
> + context->props = props;
> + if (context->props)
> + IPropertyStore_AddRef(context->props);
> + context->flags = flags;
> + context->stream = stream;
> + if (context->stream)
> + IMFByteStream_AddRef(context->stream);
> + if (url)
> + context->url = heap_strdupW(url);
> + if (!context->stream)
> + {
> + IMFAsyncResult_Release(caller);
> + IUnknown_Release(&context->IUnknown_iface);
> + return E_OUTOFMEMORY;
> + }
> +
> + hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
> + IUnknown_Release(&context->IUnknown_iface);
> + if (SUCCEEDED(hr))
> + {
> + if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
> + {
> + if (cancel_cookie)
> + {
> + *cancel_cookie = (IUnknown *)caller;
> + IUnknown_AddRef(*cancel_cookie);
> + }
> + }
> +
> + IMFAsyncResult_Release(item);
> + }
> + IMFAsyncResult_Release(caller);
> +
> + return hr;
> +}
> +
> +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);
> + struct container_stream_handler_result *found = NULL, *cur;
> + HRESULT hr;
> +
> + TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
> +
> + EnterCriticalSection(&this->cs);
> +
> + LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_stream_handler_result, entry)
> + {
> + if (result == cur->result)
> + {
> + list_remove(&cur->entry);
> + found = cur;
> + break;
> + }
> + }
> +
> + LeaveCriticalSection(&this->cs);
> +
> + if (found)
> + {
> + *obj_type = found->obj_type;
> + *object = found->object;
> + hr = IMFAsyncResult_GetStatus(found->result);
> + IMFAsyncResult_Release(found->result);
> + heap_free(found);
> + }
> + else
> + {
> + *obj_type = MF_OBJECT_INVALID;
> + *object = NULL;
> + hr = MF_E_UNEXPECTED;
> + }
> +
> + return hr;
> +}
> +
> +static HRESULT WINAPI container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
> +{
> + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
> + struct container_stream_handler_result *found = NULL, *cur;
> +
> + TRACE("%p, %p.\n", iface, cancel_cookie);
> +
> + EnterCriticalSection(&this->cs);
> +
> + LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_stream_handler_result, entry)
> + {
> + if (cancel_cookie == (IUnknown *)cur->result)
> + {
> + list_remove(&cur->entry);
> + found = cur;
> + break;
> + }
> + }
> +
> + LeaveCriticalSection(&this->cs);
> +
> + if (found)
> + {
> + IMFAsyncResult_Release(found->result);
> + if (found->object)
> + IUnknown_Release(found->object);
> + heap_free(found);
> + }
> +
> + return found ? S_OK : MF_E_UNEXPECTED;
> +}
> +
> +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 WINAPI container_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
> +{
> + if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
> + IsEqualIID(riid, &IID_IUnknown))
> + {
> + *obj = iface;
> + IMFAsyncCallback_AddRef(iface);
> + return S_OK;
> + }
> +
> + WARN("Unsupported %s.\n", debugstr_guid(riid));
> + *obj = NULL;
> + return E_NOINTERFACE;
> +}
> +
> +static ULONG WINAPI container_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
> +{
> + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
> + return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
> +}
> +
> +static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface)
> +{
> + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
> + return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
> +}
> +
> +static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
> +{
> + return E_NOTIMPL;
> +}
> +
> +static HRESULT container_stream_handler_create_object(struct container_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
> + IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
> +{
> + FIXME("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
> +
> + return E_NOTIMPL;
> +}
> +
> +static HRESULT WINAPI container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
> +{
> + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
> + struct container_stream_handler_result *handler_result;
> + MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
> + IUnknown *object = NULL, *context_object;
> + struct create_object_context *context;
> + IMFAsyncResult *caller;
> + HRESULT hr;
> +
> + caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
That doesn't seem safe at all. Surely you should call QueryInterface here?
> +
> + if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
> + {
> + WARN("Expected context set for callee result.\n");
> + return hr;
> + }
> +
> + context = impl_from_IUnknown(context_object);
> +
> + hr = container_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
> +
> + handler_result = heap_alloc(sizeof(*handler_result));
> + if (handler_result)
> + {
> + handler_result->result = caller;
> + IMFAsyncResult_AddRef(handler_result->result);
> + handler_result->obj_type = obj_type;
> + handler_result->object = object;
> +
> + EnterCriticalSection(&handler->cs);
> + list_add_tail(&handler->results, &handler_result->entry);
> + LeaveCriticalSection(&handler->cs);
> + }
> + else
> + {
> + if (object)
> + IUnknown_Release(object);
> + hr = E_OUTOFMEMORY;
> + }
> +
> + IUnknown_Release(&context->IUnknown_iface);
> +
> + IMFAsyncResult_SetStatus(caller, hr);
> + MFInvokeCallback(caller);
> +
> + return S_OK;
> +}
> +
> +static const IMFAsyncCallbackVtbl container_stream_handler_callback_vtbl =
> +{
> + container_stream_handler_callback_QueryInterface,
> + container_stream_handler_callback_AddRef,
> + container_stream_handler_callback_Release,
> + container_stream_handler_callback_GetParameters,
> + container_stream_handler_callback_Invoke,
> +};
> +
> +HRESULT container_stream_handler_create(REFIID riid, void **obj)
> +{
> + 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;
> +
> + list_init(&this->results);
> + InitializeCriticalSection(&this->cs);
> +
> + this->IMFByteStreamHandler_iface.lpVtbl = &container_stream_handler_vtbl;
> + this->IMFAsyncCallback_iface.lpVtbl = &container_stream_handler_callback_vtbl;
> + this->refcount = 1;
> +
> + hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
> + IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
> +
> + return hr;
> +}
> diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
> index 55b9b088765..3d65fe8dd48 100644
> --- a/dlls/winegstreamer/mfplat.c
> +++ b/dlls/winegstreamer/mfplat.c
> @@ -398,6 +398,11 @@ failed:
> return hr;
> }
>
> +static HRESULT mp4_stream_handler_create(REFIID riid, void **ret)
> +{
> + return container_stream_handler_create(riid, ret);
> +}
> +
This function seems redundant.
> static const struct class_object
> {
> const GUID *clsid;
> @@ -406,6 +411,7 @@ static const struct class_object
> class_objects[] =
> {
> { &CLSID_VideoProcessorMFT, &video_processor_create },
> + { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
> };
>
Even if some application creates CLSID_MPEG4ByteStreamHandler manually,
and we need to hook up this decoder thereto, I think it makes more sense
for the original patch to create it under a generic name (maybe
CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another
patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a
generic catch-all handler, i.e. we can't just set some registry keys and
have done, but regardless I think it's something we want to do, even if
that means making the modification in mfreadwrite instead.
> HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
> @@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
> unsigned int i;
> HRESULT hr;
>
> + if (!(init_gstreamer()))
> + return CLASS_E_CLASSNOTAVAILABLE;
> +
This doesn't exactly make a lot of sense in this patch, since you're not
using gstreamer yet. That said, when you do need it, I think it may make
more sense just to move the call up to the top-level DllGetClassObject()
implementation.
> for (i = 0; i < ARRAY_SIZE(class_objects); ++i)
> {
> if (IsEqualGUID(class_objects[i].clsid, rclsid))
> diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs
> index 923ba673f8c..9323bcc24dd 100644
> --- a/dlls/winegstreamer/winegstreamer.rgs
> +++ b/dlls/winegstreamer/winegstreamer.rgs
> @@ -12,3 +12,35 @@ HKCR
> }
> }
> }
> +
> +HKLM
> +{
> + NoRemove 'Software'
> + {
> + NoRemove 'Microsoft'
> + {
> + NoRemove 'Windows Media Foundation'
> + {
> + NoRemove 'ByteStreamHandlers'
> + {
> + '.m4v'
> + {
> + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
Case is not only inconsistent here, but identical to the Windows registry...
> + }
> + '.mp4'
> + {
> + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
> + }
> + 'video/m4v'
> + {
> + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
> + }
> + 'video/mp4'
> + {
> + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
> + }
> + }
> + }
> + }
> + }
> +}
This hunk should probably be a separate patch. Of course, see my
comments above...
> diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
> index fa0e1784057..997a28b052f 100644
> --- a/dlls/winegstreamer/winegstreamer_classes.idl
> +++ b/dlls/winegstreamer/winegstreamer_classes.idl
> @@ -54,3 +54,10 @@ coclass Gstreamer_Splitter {}
> uuid(88753b26-5b24-49bd-b2e7-0c445c78c982)
> ]
> coclass VideoProcessorMFT {}
> +
> +[
> + helpstring("MP4 Byte Stream Handler"),
> + threading(both),
> + uuid(271c3902-6095-4c45-a22f-20091816ee9e)
> +]
> +coclass MPEG4ByteStreamHandler {}
> diff --git a/include/mfidl.idl b/include/mfidl.idl
> index 4ceeb707bd0..6aefbe76624 100644
> --- a/include/mfidl.idl
> +++ b/include/mfidl.idl
> @@ -1241,3 +1241,4 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, 0xba491365,
> cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xbe50, 0x451e, 0x95, 0xab, 0x6d, 0x4a, 0xcc, 0xc7, 0xda, 0xd8);")
>
> cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);")
> +cpp_quote("EXTERN_GUID(CLSID_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20200828/6eba80ac/attachment-0001.sig>
More information about the wine-devel
mailing list