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。

相关推荐
aqi0017 小时前
FFmpeg开发笔记(六十四)使用国产的RedPlayer播放器观看网络视频
android·ffmpeg·音视频·直播·流媒体
道剑剑非道1 天前
QT开发技术【ffmpeg + QAudioOutput】音乐播放器 完善
开发语言·qt·ffmpeg
毒果1 天前
FFmpeg 低延迟同屏方案
ffmpeg·同屏
aqi002 天前
FFmpeg开发笔记(六十三)FFmpeg使用vvenc把视频转为H.266编码
ffmpeg·音视频·直播·流媒体
梧桐樹下3 天前
FFmpeg avformat_open_input函数分析
ffmpeg
道剑剑非道3 天前
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
开发语言·qt·ffmpeg
IOsetting3 天前
Ubuntu24.04 交叉编译 aarch64 ffmpeg
ffmpeg
却道天凉_好个秋3 天前
ffmpeg(三):处理原始数据命令
ffmpeg
@残梦3 天前
129、QT搭建FFmpeg环境
开发语言·qt·ffmpeg
阿飞__4 天前
C++ 使用 ffmpeg 解码本地视频并获取每帧的YUV数据
c++·ffmpeg·音视频