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

FFmpeg5.0源码阅读——内存池AVBufferPool

摘要:FFmpeg中大多数数据存储比如AVFrame,AVPacket都是通过AVBufferRef管理的,而承载数据的结构为AVBuffer。本文主要通过FFmpeg源码来分析下FFmpeg中AVBuffer相关的实现。
关键字AVBufferAVBufferPoolAVBufferPool

1. AVBufferRef

1.1 AVBuffer结构定义

  AVBuffer声明在libavutil/buffer_internal.h文件中,而相关的操作函数定义在libavutil/buffer.c中。先简单看下AVBuffer的结构:

struct AVBuffer {uint8_t *data;          /**< data described by this buffer */size_t size;                /**< size of data in bytes */atomic_uint refcount;   //number of existing AVBufferRef instances referring to this **buffer**void (*free)(void *opaque, uint8_t *data);//a callback for freeing the datavoid *opaque;//an opaque pointer, to be used by the freeing callbackint flags;//A combination of AV_BUFFER_FLAG_*int flags_internal;//A combination of BUFFER_FLAG_*
};

  该结构比较简单,就是一个含有引用计数的数据类型:

  • data:buffer中的数据指针;
  • size:数据的大小,即data中数据的大小;
  • refcount:引用计数,无需多说,当引用计数为0时销毁对应的内存。该变量的操作是原子的,ffmpeg内部针对不同的编译期和平台实现了一套源自变量,具体就深入了,理解意思就行;
  • free:释放内存的函数指针,如果不指定的话会使用默认的函数指针av_buffer_default_free释放内存;
  • opaque:user-defined的指针,用户可以通过该指针将数据传递给free函数;
  • flags:目前只有一个值AV_BUFFER_FLAG_READONLY
  • flags_internal:目前只有一个值BUFFER_FLAG_REALLOCATABLE

1.2 AVBufferRef结构定义

  AVBufferRef可以看做AVBuffer的一个句柄,用来操作AVBuffer

typedef struct AVBufferRef {AVBuffer *buffer;/*** The data buffer. It is considered writable if and only if* this is the only reference to the buffer, in which case* av_buffer_is_writable() returns 1.*/uint8_t *data;size_t   size;//Size of data in bytes.
} AVBufferRef;

  AVBufferRef结构比较简单,不详细描述,主要注意data字段是指向其成员buffer.data的。

1.3 操作函数

  • AVBufferRef *av_buffer_create(uint8_t *data, size_t size, void (*free)(void *opaque, uint8_t *data), void *opaque, int flags):该函数用来创建一个AVBufferRef,具体就是申请内存函数根据参数初始化各个成员。需要注意的是返回的指针和其成员buffer是在堆上的,以及AVBuferRef::data == AVBufferRef::buffer::data
  • AVBufferRef *av_buffer_alloc(size_t size):通过av_buffer_create创建对象,只不过参数都是默认值;
  • AVBufferRef *av_buffer_allocz(size_t size):相比av_buffer_alloc只是对内存进行了0初始化;
  • AVBufferRef *av_buffer_ref(AVBufferRef *buf):FFmpeg中以_ref结尾的API都是引用计数+1的含义,相反_unref就是引用计数-1。但是需要注意两点:
    • 这里不是单纯的引用计数+1,而是malloc了一个AVBufferRef作为返回值,然后浅拷贝输入参数;
    • 仅仅引用计数是原子的,类似shared_ptr,对象本身不线程安全;
  • void av_buffer_unref(AVBufferRef **buf):引用计数-1,释放内存,调用free释放data内存;
  • int av_buffer_is_writable(const AVBufferRef *buf):当flags设置了AV_BUFFER_FLAG_READONLY时始终不可写,否则只有引用计数为1时才可写;
  • int av_buffer_make_writable(AVBufferRef **pbuf):实现就是copy-on-write,将pbuf复制一份避免写共享的内存影响其他对象;
  • int av_buffer_realloc(AVBufferRef **pbuf, size_t size):重新申请内存,如果传入的*pbuf为空则create一份。当输入的对象不可写或者不是BUFFER_FLAG_REALLOCATABLE时会拷贝一份再realloc
  • int av_buffer_replace(AVBufferRef **pdst, AVBufferRef *src):可以简单的理解就是*pds=*src,当pdstsrc指向同一个buffer时,什么也不会做,实现类似C++中对象的拷贝构造函数;

2. AVBufferRef

2.1 结构定义

  AVBufferPool是一个单链表,用来管理其中的AVBuffer

typedef struct BufferPoolEntry {uint8_t *data;/** Backups of the original opaque/free of the AVBuffer corresponding to* data. They will be used to free the buffer when the pool is freed.*/void *opaque;void (*free)(void *opaque, uint8_t *data);AVBufferPool *pool;struct BufferPoolEntry *next;
} BufferPoolEntry;

  从结构定义中可以看到BufferPollEntry就是链表中的节点用来管理对应的AVBufferRef。但是仔细看又发现其中并没有AVBuffer的指针节点,而是保存了opaquefree函数指针,因为有这两个值我们就可以很顺利的释放对应的AVBuffer,而pool中又保存了对应的allocate的函数指针能够创建对象。

  • data:指向AVBuffer的地址,因为没有保存AVBuffer的地址所以需要一个指针来指向数据;
  • opaque:实现中BufferPoolEntry::opaque->AVBuffer::opaque->BufferPoolEntry,这样能够保证通过AVBuffer调用释放函数时找到管理自己的handle;
  • free:释放函数指针,实际上是固定的pool_release_buffer
  • pool:直接指向当前的内存池;
  • next:链表的节点指针;
struct AVBufferPool {AVMutex mutex;BufferPoolEntry *pool;/** This is used to track when the pool is to be freed.* The pointer to the pool itself held by the caller is considered to* be one reference. Each buffer requested by the caller increases refcount* by one, returning the buffer to the pool decreases it by one.* refcount reaches zero when the buffer has been uninited AND all the* buffers have been released, then it's safe to free the pool and all* the buffers in it.*/atomic_uint refcount;size_t size;void *opaque;AVBufferRef* (*alloc)(size_t size);AVBufferRef* (*alloc2)(void *opaque, size_t size);void         (*pool_free)(void *opaque);
};

  AVBufferPool就是内存池的管理对象:

  • mutex:线程安全用的锁;
  • opaquepool_free函数指针的第一个参数;
  • alloc:默认会被设置成av_buffer_alloc
  • alloc2:自定义的分配函数,申请AVBufferRef时优先使用,没有指定则使用alloc
  • pool_free:释放内存池的回调;
  • size:单个对象的大小,即整个内存池管理的对象大小是相同的;
  • refcount:当前从内存池中分配但是并没有在内存池链表中的节点的引用计数之和。

2.2 接口实现

  • AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef* (*alloc)(void *opaque, size_t size), void (*pool_free)(void *opaque)):初始化pool的链表,根据参数设置相应的成员,alloc2会设置输入的参数alloc,而- alloc会设置成av_buffer_alloc
  • AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size)):只会申请pool的内存设置相关参数,如果alloc为空则pool中的alloc设置为av_buffer_alloc
  • void av_buffer_pool_uninit(AVBufferPool **ppool):销毁pool,如果引用计数为1则销毁对象(不知道为什么命名没有类似_unref,可能因为没有ref吧);
  • AVBufferRef *av_buffer_pool_get(AVBufferPool *pool):获取一个AVBufferRef该内存是通过pool管理的。

2.3 内存管理

  AVBufferPool是一个以单链表形式实现的栈式内存池。其基本过程就是如果链表非空则出栈头结点,否则申请内存时就创建一个AVBUfferRef返回给用户,用户释放时就会将节点入栈到头结点,并且申请和释放内存是线程安全的。AVBufferPool就是一个空闲链表栈,通过指定对应的AVBufferRef的释放函数为pool_release_buffer来对内存进行管理。
  对于一个刚初始化的内存池,连续申请两个Buffer就是下面这种状态:
在这里插入图片描述

  连续申请3个buffer,再释放2个就是下面这种状态(红色为链表的连接线):
在这里插入图片描述

相关文章:

FFmpeg5.0源码阅读——内存池AVBufferPool

摘要&#xff1a;FFmpeg中大多数数据存储比如AVFrame,AVPacket都是通过AVBufferRef管理的&#xff0c;而承载数据的结构为AVBuffer。本文主要通过FFmpeg源码来分析下FFmpeg中AVBuffer相关的实现。 关键字&#xff1a;AVBuffer、AVBufferPool、AVBufferPool 1. AVBufferRef 1.…...

Python学习------起步7(字符串的连接、删除、修改、查询与统计、类型判断及字符串字母大小写转换)

目录 前言&#xff1a; 1.字符串的连接 join() 函数 2.字符串的删除&取代 replace()函数 3.字符串的修改&切割 &#xff08;1&#xff09;strip() 函数 &#xff08;2&#xff09;lstrip()函数 和 rstrip()函数 &#xff08;3&#xff09;split()函数-->…...

雪花算法snowflake

snowflake中文的意思是 雪花&#xff0c;雪片&#xff0c;所以翻译成雪花算法。它最早是twitter内部使用的分布式环境下的唯一ID生成算法。在2014年开源。雪花算法产生的背景当然是twitter高并发环境下对唯一ID生成的需求&#xff0c;得益于twitter内部高超的技术&#xff0c;雪…...

Part 4 描述性统计分析(占比 10%)——上

文章目录【后续会持续更新CDA Level I&II备考相关内容&#xff0c;敬请期待】【考试大纲】【考试内容】【备考资料】1、统计基本概念1.1、统计学的含义及应用1.1.1、统计学的含义1.2.1、统计学的应用1.2、统计学的基本概念1.2.1、数据及数据的分类1.2.2、总体和样本1.2.3、…...

Linux系统安全:安全技术和防火墙

目录 一、安全技术 1、安全技术 2、防火墙分类 二、防火墙 1、iptables五表五链 2、黑白名单 3、iptables基本语法 4、iptables选项 5、控制类型 6、隐藏扩展模块 7、显示扩展模块 8、iptables规则保存 9、自定义链使用 一、安全技术 1、安全技术 ①入侵检测系统…...

【干货】Python:turtle库的用法

【干货】Python&#xff1a;turtle库的用法1. turtle库概述2. turtle库与基本绘图2.1 导入库的三种方式2.1.12.1.22.1.32.2 窗体函数2.2 画笔状态函数2.2.1 seed(s)2.2.2 random()2.2.3 randint(a, b)2.2.4 getrandbits(k)2.2.5 randrange(start, stop[ , step])2.2.6 uniform(…...

信息安全与网络安全有什么区别?

生活中我们经常会听到要保障自己的或者企业的信息安全。那到底什么是信息安全呢&#xff1f;信息安全包含哪些内容&#xff1f;与网络安全又有什么区别呢&#xff1f;今天我们就一起来详细了解一下。什么叫做信息安全&#xff1f;信息安全定义如下&#xff1a;为数据处理系统建…...

花了5年时间,用过市面上95%的工具,终于找到这款万能报表工具

经常有粉丝问我有“哪个报表工具好用易上手&#xff1f;”或者是“有哪些适合绝大多数普通职场人的万能报表工具&#xff1f;” 从这里我大概总结出了大家选择报表工具最期望满足的3点&#xff1a; &#xff08;1&#xff09;简单易上手&#xff1a;也就是所谓的学习门槛要低…...

ESP32S3系列--SPI主机驱动详解(一)

一、目的SPI是一种串行同步接口&#xff0c;可用于与外围设备进行通信。ESP32S3自带4个SPI控制器外设&#xff0c;其中SPI0/SPI1内部专用,共用一组信号线,通过一个仲裁器访问外部Flash和PSRAM&#xff1b;SPI2/3各自使用一组信号线&#xff1b;开发者可以使用SPI2/3控制外部SPI…...

2023开工开学火热!远行的人们,把淘特箱包送上顶流

春暖花开&#xff0c;被疫情偷走的三年在今年开学季找补回来了。多个数据反馈&#xff0c;居民消费意愿大幅提升。在淘特上&#xff0c;开工开学节点就很是明显&#xff1a;1月30日以来&#xff0c;淘特箱包品类甚至远超2022年双11&#xff0c;成为开年“第一爆品”。与此同时&…...

Intel x86_64 PMU简介

文章目录前言一、性能监控概述二、CPUID information三、架构性能监控3.1 架构性能监控 Version 13.1.1 架构性能监控 Version 1 Facilities3.1.2 预定义的体系结构性能事件3.1.3 cmask demo测试参考资料前言 Intel 64 和 IA-32 架构提供了 PMU&#xff08;Performance Monito…...

Vue (2)

文章目录1. 模板语法1.1 插值语法1.2 指令语法2. 数据绑定3. 穿插 el 和 data 的两种写法4. MVVM 模型1. 模板语法 root 容器中的代码称为 vue 模板 1.1 插值语法 1.2 指令语法 图一 &#xff1a; 简写 &#xff1a; v-bind: 是可以简写成 &#xff1a; 的 总结 &#xff1a; …...

ESP8266 + STC15基于AT指令通过TCP通讯协议获取时间

ESP8266 + STC15基于AT指令通过TCP通讯协议获取时间 如果纯粹拿32位的ESP8266模块给8位的单片机仅供授时工具使用,有点大材小用了。这里不讨论这个拿esp8266来单独开发使用。本案例只是通过学习esp8266 AT指令功能来验证方案的可行性。 🔖STC15 单片机采用的是:STC15F2K60S…...

谈谈Spring中Bean的生命周期?(让你瞬间通透~)

目录 1.Bean的生命周期 1.1、概括 1.2、图解 2、代码示例 2.1、初始化代码 2.2、初始化的前置方法和后置方法&#xff08;重写&#xff09; 2.3、Spring启动类 2.4、执行结果 2.5、经典面试问题 3.总结 1.Bean的生命周期 1.1、概括 Spring中Bean的生命周期就是Bean在…...

如何将VirtualBox虚拟机转换到VMware中

转换前的准备 首先需要你找到你的virtualbox以及VM安装到哪个文件夹里了&#xff0c;需要将这两个文件夹添加进环境变量Path中。 如果你记不清了&#xff0c;可以用everything全局搜索一下“VBoxManage.exe’以及“vmware-vdiskmanager.exe”&#xff0c;看一眼这个程序放到哪…...

洞庭龙梦(开发技巧和结构理论集)

1、经验来源&#xff0c;单一获取方式。进行形态等级展示。唯一游戏系统经验来源。无主线和支线剧情。2、玩家使用流通货币&#xff08;充值货币&#xff09;&#xff0c;到玩家空间商城充值游戏&#xff0c;两人以上玩家进行游戏&#xff0c;掉落道具。交易系统游戏玩法&#…...

【23种设计模式】创建型模式详细介绍

前言 本文为 【23种设计模式】创建型模式详细介绍 相关内容介绍&#xff0c;下边具体将对单例模式&#xff0c;工厂方法模式&#xff0c;抽象工厂模式&#xff0c;建造者模式&#xff0c;原型模式&#xff0c;具体包括它们的特点与实现等进行详尽介绍~ &#x1f4cc;博主主页&…...

@Bean的处理流程,源码分析@Bean背后发生的事

文章目录写在前面关键类ConfigurationClassPostProcessor1、ConfigurationClassPostProcessor的注册2、ConfigurationClassPostProcessor的处理过程&#xff08;1&#xff09;parse方法中&#xff0c;Bean方法的处理&#xff08;2&#xff09;注册解析Bean标注的方法写在前面 …...

美国一级a做爰片免费网站/音乐接单推广app平台

这几天修真院又又又迎来了一位退伍的兵哥哥&#xff0c;所以在征得兵哥哥的允许后&#xff0c;我们决定把他的转行历程分享出来&#xff0c;供大家参考参考。 这位兵哥哥呢姓王&#xff0c;我们就暂时称呼他为王大锤同学吧。 大锤同学在来到修真院之前呢&#xff0c;已经在家颓…...

非常赚又一个wordpress站点/seo推广外包企业

rt转载于:https://www.cnblogs.com/PoeticalJustice/p/9646282.html...

如何申请邮箱免费注册/枣庄网络推广seo

任何电脑系统都会有瑕疵&#xff0c;win10系统也不例外。今天有用户遇到了win10隐藏防火墙和网络保护部分方法的问题&#xff0c;如果对于老鸟来说就很简单就可以处理&#xff0c;但是对于新手处理win10隐藏防火墙和网络保护部分方法的问题就很难&#xff0c;要是你同样也被win…...

视频解析网站如何做搜索/网站怎样才能在百度被搜索到

alibaba/p3c github地址 : https://github.com/alibaba/p3c可以直接clone到本地(含阿里巴巴Java开发手册(终极版).pdf)主要说说eclipse安装1.在线安装方法Help >> Install New Software 然后输入下面的地址 https://p3c.alibaba.com/plugi...等下面的列表加载出来,直接下…...

手机怎样做网站图解/win7系统优化软件

Unity上对于图像的处理&#xff0c;假设单纯使用代码。那么非常遗憾&#xff0c;程序基本会跑死&#xff0c;毕竟是直接对像素的操作&#xff0c;读取写入都是比較耗费CPU和内存的。所以。这次由于项目须要想实现类似哈哈镜的效果。想来想去&#xff0c;还是认为用unity的Shade…...

兰州网站seo服务/深圳网站建设推广方案

asp.net中word转html碰到的权限异常问题&#xff08;转&#xff09; 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败&#xff0c;原因是出现以下错误: 80070005。 说明: 执行当前 Web 请求期间&#xff0c;出现未处理的异常。请检查堆栈跟踪…...