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) //获取音频格式名称字符串
03-30 10:23