天天看點

pts_dts解析

在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_dts解析
pts_dts解析
pts_dts解析
pts_dts解析

對于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)

pts_dts解析

最後再梳理一下

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)轉換的問題。