相关概念
tbr: 是我们通常所说的帧率。time base of rate
tbn: 视频流的时间基。 time base of stream
tbc: 视频解码的时间基。time base of codec
tbn = the time base in AVStream that has come from the container
tbc = the time base in AVCodecContext for the codec used for a particular stream
tbr = tbr is guessed from the video stream and is the value users want to see when they look for the video frame rate.
ffmpeg内部时间基
ffmpeg中的内部计时单位(时间基),ffmepg中的所有时间都是于它为一个单位,
比如AVStream中的duration,即这个流的长度为duration个AV_TIME_BASE.
#define AV_TIME_BASE 1000000
它还有一种分数所表式法:
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
在 ffmpeg中进行换算,将不同时间基的值转成按秒为单位的值计算如下:
timestamp(秒) = pts * av_q2d(time_base)
相关定义
AVRatioal的定义如下:
typedef struct AVRational{ int num; //numerator int den; //denominator } AVRational; }
AVRatioal结构转double的函数:
static inline double av_q2d(AVRational a){ /** * Convert rational to double. * @param a rational to convert **/ return a.num / (double) a.den; }
av_get_time_base_q函数
返回内部时基的小数表示.
/** * Return the fractional representation of the internal time base. */ AVRational av_get_time_base_q(void);
av_rescale_q函数
av_rescale_q(a,b,c)的作用是,把时间戳从一个时基调整到另外一个时基时候用的函数。其中,a 表式要换算的值;b 表式原来的时间基;c表式要转换的时间基。其计算公式为 a * b / c。
/** * Rescale a 64-bit integer by 2 rational numbers. ** The operation is mathematically equivalent to `a * bq / cq`. ** This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. * * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() */ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
用例
用于计算Packet中的pts
if (pkt->pts != AV_NOPTS_VALUE) { pkt->pts = av_rescale_q(pkt->pts, mCtx->streams[pkt->stream_index]->time_base, av_get_time_base_q()); } if (pkt->dts != AV_NOPTS_VALUE) { pkt->dts = av_rescale_q(pkt->dts, mCtx->streams[pkt->stream_index]->time_base, av_get_time_base_q()); }
根据pts来计算一桢在整个视频中的时间位置
timestamp(秒) = pts * av_q2d(st->time_base)
计算视频长度的方法
time(秒) = st->duration * av_q2d(st->time_base)
这里的st是一个AVStream对象指针。
时间基转换公式
timestamp(ffmpeg内部时间戳) = AV_TIME_BASE * time(秒)
time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg内部时间戳)
示例:
int64_t timestamp = N * AV_TIME_BASE; av_seek_frame(fmtctx, index_of_video, timestamp, AVSEEK_FLAG_BACKWARD); //ffmpeg同样为我们提供了不同时间基之间的转换函数: int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) //时间戳转秒 time_in_seconds = av_q2d(AV_TIME_BASE_Q) * timestamp //秒转时间戳 timestamp = AV_TIME_BASE * time_in_seconds