diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index c785c62c90..26e67fe1b9 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -86,7 +86,7 @@ static int init(struct dec_audio *da, const char *decoder) struct priv *ctx = talloc_zero(NULL, struct priv); da->priv = ctx; - ctx->codec_timebase = (AVRational){0}; + ctx->codec_timebase = mp_get_codec_timebase(da->codec); ctx->force_channel_map = c->force_channels; diff --git a/common/av_common.c b/common/av_common.c index 6856a27d93..3a424b0c62 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -84,6 +85,30 @@ void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c) #endif } +// Pick a "good" timebase, which will be used to convert double timestamps +// back to fractions for passing them through libavcodec. +AVRational mp_get_codec_timebase(struct mp_codec_params *c) +{ + AVRational tb = {c->native_tb_num, c->native_tb_den}; + if (tb.num < 1 || tb.den < 1) { + if (c->reliable_fps) + tb = av_inv_q(av_d2q(c->fps, 1000000)); + if (tb.num < 1 || tb.den < 1) + tb = AV_TIME_BASE_Q; + } + + // If the timebase is too coarse, raise its precision, or small adjustments + // to timestamps done between decoder and demuxer could be lost. + if (av_q2d(tb) > 0.001) { + AVRational r = av_div_q(tb, (AVRational){1, 1000}); + tb.den *= (r.num + r.den - 1) / r.den; + } + + av_reduce(&tb.num, &tb.den, tb.num, tb.den, 1000000); + + return tb; +} + // We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it. union pts { int64_t i; double d; }; diff --git a/common/av_common.h b/common/av_common.h index e2b86bfe40..4b13dcdd0c 100644 --- a/common/av_common.h +++ b/common/av_common.h @@ -33,6 +33,7 @@ struct mp_log; int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size); void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st); void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c); +AVRational mp_get_codec_timebase(struct mp_codec_params *c); void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb); int64_t mp_pts_to_av(double mp_pts, AVRational *tb); double mp_pts_from_av(int64_t av_pts, AVRational *tb); diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index ef0a8583d5..4b236ee2be 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -670,6 +670,8 @@ static void handle_new_stream(demuxer_t *demuxer, int i) if (sh->codec->lav_headers) mp_copy_lav_codec_headers(sh->codec->lav_headers, codec); #endif + sh->codec->native_tb_num = st->time_base.num; + sh->codec->native_tb_den = st->time_base.den; if (st->disposition & AV_DISPOSITION_DEFAULT) sh->default_track = true; diff --git a/demux/demux_mf.c b/demux/demux_mf.c index c0b159e4ea..20b948630c 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -321,6 +321,7 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check) c->disp_w = 0; c->disp_h = 0; c->fps = demuxer->opts->mf_fps; + c->reliable_fps = true; demux_add_sh_stream(demuxer, sh); diff --git a/demux/demux_raw.c b/demux/demux_raw.c index bd8e11306d..51378e7031 100644 --- a/demux/demux_raw.c +++ b/demux/demux_raw.c @@ -145,6 +145,9 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check) c->force_channels = true; c->samplerate = opts->samplerate; + c->native_tb_num = 1; + c->native_tb_den = c->samplerate; + int f = opts->aformat; // See PCM(): sign float bits endian mp_set_pcm_codec(sh->codec, f & 1, f & 2, f >> 3, f & 4); @@ -233,6 +236,7 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) c->codec = decoder; c->codec_tag = imgfmt; c->fps = opts->fps; + c->reliable_fps = true; c->disp_w = width; c->disp_h = height; demux_add_sh_stream(demuxer, sh); diff --git a/demux/stheader.h b/demux/stheader.h index f9d564c230..78e86a47ee 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -74,6 +74,9 @@ struct mp_codec_params { struct AVCodecContext *lav_headers; struct AVCodecParameters *lav_codecpar; + // Timestamp granularity for converting double<->rational timestamps. + int native_tb_num, native_tb_den; + // STREAM_AUDIO int samplerate; struct mp_chmap channels; @@ -85,6 +88,7 @@ struct mp_codec_params { // STREAM_VIDEO bool avi_dts; // use DTS timing; first frame and DTS is 0 float fps; // frames per second (set only if constant fps) + bool reliable_fps; // the fps field is definitely not broken int par_w, par_h; // pixel aspect ratio (0 if unknown/square) int disp_w, disp_h; // display size int rotate; // intended display rotation, in degrees, [0, 359] diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index eb63e58e92..804bf1112d 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -449,10 +449,7 @@ static void init_avctx(struct dec_video *vd, const char *decoder, if (!lavc_codec) return; - ctx->codec_timebase = (AVRational){0}; - if (strstr(decoder, "_mmal") || strstr(decoder, "_mediacodec")) - ctx->codec_timebase = (AVRational){1, 1000000}; - + ctx->codec_timebase = mp_get_codec_timebase(vd->codec); ctx->pix_fmt = AV_PIX_FMT_NONE; ctx->hwdec = hwdec; ctx->hwdec_fmt = 0;