最近在學習FFmpeg的過程中發現,其他的知識點還比較清楚,就是對于FFmpeg中的時間基概念模糊,前面做Demo也只是照貓畫虎,沒有真正理解,所以今天花時間好好理解一下時間戳和時間基的概念。
PTS和DTS
這兩個概念其實在剛開始的時候就提到過,今天的概念跟它們還是有很大關系的,所以再說一次概念,具體解釋請看音視頻基礎概念。
- PTS: Presentation Time Stamp,顯示渲染用的時間戳,告訴我們什么時候需要顯示
- DTS: Decode Time Stamp,視頻解碼時的時間戳,告訴我們什么時候需要解碼
時間基
在寫代碼處理音視頻流的時候經常會看到in_stream->time_base
這樣的代碼,這表示的是輸入流的時間基,time_base時間基的結構體定義如下:
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented.
* 這是表示幀時間戳的基本時間單位(以秒為單位)。
**/
typedef struct AVRational{
int num; ///< Numerator 分子
int den; ///< Denominator 分母
} AVRational;
可以看出時間基是一個分數,以秒為單位,比如1/50秒,那它到底表示的是什么意思呢?以幀率為例,如果它的時間基是1/50秒,那么就表示每隔1/50秒顯示一幀數據,也就是每1秒顯示50幀,幀率為50FPS。
每一幀數據都有對應的PTS,在播放視頻或音頻的時候我們需要將PTS時間戳轉化為以秒為單位的時間,用來最后的展示。那如何計算一楨在整個視頻中的時間位置?
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
//計算一楨在整個視頻中的時間位置
timestamp(秒) = pts * av_q2d(st->time_base);
//計算視頻長度的方法:
time(秒) = st->duration * av_q2d(st->time_base);
內部時間基
FFmpeg中的所有時間都是以它為一個單位
/**
* Internal time base represented as integer
* 內部時間基
*/
#define AV_TIME_BASE 1000000
//內部時間基的分數表示,實際上它是AV_TIME_BASE的倒數
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
//ffmpeg內部的時間與標準的時間轉換方法
timestamp(ffmpeg內部時間戳) = AV_TIME_BASE * time(秒)
time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg內部時間戳)
當需要把視頻跳轉到N秒的時候可以使用下面的方法:
av_seek_frame(fmt_ctx, index_of_video, N * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
有時候我們需要在不同的時間基之間做換算。
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
這個方法實際的操作是 a * bq / cq
,看起來簡單,但它內部處理了數值溢出的問題,所以我們在操作的時候最好還是直接調用這個方法。