AVFrame和AVPacket是ffmpeg中保存音视频数据的结构体,AVFrame保存未压缩的原始音视频数据,AVPacket保存编码后的音视频数据,AVFrame和AVPacket都是使用引用计数进行的内存管理。
一、AVFrame
内存分配:
视频:
AVFrame* frame = av_frame_alloc();
frame->width = 1920;
frame->height = 1080;
frame->format = AV_PIX_FMT_YUV420P;
音频:
AVFrame* pcm = av_frame_alloc();
pcm->format = outSampleFmt;//位深 16/32位
pcm->channels = channels;
pcm->channel_layout = av_get_default_channel_layout(channels);
pcm->nb_samples = nbSample;//样本数
AVFrame *av_frame_clone(const AVFrame *src);//作用同av_frame_ref类似,增加src的引用计数,但同时会初始化av_frame_clone 对象
AVFrame buf内存分配:
av_frame_get_buffer(AVFrame *frame, int algin);
AVFrame 释放:
void av_frame_free(AVFrame** frame)
音视频内存操作相关API:
其中AVPicture,av_image_* 的函数就是涉及到了保存视频帧的方式;av_samples_*的函数则涉及了如何保存音频数据。
typedef struct AVPicture {
attribute_deprecated
uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes
attribute_deprecated
int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line
} AVPicture;
下面API中的align一般设置为1,按实际字节存储。
1、视频buf操作:
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],const uint8_t *src_data[4], const int src_linesizes[4],enum AVPixelFormat pix_fmt, int width, int height)//根据图像的宽、高、像素格式,进行图像拷贝
int av_image_copy_to_buffer(uint8_t *dst, int dst_size,const uint8_t * const src_data[4],const int src_linesize[4],enum AVPixelFormat pix_fmt,int width, int height, int align)//把图像数据拷贝到指定缓冲区:
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);//函数的作用是通过指定像素格式、图像宽、图像高来计算所需的内存大小
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],int w, int h, enum AVPixelFormat pix_fmt, int align);//根据宽高、格式分配buf,尝试使用av_freep(&pointers[0]释放,否则可能内存泄漏
int avpicture_fill(AVPicture *picture, const uint8_t *ptr,enum AVPixelFormat pix_fmt, int width, int height);//尝试使用av_freep(&pointers[0]释放,否则可能内存泄漏,这个API在新版本弃用
eg:avpicture_fill((AVPicture *)frame, (const uint8_t *)ptr,(enum AVPixelFormat)frame->format, in_width, in_height);
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align);//avpicture_fill的替代API,avpicture_fill()就是调用av_image_fill_arrays实现的
2、音频buf操作:
buf分配:视频帧最多有4个分量,音频帧只需要一个linesize而略有变化,其本质是完全相同的。
int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,int src_offset, int nb_samples, int nb_channels,enum AVSampleFormat sample_fmt)//音频帧拷贝
av_samples_copy_to_buffer:音频没有这个函数
int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align);//获取音频帧缓冲区大小
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,int nb_samples, enum AVSampleFormat sample_fmt, int align);//根据通道数、样本个数,采样格式分配buf
int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,const uint8_t *buf, int nb_channels, int nb_samples,enum AVSampleFormat sample_fmt, int align)//同av_image_fill_arrays
int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,int nb_samples, enum AVSampleFormat sample_fmt, int align)//av_samples_alloc()和av_samples_alloc_array_and_samples()函数都是用于分配存储音频数据的空间
int av_samples_set_silence(uint8_t **audio_data, int offset,int nb_samples,int nb_channels,enum AVSampleFormat sample_fmt);//以静音数据填充缓冲区
二、AVPacket
av_free_packet其实就是清空pkt中data以及buf的内容,并没有把pkt的指针清空,我们可以看到其函数内部调用了av_buffer_unref。
void av_free_packet(AVPacket *pkt)
{
if (pkt) {
if (pkt->buf)
av_buffer_unref(&pkt->buf);
pkt->data = NULL;
pkt->size = 0;
av_packet_free_side_data(pkt);
}
}
而av_packet_free是先把pkt中的内容清空,然后再把指针清空,让pkt彻底无法使用了,如果需要重新使用,需要重新分配内存。
void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return;
av_packet_unref(*pkt);
av_freep(pkt);
}
其他API:
void av_packet_ref(AVPacket *dst, const AVPacket *src)
void av_init_packet(AVPacket *pkt);//初始化packet的值为默认值,该函数不会影响data引用的数据缓存空间和size,需要单独处理。
int av_new_packet(AVPacket *pkt, int size);//av_init_packet的增强版,不但会初始化字段,还为data分配了存储空间
AVPacket *av_packet_alloc(void);//创建一个AVPacket,将其字段设为默认值(data为空,没有数据缓存空间)。
void av_packet_free(AVPacket **pkt);//释放使用av_packet_alloc创建的AVPacket,如果该Packet有引用计数(packet->buf不为空),则先调用av_packet_unref。
AVPacket *av_packet_clone(const AVPacket *src);//其功能是av_packet_alloc和av_packet_ref
int av_copy_packet(AVPacket *dst, const AVPacket *src);//复制一个新的packet,包括数据缓存
废弃 int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);//初始化一个引用计数的packet,并指定了其数据缓存
替换接口: int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
int av_grow_packet(AVPacket *pkt, int grow_by);//增大Packet->data指向的数据缓存
void av_shrink_packet(AVPacket *pkt, int size);//减小Packet->data指向的数据缓存
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)//通过压缩数据来初始化一个引用计数的AVPacket(pkt必须是创建好的),一般在读取流媒体时使用,因为解码函数的参数必须是AVPacket
int av_buffer_get_ref_count (const AVBufferRef *buf)//获取引用个数
三、其他
av_get_pix_fmt_name(AVPixelFormat) //获取视频像素格式名称字符串
av_get_sample_fmt_name(AVSampleFormat) //获取音频格式名称字符串