使用内存池来优化X264编码

     在win上使用ffmpeg调用X264编码4K的视频,突然发现每一帧内存的释放比较耗时(在linux上测试了发现并没有耗时,原因linux释放使用的是free函数,win上使用的是_aligned_free函数)。个人觉得是4K需要的内存很大(3840*2160*4+64),然后使用AVCIntraClass300的配置编码速度又很快,从而突出了内存释放的时间。

一、调用流程

从整个ffmpeg流程可以发现,最后进行释放的内存就是一开始输入线程申请的内存(通常解码会重新申请内存?在当前配置并没有发现重新申请内存)因此可以通过内存池来优化内存的释放,重复利用内存块,最终编码结束的时候才对内存进行释放。

二、内存池原理

初始化阶段:在程序启动时,内存池会申请一块连续的大块内存空间。

分配阶段:当程序需要申请内存时,内存池会从已经分配好的空闲块中找到合适大小的小块来分配给程序。

释放阶段:当程序不再需要某个内存块时,可以将其返回给内存池进行复用。

扩展阶段:如果当前内存池中没有足够的可用空间了,可以根据需要扩展内存池的大小。

三、ffmpeg应用

一般内存需要队列结构,但是应用的时候可以简化内存池,甚至只是使用内存池的思想而已。

1.最开始初始化内存池,申请空间

申请大小为size的POOL_SIZE块内存,size就是3840*2160*4+64(输入大小),POOL_SIZE理论上是越小越好,但是要保证不小于线程数,不然会多个线程同时用到同一块?

void initializeMemoryPool( size_t size) {
    memoryPool.myfront = 0;
    memoryPool.myrear = POOL_SIZE - 1;
    for (int i = 0; i < POOL_SIZE; i++) {
        memoryPool.data[i] = _aligned_malloc(size,64);
        if (memoryPool.data[i] == NULL)
            printf("内存池内存分配失败\n");
    }
}

2.输入线程申请内存,直接从内存池拿。

其实很简单,就是取指针,然后下标后移。

void* allocateMemory(MemoryPool* memoryPool) {
    ff_mutex_lock(&(memoryPool->myMutex)); 
    void* buffer = memoryPool->data[memoryPool->myfront];
    memoryPool->myfront = (memoryPool->myfront + 1) % POOL_SIZE;
    ff_mutex_unlock(&(memoryPool->myMutex)); 
    return buffer;
}

3.每帧释放内存时改为指针指空NULL即可

这里进行了简化,其实严格来说并不算内存池,因为ffmpeg里的内存里即使存在其他帧的数据,覆盖就可以了。所以直接不释放这块内存让它重复使用也行,只要最后我们申请的内存可以找到地方进行释放就行。

4.程序结束时,释放内存池里的所有内存

void destroyMemoryPool() {
    for (int i = 0; i <POOL_SIZE; i++) {
            _aligned_free(memoryPool.data[i]);
    }
    memoryPool.myfront = 0;
    memoryPool.myrear = 0;
}

这样子算下来,假如编码1000帧4K视频,池子大小设为50。优化前需要释放1000次,优化后就只要释放50次了。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值