[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