当前位置:网站首页>FFMpeg AVBufferPool 的理解与掌握
FFMpeg AVBufferPool 的理解与掌握
2022-06-30 12:14:00 【hjjdebug】
FFMpeg AVBufferPool 的理解与掌握
深刻理解含义需要调试代码,
但观赏记录可以事半功倍!
pool的总体思路是:
如果pool中没有BufferPoolEntry,则新建
内存释放时,实际数据返回到pool中,由pool将BufferPoolEntry链接起来。
如果再取数据,如果pool中有entry,则使用pool中entry.
调用av_buffer_pool_init函数
分配一个AVBufferPool 实例,返回该实例指针,
其中pool的refcount为1,size 为传入值,以后按此大小分配,alloc 函数默认为av_buffer_alloc 或者传入的内存分配函数
调用av_buffer_pool_get函数
此时pool->pool为空, 送给buf, pool->pool 是BufferPoolEntry 指针.
!buf 成立,调用pool_alloc_buffer(pool)
此函数中调用av_buffer_alloc(pool->size)分配内存,返回AVBufferRef 指针 ret. 也是该函数的返回值
然后再分配一个BufferPoolEntry实例,此实例的data指向新申请的内存空间,pool保存传来的AVBufferPool。
该实例指针赋值给AVBuffeRef的ret->buffer->opaque。
ret->buffer->free = pool_release_buffer;此句是关键,AVBuffer free时调用该函数
然后把pool->refcount 增1变成了2.
调用av_buffer_unref函数
此时传递的参数是AVBufferRef 指针, 其buffer->free 是pool_release_buffer
将AVBuffer及AVBufferRef结构体对应的内存空间都释放掉,
在释放数据时,实际调用pool_release_buffer函数。传入b->opaque,b->data, b是AVBuffer指针
b->opaque(不透明的,模糊的) 是前面传入的BufferPoolEntry 指针, 由此可以拿到pool, 将该opaque加入到pool链表顶部,供后续使用
pool 的refcount -1, 当减为0时,整个pool 要free. buffer_pool_free(pool).
再调用av_buffer_pool_get函数
此时pool->pool 不为空, 是前面分配的BufferPoolEntry实例,付给buf,此时不为空值.
然后调用av_buffer_create(buf->data,pool->size,pool_rease_buffer,buf,0)
它创建AVBuffer实例 和 AVBufferRef 实例, 然后 ref.
buf->data 就是AVBuffer 的buffer->data, pool->size 就是buffer->size pool_rease_buffer 就是buffer->free
buf 就是buffer->opaque, 0是buffer->flags
这样就用到了前面释放过的buf->data.
然后把buf->next 付给 pool->pool,调整pool 链表, buf->next 付给0
把pool->refcount 增1
其它函数说明: 直接上函数加注释.
void av_buffer_pool_uninit(AVBufferPool **ppool) //uninit 就是调用flush(), 如果pool的refcount=1,就调用free
{
AVBufferPool *pool = *ppool;
buffer_pool_flush(pool);
if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
buffer_pool_free(pool);
}
static void buffer_pool_free(AVBufferPool *pool) // 先调用flush, 再销毁mutex, 有free调用free,释放自己结构
{
buffer_pool_flush(pool);
ff_mutex_destroy(&pool->mutex);
if (pool->pool_free)
pool->pool_free(pool->opaque);
av_freep(&pool);
}
static void buffer_pool_flush(AVBufferPool *pool) // 如果pool的entry 为真,则释放该entry,同时查看下一条entry
{
while (pool->pool) {
BufferPoolEntry *buf = pool->pool;
pool->pool = buf->next;
buf->free(buf->opaque, buf->data);
av_freep(&buf);
}
}
知识点:
0. 理解的基础还是要先理解AVBuffer 的概念.后面就好办了.
1、AVBuffer的释放器默认为av_buffer_default_free,用在pool时,此值为pool_release_buffer。
2、在AVBuffer结构体定义一个opaque(模糊不确定)变量,然后将BufferPoolEntry指针存放在此opaque中,
在调用AVBuffer的free函数时, 将此opaque作为参数传递。达到内存回收到pool
付测试代码:
#include <QCoreApplication>
#include <iostream>
#include <iomanip>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/replaygain.h>
#include <libavutil/pixdesc.h>
}
using namespace std;
/*
1. av_buffer_pool_init
初始化 内存池
2 av_buffer_pool_get
从内存池中获取buffer
3.av_buffer_pool_uninit
释放内存池
4.pool_release_buffer
回收buffer
*/
const int testAVBufferPoolLoopCount = 3; // 通过修改循环次数来测试是否有内存的泄漏
void testAVBufferPool()
{
std::cout << "\n\n--------------- Test testAVBufferPool into -------------" << std::endl;
AVBufferPool *avBufferPool;
AVBufferRef *avBufferRefT;
AVBufferRef *avBufferRef0;
AVBufferRef *avBufferRef1;
AVBufferRef *avBufferRef2;
for(int i = 0; i < testAVBufferPoolLoopCount; i++)
{
avBufferPool = av_buffer_pool_init(1*1024*1024, nullptr);
avBufferRef0 = av_buffer_pool_get(avBufferPool);
std::cout <<"avBufferRef0-hex:" << hex << avBufferRef0 <<std::endl;
std::cout << "avBufferRef0 size = " <<dec << avBufferRef0->size << std::endl;
//memcpy(avBufferRefT, avBufferRef0, sizeof(*avBufferRefT));
avBufferRefT = avBufferRef0;
av_buffer_unref(&avBufferRef0); // 释放 avBufferRef0
std::cout << "avBufferRefT size = " <<dec << avBufferRefT->size << std::endl;
avBufferRef1 = av_buffer_pool_get(avBufferPool);
avBufferRef2 = av_buffer_pool_get(avBufferPool);
std::cout <<"AVBufferPool" << std::endl;
std::cout <<"avBufferRef0-hex:" << hex << avBufferRef0 <<std::endl;
std::cout <<"avBufferRefT-hex:" << hex << avBufferRefT <<std::endl;
std::cout <<"avBufferRef1-hex:" << hex << avBufferRef1 <<std::endl; // 这里可以看到打印和avBufferRef0未释放时是一样的,说明线程池内部有回收机制
std::cout <<"avBufferRef2-hex:" << hex << avBufferRef2 <<std::endl;
if(avBufferRef0)
std::cout << "av_buffer_get_ref_count(avBufferRef0) = " << av_buffer_get_ref_count(avBufferRef0) << std::endl;
if(avBufferRef1)
std::cout << "av_buffer_get_ref_count(avBufferRef1) = " << av_buffer_get_ref_count(avBufferRef1) << std::endl;
avBufferRef0 = av_buffer_pool_get(avBufferPool);
av_buffer_pool_uninit(&avBufferPool);
av_buffer_unref(&avBufferRef0); // 通过注释该部分来测试是否有内存的泄漏
av_buffer_unref(&avBufferRef1);
av_buffer_unref(&avBufferRef2);
}
std::cout << "\n--------------- Test testAVBufferPool leave -------------" << std::endl;
}
int main()
{
testAVBufferPool();
return 0;
}
边栏推荐
- 品达通用权限系统(Day 7~Day 8)
- What are the applications of 3D visual inspection in production flow
- Essay: Research on smart home scheme
- QT implementation dynamic navigation bar
- The website with id 0 that was requested wasn‘t found. Verify the website and try again
- Analysis of smart jiangcai login in Jiangxi University of Finance and Economics
- qt msvc 安装及调试
- [300+ continuous sharing of selected interview questions from large manufacturers] column on interview questions of big data operation and maintenance (II)
- Google refutes rumors and gives up tensorflow. It's still alive!
- 60 divine vs Code plug-ins!!
猜你喜欢
MySQL composite query
iServer发布ES服务查询设置最大返回数量
How to use the plug-in mechanism to gracefully encapsulate your request hook
Redis-緩存問題
21. Notes on WPF binding
[target tracking] |pytracking configuring win to compile prroi_ pool. pyd
Construction de la plate - forme universelle haisi 3559: obtenir le codage après modification du cadre de données
90. (cesium chapter) cesium high level listening events
QT implementation dynamic navigation bar
Q-learning notes
随机推荐
Redis installation on Linux system
【300+精选大厂面试题持续分享】大数据运维尖刀面试题专栏(二)
浅谈 JMeter 运行原理
rpm2rpm 打包步骤
Analysis of smart jiangcai login in Jiangxi University of Finance and Economics
Shell基础入门
FlinkSQL自定义UDAF使用的三种方式
Vision based robot grasping: from object localization, object pose estimation to parallel gripper grasping estimation
Today in history: Microsoft acquires PowerPoint developers; SGI and MIPS merge
Splitting e-commerce systems into micro services
SuperMap iClient3D for WebGL 加载TMS瓦片
How to solve cross domain problems
Clipboardjs - development learning summary 1
90. (cesium chapter) cesium high level listening events
Sublist3r error reporting solution
[bug solution] fiftyone reports attributeerror: module 'CV2' has no attribute 'GAPI_ wip_ gst_ Gstreamerpipeline 'error resolution
SuperMap iDesktop 常见倾斜数据处理全流程解析
[QNX Hypervisor 2.2用户手册]6.2.3 Guest与外部之间通信
海思3559万能平台搭建:YUV格式简介
问卷星问卷抓包分析