FFmpeg源码:av_packet_free_side_data、av_packet_unref、av_packet_free函数分析

一、av_packet_free_side_data函数

(一)av_packet_free_side_data函数的声明

av_packet_free_side_data函数声明在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavcodec/packet.h中:

cpp 复制代码
/**
 * Convenience function to free all the side data stored.
 * All the other fields stay untouched.
 *
 * @param pkt packet
 */
void av_packet_free_side_data(AVPacket *pkt);

该函数的作用是:释放一个AVPacket类型变量(形参pkt指向的AVPacket类型变量)的成员side_data指向的空间,以及指针pkt->side_data[i].data指向的空间。也就是释放该AVPacket变量的所有边数据,并让side_data的数量也就是pkt->side_data_elems的值置0,其它成员变量保持不变。

(二)av_packet_free_side_data函数的定义

av_packet_free_side_data函数定义在源文件libavcodec/avpacket.c中:

cpp 复制代码
void av_packet_free_side_data(AVPacket *pkt)
{
    int i;
    for (i = 0; i < pkt->side_data_elems; i++)
        av_freep(&pkt->side_data[i].data);
    av_freep(&pkt->side_data);
    pkt->side_data_elems = 0;
}

可以看到该函数内部调用了av_freep函数释放pkt->side_data[i].data和pkt->side_data的空间。关于av_freep函数的用法可以参考:《FFmpeg中内存分配和释放相关的源码:av_malloc函数、av_mallocz函数、av_free函数和av_freep函数分析》。

二、av_packet_unref函数

(一)av_packet_unref函数的声明

av_packet_unref函数声明在头文件libavcodec/packet.h中:

cpp 复制代码
/**
 * Wipe the packet.
 *
 * Unreference the buffer referenced by the packet and reset the
 * remaining packet fields to their default values.
 *
 * @param pkt The packet to be unreferenced.
 */
void av_packet_unref(AVPacket *pkt);

该函数作用是:释放形参pkt指向的AVPacket变量的所有边数据,并让引用计数减1。如果原本的引用计数值不为1,释放pkt->opaque_ref和pkt->buf结构体本身,不释放它们的成员buf和data指向的缓冲区;如果原本的引用计数值为1,则调用释放数据的回调函数(默认是av_buffer_default_free函数)释放pkt->opaque_ref和pkt->buf的成员data指向的缓冲区,如果pkt->opaque_ref和pkt->buf的成员buffer还没被释放,则也释放它。

注意:

1.使用FFmpeg的av_read_frame函数后,每读完一个packet(AVPacket变量),必须调用av_packet_unref函数进行内存释放,否则会导致内存释泄漏。详情参考:《FFmpeg中调用av_read_frame函数导致的内存泄漏问题》。

2.av_packet_unref函数不会释放AVPacket结构体本身,要想释放AVPacket结构体本身可以使用av_packet_free函数。

(二)av_packet_unref函数的定义

av_packet_unref函数定义在源文件libavcodec/avpacket.c中:

cpp 复制代码
void av_packet_unref(AVPacket *pkt)
{
    av_packet_free_side_data(pkt);
    av_buffer_unref(&pkt->opaque_ref);
    av_buffer_unref(&pkt->buf);
    get_packet_defaults(pkt);
}

可以看到该函数内部,首先通过语句av_packet_free_side_data(pkt)释放该AVPacket变量的所有边数据。然后通过av_buffer_unref函数让引用计数减1,释放pkt->opaque_ref和pkt->buf结构体(关于av_buffer_unref函数用法可以参考:《FFmpeg源码:av_buffer_ref、av_buffer_unref函数分析》)。最后通过get_packet_defaults函数给AVPacket变量的成员pts、dts、pos、time_base赋默认值。

三、av_packet_free函数

(一)av_packet_free函数的声明

av_packet_free函数声明在头文件libavcodec/packet.h中:

cpp 复制代码
/**
 * Free the packet, if the packet is reference counted, it will be
 * unreferenced first.
 *
 * @param pkt packet to be freed. The pointer will be set to NULL.
 * @note passing NULL is a no-op.
 */
void av_packet_free(AVPacket **pkt);

该函数作用是:让AVPacket结构体的引用计数减1,并释放AVPacket结构体本身,让其彻底无法使用。注意:执行av_packet_free函数之前必须确保已经使用了av_packet_unref函数让该AVPacket变量的引用计数减至1,否则可能会内存泄漏。

(二)av_packet_free函数的定义

av_packet_free函数定义在源文件libavcodec/avpacket.c中:

cpp 复制代码
void av_packet_free(AVPacket **pkt)
{
    if (!pkt || !*pkt)
        return;

    av_packet_unref(*pkt);
    av_freep(pkt);
}

可以看到该函数内部通过av_buffer_unref函数让引用计数减1,并通过av_freep函数释放AVPacket结构体本身。但如果执行av_packet_free函数之前,引用计数值不为1,则执行av_packet_free函数时,其内部的av_packet_unref只会释放*pkt->opaque_ref和*pkt->buf结构体本身,不释放它们的成员buf和data指向的缓冲区。所以一定要保证执行av_packet_free函数之前,引用计数值为1。

相关推荐
简鹿办公1 天前
FFmpeg vs 去水印软件:哪种方式更适合你?
ffmpeg·怎样去除视频水印·如何去视频logo视频水印
小狮子安度因2 天前
ffplay数据结构分析
数据结构·ffmpeg
小狮子安度因2 天前
ffplay音频重采样
ffmpeg·音视频
小狮子安度因2 天前
AAC ADTS格式分析
网络·ffmpeg·aac
勘察加熊人3 天前
ffmpeg切割音频
ffmpeg·音视频
xiaohouzi1122334 天前
Python读取视频-硬解和软解
python·opencv·ffmpeg·视频编解码·gstreamer
kimble_xia@oracle5 天前
性能优化笔记
ffmpeg
wang_chao1185 天前
RK3399平台ffmpeg-VPU硬编码录制USB摄像头视频、H264或MJPEG编码
ffmpeg·音视频
鹅毛在路上了6 天前
C++, ffmpeg, libavcodec-RTSP拉流,opencv实时预览
c++·opencv·ffmpeg
Hi202402177 天前
Orin-Apollo园区版本:订阅多个摄像头画面拼接与硬编码RTMP推流
ffmpeg·apollo·orin·图像拼接·图传