FFMPEG結構體分析:AVFrame

在此不再詳述,其中AVFrame是包含碼流參數較多的結構體。本文將會詳細分析一下該結構體里主要變量的含義和作用。
(位于libavutil/frame.h)

首先看一下結構體的描述:

  • 該結構描述被解碼的音頻或視頻數據(原始數據)
  • AVFrame必須用av_frame_alloc分配。注意,這僅分配AVFrame本身,對于數據緩沖器,必須通過其他手段管理。AVFrame必須使用av_frame_free釋放。AVFrame通常分配一次,然后多次重復使用(比如一個AVFrame持有多個從解碼器接收的frame)在這種情況下,av_frame_unref將釋放所持的任何引用,并重置AVFrame到初始狀態。
  • 由AVFrame描述的數據通常是通過調用AVBuffer API計數。底層緩沖引用存儲在AVFrame.buf/AVFrame.extended_buf中。如果有至少一個參數被設置過,比如AVFrame.buf[0]!= NULL,AVFrame通常被認為應該使用引用計數。 在這種情況下,每一個數據平面必須包含被包含在AVFrame.buf或AVFrame.extended_buf中。
  • AVFrame的size并不在公開的ABI中,所以在附加模塊的末尾可以新加變量。被av_opt_ptr標記為僅訪問的類似字段可以重新排序。
#define AV_NUM_DATA_POINTERS 8

變量:

指向圖片/信道層的指針
與初始化時分配的大小可能不同
一些解碼器取數據范圍超出(0,0)-(width,height),具體請查看avcodec_align_dimensions2()方法。
一些過濾器和掃描器讀數據時可能會超過16字節,所以當它們被使用的時候,必須額外分配16字節。

uint8_t *data[AV_NUM_DATA_POINTERS];

對于視頻數據,為每個圖像行的字節大小
對于音頻數據,為每個平面的字節大小。
對于音頻,只有LINESIZE[0]可以設置。
對于平面音頻,每個信道平面必須是相同的大小。
對于視頻的linesizes應為CPU的對準要求的倍數,現代桌面CPU為16或32。某些代碼需要這樣對準,其它代碼可以偏慢沒有正確對齊,但目前沒有區別。
@注意 linesize可大于可用的數據的尺寸 - 有可能存在由于性能原因額外填充。

int linesize[AV_NUM_DATA_POINTERS];

指向圖片/信道層的指針
對于視頻,只是指向數據。
對于平面音頻,每個通道都有一個單獨的數據指針,LINESIZE[0]包含各信道的緩沖區的大小。
用于打包的音頻,只有一個數據指針,和LINESIZE[0]包含緩沖所有通道的總大小。
注意:兩個數據和擴展數據應該總是在一個有效的幀進行設置,但對于具有多個信道的平面的音頻可以容納在數據,擴展的數據必須被用來對所有頻道存取。

uint8_t **extended_data;

視頻幀的寬高

int width, height;

由該幀描述的音頻樣本的數目(每個通道

int nb_samples;

幀格式,-1為未設置或者未知格式

int format;

是否為關鍵幀,1為關鍵幀

int key_frame;

幀圖片的類型

enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///靜止幀 壓縮率最低
    AV_PICTURE_TYPE_P,     ///向前預測幀
    AV_PICTURE_TYPE_B,     ///雙向預測幀
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};
enum AVPictureType pict_type;

指向第一次分配的內存
目前已廢除

uint8_t *base[AV_NUM_DATA_POINTERS];

Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
幀的長寬比 0/1為未知/不確定

typedef struct AVRational{
    int num; ///< numerator分子
    int den; ///< denominator分母
} AVRational;
 AVRational sample_aspect_ratio;

基礎時間戳(決定何時顯示)(做幀同步)

int64_t pts;

解碼產生本幀的AVPacket的pts拷貝

int64_t pkt_pts;

返回觸發此幀的AVPacket的dts拷貝(幀線程未被使用)
不使用pts值只用AVPacket的dts計算出來的該幀的描述時間

int64_t pkt_dts;

比特流隊列中圖片序號

int coded_picture_number;

顯示隊列的圖片序號

int display_picture_number;

品質(介于1(最好)和FF_LAMBDA_MAX(壞)之間)

int quality;

QP表
QP表指向一塊內存,里面存儲的是每個宏塊的QP值。宏塊的標號是從左往右,一行一行的來的。每個宏塊對應1個QP。
qscale_table[0]就是第1行第1列宏塊的QP值;qscale_table[1]就是第1行第2列宏塊的QP值;qscale_table[2]就是第1行第3列宏塊的QP值。以此類推...
宏塊的個數用下式計算:
注:宏塊大小是16x16的。
每行宏塊數:
int mb_stride = pCodecCtx->width/16+1
宏塊的總數:
int mb_sum = ((pCodecCtx->height+15)>>4)*(pCodecCtx->width/16+1)

int8_t *qscale_table
uint8_t *mbskip_table:跳過宏塊表
int16_t (*motion_val[2])[2]:運動矢量表
運動矢量表存儲了一幀視頻中的所有運動矢量。
該值的存儲方式比較特別:
int16_t (*motion_val[2])[2];  
int mv_sample_log2= 4 - motion_subsample_log2;  
int mb_width= (width+15)>>4;  
int mv_stride= (mb_width << mv_sample_log2) + 1;  
motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];  
該數據的結構:
1.首先分為兩個列表L0和L1
2.每個列表(L0或L1)存儲了一系列的MV(每個MV對應一個畫面,大小由motion_subsample_log2決定)
3.每個MV分為橫坐標和縱坐標(x,y)
注意,在FFMPEG中MV和MB在存儲的結構上是沒有什么關聯的,第1個MV是屏幕上左上角畫面的MV(畫面的大小取決于motion_subsample_log2),第2個MV是屏幕上第1行第2列的畫面的MV,以此類推。因此在一個宏塊(16x16)的運動矢量很有可能如下圖所示(line代表一行運動矢量的個數):
//例如8x8劃分的運動矢量與宏塊的關系:  
                //-------------------------  
                //|          |            |  
                //|mv[x]     |mv[x+1]     |  
                //-------------------------  
                //|          |            |  
                //|mv[x+line]|mv[x+line+1]|  
                //-------------------------  
uint32_t *mb_type:宏塊類型表
宏塊類型表存儲了一幀視頻中的所有宏塊的類型。其存儲方式和QP表差不多。只不過其是uint32類型的,而QP表是uint8類型的。每個宏塊對應一個宏塊類型變量。
short *dct_coeff:DCT系數,這個沒有提取過
int8_t *ref_index[2]:運動估計參考幀列表(貌似H.264這種比較新的標準才會涉及到多參考幀)
int interlaced_frame:是否是隔行掃描

1個運動矢量所能代表的畫面大小(用寬或者高表示,單位是像素),注意,這里取了log2。
代碼注釋中給出以下數據:
4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2
即1個運動矢量代表16x16的畫面的時候,該值取4;1個運動矢量代表8x8的畫面的時候,該值取3...以此類推

uint8_t motion_subsample_log2:一個宏塊中的運動矢量采樣個數,取log的

AVFrame結構體一般用于存儲原始數據(即非壓縮數據,例如對視頻來說是YUV,RGB,對音頻來說是PCM),此外還包含了一些相關的信息。比如說,解碼的時候存儲了宏塊類型表,QP表,運動矢量表等數據。編碼的時候也存儲了相關的數據。因此在使用FFMPEG進行碼流分析的時候,AVFrame是一個很重要的結構體。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • AVFrame AVFrame是包含碼流參數較多的結構體。本文將會詳細分析一下該結構體里主要變量的含義和作用。首先...
    心有琳鑫閱讀 810評論 0 0
  • AVFrame AVFrame是包含碼流參數較多的結構體。本文將會詳細分析一下該結構體里主要變量的含義和作用。首先...
    kys攻城獅s閱讀 1,156評論 0 0
  • 本篇博客在雷神的結構體介紹基礎上按自己的喜好整理的 后面根據自己工作中所需有所增改 AVStream 存儲每一個視...
    石丘閱讀 2,500評論 1 10
  • 我所說的信仰 不是單指傳統意義上的宗教信仰,而是心目中的忠誠,對工作的忠 對家人的忠。單純的人才會活的輕松。
    Bobo波浪閱讀 458評論 0 0
  • 觀天地生物氣象,學圣賢克己功夫。下手處是自強不息,成就處是至誠無息。
    劉偉書法_沈陽閱讀 311評論 0 1