在ffmpeg中,解码前的数据结构体为AVPacket(参考:3.AVPacket使用),而解码后的数据为AVFrame(视频的YUV, RGB, 音频的PCM,数据量更大)

1.AVFrame介绍

  • AVFrame必须使用av_frame_alloc()来分配。注意,这只是分配AVFrame本身,缓冲区的数据(解码成功后的数据)必须通过其他途径被管理.
  • 因为AVFrame通常只分配一次,然后多次复用来保存不同类型的数据,复用的时候需要调用av_frame_unref()将其重置到它前面的原始清洁状态.
  • 注意调用avcodec_receive_frame()时会自动引用减1后再获取frame,所以解码过程中无需每次调用
  • 释放的时候必须用av_frame_free()释放。

 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表示获取成功

注意事项:

由于DTS和PTS的顺序可能是不一致的.所以每次视频解码完成后,可能还有几帧frame未显示,
我们需要在末尾通过avcodec_send_packet()传入NULL来将最后几帧取出来

2.AVFrame结构体

AVFrame结构体中有很多成员,常见的成员如下所示,注释已替换:

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;

4.FFMPEG-AVFrame的更多相关文章

  1. ffmpeg AVFrame结构体及其相关函数

    0. 简介 AVFrame中存储的是原始数据(例如视频的YUV, RGB, 音频的PCM), 此外还包含了一些相关的信息, 例如: 解码的时候存储了宏块类型表, QP表, 运动矢量等数据. 编码的时候 ...

  2. FFmpeg——AVFrame中 的 data

    AVFrame中 的 data 的定义如下: typedef struct AVFrame { #define AV_NUM_DATA_POINTERS 8 /** * pointer to the ...

  3. 在iOS平台使用ffmpeg解码h264视频流(转)

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...

  4. 在iOS平台使用ffmpeg解码h264视频流

    来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,f ...

  5. ffmpeg从AVFrame取出yuv数据到保存到char*中

    ffmpeg从AVFrame取出yuv数据到保存到char*中   很多人一直不知道怎么利用ffmpeg从AVFrame取出yuv数据到保存到char*中,下面代码将yuv420p和yuv422p的数 ...

  6. ffmpeg中avframe的YUV格式数据到OpenCV中Mat的BGR格式转换

    ffmpeg实现音视频编解码是非常常用的工具,视频解码出来的raw数据是yuv格式,用来进行后续的图像处理一般是RGB格式的.所以需要从yuv到rgb或者bgr的转换,ffmpeg提供了相应的转换AP ...

  7. FFmpeg源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  8. FFMPEG结构体分析:AVFrame

    注:写了一系列的结构体的分析的文章,在这里列一个列表: FFMPEG结构体分析:AVFrameFFMPEG结构体分析:AVFormatContextFFMPEG结构体分析:AVCodecContext ...

  9. FFmpeg 结构体学习(四): AVFrame 分析

    在上文FFmpeg 结构体学习(三): AVPacket 分析我们学习了AVPacket结构体的相关内容.本文,我们将讲述一下AVFrame. AVFrame是包含码流参数较多的结构体.下面我们来分析 ...

  10. FFmpeg数据结构AVFrame

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10404502.html 本文基于FFmpeg 4.1版本. 1. 数据结构定义 stru ...

随机推荐

  1. Visual Studio 2017版本15.9现在可用

    本文转自 https://blogs.msdn.microsoft.com/visualstudio/2018/11/19/visual-studio-2017-version-15-9-now-av ...

  2. eric4 打包文件

    在.py 工程 所在目录: 按住shift,鼠标右键,在此处打开cmd或shell,然后如下操作 1.打包成文件夹 pyinstaller lrs.py 2.打包成 单文件 pyinstaller - ...

  3. 初 识 eric4

    下图展示了,如何使用eric4  新建工程,创建窗体,编译工程,运行工程这几个过程

  4. pandas | DataFrame中的排序与汇总方法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第六篇文章,我们来聊聊DataFrame的排序与汇总运算. 在上一篇文章当中我们主要介绍了DataFrame ...

  5. getting session bus failed: //bin/dbus-launch terminated abnormally with the following error: Autolaunch error: X11 initialization failed.

    今天在调试dbus程序的时候,运行程序出现了getting session bus failed: //bin/dbus-launch terminated abnormally with the f ...

  6. linux服务器核心知识

    电脑:辅助人脑的工具 现在的人们几乎无时无刻都会碰电脑!不管是桌上型电脑(桌机).笔记型电脑(笔电).平板电脑.智慧型手机等等,这些东西都算是电脑.虽然接触的这么多,但是,你了解电脑里面的元件有什么吗 ...

  7. centos7.8 安装部署 k8s 集群

    centos7.8 安装部署 k8s 集群 目录 centos7.8 安装部署 k8s 集群 环境说明 Docker 安装 k8s 安装准备工作 Master 节点安装 k8s 版本查看 安装 kub ...

  8. CentOS7 更改默认启动桌面(或命令行)模式

    centos7以后是这样的,7以前就是别的版本了 1.systemctl get-default命令获取当前模式 2.systemctl set-default graphical.target 修改 ...

  9. Protocol buffers--python 实践 简介以及安装与使用

    简介: Protocol Buffers以下简称pb,是google开发的一个可以序列化 反序列化object的数据交换格式,类似于xml,但是比xml 更轻,更快,更简单.而且以上的重点突出一个跨平 ...

  10. ZK的watch机制

    1.watcher原理框架 由图看出,zk的watcher由客户端,客户端WatchManager,zk服务器组成.整个过程涉及了消息通信及数据存储. zk客户端向zk服务器注册watcher的同时, ...