一. 本章節(jié)介紹:
本章節(jié)主要介紹FFMPEG的時間概念冰单,包括時間基肖抱、時間戳、時間轉(zhuǎn)換瓦侮、時間比較等知識點凛膏。這些知識點對于我們了解推流至關(guān)重要,因為音視頻合成本質(zhì)上是各種時間轉(zhuǎn)換的過程脏榆。
二. FFMPEG 時間基猖毫、 時間戳的講解:
2.1. 時間基(time_base):時間基也稱之為時間基準(zhǔn),它代表的是每個刻度是多少秒须喂。比方說:視頻幀率是30FPS吁断,那它的時間刻度是{1,30}。相當(dāng)于1s內(nèi)劃分出30個等分坞生,也就是每隔1/30秒后顯示一幀視頻數(shù)據(jù)仔役。具體的如下圖所示:
在FFMPEG中時間基準(zhǔn)都是用AVRational結(jié)構(gòu)體來表示:
num:它是numerator的縮小,代表的是分子
den:它是denominator的縮小是己,代表的是分母
在視頻時間基都是以幀率為單位又兵,比方說50幀。FFMPEG就以AVRational video_timebase = {1, 50}來表示卒废。
在音頻時間基都是以采樣率為單位沛厨,比方說音頻采樣率是48000HZ。FFMPEG就以AVRational audio_timebase = {1, 48000}來表示摔认。
對于封裝格式來說:flv 封裝格式的 time_base 為{1,1000}逆皮,ts 封裝格式的 time_base 為{1,90000}
從上圖ffplay的信息我們可以看到有很多關(guān)于時間基的信息:
tbr:表示幀率,該幀率是一個基準(zhǔn)参袱,通常來說tbr和fps是一致的
tbn:表示視頻流timebase(時間基)电谣,比方說:TS格式的數(shù)據(jù)timebase是90000,flv格式的視頻流timebase為1000
tbc:表示視頻流codec timebase抹蚀,這個值一般為幀率的兩倍剿牺。比方說:幀率是30fps,則tbc是60
2.2. 時間戳(PTS环壤、DTS):
首先時間戳它指的是在時間軸里面占了多少個格子晒来,時間戳的單位不是具體的秒數(shù),而是時間刻度镐捧。只有當(dāng)時間基和時間戳結(jié)合在一起的時候潜索,才能夠真正表達出來時間是多少臭增。
比方說:
有一把尺子pts = 30個刻度,time_base = {1,30} 每一個刻度是1/30厘米
所以這把尺子的長度 = pts * time_base = 30 * 1/30 = 1厘米
PTS:全稱是Presentation Time Stamp(顯示時間戳)竹习,它主要的作用是度量解碼后的視頻幀什么時候顯示出來誊抛。
視頻PTS計算:n為第n幀視頻幀,timebase是{1整陌,framerate}拗窃,fps是framerate
pts = n *(( 1 / timebase) / fps):
pts = pts++;
舉例子:n = 1, pts = 1
n = 2, pts = 2
n =3, pts = 3
音頻PTS計算:n為第n幀音頻幀,nb_samples指的是采樣個數(shù)(AAC默認(rèn)1024)泌辫,timebase是{1,samplerate}随夸,samplerate是采樣率
num_pkt = samplerate/nb_samples
pts = n * ( ( 1/ timebase) / num_pkt)
pts = pts+1024
舉例子:n = 1, pts = 1024
n = 2, pts = 2048
n = 3, pts = 3072
2.3. DTS:表示的是壓縮解碼的時間戳,在沒有B幀的情況下PTS 等于 DTS震放。假設(shè)編碼的里面引入了B幀宾毒,則還要計算B幀的時間。
沒有B幀:dts = pts
存在B幀:dts = pts + b_time
三. 時間轉(zhuǎn)換的原理:
在FFMPEG中由于不同的復(fù)合流殿遂,時間基是不同的诈铛,比方說:ts的時間基time_base= {1,90000},假設(shè)一個視頻time_base = {1,30}墨礁,我們需要合成mpegts文件幢竹,它就需要把time_base = {1,30}占的格子轉(zhuǎn)換成time_base = {1,90000}占的格子。
在FFMPEG中用以下的API進行時間基轉(zhuǎn)換:
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
第一個參數(shù):AVPacket結(jié)構(gòu)體指針
第二個參數(shù):源時間基
第三個參數(shù):目的時間基
上面這個api的用法是恩静,把AVPacket的時間基tb_src轉(zhuǎn)換成時間基tb_dst焕毫。下面我們用H264和AAC時間基TS轉(zhuǎn)換的例子來說明這個轉(zhuǎn)換時間基的用法:
視頻H264時間基轉(zhuǎn)換成MPEGTS時間基: av_packet_rescale_ts
*DST_VIDEO_PTS = VIDEO_PTS * VIDEO_TIME_BASE / DST_TIME_BASE
例src_pts=1:dst_pts=1(1/30)/(1/90000)=3000
H264 {1,30} MPEGTS {1,90000}
pts = 1 pts = 3000
pts = 2 pts = 6000
pts = 3 pts = 9000
pts = 4 pts = 12000
音頻AAC時間基轉(zhuǎn)換成MPEGTS時間基:av_packet_rescale_ts
DST_AUDIO_PTS = AUDIO_PTS * AUDIO_TIME_BASE / DST_TIME_BASE
例src_pts=1024:dst_pts=1024(1/48000)(1/90000)
AAC {1,48000} MPEGTS {1,90000}
pts =1024 pts = 1920
pts =2048 pts = 3840
pts =3072 pts = 5760
pts =4096 pts = 7680
從上述推導(dǎo)的結(jié)果可以看出來,如果使用av_packet_rescale_ts的API對視頻時間基進行轉(zhuǎn)換驶乾,實際上是使用DST_VIDEO_PTS = VIDEO_PTS * VIDEO_TIME_BASE / DST_TIME_BASE去計算推流的視頻時間戳邑飒。
同理用av_packet_rescale_ts對音頻時間基進行轉(zhuǎn)換,實際上是使用DST_AUDIO_PTS = AUDIO_PTS * AUDIO_TIME_BASE / DST_TIME_BASE去計算我們真實推流的音頻時間戳轻掩。
四. FFMPEG時間戳的比較:
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
第一個參數(shù):ts_a它指的是當(dāng)前相對tb_a的時間戳
第二個參數(shù):ts_a相對應(yīng)的時間基
第三個參數(shù):ts_b它指的是當(dāng)前相對tb_a的時間戳
第四個參數(shù):ts_b相對應(yīng)的時間基
返回值判斷:
當(dāng)ret == -1幸乒, ts_a的時間戳快過ts_b時間戳懦底。
當(dāng)ret == 1唇牧, ts_a的時間戳慢過ts_b時間戳。
當(dāng)ret == 0聚唐, ts_a的時間戳等于ts_b時間戳
av_compare_ts它的主要作用是進行時間戳進行實時比較丐重,它能夠?qū)崟r保證當(dāng)前的時間戳是準(zhǔn)確無誤的。它不會出現(xiàn)時間戳混亂的情況杆查,所謂混亂的情況就相當(dāng)于:視頻時間戳當(dāng)成音頻時間戳處理扮惦,音頻時間戳當(dāng)成視頻時間戳處理。
下面這張圖是編碼視頻亲桦、音頻然后進行時間戳比較然后合成復(fù)合流的流程:
視頻時間戳參考視頻幀率進行比較崖蜜、音頻時間戳進行比較(這里我們默認(rèn)tb_a時間基是視頻時間基浊仆、tb_b時間基是音頻時間基)。所以當(dāng)比較的結(jié)果ret <= 0的時候豫领,則要取出視頻數(shù)據(jù)抡柿,否則就取出音頻數(shù)據(jù)。取出視頻數(shù)據(jù)后則利用av_packet_rescale_ts進行時間轉(zhuǎn)換等恐、同樣取出音頻數(shù)據(jù)后也要對其進行時間轉(zhuǎn)換洲劣。音視頻數(shù)據(jù)進行時間轉(zhuǎn)換后,則用av_interleaved_write_frame對復(fù)合流進行寫入操作课蔬。