天天看點

ffmpeg中的時間

目錄 [​​hide​​]

  • ​​1 視訊的顯示和存放原理​​
  • ​​1.1 DTS和PTS​​
  • ​​2 ffmpeg中的時間機關​​
  • ​​2.1 AV_TIME_BASE​​
  • ​​2.2 AV_TIME_BASE_Q​​
  • ​​2.3 時間基轉換公式​​

視訊的顯示和存放原理

對于一個電影,幀是這樣來顯示的:I B B P。現在我們需要在顯示B幀之前知道P幀中的資訊。是以,幀可能會按照這樣的方式來存儲:IPBB。這就是為什麼我們會有一個解碼時間戳和一個顯示時間戳的原因。解碼時間戳告訴我們什麼時候需要解碼,顯示時間戳告訴我們什麼時候需要顯示。是以,在這種情況下,我們的流可以是這樣的:

PTS: 1 4 2 3
DTS: 1 2 3 4
Stream: I P B B      

通常PTS和DTS隻有在流中有B幀的時候會不同。

DTS和PTS

音頻和視訊流都有一些關于以多快速度和什麼時間來播放它們的資訊在裡面。音頻流有采樣,視訊流有每秒的幀率。然而,如果我們隻是簡單的通過數幀和乘以幀率的方式來同步視訊,那麼就很有可能會失去同步。于是作為一種補充,在流中的包有種叫做DTS(解碼時間戳)和PTS(顯示時間戳)的機制。為了這兩個參數,你需要了解電影存放的方式。像MPEG等格式,使用被叫做B幀(B表示雙向bidrectional)的方式。另外兩種幀被叫做I幀和P幀(I表示關鍵幀,P表示預測幀)。I幀包含了某個特定的完整圖像。P幀依賴于前面的I幀和P幀并且使用比較或者差分的方式來編碼。B幀與P幀有點類似,但是它是依賴于前面和後面的幀的資訊的。這也就解釋了為什麼我們可能在調用avcodec_decode_video以後會得不到一幀圖像。

ffmpeg中的時間機關

AV_TIME_BASE

ffmpeg中的内部計時機關(時間基),ffmepg中的所有時間都是于它為一個機關,比如AVStream中的duration即以為着這個流的長度為duration個AV_TIME_BASE。AV_TIME_BASE定義為:

#define         AV_TIME_BASE   1000000      

AV_TIME_BASE_Q

ffmpeg内部時間基的分數表示,實際上它是AV_TIME_BASE的倒數。從它的定義能很清楚的看到這點:

#define         AV_TIME_BASE_Q   (AVRational){1, AV_TIME_BASE}      

AVRatioal的定義如下:

typedef struct AVRational{
int num; //numerator
int den; //denominator
} AVRational;      

ffmpeg提供了一個把AVRatioal結構轉換成double的函數:

static inline double av_q2d(AVRational a){
/**
* Convert rational to double.
* @param a rational to convert
**/
    return a.num / (double) a.den;
}      

現在可以根據pts來計算一桢在整個視訊中的時間位置:

timestamp(秒) = pts * av_q2d(st->time_base)      

計算視訊長度的方法:

time(秒) = st->duration * av_q2d(st->time_base)      

這裡的st是一個AVStream對象指針。

時間基轉換公式

  • timestamp(ffmpeg内部時間戳) = AV_TIME_BASE * time(秒)
  • time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg内部時間戳)
int64_t timestamp = N * AV_TIME_BASE; 
2
av_seek_frame(fmtctx, index_of_video, timestamp, AVSEEK_FLAG_BACKWARD);      
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)