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

ffmpeg内存模型

在这里插入图片描述## AVPacket和AVFrame内存模型

从现有的Packet拷贝到一个新Packet的时候,有两种情况:

  1. 两个Packet的buf引用的是同一个数据缓存空间,这时候就要注意数据缓存空间的释放问题;

  2. 两个Packet的buf是引用的不同的数据缓存空间,每个Packet都有数据缓存空间的copy;

第一种方式可以理解为引用计数,有多个对象对一段内存进行操作。

在这里插入图片描述

第二个就是两个对象有各自的数据域,不会互相影响。

在这里插入图片描述

数据域对象AVBuffer中是有引用计数相关的成员的,UML如下:

在这里插入图片描述

对于多个AVPacket共享同一个缓存空间,FFmpeg使用的引用计数的机制:

  • 初始化引用计数为0,只有真正分配AVBuffer的时候,引用计数初始化为1;
  • 当有新的Packet引用共享的缓存空间的时候,就将引用计数+1;
  • 当释放了引用共享空间的Packet,就将引用计数-1;引用计数为0时,就释放了引用的缓存空间AVBuffer。

AVFrame也是使用相同的机制。

AVPacket常用API

在这里插入图片描述

AVFrame常用API

在这里插入图片描述## 测试代码

#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <stdio.h>#define MEM_ITEM_SIZE (1024*20*102)
#define AVPACKET_LOOP_COUNT 1000void av_packet_test1() {AVPacket* pkt = NULL;int ret = 0;pkt = av_packet_alloc();ret = av_new_packet(pkt, MEM_ITEM_SIZE);memccpy(pkt->data, (void*)&av_packet_test1, 1, MEM_ITEM_SIZE);av_packet_unref(pkt); // 不需要这一步,av_packet_free中会调用av_packet_unrefav_packet_free(pkt);
}void av_packet_test2() {AVPacket* pkt = NULL;int ret = 0;pkt = av_packet_alloc();ret = av_new_packet(pkt, MEM_ITEM_SIZE);memccpy(pkt->data, (void*)&av_packet_test1, 1, MEM_ITEM_SIZE);// av_init_packet(pkt); // 只会初始化结构体,不会分配内存,将data=NULL,但是size!=0,不会被判断为空包av_packet_free(pkt); // 会释放data的内存,如果data没有被分配,则会导致内存泄漏
}void av_packet_test3() {AVPacket* pktsrc = NULL;AVPacket* pktdst = NULL;int ret = 0;pktsrc = av_packet_alloc();ret = av_new_packet(pktsrc, MEM_ITEM_SIZE);memccpy(pktsrc->data, (void*)av_packet_test1, 1, MEM_ITEM_SIZE);pktdst = av_packet_alloc();av_packet_move_ref(pktdst, pktsrc); // 执行完后pktsrc会变成空包,即data为NULL,size=0av_init_packet(pktsrc); // 没有必要执行这一步,因为av_packet_move_ref中会执行av_init_packet,av_packet_free(pktsrc); // 由于data=NULL size=0 所以判断是空包,只会释放结构体,不会释放dataav_packet_free(pktdst);
}void av_packet_test4()
{AVPacket *pkt = NULL;// av_packet_alloc()没有必要,因为av_packet_clone内部有调用 av_packet_allocAVPacket *pkt2 = NULL;int ret = 0;pkt = av_packet_alloc();ret = av_new_packet(pkt, MEM_ITEM_SIZE);memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);pkt2 = av_packet_clone(pkt); // av_packet_alloc()+av_packet_ref()av_init_packet(pkt);av_packet_free(&pkt);av_packet_free(&pkt2);
}void av_packet_test5()
{AVPacket *pkt = NULL;AVPacket *pkt2 = NULL;int ret = 0;pkt = av_packet_alloc(); //if(pkt->buf)        // 打印referenc-counted,必须保证传入的是有效指针{    printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,av_buffer_get_ref_count(pkt->buf));}ret = av_new_packet(pkt, MEM_ITEM_SIZE);if(pkt->buf)        // 打印referenc-counted,必须保证传入的是有效指针{    printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,av_buffer_get_ref_count(pkt->buf));}memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);pkt2 = av_packet_alloc();   // 必须先allocav_packet_move_ref(pkt2, pkt); // av_packet_move_ref
//    av_init_packet(pkt);  //av_packet_move_refav_packet_ref(pkt, pkt2);av_packet_ref(pkt, pkt2);     // 多次ref如果没有对应多次unref将会内存泄漏if(pkt->buf)        // 打印referenc-counted,必须保证传入的是有效指针{    printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,av_buffer_get_ref_count(pkt->buf));}if(pkt2->buf)        // 打印referenc-counted,必须保证传入的是有效指针{    printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,av_buffer_get_ref_count(pkt2->buf));}av_packet_unref(pkt);   // 将为2av_packet_unref(pkt);   // 做第二次是没有用的if(pkt->buf)printf("pkt->buf没有被置NULL\n");elseprintf("pkt->buf已经被置NULL\n");if(pkt2->buf)        // 打印referenc-counted,必须保证传入的是有效指针{    printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,av_buffer_get_ref_count(pkt2->buf));}av_packet_unref(pkt2);av_packet_free(&pkt);av_packet_free(&pkt2);
}int main() {// av_packet_test1();// av_packet_test2();// av_packet_test3();av_packet_test5();return 0;
}

参考资料:https://github.com/0voice


文章转载自:

http://iaVvftj7.qrhng.cn
http://VXYa6jpV.qrhng.cn
http://UQB9Z7F2.qrhng.cn
http://IFNg4XM9.qrhng.cn
http://fc6gVA5Y.qrhng.cn
http://6rn54c77.qrhng.cn
http://7aUbSVmH.qrhng.cn
http://i9tWJAeD.qrhng.cn
http://rqETfA8l.qrhng.cn
http://vS0rpcy6.qrhng.cn
http://GXsCF6Zh.qrhng.cn
http://tjheqAMO.qrhng.cn
http://LJ90zMyz.qrhng.cn
http://a8jTv06F.qrhng.cn
http://aebFY9Hg.qrhng.cn
http://ZzxGFYAV.qrhng.cn
http://zUGqtnJb.qrhng.cn
http://ZehuXWQB.qrhng.cn
http://c4iAjW6w.qrhng.cn
http://IL6hSfTd.qrhng.cn
http://hnkT9u5D.qrhng.cn
http://8MVJx7l6.qrhng.cn
http://PHfMWxpX.qrhng.cn
http://3qpiT7Tk.qrhng.cn
http://uEu9r8KK.qrhng.cn
http://sFkdmbrS.qrhng.cn
http://AtwXiWK5.qrhng.cn
http://JbLt0anS.qrhng.cn
http://ZF3ORHtW.qrhng.cn
http://TNimj08j.qrhng.cn
http://www.dtcms.com/a/376407.html

相关文章:

  • Android面试指南(八)
  • 不止是进度条:深入PiXSingleGUI的TpSlideProgressBar组件架构设计​
  • Flutter 视频播放器——flick_video_player 介绍与使用
  • 【Java】Hibernate管理Session
  • 【ARMv7】系统复位上电后的程序执行过程
  • Ubuntu引导修复
  • PetaLinux_User_udev
  • 《链表的优雅封装:C++ list 模拟实现与迭代器之美》
  • 基于Redis设计一个高可用的缓存
  • 看涨看跌期权平价公式原理及其拓展
  • Django 基础入门:命令、结构与核心配置全解析
  • 中断系统介绍
  • 算法题 Day5---String类(2)
  • 关于Linux系统调试和性能优化技巧有哪些?
  • 大数据电商流量分析项目实战:Hadoop初认识+ HA环境搭建(二)
  • 软考中级习题与解答——第四章_软件工程(2)
  • AutoTrack-IR-DR200底盘仿真详解:为教育领域打造的高效机器人学习实验平台
  • 介绍 Python Elasticsearch Client 的 ES|QL 查询构建器
  • LeetCode 234. 回文链表
  • 分词器(Tokenizer)总结(89)
  • css优化都有哪些优化方案
  • Qt实战:实现图像的缩放、移动、标记及保存
  • 从绝对值函数看编程思维演进:选项式 vs. 组合式
  • 内网环境下ubuntu 20.04搭建深度学习环境总结
  • 【SQL注入】延时盲注
  • 解决React中通过外部引入的css/scss/less文件更改antDesign中Modal组件内部的样式不生效问题
  • 0-1 VS中的git基本操作
  • 组件库打包工具选型(npm/pnpm/yarn)的区别和技术考量
  • 前端学习之后端java小白(三)-sql外链一对多
  • 学习triton-第1课 向量加法