背景

  • 基于ffmpeg实现录像功能,性能不理想,前后路摄像头视频码率相加只有28Mbps加上音频也只有4MB/s左右,使用class 10的sd卡 + 2秒 ringbuffer缓存的情况下,依然出现写卡不及时导致的丢帧现象,class 4 sd卡表现更差。

分析

  • 使用dd命令测试class 10 SD卡在该平台上的读写速度,写速度能达到7~8MB/s,因此丢帧问题不是SD卡写性能不足导致的,是录像逻辑的问题。
  • 通过测试定位到ffmpeg接口av_write_frame(写一帧数据)耗时异常,异常部分log如下:
01-01 00:01:13.064   139   310 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE/2022_01_01_000059_00.MOV]: av_write_frame take [19] ms
01-01 00:01:13.067   139   313 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/2022_01_01_000059_00_b.MOV]: av_write_frame take [23] ms
01-01 00:01:13.170   139   313 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/2022_01_01_000059_00_b.MOV]: av_write_frame take [102] ms
01-01 00:01:13.185   139   310 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE/2022_01_01_000059_00.MOV]: av_write_frame take [119] ms
01-01 00:01:13.187   139   313 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/2022_01_01_000059_00_b.MOV]: av_write_frame take [16] ms
01-01 00:01:13.190   139   310 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE/2022_01_01_000059_00.MOV]: av_write_frame take [4] ms
01-01 00:01:13.194   139   313 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/2022_01_01_000059_00_b.MOV]: av_write_frame take [6] ms
....
01-01 00:18:57.202   139   479 I write_packet@CviMuxer.cpp:577 [/mnt/sd/CARDV/MOVIE_b/2022_01_01_001833_00_b.MOV]: av_write_frame take [2249] ms
  • 异常现象总结
  1. av_write_frame耗时不稳定,普遍耗时几毫秒,和预期缓存未满时写缓存(内存拷贝)耗时较少不符。
  2. 间隔性出现耗时100ms以上,时常出现200、300,甚至500ms以上,偶尔出现耗时1s ~ 2s,一帧I帧视频数据才100KB~200KB,耗时完全不符合预期。

ffmpeg 实现

  • ffmpeg录像写文件操作的代码(libavformat/file.c)是调用的open,write,read,seek等系统接口,使用open接口打开文件是没有应用层缓存,因此需要ffmpeg自己实现缓存机制,在file_open中可以设置URLContext 的min_packet_size和max_packet_size来定义缓存大小,代码(libavformat/aviobuf.c)会根据定义的缓存大小申请内存创建缓存,av_write_frame时会先将数据写入该缓存,缓存满了或者主动调用avio_flush接口会调用write接口将缓存数据传递给linux内核。

文件缓存

  • 定义一定大小的文件缓存可以减少系统接口write的调用频率,以及内存拷贝的次数,以提高性能。
  1. 缓存大小需要是内存页,文件系统块(Block),文件系统IO操作块(IO Block)大小的整倍数,以避免跨页操作
  • 系统读写SD卡都是以块为单位,而不是一个字节一个字节的读写,因此缓存大小如果出现不满一块的余量,系统也要将一整块写入sd卡,并且为了保证存储数据的正确性,系统需要先从sd卡读取出该块中缓存未覆盖到的数据,补充到写入数据中,浪费了一定的性能。
  • 不同文件系统或者同一个文件系统,不同SD卡的IO Block也可能不同,需要注意:
[root]/mnt/usb# stat xxx File: xxxSize: 49           Blocks: 128        IO Block: 65536  regular file
...
[root]/mnt/usb# stat b.txt File: b.txtSize: 6           Blocks: 64         IO Block: 32768  regular file
...
# stat testfile              File: `testfile'Size: 102             Blocks: 8          IO Block: 4096   regular file
...
  1. 缓存大小需要根据实际情况进行调整
  • 同步IO情况下,缓存大小也会造成一定的性能影响,需要参考数据量,写文件间隔等因素,例如:视频25fps,写文件间隔40ms,缓存的数据最好保证在40ms内传递给linux内核,耗时多了会阻塞下一帧,一些嵌入式平台会影响帧率,耗时少了会增加write的调用次数。

异常原因

  • 现有代码设置了的ffmpeg缓存大小为32KB,理论上不应该出现问题。
  • 分析自有代码和ffmpeg源码可知上面的异常现象中的间隔性耗时过长应该是缓存满了调用write导致的,av_write_frame普遍耗时几毫秒以及偶发性耗时过长是录像逻辑破坏了缓存机制出现。
  • 缓存机制被破坏
  1. 为满足其它功能,我们修改了ffmpeg源码,在一些条件下会做seek和write操作,这种情况下就会导致缓存机制被破坏。
  2. MOV,MP4文件有固定的头部数据 ftyp 和wide box 再加上mdat box 的HEAD一共36个字节,ffmpeg写完这部分数据后会主动调用avio_flush 先将这部分数据写入SD卡,后续再按缓存大小写数据,虽然写的数据大小是满足块的整倍数,但是已经发生错位和跨页。
源码:libavformat/movenc.c
@@ -6744,7 +6744,7 @@ static int mov_write_header(AVFormatContext *s)}}....avio_flush(pb); //需要注释掉if (mov->flags & FF_MOV_FLAG_ISML)mov_write_isml_manifest(pb, mov, s);...

修复结果

  • 修复完后测试结果
01-01 08:03:54.641   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [4] ms
01-01 08:03:54.641   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.641   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.641   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.641   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.642   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.642   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.642   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.644   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [1] ms
01-01 08:03:54.644   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.644   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.644   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
01-01 08:03:54.644   139   329 I write_packet@CviMuxer.cpp:575 [/mnt/sd/CARDV/MOVIE_b/1970_01_01_080317_00_b.MOV]: av_write_frame take [0] ms
  • 大部分情况下av_write_frame耗时1ms以下,缓存满时耗时会稍微多点,最高时也不超过20ms。

行车记录仪 - 录像 - 文件缓存相关推荐

  1. 行车记录仪视频文件损坏如何修复

    行车记录仪是日常行车过程中必备的一个设备.使用过程中难免出现录像文件损坏.丢失等等故障.这里小编针对该问题准备了以下几种方法: 格式化SD卡,但是记得在格式化前备份视频数据. 重启机器 清空SD卡里面 ...

  2. php数据库缓存类,常见php数据文件缓存类汇总

    本文实例汇总了常见php数据文件缓存类.分享给大家供大家参考.具体分析如下: 数据文件缓存的做法我们常用的有php文件缓存与利用memcache来缓存数据,下面面我分别总结了memcache缓存数据与 ...

  3. 使用ReaderWriterLock优化文件缓存

        公司使用的文件缓存经常出现大量的并发冲突,主要原因有两个:一个是读取文件时刚好文件被删除了,这样会抛出找不到文件的异常: 另一个是资源权限争抢的问题,可能会导致没有权限操作的情况.     R ...

  4. android 内部存储 清空,Android清空应用内部文件缓存

    Android应用中加载的图片以及一些数据缓存怎么清掉呢?最近在做项目中遇到了这个问题,网上搜了一下找到了不少的源代码,综合了这些源码,下面给大家说一下吧,怎么有效的清除应用内存的缓存信息? 清除应用 ...

  5. 缓存处理类(MemoryCache结合文件缓存)

    想提升站点的性能,于是增加了缓存,但是站点不会太大,于是不会到分布式memcached的缓存和redis这个nosql库,于是自己封装了.NET内置的缓存组件 原先使用System.Web.Cachi ...

  6. android文件缓存,并SD卡创建目录未能解决和bitmap内存溢出解决

    1.相关代码: 加入权限: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" ...

  7. linux 更改ctime_Linux 的文件系统及文件缓存知识点整理

    Linux的文件系统特点 文件系统要有严格的组织形式,使得文件能够以块为单位进行存储. 文件系统中也要有索引区,用来方便查找一个文件分成的多个块都存放在了什么位置. 如果文件系统中有的文件是热点文件, ...

  8. 不错php文件缓存类,一个不错的PHP文件页面缓存类

    [导读]在php中缓存分类数据库缓存,文件缓存和内存缓存,下面我来给各位同学详细介绍PHP文件缓存类实现代码,有需要了解的朋友可参考.页面缓存类 代码如下复制代码 在 缓存分类数据库缓存,文件缓存和内 ...

  9. PHP Memcached + APC + 文件缓存封装

    使用方法: Memcached $cache = new Cache_MemCache(); $cache->addServer('www1'); $cache->addServer('w ...

最新文章

  1. 0基础学python难吗-零基础入门学习Python技术难不难?
  2. Nginx-04:Nginx配置实例之反向代理1
  3. 垃圾收集器–串行,并行,CMS,G1(以及Java 8中的新增功能)
  4. 面试中遇到回答不上来的问题可以这样做
  5. Web前端笔记-移动端触屏移动视角(two.js)
  6. deinstall oracle 11g on linux
  7. 最全面的理解 | 工业互联网的前世今生
  8. Android tombstone文件是如何生成的
  9. MATLAB绘制微分方程的相图/方向场/向量场
  10. 万字讲述如何通过Doris构建数据中台
  11. python3爬虫系列21之selenium自动化登录163邮箱并读取未读邮件内容
  12. A slap on the back 祝贺一下
  13. 在word中添加mendeley插件
  14. 领导拒绝涨薪?我直接跳槽,涨薪6k
  15. 计算机网络-面试题汇总
  16. Flask Web开发入门(一)之简单的登录验证
  17. Oracle 数据库登录详解
  18. Thirteenth
  19. unset 函数php,PHP unset()函数
  20. 星图html5,首页|星图注册|首页

热门文章

  1. Python+获取字典中某一个键的值
  2. 想嫁有钱人,金融家的回复令人拍案叫绝
  3. matlab计算光纤有效折射率,使用matlab计算长周期光纤光栅的有效折射率
  4. 11-1-败者树-外部排序-第11章-《数据结构》课本源码-严蔚敏吴伟民版
  5. 什么是性格冲动?如何改变爱冲动的性格?
  6. 2019年互联网高频Java面试题指南!互联网升职加薪方案!
  7. office套件_OfficeSuite Premium 免费专业Office办公套件
  8. Mac新手必备----MacOS系统常用软件
  9. 遗传算法 求解物流配送中心选址问题 免疫算法物流配送中心选址
  10. Amlogic Linux系列(二)新增测试驱动