FFmpeg源码:av_packet_move_ref、av_packet_make_refcounted函数分析

一、av_packet_move_ref函数

(一)av_packet_move_ref函数的声明

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

cpp 复制代码
/**
 * Move every field in src to dst and reset src.
 *
 * @see av_packet_unref
 *
 * @param src Source packet, will be reset
 * @param dst Destination packet
 */
void av_packet_move_ref(AVPacket *dst, AVPacket *src);

该函数作用是:类似C++11中的移动语义,将形参src指向的AVPacket对象的所有属性(包括其成员变量,src->buf、src->data、src->side_data指向的缓冲区中的数据)移动到形参dst指向的AVPacket对象中。执行该函数后,src指向的AVPacket对象会被初始化(成员变量pts、dts、pos、time_base赋默认值,其它成员变量包括指针赋值为0或NULL)。

(二)av_packet_move_ref函数的定义

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

cpp 复制代码
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
{
    *dst = *src;
    get_packet_defaults(src);
}

该函数内部,首先通过下面语句,将形参src指向的AVPacket对象(以下简称原对象)浅拷贝(这里就是模仿C++的浅拷贝)到形参dst指向的AVPacket对象(以下简称目标对象)中,通过浅拷贝只对目标对象赋值原对象的成员变量的值,并不复制原对象的动态分配内存(src->buf、src->data、src->side_data指向的缓冲区)等外部资源:

cpp 复制代码
*dst = *src;

为了避免原对象修改自己指向的外部资源时,可能会影响到目标对象,通过下面语句给原对象的成员变量pts、dts、pos、time_base赋默认值,给原对象的其它成员变量包括指针值赋值为0或NULL:

cpp 复制代码
get_packet_defaults(src);

可以看到,FFmpeg通过上面两个语句实现了类似C++11中的移动语义效果,实现AVPacket的所有权从原对象转移到目标对象,只是转移,没有内存的搬迁或者内存拷贝,从而极大地提高代码运行效率。

二、av_packet_make_refcounted函数

(一)av_packet_make_refcounted函数的声明

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

cpp 复制代码
/**
 * Ensure the data described by a given packet is reference counted.
 *
 * @note This function does not ensure that the reference will be writable.
 *       Use av_packet_make_writable instead for that purpose.
 *
 * @see av_packet_ref
 * @see av_packet_make_writable
 *
 * @param pkt packet whose data should be made reference counted.
 *
 * @return 0 on success, a negative AVERROR on error. On failure, the
 *         packet is unchanged.
 */
int av_packet_make_refcounted(AVPacket *pkt);

该函数作用是:确保给定数据包(pkt指向的对象)描述的数据是引用计数的。

1.如果pkt->buf不为空,表示给定数据包描述的数据已经是引用计数了。该函数返回0,不执行也不需要执行其它操作。

2.如果pkt->buf为空,给pkt->buf和pkt->buf->buffer分配内存,给pkt->buf->data重新分配大小为(pkt->size + AV_INPUT_BUFFER_PADDING_SIZE)个字节内存。然后把pkt->data中的数据拷贝pkt->size个字节到pkt->buf->data中。执行上述操作(情况"2"的操作)后,pkt->buf->buffer->refcount的值会是1,所以可以保证数据已经是引用计数了。

返回值:返回0表示成功,返回一个负数表示失败。

(二)av_packet_make_refcounted函数的定义

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

cpp 复制代码
int av_packet_make_refcounted(AVPacket *pkt)
{
    int ret;

    if (pkt->buf)
        return 0;

    ret = packet_alloc(&pkt->buf, pkt->size);
    if (ret < 0)
        return ret;
    av_assert1(!pkt->size || pkt->data);
    if (pkt->size)
        memcpy(pkt->buf->data, pkt->data, pkt->size);

    pkt->data = pkt->buf->data;

    return 0;
}

当pkt->buf为空时,av_packet_make_refcounted函数内部会执行packet_alloc函数,而packet_alloc函数内部会执行av_buffer_realloc函数,av_buffer_realloc函数内部又会执行av_buffer_create函数,从《FFmpeg源码:buffer_create、av_buffer_create、av_buffer_default_free、av_buffer_alloc、av_buffer_allocz函数分析》中可以知道,av_buffer_create函数会让refcount的值被初始化为1,所以可以保证数据是引用计数的。

相关推荐
luoyayun3612 小时前
Qt/QML + FFmpeg 实现多音频文件顺序拼接功能
qt·ffmpeg·音频拼接
wbcuc10 小时前
ffmpeg工具把m4s合并为mp4 powershell脚本
ffmpeg·m4s
luoyayun3612 天前
Qt + FFmpeg 实战:实现音频格式转换功能
qt·ffmpeg·音频格式转换
都在酒里2 天前
【极致低延时】香橙派部署 MediaMTX 实现 WebRTC 推流,延时仅 500-800ms,比局域网 ffmpeg 拉流快近 10 倍!(附踩坑全记录)
linux·arm开发·ffmpeg·webrtc·orangepi·嵌入式软件
Empty-Filled2 天前
用 Kap + FFmpeg 把录屏转成小体积 GIF:产品操作演示图制作实践
ffmpeg·kap
矜辰所致3 天前
嵌入式语音开发应用基础说明
ffmpeg·ai 语音·嵌入式语音·语音播放·语音采样
luoyayun3613 天前
Qt + FFmpeg 实战:音频静音段检测
qt·ffmpeg·音视频·静音段检测
小鹿研究点东西5 天前
直播带货长视频AI自动剪辑开播:一场直播如何反复利用?
ffmpeg·自动化·音视频·语音识别
luoyayun3615 天前
Qt + FFmpeg 实战:获取音视频文件基础属性、流信息和元数据
qt·ffmpeg·音视频·元数据·获取音视频文件属性
Rudon滨海渔村5 天前
ffmpeg裁剪视频黑屏、不准时等处理方式 - ffmpeg基本操作
ffmpeg·音视频