[PATCH 2/2] winegstreamer: Continuously query duration for mp3 audio streams.

Zebediah Figura (she/her) zfigura at codeweavers.com
Tue May 4 14:10:37 CDT 2021


On 5/4/21 9:46 AM, Connor McAdams wrote:
> On Mon, May 03, 2021 at 11:35:20AM -0500, Zebediah Figura (she/her) wrote:
>> On 5/3/21 7:53 AM, Connor McAdams wrote:
>>> For mp3 audio streams, continuously call gst_pad_query_duration until
>>> the duration arrives. Fixes issue of incorrect song duration in Fallout:
>>> New Vegas.
>>>
>>> Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
>>> ---
>>>    dlls/winegstreamer/wg_parser.c | 27 +++++++++++++++++++++++++--
>>>    1 file changed, 25 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
>>> index 1653701506c..1dae3bfb922 100644
>>> --- a/dlls/winegstreamer/wg_parser.c
>>> +++ b/dlls/winegstreamer/wg_parser.c
>>> @@ -1504,13 +1504,22 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
>>>        return ret;
>>>    }
>>> -static LONGLONG query_duration(GstPad *pad)
>>> +static LONGLONG query_duration(GstPad *pad, gboolean query_duration)
>>>    {
>>>        gint64 duration, byte_length;
>>>        if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
>>>            return duration / 100;
>>> +    if (query_duration)
>>> +    {
>>> +        for (;;)
>>> +        {
>>> +            if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
>>> +                return duration / 100;
>>> +        }
>>> +    }
>>> +
>>
>> We don't want to risk an infinite loop here, or busy-wait. We should wait
>> for duration-changed with a time-out.
>>
>> We also should be calling query_duration when polling, rather than
>> gst_pad_query_duration(). That is, this loop should be in
>> wg_parser_connect().
>>
> 
> Using something like pthread_cond_timedwait? I was waiting on the
> duration-changed event prior to my current solution of continuously
> calling gst_pad_query_duration(), but it was still querying too early
> and getting incorrect results. If we want to continuously call
> query_duration(), should we have some way for it to return if it
> converted from byte length and try again in that circumstance? It seems
> that converting from byte length just doesn't work for this format.

I'm not sure I fully understand what you're referring here. Is there an 
element that is returning inaccurate results when we try to convert from 
byte length, but later accurate results when we request duration in time 
directly? How inaccurate is the initial guess?

> 
>>>        WARN("Failed to query time duration; trying to convert from byte length.\n");
>>>        /* To accurately get a duration for the stream, we want to only consider the
>>> @@ -1569,6 +1578,7 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s
>>>        for (i = 0; i < parser->stream_count; ++i)
>>>        {
>>>            struct wg_parser_stream *stream = parser->streams[i];
>>> +        gboolean duration_wait = FALSE;
>>>            while (!stream->has_caps && !parser->error)
>>>                pthread_cond_wait(&parser->init_cond, &parser->mutex);
>>> @@ -1577,12 +1587,25 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s
>>>                pthread_mutex_unlock(&parser->mutex);
>>>                return E_FAIL;
>>>            }
>>> +
>>> +        /*
>>> +         * On MP3 audio streams, sometimes the duration value takes time to be
>>> +         * set. In this case, we need to continuously call query_duration
>>> +         * until we get it.
>>> +         */
>>> +        if (input_format.major_type == WG_MAJOR_TYPE_AUDIO &&
>>> +            input_format.u.audio.format >= WG_AUDIO_FORMAT_MPEG1_LAYER1 &&
>>> +            input_format.u.audio.format <= WG_AUDIO_FORMAT_MPEG1_LAYER3)
>>> +        {
>>> +            duration_wait = TRUE;
>>> +        }
>>> +
>>
>> I don't think there's really a good reason to limit this to MPEG audio. If
>> there are other demuxers (now or in the future, or even in the past) that
>> force us to wait for duration, we want to do so.
>>
> 
> Good point, I can probably do something similar to how certain decoders
> are blacklisted/disabled, and instead have certain decoders have a wait
> duration wait behavior flag.

I don't think there's any reason to do that either. If an element 
reports duration immediately, we won't wait anyway. If it doesn't, we 
always want to wait.

> 
>>>            /* GStreamer doesn't actually provide any guarantees about when duration
>>>             * is available, even for seekable streams. However, many elements (e.g.
>>>             * avidemux, wavparse, qtdemux) in practice record duration before
>>>             * fixing caps, so as a heuristic, wait until we get caps before trying
>>>             * to query for duration. */
>>> -        stream->duration = query_duration(stream->their_src);
>>> +        stream->duration = query_duration(stream->their_src, duration_wait);
>>>        }
>>>        pthread_mutex_unlock(&parser->mutex);
>>>
>>
> 
> Thank you very much for the review.
> 



More information about the wine-devel mailing list