4.FFMPEG-AVFrame


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

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

注意事项: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,则对于全部jnb_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;

相关