在ffmpeg中,解碼前的數據結構體爲AVPacket(參考:3.AVPacket使用),而解碼後的數據爲AVFrame(視頻的YUV, RGB, 音頻的PCM,數據量更大)html
1.AVFrame介紹數組
2.經常使用函數使用數據結構
AVFrame *av_frame_alloc(void); // 初始化 void av_frame_unref(AVFrame *frame); //引用減1.若爲0則釋放緩衝區數據,注意調用avcodec_receive_frame()時會自動引用減1後再獲取frame,因此解碼過程當中無需每次調用 void av_frame_free(AVFrame **frame); //釋放frame自己 av_frame_ref(AVFrame *dst, const AVFrame *src); //從src複製到一個初始化好的dst中,並引用+1 av_frame_clone(const AVFrame *src); //建立並返回一個複製好的AVPacket(在音視頻同步處理中用到該函數) //獲取frame相關函數 int avcodec_send_packet(pCodecCtx, pPacket); //發送要解碼的數據到解碼隊列中,並引用+1.返回0表示發送成功 int avcodec_receive_frame(pCodecCtx, pFrame); //從解碼隊列中獲取一幀AVFrame,而且獲取的AVFrame是已經經過pts排列好的數據,返回0表示獲取成功
注意事項:ide
因爲DTS和PTS的順序多是不一致的.因此每次視頻解碼完成後,可能還有幾幀frame未顯示,
咱們須要在末尾經過avcodec_send_packet()傳入NULL來將最後幾幀取出來函數
2.AVFrame結構體佈局
AVFrame結構體中有不少成員,常見的成員以下所示,註釋已替換:post
typedef struct AVFrame { #define AV_NUM_DATA_POINTERS 8 uint8_t *data[AV_NUM_DATA_POINTERS]; //存儲原始幀數據(視頻的YUV, RGB, 音頻的PCM),數組的每個元素是一個指針,指向了AVBufferRef *buf中的data //對於packet格式,都存在data[0]中,好比yuv,data[0]中就存的是yuvyuvyuv...,pcm則是lrlrlrlr... //對於planar格式,則是分開存儲,好比yuv,data[0]存y,data[1]存u,data[2]存v,pcm則是data[0]存L,data[1]存R
int linesize[AV_NUM_DATA_POINTERS]; //對於視頻,linesize是每一個圖像的一行(寬)數據大小(字節數)。注意有對齊要求(16或32對齊) //對於音頻,則是每一個data[]通道里的字節大小,而且每一個通道(通常就兩通道:L和R)的字節數相同
uint8_t **extended_data; //extended_data:*extended_data始終等於data[0]裏的成員。 //之因此取名爲extended_data,是由於data[]最大隻能8個通道. //好比planar格式的pcm的通道數超過了8個,那麼就只能使用extended_data來獲取數據.
int width, height; //視頻幀的尺寸(以像素爲單位) //用戶能夠經過if (frame->width > 0 && frame->height > 0)來判斷是否爲視頻流
int nb_samples; //音頻幀的單通道樣本數據數量(不是以字節爲單位,以單個音頻數據爲單位)
//好比frame的linesize[0]=8192,LR雙通道,format爲float planar格式(4字節),那麼nb_samples=8192/2/4=1024
int format; //幀的格式,若是未知或未設置爲-1 //對於視頻幀,參考AVPixelFormat枚舉值,好比:AV_PIX_FMT_YUV420P //對於音頻幀,參考AVSampleFormat枚舉值,好比:AV_SAMPLE_FMT_U8
int key_frame; //是否爲一幅完整的畫面,關鍵幀(I幀)的標識 //1->關鍵幀,0->非關鍵幀
enum AVPictureType pict_type; //視頻幀類型(I、B、P等),好比:AV_PICTURE_TYPE_I(I幀) //I幀:一幅完整的畫面 //B幀:參考前面和後面兩幀的數據加上本幀的變化而得出的本幀數據 //P幀:參考前面而得出的本幀數據. //若是I幀不完整,那麼整個GOP(Group of Picture)都是花屏的.
/** * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. */ AVRational sample_aspect_ratio; //像素的寬高比,經過av_q2d()來獲取值,若是未知/未指定,爲0/1。
/** * Presentation timestamp in time_base units (time when frame should be shown to user). */ int64_t pts; //顯示時間戳,表示當前爲第幾幀,若是要換算爲時分秒,則須要AVStream的time_base時基來一塊兒換算 //好比: //int timeVal=av_q2d(pFormatCtx->streams[videoindex]->time_base) * pFrame->pts*100; //int hour = timeVal/360000; //int minute = timeVal%360000/6000; //int second = timeVal%6000/100; //int msec = timeVal%100*10;
#if FF_API_PKT_PTS
/** * PTS copied from the AVPacket that was decoded to produce this frame. * @deprecated use the pts field instead */ int64_t pkt_pts; //使用pts字段代替(pts=pkt_pts)
#endif int64_t pkt_dts; //pkt_dts:解碼時間戳,等於AVPacket的dts,若是AVPacket只有dts而未設置pts,此值也是此frame的pts
//好比mjpeg格式的視頻,就只有I幀,不須要對pts進行排序,因此dts和pts值同樣
int coded_picture_number; //編碼順序的圖像
int display_picture_number; //播放順序的圖像
/** * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) */
int quality; //視頻質量,值越小越好
int repeat_pict; //當解碼時,這表示圖片必須延遲多少.extra_delay = repeat_pict / (2*fps)
int interlaced_frame; //圖像逐行/隔行模式標識。
int top_field_first; //若是內容是隔行模式掃描,則首先顯示頂部字段。
int palette_has_changed; //用來告訴應用程序,調色板已從前一幀更改。
int64_t reordered_opaque; //從新排序的不透明64位(一般是整數或雙精度浮點PTS,但能夠是任何東西)。
int sample_rate; //音頻數據的採樣率。
uint64_t channel_layout; //音頻數據的通道佈局,參考channel_layout.h //好比AV_CH_FRONT_LEFT:表示前左聲道
/** * AVBuffer references backing the data for this frame. If all elements of * this array are NULL, then this frame is not reference counted. This array * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must * also be non-NULL for all j < i. * * There may be at most one AVBuffer per data plane, so for video this array * always contains all the references. For planar audio with more than * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in * this array. Then the extra AVBufferRef pointers are stored in the * extended_buf array. */ AVBufferRef *buf[AV_NUM_DATA_POINTERS]; //經過引用計數,使該AVBufferRef來間接使用AVBuffer緩衝區,也就是data[]指向的原始數據. //用戶不該直接使用data成員,應經過buf成員間接使用data成員 //若是buf[]的全部元素都爲NULL,則此幀不會被引用計數。必須連續填充buf[] - 若是buf[i]爲非NULL,則對於全部j<i,buf[j]也必須爲非NULL
AVBufferRef **extended_buf; int nb_extended_buf; //和extended_data相似,由於buf最多存儲8通道. //extended_buf和AVFrame.extended_data惟一不一樣在於:extended_data包含全部指向各plane的指針,而extended_buf只包含buf中裝不下的指針。
AVFrameSideData **side_data; int nb_side_data; //邊緣數據和數目
/** * @defgroup lavu_frame_flags AV_FRAME_FLAGS * @ingroup lavu_frame * Flags describing additional frame properties. * * @{ */
#define AV_FRAME_FLAG_CORRUPT (1 << 0)
//標記須要解碼但不該該輸出的幀的標誌。幀數據可能被損壞,例如因爲解碼錯誤
#define AV_FRAME_FLAG_DISCARD (1 << 2)
//標記須要解碼但不該該輸出的幀的標誌。
int flags; //編解碼失敗後,用戶能夠經過該flag查看是否爲AV_FRAME_FLAG_CORRUPT或者AV_FRAME_FLAG_DISCARD
enum AVColorRange color_range; //圖像的編碼格式(MPEG/JPEG),解碼時,由庫設置,編碼時,由用戶來設置
enum AVColorPrimaries color_primaries; //圖像源初選的色度座標
enum AVColorTransferCharacteristic color_trc; //圖像顏色傳輸特性
/** * YUV colorspace type. * - encoding: Set by user * - decoding: Set by libavcodec */
enum AVColorSpace colorspace; //圖像彩色空間類型,解碼時,由庫設置,編碼時,由用戶來設置 //好比等於AVCOL_SPC_RGB時,那麼color_trc等於AVCOL_TRC_IEC61966_2_1
enum AVChromaLocation chroma_location; //儲存的顏色色度樣品的位置
/** * reordered pos from the last AVPacket that has been input into the decoder * - encoding: unused * - decoding: Read by user. */ int64_t pkt_pos; //標記最後一個解碼的packet在輸入文件中的位置偏移量。
int64_t pkt_duration; //該幀的持續時間,須要經過AVStream的time_base時基來換算
/** * metadata. * - encoding: Set by user. * - decoding: Set by libavcodec. */ AVDictionary *metadata; int decode_error_flags; //解碼幀的錯誤標誌
#define FF_DECODE_ERROR_INVALID_BITSTREAM 1
#define FF_DECODE_ERROR_MISSING_REFERENCE 2
#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4
#define FF_DECODE_ERROR_DECODE_SLICES 8
int channels; //音頻通道數量,僅用於音頻 //用戶能夠經過 if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))來判斷該frame是否爲音頻
int pkt_size; //壓縮幀的相應數據包的大小。
size_t crop_top; size_t crop_bottom; size_t crop_left; size_t crop_right; //用於裁剪視頻幀圖像用的。四個值分別爲從frame的上/下/左/右邊界裁切的像素數。 //...
}AVFrame;