一个偶现的MP4录制问题解决过程记录
2022/2/24 23:56:23
本文主要是介绍一个偶现的MP4录制问题解决过程记录,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 解决思路
- 1. 定位MP4中哪块数据出现问题
- a. 查看adb错误日志
- b. 定位AOSP报错的源码位置
- c. 用gdb打印MP4中的hvcc
- d. 根据ISO/IEC 14496-15文档,阅读hvcc
- 2. 在代码中定位问题
- 总结
前言
LG发现了一个偶现的录制问题,为了上线必须解决。这里记录一下问题解决的过程。
问题的现象是这样的,偶然出现录制的视频会出现无法播放的问题,而且那个视频有些手机能播,有些不能播,很诡异。
解决思路
由于使用的是MediaPlayer播放出现问题,正好在我自己编译的Pixel 3(Android 11)上也无法播放,那就在上面调试查看出错的地方吧。找到报错的地方后,就可以定位到是解析MP4文件中具体哪块数据的时候出现的问题。然后再去看生成这块数据的代码,阅读理解相关逻辑,看看哪里出错了。暂时就想到这,开始行动。
1. 定位MP4中哪块数据出现问题
由于MP4数据还是很多的,要一个个排查不现实。所以就根据报错的日志来定位问题。
a. 查看adb错误日志
$ adb logcat *:E 02-24 17:59:30.569 352 352 E Utils : did not find width and/or height 02-24 17:59:30.570 352 352 E Utils : did not find width and/or height 02-24 17:59:30.583 354 1906 E Utils : b/23680780 02-24 17:59:30.584 1878 1896 E MediaPlayerNative: error (1, -22) 02-24 17:59:30.634 1878 1878 E MediaPlayer: Error (1,-22)
发现错误出现在 E Utils : b/23680780
根据进程号354,发现是mediaserver进程
$ adb shell ps | grep 354 media 354 1 93744 26112 binder_thread_read 0 S mediaserver
b. 定位AOSP报错的源码位置
通过在AOSP源码搜索b/23680780
定位到源文件位置在/home/kevin/ExtraSpace/aosp/frameworks/av/media/libstagefright/Utils.cpp
这里面有好几处都打印了这个日志,那就没什么好说的,把全部都设置上断点
然后调试。点击播放有问题的MP4,发现断点停在解析hvcc的地方
c. 用gdb打印MP4中的hvcc
其实不用gdb打印,也可以通过MP4分析工具查看,只是我这里在调试,所以就直接用gdb输出了。至于MP4分析工具还是用挺多,我这里讲一下Linux上。推荐使用MediaParser,这个原来的在qt6上编译有问题,我修复了。需要的话自己下载编译就行了。
好了回归正题。为了后续方便,这里称呼:
good表示正常的mp4的hvcc,bad表示有问题的mp4的hvcc
将两个打印出来,方便后续对比。
(gdb) x/110x data
good hvcC 0xee100380: 0x01 0x01 0x40 0x00 0x00 0x00 0x80 0x00 0xee100388: 0x00 0x00 0x00 0x00 0x7b 0xf0 0x00 0xfc (numOfArrays==3) 0xee100390: 0xfd 0xf8 0xf8 0x00 0x00 0x0f 0x03 0x20 0xee100398: 0x00 0x01 0x00 0x17 0x40 0x01 0x0c 0x01 bad hvcC 0xea580e10: 0x01 0x00 0x01 0x03 0x00 0x00 0x00 0x18 0xea580e18: 0x00 0x10 0x00 0x00 0x2d 0x00 0x00 0x00 (numOfArrays==255溢出) 0xea580e20: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x20 0xea580e28: 0x00 0x01 0x00 0x18 0x40 0x01 0x0c 0x01 bad2 hvcC(这是后面又复现的有问题的MP4文件) 0xe6d40c10: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xe6d40c18: 0x00 0x00 0x00 0x00 0x00 0x49 0x00 0xe7 (numOfArrays==0) 0xe6d40c20: 0xff 0xa4 0x00 0x00 0x00 0x00 0x00 0x20 0xe6d40c28: 0x00 0x01 0x00 0x18 0x40 0x01 0x0c 0x01
d. 根据ISO/IEC 14496-15文档,阅读hvcc
这里面对比发现bad.mp4的hvcc的确有问题。
这是ISO文档中对应的数据组成
aligned(8) class HEVCDecoderConfigurationRecord { unsigned int(8) configurationVersion = 1; //1 byte (第2个byte) unsigned int(2) general_profile_space; unsigned int(1) general_tier_flag; unsigned int(5) general_profile_idc; //4 bytes (第3~6个byte) unsigned int(32) general_profile_compatibility_flags; //6 byte (第7~12个byte) unsigned int(48) general_constraint_indicator_flags; //(第13个byte) unsigned int(8) general_level_idc; //(第14~15个byte) bit(4) reserved = ‘1111’b; unsigned int(12) min_spatial_segmentation_idc; //(第16个byte) bit(6) reserved = ‘111111’b; unsigned int(2) parallelismType; //(第17个byte) bit(6) reserved = ‘111111’b; unsigned int(2) chroISO/IEC 23008-2 ma_format_idc; //(第18个byte) bit(5) reserved = ‘11111’b; unsigned int(3) bit_depth_luma_minus8; //(第19个byte) bit(5) reserved = ‘11111’b; unsigned int(3) bit_depth_chroma_minus8; //(第20~21个byte) bit(16) avgFrameRate; //(第22个byte) bit(2) constantFrameRate; bit(3) numTemporalLayers; bit(1) temporalIdNested; unsigned int(2) lengthSizeMinusOne; //(第23个byte) unsigned int(8) numOfArrays; for (j=0; j < numOfArrays; j++) { //1个byte bit(1) array_completeness; unsigned int(1) reserved = 0; unsigned int(6) NAL_unit_type; //2个byte unsigned int(16) numNalus; for (i=0; i< numNalus; i++) { //2个byte unsigned int(16) nalUnitLength; bit(8*nalUnitLength) nalUnit; } } }
根据ISO文档,解析hvcc数据,发现bad在[general_profile_space, numOfArrays]之间是不正常的。
numOfArrays应该是3(vps,sps,pps,一共3个)
good 0xee101350: 0x01 0x01 0x40 0x00 0x00 0x00 0x80 0x00 0xee101358: 0x00 0x00 0x00 0x00 0x7b 0xf0 0x00 0xfc (numOfArrays)(32,vps) 0xee101360: 0xfd 0xf8 0xf8 0x00 0x00 0x0f 0x03 0x20 (numNalus == 1) (nalUnitLength==23)(nalUnit 0xee101368: 0x00 0x01 0x00 0x17 0x40 0x01 0x0c 0x01 0xee101370: 0xff 0xff 0x01 0x40 0x00 0x00 0x03 0x00 0xee101378: 0x80 0x00 0x00 0x03 0x00 0x00 0x03 0x00 )(33,sps) (numNalus == 1)(nalUnitLength==33) 0xee101380: 0x7b 0xac 0x09 0x21 0x00 0x01 0x00 0x21 (nalUnit 0xee101388: 0x42 0x01 0x01 0x01 0x40 0x00 0x00 0x03 0xee101390: 0x00 0x80 0x00 0x00 0x03 0x00 0x00 0x03 0xee101398: 0x00 0x7b 0xa0 0x02 0x80 0x80 0x2d 0x16 0xee1013a0: 0x5a 0xe4 0xb2 0xb6 0x6b 0x95 0x44 0xd8 ) (34,pps)(numNalus == 1)(nalUnitLength==8)(nalUnit 0xee1013a8: 0x02 0x22 0x00 0x01 0x00 0x3d 0x44 0x01 ) 0xee1013b0: 0xc0 0xe3 0x0f 0x03 0x32 0x40 bad (不正常的数据 0xea580a90: 0x01 0x00 0x01 0x03 0x00 0x00 0x00 0x18 0xea580a98: 0x00 0x10 0x00 0x00 0x2d 0x00 0x00 0x00 (numOfArrays))(32,vps) 0xea580aa0: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x20 (numNalus==1)(nalUnitLength==24)(nalUnit 0xea580aa8: 0x00 0x01 0x00 0x18 0x40 0x01 0x0c 0x01 0xea580ab0: 0xff 0xff 0x01 0x60 0x00 0x00 0x03 0x00 0xea580ab8: 0x00 0x03 0x00 0x00 0x03 0x00 0x00 0x03 ) (33,sps)(numNalus == 1)(nalUnitLength==41 0xea580ac0: 0x00 0x96 0xac 0x09 0x21 0x00 0x01 0x00 ) (nalUnit 0xea580ac8: 0x29 0x42 0x01 0x01 0x01 0x60 0x00 0x00 0xea580ad0: 0x03 0x00 0x00 0x03 0x00 0x00 0x03 0x00 0xea580ad8: 0x00 0x03 0x00 0x96 0xa0 0x05 0x02 0x01 0xea580ae0: 0x69 0x63 0x6b 0x92 0x4c 0x9a 0xe5 0x9c 0xea580ae8: 0x02 0x00 0x00 0x07 0xd2 0x00 0x00 0x9c ) (34,pps) (numNalus==1)(nalUnitLength==7)(nalUnit 0xea580af0: 0x68 0x10 0x22 0x00 0x01 0x00 0x07 0x44 ) 0xea580af8: 0x01 0xe0 0x76 0xb0 0x26 0x40
2. 在代码中定位问题
定位代码问题还是花了不少时间。具体源码分析这里就不展开了,参考意义不大。过程概括起来就以下这些步骤
-
阅读相关代码,理解numOfArrays是如何生成并写入到MP4中的,发现这块并没有什么问题
-
怀疑是数据问题。让测试复现,拿到原始数据,发现生成的MP4可以播放。(测试用了差不多2天才复现,辛苦了)
-
怀疑是内存相关的错误。(刚开始没想到这个,后来边阅读源码边思考,终于想到了可能是这个问题)
- 读取未初始化过的变量
- 野指针/悬垂指针读写
- 错误的指针类型转换
- 从已分配内存块的尾部进行读/写(数组等类型读写越界)
- 不匹配地使用 malloc/new/new[] 和 free/delete/delete[]
- 等等
-
于是先尝试使用valgrind做检查,发现读取未初始化过的变量,并且这块就是hvcc生成赋值的地方!!!
上面的圈起来的变量和另外一个变量(没截图),没有初始化。(其实这里圈起来的最后一个变量错了,但是不是问题的原因)
-
应该就是这里了,但是是什么样的值才会导致问题呢?仔细阅读了代码,并测试验证后。确定是uint8 m_spsCount = 255(0xff)的时候会出现问题
总结
花时间比较多,原因还是因为没能第一时间想到可能是读取未初始化变量的问题,经验不足导致。不过后面排查完其它错误之后终于发现了真正的错误原因。
通过这个问题的解决,并结合以往解决偶现问题的经验。偶现的问题,要么就是某些特殊输入导致,要么就是进程在偶现问题的那个时刻的状态(也就是依赖的相关变量)有问题,导致程序并没按照看起来的那样执行。
总的来说遇到问题,不断的排除可能的原因,那离真正的原因就不远了。
这篇关于一个偶现的MP4录制问题解决过程记录的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15鸿蒙生态设备数量超8亿台
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?