經過簡單的計算來,線上I幀在視頻中出現的時間點。 完整代碼請參考 https://andy-zhangtao.github.io/ffmpeg-examples/git
首先須要明確如下名詞概念:github
視頻內沒有絕對時間,只有相對時間(相對視頻起始位置)。例如在播放器中看到的時間進度條"00:00:05"表示的是當前看到的幀是在相對起始時間點(00:00:00)解碼並渲染的。函數
而"00:00:05"只是爲了讓用戶方便理解而展示出來的,在視頻內部則是使用時間戳來保存的,"00:00:05"可能相對的時間戳則是"5000000µs"(不考慮四捨五入)。編碼
那麼時間戳又是怎麼計算出來的呢?此時就須要經過PTS和Time_base來配合計算。code
首先來看Time_base。 Time_base比如一把尺子,上面標滿了刻度,例如(1,60)表示時間刻度就是1/60,每一個時間單位就是1/60秒。 若是是(1,1000)就表示每一個時間單位是1微秒。orm
上面說到pts是顯示的時間刻度, 也就是佔用了多少時間刻度。 換算成大白話就是pts佔用了多少個刻度,而time_base表示每一個刻度是多長。視頻
然而這有什麼用呢?Time_base最重要的做用是用來統一」時間節奏"的。 例如視頻A編碼時採用1/1000的time_base,則某個幀的pts保存爲465000。 當對視頻A進行解碼時,換成了1/9000的time_base,此時時間刻度不一致了,就須要經過pts*encode_time_base來換算成解碼時的timestamp,這樣才能保證正確解碼。get
上面是理論介紹,下面來看如何經過代碼來計算timestamp和換算成time.input
此次只須要顯示每幀的pts,time_base,time所以不須要初始化output, 只要初始化input便可。iframe
按照前幾篇介紹的初始化思路,只須要按照打開文件
->判斷視頻流
->初始化解碼器
這樣的步驟就能夠了。
+------------------------+ +-------------------------+ | avformat_open_input | ------------>|avformat_find_stream_info| +------------------------+ +-------------------------+ | | | \|/ +-----------------------------+ +-------------------------+ |avcodec_parameters_to_context| <---------| avcodec_find_decoder | +-----------------------------+ +-------------------------+
avcodec_parameters_to_context
尤爲須要關注,這個函數會根據輸入源的編碼信息來初始化用戶指定的編碼上下文。若是編碼信息不匹配或者設置錯誤時,會出現莫名的解碼錯誤。通常調用這個函數後,大多數的解碼錯誤都能消失。
time_base是一個struct
typedef struct AVRational{ int num; ///< Numerator int den; ///< Denominator } AVRational;
num 表示的是分子,den表示分母。 對於time_base來講num就是1,den表示每一秒等分了多少份。 上面說過經過pts*time_base
就能夠得出時間戳,因此須要計算出每一個時間刻度具體表明多少,因此經過av_q2d
得出每一個刻度具體值。
在循環讀入解碼後的幀數據以後,能夠直接經過iframe->pts
來讀取當前幀的pts值,而後再乘以刻度值就能夠得出當前時間戳iframe->pts * av_q2d(_time_base)
。
僞代碼以下:
while av_read_frame { avcodec_send_packet ... while avcodec_receive_frame { ... iframe->pts * av_q2d(_time_base) ... } }