mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
1bf6abc62d
commit
e6afc53e7c
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue