diff options
author | llyyr <llyyr.public@gmail.com> | 2023-08-31 15:20:32 +0530 |
---|---|---|
committer | Dudemanguy <random342@airmail.cc> | 2023-09-02 19:02:21 +0000 |
commit | e6afc53e7cabf7d36aab4a8b25a6e2688e4449c8 (patch) | |
tree | 1f8e36de1605abd9cd98ef152032fd6d64c1380c /demux | |
parent | 1bf6abc62d2ac09745c0764328de22335cd93ec0 (diff) | |
download | mpv-e6afc53e7cabf7d36aab4a8b25a6e2688e4449c8.tar.bz2 mpv-e6afc53e7cabf7d36aab4a8b25a6e2688e4449c8.tar.xz |
demux_lavf: get total duration from track durations
Before this change, mpv used to get the total duration from
`avformat_find_stream_info` and used the per-track duration as a
fallback. This change reverses this order of preference.
The timestamps returned by `avformat_find_stream_info` are truncated or
rounded or floored (depending on the decoder) at the 6th decimal place.
For e.g. `avformat_find_stream_info` may return us a duration like
44.138667, whereas the duration we get from the per-track struct has a
higher degree of precision like 44.13866666666... and so on.
This caused various problems such as the playback_pts being a bigger
value than the duration, which would cause time-remaining to be a
negative value in some cases. Or cause you to reach a negative starting
timestamp when looping on an audio file with `gapless-audio`.
Moreover, we already skipped calling `avformat_find_stream_info` for
mp4, so we had already been utilizing this per-track fallback method for
finding the duration for mp4 files. It should be noted that while this
change is only required for audio-only formats, there is no harm in
doing this for videos as well.
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux_lavf.c | 36 |
1 files changed, 18 insertions, 18 deletions
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 166bc8f908..ed4d1a21f5 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -1150,25 +1150,25 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) demuxer->is_network |= priv->format_hack.is_network; demuxer->seekable &= !priv->format_hack.no_seek; - if (priv->avfc->duration > 0) { - demuxer->duration = (double)priv->avfc->duration / AV_TIME_BASE; - } else { - double total_duration = 0; - double av_duration = 0; - for (int n = 0; n < priv->avfc->nb_streams; n++) { - AVStream *st = priv->avfc->streams[n]; - if (st->duration <= 0) - continue; - double f_duration = st->duration * av_q2d(st->time_base); - total_duration = MPMAX(total_duration, f_duration); - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || - st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - av_duration = MPMAX(av_duration, f_duration); - } - double duration = av_duration > 0 ? av_duration : total_duration; - if (duration > 0) - demuxer->duration = duration; + // We initially prefer track durations over container durations because they + // have a higher degree of precision over the container duration which are + // only accurate to the 6th decimal place. This is probably a lavf bug. + double total_duration = 0; + double av_duration = 0; + for (int n = 0; n < priv->avfc->nb_streams; n++) { + AVStream *st = priv->avfc->streams[n]; + if (st->duration <= 0) + continue; + double f_duration = st->duration * av_q2d(st->time_base); + total_duration = MPMAX(total_duration, f_duration); + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || + st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + av_duration = MPMAX(av_duration, f_duration); } + double duration = av_duration > 0 ? av_duration : total_duration; + if (duration == 0 && priv->avfc->duration > 0) + duration = (double)priv->avfc->duration / AV_TIME_BASE; + demuxer->duration = duration; if (demuxer->duration < 0 && priv->format_hack.no_seek_on_no_duration) demuxer->seekable = false; |