在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)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL4EzM2ADO0gTMxIjMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
對于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)轉換的問題。