mirror of
https://github.com/mpv-player/mpv
synced 2025-04-01 23:00:41 +00:00
video/audio: always provide "proper" timestamps to libavcodec
Instead of passing through double float timestamps opaquely, pass real timestamps. Do so by always setting a valid timebase on the AVCodecContext for audio and video decoding. Specifically try not to round timestamps to a too coarse timebase, which could round off small adjustments to timestamps (such as for start time rebasing or demux_timeline). If the timebase is considered too coarse, make it finer. This gets rid of the need to do this specifically for some hardware decoding wrapper. The old method of passing through double timestamps was also a bit questionable. While libavcodec is not supposed to interpret timestamps at all if no timebase is provided, it was needlessly tricky. Also, it actually does compare them with AV_NOPTS_VALUE. This change will probably also reduce confusion in the future.
This commit is contained in:
parent
4aaa83339c
commit
05e4df3f0c
@ -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;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/log.h>
|
||||
@ -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; };
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user