0. 簡介
AVFrame中存儲的是原始數據(例如視頻的YUV, RGB, 音頻的PCM), 此外還包含了一些相關的信息, 例如: 解碼的時候存儲了宏塊類型表, QP表, 運動矢量等數據. 編碼的時候也存儲了相關的數據.
1. AVFrame 數據結構定義
FFmpeg 版本3.4.1
struct AVFrame 定義於<libavutil/frame.h>
結構體源碼(我去除了注釋):
1 typedef struct AVFrame { 2 #define AV_NUM_DATA_POINTERS 8 3 4 uint8_t *data[AV_NUM_DATA_POINTERS]; 5 6 int linesize[AV_NUM_DATA_POINTERS]; 7 8 uint8_t **extended_data; 9 10 int width, height; 11 12 int nb_samples; 13 14 int format; 15 16 int key_frame; 17 18 enum AVPictureType pict_type; 19 20 AVRational sample_aspect_ratio; 21 22 int64_t pts; 23 24 #if FF_API_PKT_PTS 25 26 attribute_deprecated 27 int64_t pkt_pts; 28 #endif 29 30 int64_t pkt_dts; 31 32 int coded_picture_number; 33 34 int display_picture_number; 35 36 int quality; 37 38 void *opaque; 39 40 #if FF_API_ERROR_FRAME 41 42 attribute_deprecated 43 uint64_t error[AV_NUM_DATA_POINTERS]; 44 #endif 45 46 int repeat_pict; 47 48 int interlaced_frame; 49 50 int top_field_first; 51 52 int palette_has_changed; 53 54 int64_t reordered_opaque; 55 56 int sample_rate; 57 58 uint64_t channel_layout; 59 60 AVBufferRef *buf[AV_NUM_DATA_POINTERS]; 61 62 AVBufferRef **extended_buf; 63 64 int nb_extended_buf; 65 66 AVFrameSideData **side_data; 67 int nb_side_data; 68 69 #define AV_FRAME_FLAG_CORRUPT (1 << 0) 70 71 #define AV_FRAME_FLAG_DISCARD (1 << 2) 72 73 int flags; 74 75 enum AVColorRange color_range; 76 77 enum AVColorPrimaries color_primaries; 78 79 enum AVColorTransferCharacteristic color_trc; 80 81 enum AVColorSpace colorspace; 82 83 enum AVChromaLocation chroma_location; 84 85 int64_t best_effort_timestamp; 86 87 int64_t pkt_pos; 88 89 int64_t pkt_duration; 90 91 AVDictionary *metadata; 92 93 int decode_error_flags; 94 #define FF_DECODE_ERROR_INVALID_BITSTREAM 1 95 #define FF_DECODE_ERROR_MISSING_REFERENCE 2 96 97 int channels; 98 99 int pkt_size; 100 101 #if FF_API_FRAME_QP 102 attribute_deprecated 103 int8_t *qscale_table; 104 105 attribute_deprecated 106 int qstride; 107 108 attribute_deprecated 109 int qscale_type; 110 111 AVBufferRef *qp_table_buf; 112 #endif 113 114 AVBufferRef *hw_frames_ctx; 115 116 AVBufferRef *opaque_ref; 117 118 size_t crop_top; 119 size_t crop_bottom; 120 size_t crop_left; 121 size_t crop_right; 122 } AVFrame;
- 帶有#if ... #end包含的字段, 都是將要被棄用或已經棄用的. 不再進行解釋.
- 必須使用av_frame_alloc()分配AVFrame, 這只是分配AVFram本身.
- 必須使用av_frame_free()釋放.
- uint8_t *data[AV_NUM_DATA_POINTERS];
原始數據(對視頻來說是YUB, RGB, 對音頻來說是PCM)
data是一個指針數組, 數組的每一個元素都是一個指針. 指向視頻中圖像的某一plane或者音頻中某一聲道的plane.
對於packed格式, 一個YUV圖像的Y, U, V交織存儲在一個plane中, 例如: YUVYUVYUV... ..., data[0]指向這個plane;
一個雙聲道的音頻幀有左聲道L和右聲道R, 它們交織存儲在一個plane中, 例如: LRLRLR... ..., data[0]指向這個plane.
對於planar格式, 一個YUV圖像有Y, U, V三個plane, data[0]指向Y plane, data[1]質量U plane, data[2]指向V plane.
一個雙聲道的音頻幀有左聲道L和右聲道R兩個plane, data[0]指向L plane, data[1]指向R plane
- int linesize[AV_NUM_DATA_POINTERS];
對於視頻來說, linesize是每行圖像的大小(字節數, 有字節對齊).
對於音頻來說, linesize是每個plane的大小(字節數). 音頻只是用linesize[0]. 對於planar音頻來說, 每個plane的大小必須一樣.
linesize可能會因為性能上的考慮而填充一些額外的數據, 因此linesize可能比實際對應的音視頻數據尺寸要大.
- uint8_t **extended_data;
指向數據plane
- int width, height;
視頻幀像素寬和高.
- int nb_samples;
音頻幀中單個聲道包含的采樣點數.
- int format;
幀格式. 如果是未知格式或未設置, 值為-1.
對於視頻幀, 值對應enum AVPixelFormat結構:
1 enum AVPixelFormat { 2 AV_PIX_FMT_NONE = -1, 3 AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) 4 AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr 5 AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... 6 AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... 7 AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) 8 AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
... ...
};
對於音頻幀, 值對應於enum AVSampleFormat結構:
1 enum AVSampleFormat { 2 AV_SAMPLE_FMT_NONE = -1, 3 AV_SAMPLE_FMT_U8, ///< unsigned 8 bits 4 AV_SAMPLE_FMT_S16, ///< signed 16 bits 5 AV_SAMPLE_FMT_S32, ///< signed 32 bits 6 AV_SAMPLE_FMT_FLT, ///< float 7 AV_SAMPLE_FMT_DBL, ///< double 8 9 AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar 10 AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar 11 AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar 12 AV_SAMPLE_FMT_FLTP, ///< float, planar 13 AV_SAMPLE_FMT_DBLP, ///< double, planar 14 AV_SAMPLE_FMT_S64, ///< signed 64 bits 15 AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar 16 17 AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically 18 };
- int key_frame;
視頻幀是否是關鍵幀的標識, 1: 關鍵幀; 0: 非關鍵幀.
- enum AVPictureType pict_type;
視頻幀類型(I, B, P等)
enum AVPictureType結構:
1 enum AVPictureType { 2 AV_PICTURE_TYPE_NONE = 0, ///< Undefined 3 AV_PICTURE_TYPE_I, ///< Intra 4 AV_PICTURE_TYPE_P, ///< Predicted 5 AV_PICTURE_TYPE_B, ///< Bi-dir predicted 6 AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG-4 7 AV_PICTURE_TYPE_SI, ///< Switching Intra 8 AV_PICTURE_TYPE_SP, ///< Switching Predicted 9 AV_PICTURE_TYPE_BI, ///< BI type 10 };
- AVRational sample_aspect_ratio;
視頻幀的寬高比.
- int64_t pts;
顯示時間戳. 單位是time_base.
- int64_t pkt_dts;
對應packet中的解碼時間戳. 是從對應pacekt中拷貝得到此值.
如果對應的packet中只有dts而未設置pts, 則此值也是frame的pts.
- int coded_picture_number;
編碼幀序號.
- int display_picture_number;
顯示幀序號
- int quality;
品質(介於1(最好)和FF_LAMBDA_MAX(壞)之間)
- void *opaque;
用戶私有信息.
- int repeat_pict;
解碼時, 每幀圖片的延遲時間.
extra_delay = repeat_pict / (2*fps)
- int interlaced_frame;
是否是隔行掃描.
- int top_field_first;
圖像的top field first變量. 如果內容是隔行的, 則首先顯示頂部字段.
- int palette_has_changed;
告訴用戶應用程序調色板已從上一幀更改
- int sample_rate;
音頻采樣率.
- uint64_t channel_layout;
音頻聲道布局. 每bit代表一個特定的聲道.
參考源碼channel_layout.h中定義:
1 #define AV_CH_FRONT_LEFT 0x00000001 2 #define AV_CH_FRONT_RIGHT 0x00000002 3 #define AV_CH_FRONT_CENTER 0x00000004 4 #define AV_CH_LOW_FREQUENCY 0x00000008 5 #define AV_CH_BACK_LEFT 0x00000010 6 ... ... 7 8 #define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) 9 #define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) 10 #define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) 11 #define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) 12 #define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) 13 #define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) 14 ... ...
- AVBufferRef *buf[AV_NUM_DATA_POINTERS];
此幀的數據可以由AVBufferRef管理, AVBufferRef提供AVBuffer引用機制.
如果buf[]的所有元素都為NULL, 則此幀不會被引用計數.
必須連續填充buf[], 如果buf[i]為非NULL, 則對所有的j < i, 也必須有b[j]必須為非NULL.
對於視頻來說, buf[]包含所有的AVBufferRef指針.
對於具有多於AV_NUM_DATA_POINTERS個聲道的planar音頻來說, 可能buf[]存不下所有的AVBufferRef指針, 多出的AVBufferRef指針存儲在extended_buf數組中.
- AVBufferRef **extended_buf;
對於具有多於AV_NUM_DATA_POINTERS個聲道的planar音頻來說, 可能buf[]存不下所有的AVBufferRef指針, 多出的AVBufferRef指針存儲在extended_buf數組中.
- int nb_extended_buf;
extended_buf中元素的數目.
- AVFrameSideData **side_data;
邊緣數據
- int nb_side_data;
邊緣數據的數目
- int64_t best_effort_timestamp;
在流時間基中估計幀時間戳.
編碼時未使用
解碼時由解碼器設置. 用戶讀取.
- int64_t pkt_pos;
記錄最后一個扔進解碼器的packet在輸入文件中的位置偏移量.
- int64_t pkt_duration;
對應packet的時長, 單位是AVStream->time_base.
- int channels;
音頻聲道數量.
- int pkt_size;
對應packet的大小.
size_t crop_top;
size_t crop_bottom;
size_t crop_left;
size_t crop_right;
用於視頻幀圖像裁切. 四個值分別為從frame的上/下/左/右邊界裁切的像素數.
- 這寫成員暫時沒有找到完美的解釋(可能也不是很重要或不太常用)
int flags;
enum AVColorRange color_range;
enum AVColorPrimaries color_primaries;
enum AVColorTransferCharacteristic color_trc;
enum AVColorSpace colorspace;
enum AVChromaLocation chroma_location;
AVDictionary *metadata;
int decode_error_flags;
AVBufferRef *hw_frames_ctx;
AVBufferRef *opaque_ref;
2. 相關函數
- AVFrame *av_frame_alloc(void);
構造一個AVFrame, 對象成員被設為默認值.
此函數只分配AVFrame對象本身, 而不分配AVFrame中的數據緩存區.
- void av_frame_free(AVFrame **frame);
釋放AVFrame.
- int av_frame_ref(AVFrame *dst, const AVFrame *src);
為src中的數據建立一個新的引用.
將src中幀的各屬性拷到dst中, 並且為src中每個AVBufferRef創建一個新的引用.
如果src未使用引用計數, 則dst中會分配新的數據緩存區, 將src中緩存區的數據拷貝到dst中的緩存區.
- AVFrame *av_frame_clone(const AVFrame *src);
創建一個新的AVFrame, 新的AVFrame和src使用統一數據緩存區, 緩存區管理使用引用計數機制.
- void av_frame_unref(AVFrame *frame);
解除本AVFrame對AVFrame中所有緩存區的引用, 並復位AVFrame中的各成員.
- void av_frame_move_ref(AVFrame *dst, AVFrame *src);
將src中所有數據拷貝到dst中, 並復位src.
為避免內存泄漏, 在調用av_frame_move_ref(dst, src)之前應先調用av_frame_unref(dst);
- int av_frame_get_buffer(AVFrame *frame, int align);
為音頻或視頻數據分配新的緩沖區.
調用本函數前, 幀中的以下成員必須先設置好:
-
- format
- width, height
- nb_samples, channel_layout
本函數會填充AVFrame.data和AVFrame.buf數組, 如果有需要, 還會分配和填充AVFrame.extended_data和AVFrame.extended_buf.
對於planar格式, 回味每個plane分配一個緩沖區.
- int av_frame_copy(AVFrame *dst, const AVFrame *src);
將src中的幀數據拷貝到dst中.
本函數並不會有任何分配緩沖區的動作, 調用此函數前dst必須已經使用了和src同樣的參數完成了初始化.
本函數只拷貝幀中的數據緩沖區的內容, 而不涉及幀中的其它屬性.
參考
[1] 雷霄驊博士結構體分析:AVFrame https://blog.csdn.net/leixiaohua1020/article/details/14214577
[2] 葉余 FFmpeg數據結構AVFrame https://www.cnblogs.com/leisure_chn/p/10404502.html
[3]YelloLayne FFmpeg結構體:AVFrame https://www.jianshu.com/p/25a329b20078