当前位置: 首页 > news >正文

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

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

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_MALLOCret = _aligned_realloc(ptr, size + !size, ALIGN);
#elseret = realloc(ptr, size + !size);
#endif
#if CONFIG_MEMORY_POISONINGif (ret && !ptr)memset(ret, FF_MEMORY_POISON, size);
#endifreturn 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);
#elset = 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函数来分配或重新分配内存块。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Springboot 开发之 Quartz 任务调度框架简介
  • 自定义View-- wifi强度
  • 从0开始搭建vue + flask 旅游景点数据分析系统( 六):搭建后端flask框架
  • Win32注册表操作
  • Rust 所有权
  • 大数据-Big Data(一):概述与基础
  • Tracecat:开源 SOAR
  • Transformer 模型中的 QKV 机制是如何运作的
  • 区块链平台的图灵完备性
  • 探秘C# LINQ元素运算:原理阐释与实践指南
  • day 22线程间通信
  • Java参数传递
  • 深度学习-----------数值稳定性
  • docker部署jenkins和jenkins的基本使用
  • 【SpringCloud】SpringCloudNetflix笔记
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • CAP理论的例子讲解
  • Fabric架构演变之路
  • JDK9: 集成 Jshell 和 Maven 项目.
  • jquery cookie
  • Koa2 之文件上传下载
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Linux各目录及每个目录的详细介绍
  • Python socket服务器端、客户端传送信息
  • python 装饰器(一)
  • 官方解决所有 npm 全局安装权限问题
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 网络应用优化——时延与带宽
  • 我是如何设计 Upload 上传组件的
  • ### RabbitMQ五种工作模式:
  • #### go map 底层结构 ####
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #Spring-boot高级
  • %@ page import=%的用法
  • %check_box% in rails :coditions={:has_many , :through}
  • (LeetCode C++)盛最多水的容器
  • (ZT)薛涌:谈贫说富
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (四)linux文件内容查看
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)IOS中获取各种文件的目录路径的方法
  • (自用)gtest单元测试
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net framework4与其client profile版本的区别
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • @ConfigurationProperties注解对数据的自动封装
  • [ 云计算 | AWS ] 对比分析:Amazon SNS 与 SQS 消息服务的异同与选择
  • [000-01-022].第03节:RabbitMQ环境搭建
  • [AIGC] 如何建立和优化你的工作流?
  • [Android] 240204批量生成联系人,短信,通话记录的APK
  • [Android]使用Android打包Unity工程
  • [Asp.net mvc]国际化