在ffmpeg中,经常看到avpriv_set_pts_info(st, 33, 1, 90000);
用来设置AVStream的time_base。
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
但是,为什么pts_wrap_bits为33,pts_den为90000,我们并不知道原因。本文将详细讲解,为什么pts、dts的采样频率为90KHz。
ISO/IEC 13818-1
标准或ITU-T H.222.0
标准都是指MPEG-2标准。
H.222标准中规定,系统时钟频率(system clock frequency)为27MHz。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x219wqNK-1613904470548)(system_clock_frequency.png)]
H.222标准中规定,PTS和DTS由33个bits来表示,time scale 为90000(system_clock_frequency/300)
对于PTS, t p n ( k ) = P T S ( k ) 90 K H z tp_n(k)=\frac {PTS(k)}{90KHz} tpn(k)=90KHzPTS(k);PTS(k)是以系统时钟频率的300分频为单位的计数值, t p n ( k ) tp_n(k) tpn(k)是以秒为单位的显示时间戳;
对于DTS, t d n ( k ) = D T S ( k ) 90 K H z td_n(k)=\frac {DTS(k)}{90KHz} tdn(k)=90KHzDTS(k);DTS(k)是以系统时钟频率的300分频为单位的计数值, t d n ( k ) td_n(k) tdn(k)是以秒为单位的解码时间戳;
这里可将 s y s t e m _ c l o c k _ f r e q u e n c y 300 \frac {system\_clock\_frequency}{300} 300system_clock_frequency叫做time_scale。time_scale = 90000,time_base = 1/90000(s)
最后再梳理一下avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
unsigned int pts_num, unsigned int pts_den)
{
AVRational new_tb;
if (av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)) {
if (new_tb.num != pts_num)
av_log(NULL, AV_LOG_DEBUG,
"st:%d removing common factor %d from timebase\n",
s->index, pts_num / new_tb.num);
} else
av_log(NULL, AV_LOG_WARNING,
"st:%d has too large timebase, reducing\n", s->index);
if (new_tb.num <= 0 || new_tb.den <= 0) {
av_log(NULL, AV_LOG_ERROR,
"Ignoring attempt to set invalid timebase %d/%d for st:%d\n",
new_tb.num, new_tb.den,
s->index);
return;
}
s->time_base = new_tb; // 设置AVStream的时间基准
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
s->codec->pkt_timebase = new_tb;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
s->internal->avctx->pkt_timebase = new_tb; // 设置AVCodecContext的时间基准
s->pts_wrap_bits = pts_wrap_bits; // 记录pts存储所需的位数,33bits
}
avpriv_set_pts_info(st, 33, 1, 90000);
最终s->time_base = {1, 90000}。通过AVRational的num/den,即1/90000就可以非常容易的将pts转为pts_time。
总之,ffmpeg中所谓的time_base,time_scale不管它怎么变,本质上就是一个pts(dts)和pts_time(dts_time)转换的问题。