On 8/28/20 11:00 AM, Derek Lesho wrote:
On 8/28/20 10:19 AM, Zebediah Figura wrote:
On 8/27/20 1:22 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@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"?
Because it's a media source which derives streams out of container formats (mp4, wmv).
Surely it also supports non-container formats, such as mp3?
+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?
I don't think so, in BeginCreateObject we always send in a IMFAsyncResult.Β FWIW, I copied most of the implementation of this object from the file scheme handler https://source.winehq.org/git/wine.git/blob/7489efa03f09c6c3613668a0169abade...
I see; that's still more than a little concerning, but...
.
- 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.
I'm not sure why that's necessary, as 99% of games will just be using mp4 or WMV, but I guess it wouldn't hurt to do this.Β FWIW, the modification would be in source_resolver_CreateObjectFromByteStream, in place of the old fallback code.
The point of doing this is mainly for generic media players (which, as bug reports will tell you, are used quite frequently with Wine, for one reason or another). It also has the benefit of obviating most of the registry entries (like the ones below) and CLSID mappings that we'd otherwise have to add.
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);")