首页 > 编程语言 >FFmpeg源码:av_realloc、av_reallocp、size_mult、av_realloc_f函数分析

FFmpeg源码:av_realloc、av_reallocp、size_mult、av_realloc_f函数分析

时间:2024-08-08 18:53:06浏览次数:9  
标签:函数 形参 realloc 源码 av ptr size

=================================================================

FFmpeg内存管理相关的源码分析:

FFmpeg中内存分配和释放相关的源码:av_malloc函数、av_mallocz函数、av_free函数和av_freep函数分析

FFmpeg源码:av_realloc、av_reallocp、size_mult、av_realloc_f函数分析
FFmpeg引用计数数据缓冲区相关的结构体:AVBuffer、AVBufferRef简介

FFmpeg源码:buffer_create、av_buffer_create、av_buffer_default_free、av_buffer_alloc、av_buffer_allocz函数分析

FFmpeg源码:av_buffer_ref、av_buffer_unref函数分析

FFmpeg源码:av_buffer_is_writable、av_buffer_realloc函数分析

=================================================================

一、av_realloc函数

(一)av_realloc函数的声明

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

/**
 * Allocate, reallocate, or free a block of memory.
 *
 * If `ptr` is `NULL` and `size` > 0, allocate a new block. Otherwise, expand or
 * shrink that block of memory according to `size`.
 *
 * @param ptr  Pointer to a memory block already allocated with
 *             av_realloc() or `NULL`
 * @param size Size in bytes of the memory block to be allocated or
 *             reallocated
 *
 * @return Pointer to a newly-reallocated block or `NULL` if the block
 *         cannot be reallocated
 *
 * @warning Unlike av_malloc(), the returned pointer is not guaranteed to be
 *          correctly aligned. The returned pointer must be freed after even
 *          if size is zero.
 * @see av_fast_realloc()
 * @see av_reallocp()
 */
void *av_realloc(void *ptr, size_t size) av_alloc_size(2);

该函数作用是:分配或重新分配(更改动态分配的内存大小)一个内存块。使用完该内存块后必须使用av_free或av_freep函数对其进行释放。

1.如果形参ptr值为NULL,并且形参size的值大于0,会分配一个新的内存块,该函数返回一个指向新分配的内存块的指针;

2.如果形参ptr指向一个已存在的内存块,并且形参size的值大于0,根据size的值扩展或缩小该内存块。新的大小(size的值)可大可小,如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失。

形参ptr:既是输入型参数,也是输出型参数。指向一个要重新分配内存的内存块,也可以是空指针。

形参size:输入型参数。新内存块的大小,单位为字节。

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

(二)av_realloc函数的定义

av_realloc函数定义在libavutil/mem.c中:

void *av_realloc(void *ptr, size_t size)
{
    void *ret;
    if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))
        return NULL;

#if HAVE_ALIGNED_MALLOC
    ret = _aligned_realloc(ptr, size + !size, ALIGN);
#else
    ret = realloc(ptr, size + !size);
#endif
#if CONFIG_MEMORY_POISONING
    if (ret && !ptr)
        memset(ret, FF_MEMORY_POISON, size);
#endif
    return ret;
}

去掉一大堆其它东西,av_realloc函数的核心实现就是:

void *av_realloc(void *ptr, size_t size)
{
//...
    void *ret;
    ret = realloc(ptr, size + !size);
    return ret;
}

可以看到其本质就是调用了realloc函数来更改内存大小。 语句“ret = realloc(ptr, size + !size)”保证了:即使av_realloc函数的形参size的值为0,传递给其内部realloc函数的也会是“ret = realloc(ptr, 1)”,从而让size的值为0时,ptr也能指向一个大小为1字节的内存块,避免其所指向的内存块被释放,避免size的值为0时函数返回一个空指针。

realloc函数有个问题:当realloc函数返回NULL时,它可能是执行失败(内存分配失败),也可能执行成功只是用户是使用它来释放内存(让size的值为0)。你压根没办法仅仅通过realloc函数的返回值来判断它是执行成功还是失败。av_realloc函数的设计艺术在于:它对realloc函数进行了封装,解决了realloc函数的上述痛点,当av_realloc函数返回NULL时,就是执行失败(内存分配失败)了。

二、av_reallocp函数

(一)av_reallocp函数的声明

av_reallocp函数声明在头文件libavutil/mem.h中:

/**
 * Allocate, reallocate, or free a block of memory through a pointer to a
 * pointer.
 *
 * If `*ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is
 * zero, free the memory block pointed to by `*ptr`. Otherwise, expand or
 * shrink that block of memory according to `size`.
 *
 * @param[in,out] ptr  Pointer to a pointer to a memory block already allocated
 *                     with av_realloc(), or a pointer to `NULL`. The pointer
 *                     is updated on success, or freed on failure.
 * @param[in]     size Size in bytes for the memory block to be allocated or
 *                     reallocated
 *
 * @return Zero on success, an AVERROR error code on failure
 *
 * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be
 *          correctly aligned.
 */
av_warn_unused_result
int av_reallocp(void *ptr, size_t size);

该函数作用是:分配、重新分配或释放内存块。如果形参ptr为NULL并且形参size大于0,分配一个新的内存块。如果形参size值为0,释放*ptr指向的内存块。与av_malloc()函数不同,用av_reallocp函数分配得到的内存不能保证正确对齐。

形参ptr:既是输入型参数,也是输出型参数,类型为指针的指针。*ptr指向一个要重新分配内存的内存块,也可以是空指针。该指针在成功时更新,失败时释放。

形参size:输入型参数。要分配或重新分配的内存块的大小,单位为字节。

返回值:返回0表示成功,返回错误码AVERROR(ENOMEM)表示失败。

(二)av_reallocp函数的定义

av_reallocp函数定义在libavutil/mem.c中:

int av_reallocp(void *ptr, size_t size)
{
    void *val;

    if (!size) {
        av_freep(ptr);
        return 0;
    }

    memcpy(&val, ptr, sizeof(val));
    val = av_realloc(val, size);

    if (!val) {
        av_freep(ptr);
        return AVERROR(ENOMEM);
    }

    memcpy(ptr, &val, sizeof(val));
    return 0;
}

可以看到该函数内部调用了av_realloc函数来分配或重新分配内存块,调用了av_freep函数来释放内存。由于av_freep函数的形参是指针的指针,所以av_reallocp函数的形参ptr也必须是指针的指针。关于av_freep函数的用法可以参考:《FFmpeg中内存分配和释放相关的源码:av_malloc函数、av_mallocz函数、av_free函数和av_freep函数分析

三、size_mult函数

size_mult函数定义在libavutil/mem.c中:

static int size_mult(size_t a, size_t b, size_t *r)
{
    size_t t;

#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow)
    if (__builtin_mul_overflow(a, b, &t))
        return AVERROR(EINVAL);
#else
    t = a * b;
    /* Hack inspired from glibc: don't try the division if nelem and elsize
     * are both less than sqrt(SIZE_MAX). */
    if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
        return AVERROR(EINVAL);
#endif
    *r = t;
    return 0;
}

该函数作用是:检查形参a和形参b相乘是否会溢出,并把它们相乘的结果保存到形参r指向的变量中。

形参a:输入型参数。进行乘法的第一个乘数。

形参b:输入型参数。进行乘法的第二个乘数。

形参r:输出型参数。指针,执行size_mult函数后,形参r指向的变量值会变为a * b的结果。

返回值:返回0表示没有溢出。返回AVERROR(EINVAL)表示溢出了。

四、av_realloc_f函数

(一)av_realloc_f函数的声明

av_realloc_f函数声明在头文件libavutil/mem.h中:

/**
 * Allocate, reallocate, or free a block of memory.
 *
 * This function does the same thing as av_realloc(), except:
 * - It takes two size arguments and allocates `nelem * elsize` bytes,
 *   after checking the result of the multiplication for integer overflow.
 * - It frees the input block in case of failure, thus avoiding the memory
 *   leak with the classic
 *   @code{.c}
 *   buf = realloc(buf);
 *   if (!buf)
 *       return -1;
 *   @endcode
 *   pattern.
 */
void *av_realloc_f(void *ptr, size_t nelem, size_t elsize);

该函数作用是:分配或重新分配一个大小为elsize * nelem字节的内存块。如果elsize * nelem溢出,释放形参ptr指向的内存块的空间。如果内存分配失败,也会自动释放空间。

形参ptr:既是输入型参数,也是输出型参数。指向一个要重新分配内存的内存块,也可以是空指针。

形参nelem和形参elsize:输入型参数。elsize * nelem为新内存块的大小,单位为字节。

(二)av_realloc_f函数的定义

av_realloc_f函数定义在libavutil/mem.c中:

void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
{
    size_t size;
    void *r;

    if (size_mult(elsize, nelem, &size)) {
        av_free(ptr);
        return NULL;
    }
    r = av_realloc(ptr, size);
    if (!r)
        av_free(ptr);
    return r;
}

可以看到该函数内部调用了size_mult检查相乘是否会溢出,如果没有溢出调用av_realloc函数来分配或重新分配内存块。

标签:函数,形参,realloc,源码,av,ptr,size
From: https://blog.csdn.net/u014552102/article/details/140971393

相关文章

  • FFmpeg存放压缩后的音视频数据的结构体:AVPacket简介
    FFmpeg源码中通过AVPacket存储压缩后的音视频数据。它通常由解复用器(demuxers)输出,然后作为输入传递给解码器,或者从编码器作为输出接收,然后传递给多路复用器(muxers)。对于视频,它通常包含一个压缩帧;对于音频,它可能包含几个压缩帧。编码器允许输出不包含压缩音视频数据、只包含side......
  • Java设计模式—责任链模式(Chin of Responsibility)
    目录引言1.职责链设计模式简介1.1定义1.2解决的问题2.设计模式的结构2.1类图2.2示例代码3.优点4.缺点5.实际应用5.1SpringAOP5.2JavaServletFilter5.3ReactorPattern5.4Java中的日志记录库6.结论注意事项引言在软件开发中,设计模式是一......
  • Springboot计算机毕业设计高校女生的饮食营养管理系统(程序+源码+数据库+调试部署+开发
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,个人食谱,特殊食谱,饮食类型,运动打卡,饮食登记开题报告内容一、研究背景与意义1.1研究背景随着社会经济的快速发展和人们生活水平的不断提高,人们对健康......
  • Springboot计算机毕业设计高校培养方案管理系统(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表教务处,系部负责人,专业负责人,理论课程,教学安排,课程,教师信息,院系,年级,专业,班级,学生,实践课程开题报告内容一、研究背景与意义研究背景随着教育信息化......
  • OS-Ubuntu-gcc-源码安装gcc7.5.0
    OS-Ubuntu-gcc-源码安装gcc7.5.0GNUMirrorListFTPserverofthetheGNUproject--gccGcc-依赖下载GCC源代码wgethttps://ftp.gnu.org/gnu/gcc/gcc-X.Y.Z/gcc-X.Y.Z.tar.gz解压、配置、编译gcc7.5.0操作指令序列://解压源代码tar-xzfgcc-7.5.0.tar.gzcdgcc-X.Y.......
  • LLM大模型:LLaVa多模态图片检索原理
    训练安全垂直领域的LLM,会用到很多著名安全论坛(52pojie\kanxue\xianzhi\freebuf等)、博客的数据,这些数据100%都有很多图片(文不如图嘛,图片比文字更直观,更容易表达业务意义),之前微调LLM只能使用文字,图片只能丢弃,非常可惜,需要利用多模态的技术充分提取图片信息! 1、以前做传......
  • 电话号码转换 - 华为机试真题题解(Java)
    考试平台:时习知分值:200分(第二题)考试时间:两小时(共2题)题目描述将电话号码转换,需要实现如下的中英文电话号码转换:输入的字符串中每个数字对应为中文数字中的英文单词,如Double表示两个数字相同。将输入的中文数字字符串转换为英文单词的电话号码。若输入不合法,则输出......
  • 图片表格内容识别转换-II - 华为机试真题题解(Java)
    考试平台:时习知分值:200分考试时间:两小时(共2题)题目描述华为云推出了“通用表格识别”服务,可以将图片表格转换成文本数据。请你将文本数据进一步转换为“文本型表格”,如下图所示:输入现给出一个图片表格的文本数据:每行数据形如line3col1A,表示第3行第1列的单......
  • 【轻松拿捏】Java是如何实现跨平台性的?
    Java是如何实现跨平台性的?一、Java的跨平台性主要通过以下几个核心机制实现:二、具体实现三、示例 四、JVM工作示意图五、总结......
  • Java毕业设计 基于Springboot+Vue的电影院剧院订票选座管理系统(源码+lw+部署文档+讲
    文末获取资源,收藏关注不迷路文章目录项目介绍功能需求技术介绍项目界面关键代码目录项目介绍随着经济的发展和信息技术的普及,国内许多企业都面临了重大的挑战。企业的管理流程、战略规划如果不能进行调整,极有可能面临淘汰的风险。特别是郑州大剧院,面对大量的会员和......