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。

相关推荐
superconvert17 小时前
主流流媒体的综合性能大 PK ( smart_rtmpd, srs, zlm, nginx rtmp )
websocket·ffmpeg·webrtc·hevc·rtmp·h264·hls·dash·rtsp·srt·flv
cuijiecheng20181 天前
音视频入门基础:AAC专题(8)——FFmpeg源码中计算AAC裸流AVStream的time_base的实现
ffmpeg·音视频·aac
0点51 胜1 天前
[ffmpeg] 视频格式转换
ffmpeg
Jerry 二河小鱼1 天前
在Linux中安装FFmpeg
linux·运维·服务器·ffmpeg
0点51 胜2 天前
[ffmpeg] 音视频编码
ffmpeg·音视频
0点51 胜2 天前
[ffmpeg]音频格式转换
开发语言·c++·ffmpeg
PlumCarefree3 天前
基于鸿蒙API10的RTSP播放器(五:拖动底部视频滑轨实现跳转)
华为·ffmpeg·音视频
LuckyInn3 天前
从安装ffmpeg开始,把一个视频按照每秒30帧fps剪切为图片
ffmpeg·音视频
cuijiecheng20183 天前
FFmpeg源码:skip_bits、skip_bits1、show_bits函数分析
ffmpeg
__Destiny__3 天前
视频格式转为mp4(使用ffmpeg)
ffmpeg·视频编解码