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:
wm4 2016-08-19 14:19:46 +02:00
parent 4aaa83339c
commit 05e4df3f0c
8 changed files with 39 additions and 5 deletions

View File

@ -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;

View File

@ -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; };

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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]

View File

@ -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;