summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorllyyr <llyyr.public@gmail.com>2023-08-31 15:20:32 +0530
committerDudemanguy <random342@airmail.cc>2023-09-02 19:02:21 +0000
commite6afc53e7cabf7d36aab4a8b25a6e2688e4449c8 (patch)
tree1f8e36de1605abd9cd98ef152032fd6d64c1380c /demux
parent1bf6abc62d2ac09745c0764328de22335cd93ec0 (diff)
downloadmpv-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.c36
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;