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。

相关推荐
ZouZou老师38 分钟前
FFmpeg性能优化经典案例
性能优化·ffmpeg
aqi003 小时前
FFmpeg开发笔记(九十)采用FFmpeg套壳的音视频转码百宝箱FFBox
ffmpeg·音视频·直播·流媒体
齐齐大魔王5 小时前
FFmpeg
ffmpeg
你好音视频7 小时前
FFmpeg RTSP拉流流程深度解析
ffmpeg
IFTICing17 小时前
【环境配置】ffmpeg下载、安装、配置(Windows环境)
windows·ffmpeg
haiy201118 小时前
FFmpeg 编译
ffmpeg
aqi0021 小时前
FFmpeg开发笔记(八十九)基于FFmpeg的直播视频录制工具StreamCap
ffmpeg·音视频·直播·流媒体
八月的雨季 最後的冰吻1 天前
FFmepg--28- 滤镜处理 YUV 视频帧:实现上下镜像效果
ffmpeg·音视频
ganqiuye1 天前
向ffmpeg官方源码仓库提交patch
大数据·ffmpeg·video-codec
草明1 天前
ffmpeg 把 ts 转换成 mp3
ffmpeg