FFmpeg5.0源码阅读——内存池AVBufferPool
摘要:FFmpeg中大多数数据存储比如AVFrame
,AVPacket
都是通过AVBufferRef
管理的,而承载数据的结构为AVBuffer
。本文主要通过FFmpeg源码来分析下FFmpeg中AVBuffer
相关的实现。
关键字:AVBuffer
、AVBufferPool
、AVBufferPool
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
,对象本身不线程安全;
- 这里不是单纯的引用计数+1,而是
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
,当pdst
和src
指向同一个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
的指针节点,而是保存了opaque
和free
函数指针,因为有这两个值我们就可以很顺利的释放对应的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
:线程安全用的锁;opaque
:pool_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
摘要:FFmpeg中大多数数据存储比如AVFrame,AVPacket都是通过AVBufferRef管理的,而承载数据的结构为AVBuffer。本文主要通过FFmpeg源码来分析下FFmpeg中AVBuffer相关的实现。 关键字:AVBuffer、AVBufferPool、AVBufferPool 1. AVBufferRef 1.…...
Python学习------起步7(字符串的连接、删除、修改、查询与统计、类型判断及字符串字母大小写转换)
目录 前言: 1.字符串的连接 join() 函数 2.字符串的删除&取代 replace()函数 3.字符串的修改&切割 (1)strip() 函数 (2)lstrip()函数 和 rstrip()函数 (3)split()函数-->…...
雪花算法snowflake
snowflake中文的意思是 雪花,雪片,所以翻译成雪花算法。它最早是twitter内部使用的分布式环境下的唯一ID生成算法。在2014年开源。雪花算法产生的背景当然是twitter高并发环境下对唯一ID生成的需求,得益于twitter内部高超的技术,雪…...
Part 4 描述性统计分析(占比 10%)——上
文章目录【后续会持续更新CDA Level I&II备考相关内容,敬请期待】【考试大纲】【考试内容】【备考资料】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: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(…...
信息安全与网络安全有什么区别?
生活中我们经常会听到要保障自己的或者企业的信息安全。那到底什么是信息安全呢?信息安全包含哪些内容?与网络安全又有什么区别呢?今天我们就一起来详细了解一下。什么叫做信息安全?信息安全定义如下:为数据处理系统建…...
花了5年时间,用过市面上95%的工具,终于找到这款万能报表工具
经常有粉丝问我有“哪个报表工具好用易上手?”或者是“有哪些适合绝大多数普通职场人的万能报表工具?” 从这里我大概总结出了大家选择报表工具最期望满足的3点: (1)简单易上手:也就是所谓的学习门槛要低…...
ESP32S3系列--SPI主机驱动详解(一)
一、目的SPI是一种串行同步接口,可用于与外围设备进行通信。ESP32S3自带4个SPI控制器外设,其中SPI0/SPI1内部专用,共用一组信号线,通过一个仲裁器访问外部Flash和PSRAM;SPI2/3各自使用一组信号线;开发者可以使用SPI2/3控制外部SPI…...
2023开工开学火热!远行的人们,把淘特箱包送上顶流
春暖花开,被疫情偷走的三年在今年开学季找补回来了。多个数据反馈,居民消费意愿大幅提升。在淘特上,开工开学节点就很是明显:1月30日以来,淘特箱包品类甚至远超2022年双11,成为开年“第一爆品”。与此同时&…...
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(Performance Monito…...
Vue (2)
文章目录1. 模板语法1.1 插值语法1.2 指令语法2. 数据绑定3. 穿插 el 和 data 的两种写法4. MVVM 模型1. 模板语法 root 容器中的代码称为 vue 模板 1.1 插值语法 1.2 指令语法 图一 : 简写 : v-bind: 是可以简写成 : 的 总结 : …...
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、初始化的前置方法和后置方法(重写) 2.3、Spring启动类 2.4、执行结果 2.5、经典面试问题 3.总结 1.Bean的生命周期 1.1、概括 Spring中Bean的生命周期就是Bean在…...
如何将VirtualBox虚拟机转换到VMware中
转换前的准备 首先需要你找到你的virtualbox以及VM安装到哪个文件夹里了,需要将这两个文件夹添加进环境变量Path中。 如果你记不清了,可以用everything全局搜索一下“VBoxManage.exe’以及“vmware-vdiskmanager.exe”,看一眼这个程序放到哪…...
洞庭龙梦(开发技巧和结构理论集)
1、经验来源,单一获取方式。进行形态等级展示。唯一游戏系统经验来源。无主线和支线剧情。2、玩家使用流通货币(充值货币),到玩家空间商城充值游戏,两人以上玩家进行游戏,掉落道具。交易系统游戏玩法&#…...
【23种设计模式】创建型模式详细介绍
前言 本文为 【23种设计模式】创建型模式详细介绍 相关内容介绍,下边具体将对单例模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,具体包括它们的特点与实现等进行详尽介绍~ 📌博主主页&…...
@Bean的处理流程,源码分析@Bean背后发生的事
文章目录写在前面关键类ConfigurationClassPostProcessor1、ConfigurationClassPostProcessor的注册2、ConfigurationClassPostProcessor的处理过程(1)parse方法中,Bean方法的处理(2)注册解析Bean标注的方法写在前面 …...
美国一级a做爰片免费网站/音乐接单推广app平台
这几天修真院又又又迎来了一位退伍的兵哥哥,所以在征得兵哥哥的允许后,我们决定把他的转行历程分享出来,供大家参考参考。 这位兵哥哥呢姓王,我们就暂时称呼他为王大锤同学吧。 大锤同学在来到修真院之前呢,已经在家颓…...
非常赚又一个wordpress站点/seo推广外包企业
rt转载于:https://www.cnblogs.com/PoeticalJustice/p/9646282.html...
如何申请邮箱免费注册/枣庄网络推广seo
任何电脑系统都会有瑕疵,win10系统也不例外。今天有用户遇到了win10隐藏防火墙和网络保护部分方法的问题,如果对于老鸟来说就很简单就可以处理,但是对于新手处理win10隐藏防火墙和网络保护部分方法的问题就很难,要是你同样也被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上对于图像的处理,假设单纯使用代码。那么非常遗憾,程序基本会跑死,毕竟是直接对像素的操作,读取写入都是比較耗费CPU和内存的。所以。这次由于项目须要想实现类似哈哈镜的效果。想来想去,还是认为用unity的Shade…...
兰州网站seo服务/深圳网站建设推广方案
asp.net中word转html碰到的权限异常问题(转) 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005。 说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪…...