【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )

文章目录

FFmpeg 4.0 版本源码地址 :

一、av_packet_ref 函数


1、函数原型

av_packet_ref 函数 用于 将 源 AVPacket 结构体的属性 和 buf 数据引用 拷贝复制给 目标 AVPacket 结构体 , AVPacket 中的 实际数据 不会进行复制 , 新创建的 AVPacket 只会复制 实际音视频数据的 指针地址 , 函数原型如下 :

cpp 复制代码
int av_packet_ref(AVPacket *dst, const AVPacket *src)
  • 函数功能 :

    • 将 src 的 结构体字段 复制到 dst ;
    • 拷贝 数据的引用 , 并增加 src 中底层数据的引用计数 ; 拷贝的是引用 , 不会对 src 中的实际数据缓冲区进行内存复制 , 避免不必要的性能开销 ;
  • 参数解析 :

    • AVPacket *dst 参数 : 指向 目标 AVPacket 的指针 , 被赋值的对象 ;
    • const AVPacket *src 参数 : 指向 源 AVPacket 的指针 , 数据源 , 被拷贝的对象 ;
  • 返回值 :

    • 拷贝成功 , 返回 0 ;
    • 拷贝失败 , 返回 负值 , 该负值表示错误码 ;

2、函数源码分析

av_packet_ref 函数的源码如下 :

  • 分析该函数的源码可知 , 该函数执行两个操作 , 分别是 :
    • 第一步 : 复制 源 结构体 中的 字段值 到 目标结构体 中 ;
    • 第二步 : 将 原结构体 的 数据缓冲区 引用 赋值给 目标 数据缓冲区 引用 , 注意 这里 只 复制引用 , 不复制数据 ;
  • 该函数中直接为 AVPacket 结构体字段辅助 , 因此执行该函数之前 , 目标 AVPacket 必须是已经分配好内存 ;
cpp 复制代码
int av_packet_ref(AVPacket *dst, const AVPacket *src)
{
    int ret;

    // 复制源包(src)的属性到目标包(dst),包括时间戳、流索引等元数据。
    ret = av_packet_copy_props(dst, src);
    if (ret < 0)  // 如果属性复制失败,则返回错误码。
        return ret;

    // 检查源包是否有缓冲区 (buf),如果没有,说明需要分配新的缓冲区。
    if (!src->buf) {
        // 为目标包分配缓冲区,大小为源包的数据大小。
        ret = packet_alloc(&dst->buf, src->size);
        if (ret < 0)  // 如果缓冲区分配失败,跳转到错误处理。
            goto fail;
        
        // 如果源包的数据大小不为 0,将数据从源包复制到目标包的缓冲区。
        if (src->size)
            memcpy(dst->buf->data, src->data, src->size);

        // 将目标包的 data 指针指向分配的缓冲区。
        dst->data = dst->buf->data;
    } else {
        // 如果源包有缓冲区,通过引用计数创建缓冲区的引用。
        dst->buf = av_buffer_ref(src->buf);
        if (!dst->buf) {  // 如果引用创建失败,返回内存分配错误。
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        // 目标包的 data 指针直接指向源包的 data。
        dst->data = src->data;
    }

    // 将源包的大小复制到目标包。
    dst->size = src->size;

    // 如果执行成功,返回 0。
    return 0;

fail:
    // 如果发生错误,释放目标包的附加数据(如 side data)以防止资源泄漏。
    av_packet_free_side_data(dst);
    return ret;  // 返回错误码。
}

3、函数使用代码示例

代码示例 :

cpp 复制代码
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

int main() {
    AVPacket src_pkt, dst_pkt;

    // 初始化源包和目标包
    // av_init_packet 初始化 AVPacket 结构体,为其成员赋初始值。
    av_init_packet(&src_pkt);
    av_init_packet(&dst_pkt);

    // 为源包分配内存并假设数据已填充
    // src_pkt.data 指向分配的 100 字节内存,用于模拟填充数据。
    src_pkt.data = av_malloc(100);
    src_pkt.size = 100; // 数据大小设置为 100 字节。

    // 创建引用
    // av_packet_ref 创建目标包 dst_pkt 对源包 src_pkt 的引用。
    // 如果失败,打印错误信息并返回 -1。
    if (av_packet_ref(&dst_pkt, &src_pkt) < 0) {
        fprintf(stderr, "Failed to create packet reference.\n");
        return -1;
    }

    // 此时,src_pkt 和 dst_pkt 共享同一底层数据
    // 打印源包和目标包的数据大小以验证共享关系。
    printf("src size: %d, dst size: %d\n", src_pkt.size, dst_pkt.size);

    // 释放引用
    // 使用 av_packet_unref 释放源包和目标包的引用,减少引用计数。
    av_packet_unref(&src_pkt);
    av_packet_unref(&dst_pkt);

    return 0;
}

二、av_packet_clone 函数


1、函数原型

av_packet_clone 函数 用于 克隆一个完整的 AVPacket , 该函数实际上相当于 av_packet_alloc 函数 + av_packet_ref 函数 ;

cpp 复制代码
AVPacket *av_packet_clone(const AVPacket *src)
  • const AVPacket *src 参数 : 指向 需要克隆的源 AVPacket 的指针 ;
  • 返回值 :
    • 拷贝成功 : 返回一个指向 新克隆的 AVPacket 的指针 ;
    • 拷贝失败 : 返回 NULL , 通常是因为内存分配失败 ;

2、函数源码分析

在下面的 av_packet_clone 函数源码中可以分析处 , av_packet_clone 函数相当于

av_packet_alloc 函数 和 av_packet_ref 函数 的总体效果 ;

在 av_packet_clone 函数中 , 先调用了 av_packet_alloc 函数 , 创建 目标 AVPacket ,

然后调用 av_packet_ref 函数 , 将 源 AVPacket 的 数据拷贝给 目标 AVPacket ;

cpp 复制代码
AVPacket *av_packet_clone(const AVPacket *src)
{
    // 为克隆的包分配内存并初始化。
    // 调用 av_packet_alloc 返回一个新的 AVPacket 指针,默认值为初始状态。
    AVPacket *ret = av_packet_alloc();

    // 如果分配失败,直接返回 NULL。
    if (!ret)
        return ret;

    // 使用 av_packet_ref 函数将源包 src 的数据和元信息复制到新包 ret 中。
    // av_packet_ref 返回非零值表示复制失败。
    if (av_packet_ref(ret, src))
        // 如果复制失败,释放已分配的 AVPacket,并将 ret 置为 NULL。
        av_packet_free(&ret);

    // 返回克隆后的 AVPacket 指针(成功)或 NULL(失败)。
    return ret;
}
相关推荐
上海合宙LuatOS9 小时前
LuatOS核心库API——【audio 】
java·网络·单片机·嵌入式硬件·物联网·音视频·硬件工程
Android系统攻城狮10 小时前
Android16进阶之音频播放定位MediaPlayer.seekTo调用流程与实战(二百二十七)
音视频·mediaplayer·android16·音频进阶·音频性能实战
晚霞的不甘11 小时前
Flutter for OpenHarmony 可视化教学:A* 寻路算法的交互式演示
人工智能·算法·flutter·架构·开源·音视频
听麟11 小时前
HarmonyOS 6.0+ 跨端智慧政务服务平台开发实战:多端协同办理与电子证照管理落地
笔记·华为·wpf·音视频·harmonyos·政务
晚霞的不甘12 小时前
Flutter for OpenHarmony 实现计算几何:Graham Scan 凸包算法的可视化演示
人工智能·算法·flutter·架构·开源·音视频
零一iTEM13 小时前
MAX98357A_音频输出测试
单片机·嵌入式硬件·开源·音视频·硬件工程
Android系统攻城狮14 小时前
Android16进阶之获取播放位置MediaPlayer.getCurrentPosition调用流程与实战(二百二十八)
音视频·android16·音频进阶·音频性能实战
炼金术14 小时前
SkyPlayer v1.2.0 : AI 字幕-端侧 Whisper 实时语音识别实践
ffmpeg·openai
愚公搬代码16 小时前
【愚公系列】《AI短视频创作一本通》020-AI短视频创作实例精解(文旅宣传AI短视频实例精解)
人工智能·音视频
有位神秘人16 小时前
Android获取设备中本地音频
android·音视频