• FFMpeg AVBufferPool 的理解与掌握


    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

    付测试代码:

    1. #include <QCoreApplication>
    2. #include <iostream>
    3. #include <iomanip>
    4. extern "C"
    5. {
    6. #include <libavcodec/avcodec.h>
    7. #include <libavformat/avformat.h>
    8. #include <libswscale/swscale.h>
    9. #include <libswresample/swresample.h>
    10. #include <libavutil/replaygain.h>
    11. #include <libavutil/pixdesc.h>
    12. }
    13. using namespace std;
    14. /*
    15. 1. av_buffer_pool_init
    16. 初始化 内存池
    17. 2 av_buffer_pool_get
    18. 从内存池中获取buffer
    19. 3.av_buffer_pool_uninit
    20. 释放内存池
    21. 4.pool_release_buffer
    22. 回收buffer
    23. */
    24. const int testAVBufferPoolLoopCount = 3; // 通过修改循环次数来测试是否有内存的泄漏
    25. void testAVBufferPool()
    26. {
    27. std::cout << "\n\n--------------- Test testAVBufferPool into -------------" << std::endl;
    28. AVBufferPool *avBufferPool;
    29. AVBufferRef *avBufferRefT;
    30. AVBufferRef *avBufferRef0;
    31. AVBufferRef *avBufferRef1;
    32. AVBufferRef *avBufferRef2;
    33. for(int i = 0; i < testAVBufferPoolLoopCount; i++)
    34. {
    35. avBufferPool = av_buffer_pool_init(1*1024*1024, nullptr);
    36. avBufferRef0 = av_buffer_pool_get(avBufferPool);
    37. std::cout <<"avBufferRef0-hex:" << hex << avBufferRef0 <<std::endl;
    38. std::cout << "avBufferRef0 size = " <<dec << avBufferRef0->size << std::endl;
    39. //memcpy(avBufferRefT, avBufferRef0, sizeof(*avBufferRefT));
    40. avBufferRefT = avBufferRef0;
    41. av_buffer_unref(&avBufferRef0); // 释放 avBufferRef0
    42. std::cout << "avBufferRefT size = " <<dec << avBufferRefT->size << std::endl;
    43. avBufferRef1 = av_buffer_pool_get(avBufferPool);
    44. avBufferRef2 = av_buffer_pool_get(avBufferPool);
    45. std::cout <<"AVBufferPool" << std::endl;
    46. std::cout <<"avBufferRef0-hex:" << hex << avBufferRef0 <<std::endl;
    47. std::cout <<"avBufferRefT-hex:" << hex << avBufferRefT <<std::endl;
    48. std::cout <<"avBufferRef1-hex:" << hex << avBufferRef1 <<std::endl; // 这里可以看到打印和avBufferRef0未释放时是一样的,说明线程池内部有回收机制
    49. std::cout <<"avBufferRef2-hex:" << hex << avBufferRef2 <<std::endl;
    50. if(avBufferRef0)
    51. std::cout << "av_buffer_get_ref_count(avBufferRef0) = " << av_buffer_get_ref_count(avBufferRef0) << std::endl;
    52. if(avBufferRef1)
    53. std::cout << "av_buffer_get_ref_count(avBufferRef1) = " << av_buffer_get_ref_count(avBufferRef1) << std::endl;
    54. avBufferRef0 = av_buffer_pool_get(avBufferPool);
    55. av_buffer_pool_uninit(&avBufferPool);
    56. av_buffer_unref(&avBufferRef0); // 通过注释该部分来测试是否有内存的泄漏
    57. av_buffer_unref(&avBufferRef1);
    58. av_buffer_unref(&avBufferRef2);
    59. }
    60. std::cout << "\n--------------- Test testAVBufferPool leave -------------" << std::endl;
    61. }
    62. int main()
    63. {
    64. testAVBufferPool();
    65. return 0;
    66. }

  • 相关阅读:
    java面试题2019_java面试题及答案_java面试题库
    爬虫笔记15——爬取网页数据并使用redis数据库set类型去重存入,以爬取芒果踢V为例
    多家饮料企业进入暖饮市场,APS智能排产在饮料行业的应用
    .net6+aspose.words导出word并转pdf
    Kotlin | 在for、forEach循环中正确的使用break、continue
    Aviator表达式引擎
    后端配置跨域怎么配置
    Kafka、RocketMQ、RabbitMQ的比较总结Kafka、RocketMQ、RabbitMQ的比较总结
    算法-1.两数之和
    基于人工神经网络的车牌识别系统的研究(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/hejinjing_tom_com/article/details/125495832