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。

相关推荐
auspicious航3 小时前
数据库同步技术演进:从备份转储到实时CDC的DBA实战指南
数据库·ffmpeg·dba
小馬佩德罗1 天前
如何将x264 x265的动态库编译入Linux系统中的FFmpeg源码 - x264库编译
linux·ffmpeg·x264
Black蜡笔小新1 天前
视频融合平台EasyCVR融合无线监控,打造智能高效安防解决方案
ffmpeg·音视频
jianghusanren32 天前
【无标题】
ffmpeg
芒鸽2 天前
鸿蒙PC上FFmpeg+Electron的Encode Smoke(P2) 排错实录:从“无法播放/时长为 0”到“保留画面且转完整时长”
ffmpeg·electron·harmonyos
小馬佩德罗2 天前
如何将x264 x265的动态库编译入Linux系统中的FFmpeg源码 - x265库编译
linux·ffmpeg·x265
bugtraq20212 天前
使用FFmpeg API转音频格式
ide·ffmpeg·myeclipse
小馬佩德罗2 天前
如何将x264 x265的动态库编译入Linux系统中的FFmpeg源码 - FFmpeg编译
linux·ffmpeg
你好音视频3 天前
FFmpeg HLS编码流程深度解析:从数据包到播放列表的完整实现
c++·ffmpeg·音视频
芒鸽3 天前
macOS 上用 lycium 交叉编译 FFmpeg 适配鸿蒙(OHOS):从构建到 HNP 打包
macos·ffmpeg·harmonyos