0. 简介
AVFrame中存储的是原始数据(例如视频的YUV, RGB, 音频的PCM), 此外还包含了一些相关的信息, 例如: 解码的时候存储了宏块类型表, QP表, 运动矢量等数据. 编码的时候也存储了相关的数据.
1. AVFrame 数据结构定义
FFmpeg 版本3.4.1
struct AVFrame 定义于
结构体源码(我去除了注释):
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