[PATCH 3/3] winegstreamer: Implement IMFMediaStream::GetStreamDescriptor.

Zebediah Figura z.figura12 at gmail.com
Thu Sep 10 19:54:33 CDT 2020



On 9/10/20 12:02 PM, Derek Lesho wrote:
> On 9/9/20 7:00 PM, Zebediah Figura wrote:
> 
>> On 9/8/20 10:47 AM, Derek Lesho wrote:
>>> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
>>> ---
>>>   dlls/winegstreamer/gst_cbs.c      |  13 ++
>>>   dlls/winegstreamer/gst_cbs.h      |   8 ++
>>>   dlls/winegstreamer/gst_private.h  |   5 +
>>>   dlls/winegstreamer/media_source.c | 137 +++++++++++++++++++-
>>>   dlls/winegstreamer/mfplat.c       | 208 ++++++++++++++++++++++++++++++
>>>   5 files changed, 368 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
>>> index 4755f5b42f1..e56c987eb38 100644
>>> --- a/dlls/winegstreamer/gst_cbs.c
>>> +++ b/dlls/winegstreamer/gst_cbs.c
>>> @@ -404,3 +404,16 @@ void source_all_streams_wrapper(GstElement *element, gpointer user)
>>>   
>>>       call_cb(&cbdata);
>>>   }
>>> +
>>> +GstPadProbeReturn caps_listener_wrapper(GstPad *pad, GstPadProbeInfo *info, gpointer user)
>>> +{
>>> +    struct cb_data cbdata = { STREAM_PAD_EVENT };
>>> +
>>> +    cbdata.u.pad_probe_data.pad = pad;
>>> +    cbdata.u.pad_probe_data.info = info;
>>> +    cbdata.u.pad_probe_data.user = user;
>>> +
>>> +    call_cb(&cbdata);
>>> +
>>> +    return cbdata.u.pad_probe_data.ret;
>>> +}
>>> diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
>>> index d87cc8c21e9..7173c09746e 100644
>>> --- a/dlls/winegstreamer/gst_cbs.h
>>> +++ b/dlls/winegstreamer/gst_cbs.h
>>> @@ -52,6 +52,7 @@ enum CB_TYPE {
>>>       SOURCE_STREAM_ADDED,
>>>       SOURCE_STREAM_REMOVED,
>>>       SOURCE_ALL_STREAMS,
>>> +    STREAM_PAD_EVENT,
>>>       MEDIA_SOURCE_MAX,
>>>   };
>>>   
>>> @@ -137,6 +138,12 @@ struct cb_data {
>>>               GstQuery *query;
>>>               gboolean ret;
>>>           } query_sink_data;
>>> +        struct pad_probe_data {
>>> +            GstPad *pad;
>>> +            GstPadProbeInfo *info;
>>> +            gpointer user;
>>> +            GstPadProbeReturn ret;
>>> +        } pad_probe_data;
>>>       } u;
>>>   
>>>       int finished;
>>> @@ -172,5 +179,6 @@ GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpoin
>>>   void source_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
>>>   void source_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
>>>   void source_all_streams_wrapper(GstElement *element, gpointer user) DECLSPEC_HIDDEN;
>>> +GstPadProbeReturn caps_listener_wrapper(GstPad *pad, GstPadProbeInfo *info, gpointer user);
>>>   
>>>   #endif
>>> diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
>>> index ef07d3591e7..86392eea4e3 100644
>>> --- a/dlls/winegstreamer/gst_private.h
>>> +++ b/dlls/winegstreamer/gst_private.h
>>> @@ -36,6 +36,7 @@
>>>   #include "winuser.h"
>>>   #include "dshow.h"
>>>   #include "strmif.h"
>>> +#include "mfobjects.h"
>>>   #include "wine/heap.h"
>>>   #include "wine/strmbase.h"
>>>   
>>> @@ -54,6 +55,10 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
>>>   
>>>   extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
>>>   
>>> +HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
>>> +GstCaps *make_mf_compatible_caps(GstCaps *caps);
>>> +IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
>> Missing DECLSPEC_HIDDEN.
> 👌
>>
>>> +
>>>   HRESULT winegstreamer_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
>>> index 29af2b72def..345b1fe4528 100644
>>> --- a/dlls/winegstreamer/media_source.c
>>> +++ b/dlls/winegstreamer/media_source.c
>>> @@ -47,14 +47,19 @@ struct media_stream
>>>       LONG ref;
>>>       struct media_source *parent_source;
>>>       IMFMediaEventQueue *event_queue;
>>> +    IMFStreamDescriptor *descriptor;
>>>       GstElement *appsink;
>>>       GstPad *their_src, *my_sink;
>>> +    GstCaps *their_caps;
>>>       enum
>>>       {
>>>           STREAM_STUB,
>>>           STREAM_INACTIVE,
>>>           STREAM_SHUTDOWN,
>>>       } state;
>>> +    /* used when in STUB state: */
>>> +    DWORD stream_id;
>>> +    HANDLE caps_event;
>>>   };
>>>   
>>>   struct media_source
>>> @@ -312,6 +317,8 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
>>>       {
>>>           if (stream->my_sink)
>>>               gst_object_unref(GST_OBJECT(stream->my_sink));
>>> +        if (stream->descriptor)
>>> +            IMFStreamDescriptor_Release(stream->descriptor);
>>>           if (stream->event_queue)
>>>               IMFMediaEventQueue_Release(stream->event_queue);
>>>           if (stream->parent_source)
>>> @@ -393,7 +400,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
>>>       if (stream->state == STREAM_SHUTDOWN)
>>>           return MF_E_SHUTDOWN;
>>>   
>>> -    return E_NOTIMPL;
>>> +    IMFStreamDescriptor_AddRef(stream->descriptor);
>>> +    *descriptor = stream->descriptor;
>>> +
>>> +    return S_OK;
>>>   }
>>>   
>>>   static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
>>> @@ -436,9 +446,12 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD
>>>       IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
>>>       object->parent_source = source;
>>>       object->their_src = pad;
>>> +    object->stream_id = stream_id;
>>>   
>>>       object->state = STREAM_STUB;
>>>   
>>> +    object->caps_event = CreateEventA(NULL, TRUE, FALSE, NULL);
>>> +
>>>       if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
>>>           goto fail;
>>>   
>>> @@ -455,10 +468,10 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD
>>>       g_object_set(object->appsink, "wait-on-eos", FALSE, NULL);
>>>   
>>>       object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
>>> -    gst_pad_set_element_private(object->my_sink, object);
>>> -
>>>       gst_pad_link(object->their_src, object->my_sink);
>>>   
>>> +    gst_pad_add_probe(object->my_sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, caps_listener_wrapper, object, NULL);
>>> +
>>>       gst_element_sync_state_with_parent(object->appsink);
>>>   
>>>       TRACE("->(%p)\n", object);
>>> @@ -473,6 +486,43 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD
>>>       return hr;
>>>   }
>>>   
>>> +static HRESULT media_stream_init_desc(struct media_stream *stream)
>>> +{
>>> +    HRESULT hr;
>>> +    IMFMediaTypeHandler *type_handler;
>>> +    IMFMediaType *stream_type = NULL;
>>> +
>>> +    stream->their_caps = gst_caps_fixate(stream->their_caps);
>> I think this is unnecessary; the caps should already be fixed.
> 👌
>>
>>> +
>>> +    stream_type = mf_media_type_from_caps(stream->their_caps);
>>> +    gst_caps_unref(stream->their_caps);
>> This seems a bit error-prone. I'd suggest getting rid of the field and
>> instead calling gst_caps_copy(gst_pad_get_current_caps(...))
> Can we be sure that the caps will be set after the pad probe callback is 
> complete?

No, I guess we can't. In that case you might want to add a comment to
the definition of "their_caps" (and maybe also set it to NULL?), lest
someone assume that it's always valid.

>>
>>> +    if (!stream_type)
>>> +    {
>>> +        hr = E_FAIL;
>>> +        goto fail;
>>> +    }
>>> +
>>> +    if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, 1, &stream_type, &stream->descriptor)))
>>> +        goto fail;
>>> +
>>> +    if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
>>> +        goto fail;
>>> +
>>> +    if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type)))
>>> +        goto fail;
>>> +
>>> +    IMFMediaTypeHandler_Release(type_handler);
>>> +
>>> +    stream->state = STREAM_INACTIVE;
>>> +
>>> +    return S_OK;
>>> +    fail:
>>> +    ERR("media stream initialization failed with %x\n", hr);
>> While this does tell you that one of the mfplat functions failed, it
>> doesn't actually tell you which one. There's similar patterns elsewhere
>> in this series.
> Is that a problem?  The likelyhood of one of these functions failing is 
> very slim, and in that case, you could use use +mfplat to see the last 
> function to run before the error.  If conversion to a media type failed, 
> the relevant conversion function will also emit an error.

It's not necessarily a problem, but it strikes me as unidiomatic. The
likelihood is indeed slim, which is kind of why I wouldn't necessarily
bother with the trace in the first place. If I did and didn't want to
emit more than one trace, though, I'd probably put it in the caller of
this function.

>>
>>> +    if (type_handler)
>>> +        IMFMediaTypeHandler_Release(type_handler);
>>> +    return hr;
>>> +}
>>> +
>>>   static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
>>>   {
>>>       struct media_source *source = impl_from_IMFMediaSource(iface);
>>> @@ -680,6 +730,23 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
>>>       media_source_Shutdown,
>>>   };
>>>   
>>> +/* If this callback is extended to use any significant win32 APIs, a wrapper function
>>> +   should be added */
>>> +gboolean stream_found(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user)
>>> +{
>>> +    GstCaps *target_caps;
>>> +
>>> +    /* if the stream can be converted into an MF compatible type, we'll go that route
>>> +       otherwise, we'll rely on decodebin for the whole process */
>>> +
>> I think we should leave this part out for now.
> I disagree, without it, a lot of compressed media type conversion code 
> becomes dead, and this codepath which this triggers is closer to the 
> windows one.

I don't think a need for such code has been shown. At least it shouldn't
be part of this patch.

>>
>>> +    if ((target_caps = make_mf_compatible_caps(caps)))
>>> +    {
>>> +        gst_caps_unref(target_caps);
>>> +        return FALSE;
>>> +    }
>>> +    return TRUE;
>>> +}
>>> +
>>>   static void source_stream_added(GstElement *element, GstPad *pad, gpointer user)
>>>   {
>>>       struct media_source *source = (struct media_source *) user;
>>> @@ -697,6 +764,36 @@ static void source_stream_added(GstElement *element, GstPad *pad, gpointer user)
>>>   
>>>       TRACE("stream-id: %u\n", stream_id);
>>>   
>>> +    /* This codepath is currently never triggered, as we don't need to ever restart the gstreamer pipeline.  It is retained in
>>> +       case this becomes necessary in the future, for example in a case where different media types require different
>>> +       post-processing elements. */
>> In general, if a code path is dead, it shouldn't be introduced (yet).
> 👌
>>
>>> +    for (unsigned int i = 0; i < source->stream_count; i++)
>>> +    {
>>> +        DWORD existing_stream_id;
>>> +        IMFStreamDescriptor *descriptor = source->streams[i]->descriptor;
>>> +
>>> +        if (source->streams[i]->state == STREAM_STUB)
>>> +            continue;
>>> +
>>> +        if (FAILED(IMFStreamDescriptor_GetStreamIdentifier(descriptor, &existing_stream_id)))
>>> +            goto leave;
>>> +
>>> +        if (existing_stream_id == stream_id)
>>> +        {
>>> +            struct media_stream *existing_stream = source->streams[i];
>>> +            GstPadLinkReturn ret;
>>> +
>>> +            TRACE("Found existing stream %p\n", existing_stream);
>>> +
>>> +            existing_stream->their_src = pad;
>>> +
>>> +            if ((ret = gst_pad_link(existing_stream->their_src, existing_stream->my_sink)) != GST_PAD_LINK_OK)
>>> +                ERR("Error linking decodebin pad to stream %p, err = %d\n", existing_stream, ret);
>>> +
>>> +            goto leave;
>>> +        }
>>> +    }
>>> +
>>>       if (FAILED(new_media_stream(source, pad, stream_id, &stream)))
>>>       {
>>>           goto leave;
>>> @@ -737,6 +834,26 @@ static void source_all_streams(GstElement *element, gpointer user)
>>>       SetEvent(source->all_streams_event);
>>>   }
>>>   
>>> +static GstPadProbeReturn caps_listener(GstPad *pad, GstPadProbeInfo *info, gpointer user)
>>> +{
>>> +    struct media_stream *stream = (struct media_stream *) user;
>> The cast is unnecessary, here and elsewhere.
> 👌
>>
>>> +    GstEvent *event = gst_pad_probe_info_get_event(info);
>>> +
>>> +    if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS)
>>> +    {
>>> +        GstCaps *caps;
>>> +        TRACE("got caps for stream %p\n", stream);
>>> +
>>> +        gst_event_parse_caps(event, &caps);
>>> +        stream->their_caps = gst_caps_copy(caps);
>>> +        SetEvent(stream->caps_event);
>>> +
>>> +        return GST_PAD_PROBE_REMOVE;
>>> +    }
>>> +
>>> +    return GST_PAD_PROBE_OK;
>>> +}
>>> +
>>>   static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
>>>   {
>>>       GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
>>> @@ -787,6 +904,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
>>>   
>>>       gst_bin_add(GST_BIN(object->container), object->decodebin);
>>>   
>>> +    if(!GetEnvironmentVariableA("MF_DECODE_IN_SOURCE", NULL, 0))
>> Debugging code?
> Yeah, it's useful for finding out whether an issue is caused by the real 
> decoder MFT path, or topology loader.  (As it skips all that)

I mean, you probably didn't mean to include this here. In general I
think we try to avoid such debugging switches, and it's not clear to me
this warrants an exception.

>>
>>> +        g_signal_connect(object->decodebin, "autoplug-continue", G_CALLBACK(stream_found), object);
>>>       g_signal_connect(object->decodebin, "pad-added", G_CALLBACK(source_stream_added_wrapper), object);
>>>       g_signal_connect(object->decodebin, "pad-removed", G_CALLBACK(source_stream_removed_wrapper), object);
>>>       g_signal_connect(object->decodebin, "no-more-pads", G_CALLBACK(source_all_streams_wrapper), object);
>>> @@ -812,6 +931,12 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
>>>       }
>>>   
>>>       WaitForSingleObject(object->all_streams_event, INFINITE);
>>> +    for (unsigned int i = 0; i < object->stream_count; i++)
>> Misplaced declaration.
> 👌
>>
>>> +    {
>>> +        WaitForSingleObject(object->streams[i]->caps_event, INFINITE);
>>> +        if (FAILED(hr = media_stream_init_desc(object->streams[i])))
>>> +            goto fail;
>>> +    }
>>>   
>>>       object->state = SOURCE_STOPPED;
>>>   
>>> @@ -1337,6 +1462,12 @@ void perform_cb_media_source(struct cb_data *cbdata)
>>>               source_all_streams(data->element, data->user);
>>>               break;
>>>           }
>>> +    case STREAM_PAD_EVENT:
>>> +        {
>>> +            struct pad_probe_data *data = &cbdata->u.pad_probe_data;
>>> +            cbdata->u.pad_probe_data.ret = caps_listener(data->pad, data->info, data->user);
>>> +            break;
>>> +        }
>>>       default:
>>>           {
>>>               ERR("Wrong callback forwarder called\n");
>>> diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
>>> index c996f06211e..3667bc3cc38 100644
>>> --- a/dlls/winegstreamer/mfplat.c
>>> +++ b/dlls/winegstreamer/mfplat.c
>>> @@ -16,6 +16,11 @@
>>>    * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>>>    */
>>>   
>>> +#include "config.h"
>>> +#include <gst/gst.h>
>>> +
>>> +#include "gst_private.h"
>>> +
>>>   #include <stdarg.h>
>>>   
>>>   #include "gst_private.h"
>>> @@ -436,3 +441,206 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
>>>   
>>>       return CLASS_E_CLASSNOTAVAILABLE;
>>>   }
>>> +
>>> +const static struct
>> "static const"
> 👌
>>
>>> +{
>>> +    const GUID *subtype;
>>> +    GstVideoFormat format;
>>> +}
>>> +uncompressed_formats[] =
>> "uncompressed_video_formats", probably.
> 👌
>>
>>> +{
>>> +    {&MFVideoFormat_ARGB32,  GST_VIDEO_FORMAT_BGRA},
>>> +    {&MFVideoFormat_RGB32,   GST_VIDEO_FORMAT_BGRx},
>>> +    {&MFVideoFormat_RGB24,   GST_VIDEO_FORMAT_BGR},
>>> +    {&MFVideoFormat_RGB565,  GST_VIDEO_FORMAT_BGR16},
>>> +    {&MFVideoFormat_RGB555,  GST_VIDEO_FORMAT_BGR15},
>>> +};
>>> +
>>> +/* caps will be modified to represent the exact type needed for the format */
>> This seems wrong in general.
> Why?

It's not really idiomatic code structure. More concretely, it also means
you're copying the caps when you don't need to.

If you really need to do something like this, you probably want a
separate function that takes a GstCaps and returns a new GstCaps that is
compatible with mfplat, then you feed the output of that through
mf_media_type_from_caps().

>>
>>> +static IMFMediaType* transform_to_media_type(GstCaps *caps)
>>> +{
>>> +    IMFMediaType *media_type;
>>> +    GstStructure *info;
>>> +    const char *mime_type;
>>> +
>>> +    if (TRACE_ON(mfplat))
>>> +    {
>>> +        gchar *human_readable = gst_caps_to_string(caps);
>>> +        TRACE("caps = %s\n", debugstr_a(human_readable));
>>> +        g_free(human_readable);
>>> +    }
>>> +
>>> +    if (FAILED(MFCreateMediaType(&media_type)))
>>> +    {
>>> +        return NULL;
>>> +    }
>>> +
>>> +    info = gst_caps_get_structure(caps, 0);
>>> +    mime_type = gst_structure_get_name(info);
>>> +
>>> +    if (!(strncmp(mime_type, "video", 5)))
>> There's a lot of superfluous parentheses after local not operators in
>> this series; this one seems especially superfluous.
> 👌
>>
>>> +    {
>>> +        GstVideoInfo video_info;
>>> +
>>> +        if (!(gst_video_info_from_caps(&video_info, caps)))
>>> +        {
>>> +            return NULL;
>>> +        }
>>> +
>>> +        IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
>>> +
>>> +        IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
>>> +
>>> +        IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
>>> +
>>> +        if (!(strcmp(mime_type, "video/x-raw")))
>>> +        {
>>> +            GUID fourcc_subtype = MFVideoFormat_Base;
>>> +            unsigned int i;
>>> +
>>> +            IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
>>> +
>>> +            /* First try FOURCC */
>>> +            if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
>>> +            {
>>> +                IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
>>> +            }
>>> +            else
>>> +            {
>>> +                for (i = 0; i < ARRAY_SIZE(uncompressed_formats); i++)
>>> +                {
>>> +                    if (uncompressed_formats[i].format == video_info.finfo->format)
>>> +                    {
>>> +                        IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_formats[i].subtype);
>>> +                        break;
>>> +                    }
>>> +                }
>>> +                if (i == ARRAY_SIZE(uncompressed_formats))
>>> +                    FIXME("Unrecognized format.\n");
>> In which case the function should probably fail.
> 👌
>>
>>> +            }
>>> +        }
>>> +        else
>>> +        {
>>> +            FIXME("Unrecognized video format %s\n", mime_type);
>>> +            IMFMediaType_Release(media_type);
>>> +            return NULL;
>>> +        }
>>> +    }
>>> +    else if (!(strncmp(mime_type, "audio", 5)))
>>> +    {
>>> +        gint rate, channels, bitrate;
>>> +        guint64 channel_mask;
>>> +        IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
>>> +
>>> +        if (gst_structure_get_int(info, "rate", &rate))
>>> +            IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate);
>>> +
>>> +        if (gst_structure_get_int(info, "channels", &channels))
>>> +            IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channels);
>>> +
>>> +        if (gst_structure_get(info, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL))
>>> +            IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, (DWORD)channel_mask);
>> Superfluous cast.
> 👌
>>
>>> +
>>> +        if (gst_structure_get_int(info, "bitrate", &bitrate))
>>> +            IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate);
>>> +
>>> +        if (!(strcmp(mime_type, "audio/x-raw")))
>>> +        {
>>> +            const char *format;
>>> +            if ((format = gst_structure_get_string(info, "format")))
>> You may find it easier to use gst_audio_info_from_caps() here.
> Does this work on compressed audio types as well?

Yes (it yields GST_AUDIO_FORMAT_ENCODED), but it doesn't matter since
you're already dealing with raw audio here.

>>
>>> +            {
>>> +                char type;
>>> +                unsigned int bits_per_sample;
>>> +                char endian[2];
>>> +                char new_format[6];
>>> +                if ((strlen(format) > 5) || (sscanf(format, "%c%u%2c", &type, &bits_per_sample, endian) < 2))
>>> +                {
>>> +                    FIXME("Unhandled audio format %s\n", format);
>>> +                    IMFMediaType_Release(media_type);
>>> +                    return NULL;
>>> +                }
>>> +
>>> +                if (type == 'F')
>>> +                {
>>> +                    IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
>>> +                }
>>> +                else if (type == 'U' || type == 'S')
>>> +                {
>>> +                    IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
>>> +                    if (bits_per_sample == 8)
>>> +                        type = 'U';
>>> +                    else
>>> +                        type = 'S';
>>> +                }
>>> +                else
>>> +                {
>>> +                    FIXME("Unrecognized audio format: %s\n", format);
>>> +                    IMFMediaType_Release(media_type);
>>> +                    return NULL;
>>> +                }
>>> +
>>> +                IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bits_per_sample);
>>> +
>>> +                if (endian[0] == 'B')
>>> +                    endian[0] = 'L';
>>> +
>>> +                sprintf(new_format, "%c%u%.2s", type, bits_per_sample, bits_per_sample > 8 ? endian : 0);
>>> +                gst_caps_set_simple(caps, "format", G_TYPE_STRING, new_format, NULL);
>>> +            }
>>> +            else
>>> +            {
>>> +                ERR("Failed to get audio format\n");
>>> +            }
>>> +        }
>>> +        else
>>> +        {
>>> +            FIXME("Unrecognized audio format %s\n", mime_type);
>>> +            IMFMediaType_Release(media_type);
>>> +            return NULL;
>>> +        }
>>> +    }
>>> +    else
>>> +    {
>>> +        IMFMediaType_Release(media_type);
>>> +        return NULL;
>>> +    }
>>> +
>>> +    return media_type;
>>> +}
>>> +
>>> +/* returns NULL if doesn't match exactly */
>>> +IMFMediaType *mf_media_type_from_caps(GstCaps *caps)
>>> +{
>>> +    GstCaps *writeable_caps;
>>> +    IMFMediaType *ret;
>>> +
>>> +    writeable_caps = gst_caps_copy(caps);
>>> +    ret = transform_to_media_type(writeable_caps);
>>> +
>>> +    if (!(gst_caps_is_equal(caps, writeable_caps)))
>>> +    {
>>> +        IMFMediaType_Release(ret);
>>> +        ret = NULL;
>>> +    }
>>> +    gst_caps_unref(writeable_caps);
>>> +    return ret;
>>> +}
>>> +
>>> +GstCaps *make_mf_compatible_caps(GstCaps *caps)
>>> +{
>>> +    GstCaps *ret;
>>> +    IMFMediaType *media_type;
>>> +
>>> +    ret = gst_caps_copy(caps);
>>> +
>>> +    if ((media_type = transform_to_media_type(ret)))
>>> +        IMFMediaType_Release(media_type);
>>> +
>>> +    if (!media_type)
>>> +    {
>>> +        gst_caps_unref(ret);
>>> +        return NULL;
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>>
>>
> 

-------------- 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/20200910/47ed8b2b/attachment-0001.sig>


More information about the wine-devel mailing list