Android MediaCodec踩坑笔记
关于编解码,FFMpeg不香吗,为什么要吊死在Android的MediaCodec上?对于这个问题,我也很无奈,FFMpeg很香,但是因为包体积、效率等问题引发的工作业务的需要,使我不得不在Android MediaCodec的摧残下苟且偷生。MediaCodec的api比较简单,用来写demo毫无难度,让人痛不欲生的是它的兼容性问题。使用MediaCodec遇到的问题,往往都是和机型、版本、某类媒体文件相关的问题。从开始使用MediaCodec到现在,遇到了许多问题,很多解决了后过了许久又忘记了,这篇博客作为一个记录,也为后来不得不趟坑的人提供一点点经验吧。
编码器或者解码器Config时候崩溃
这个问题对于MediaCodec的使用者来说应该是一个比较普遍的问题了,在MediaCodec进行config崩溃,往往会给出具体的崩溃信息,比较常见的是格式不支持,最多的是宽高不支持或者编解码器数量限制。
一个手机能够解码或者编码视频能力是有限的,在手机的/etc/media_codec.xml中是有说明的,比如使用一个15年左右的低端机型去解码1080p的视频,大概率会失败。当然,时代发展,限制的低端机型也大多支持1080p,那不妨解码4k视频试试。
另外,在现在的一些能够支持1080p解码的机型上,使用MediaCodec同时解码两路1080p视频也会出现config失败的问题,比如SM-J250f、SM-J700f等手机。这种情况,就只能避免这么使用了,引入软解,或者把1080p视频先转成小视频等。
解码视频,渲染出来的图像异常
这个一般是新手可能会遇到的问题,不是MediaCodec的问题,而是使用者的问题。有时候为了加速解码或者是其他的原因,使用者在进行解码的时候,会对一些帧进行丢弃,但是如果丢弃后,解码帧不是从关键帧开始的话,到下一个关键帧之前,解码出来的图像,都会是花屏的图像。所以需要做的就是要保证每次解码的流程开始时,塞入给解码的数据要从关键帧开始,并且不要随意丢输入帧。否则不会只有MediaCodec解码会花屏,FFMpeg同样无解。
在使用MediaCodec解码到ByteBuffer中,然后拿出来渲染,没有丢帧也有可能会遇到这个问题。这种情况下一般也不是解码器的问题,而是渲染的问题,比如stride和width不匹配,在渲染的时候需要对数据进行处理。或者是颜色空间不正确,导致了渲染的色彩不正确等问题。
解码Mp4中的音频,seek到0后解码,解码出的音频数据不是从头开始的
遇到了使用MediaCodec进行Mp4音频解码,MediaExtractor已经选中音频轨道,并且seek到0后,播放出来的音频并不是从头开始的问题。并且同样的视频,在有的手机上是好的,有的手机上又有问题,不仅仅是使用MediaCodec,使用MediaPlayer直接来播放也会遇到同样的问题。调试后发现,解码出来的数据前面有很多帧给出来的pts是对的,但是数据的size一直为0,而塞入的数据又的确没啥问题。
在有问题的手机上,使用另外一个不存在问题的视频,和存在问题的视频对比了下,解码器解码时候的MediaFormat,发现有问题的视频带有"encoder-delay"标记,值为1,而正常的视频是没有的。google了下发现罪魁祸首果然是它,Android P此问题存在,Android Q版本进行了修复。本地解决方案将"encoder-delay"标记值设置为0即可修复音频不是从头开始的问题。
音频解码无数据
三星J200G解码mp4中的音频,格式为mp4a-latm时遇到的偶现的问题。MediaCodec未返回错误,dequeueInputBuffer返回值正常,可以请求到buffer,但是dequeueOutputBuffer一直无法获得输出。log中有error信息:
4-18 12:27:47.926 32443-2244/com.uc.vmate E/ACodec: OMXCodec::onEvent, OMX_ErrorStreamCorrupt
04-18 12:27:47.931 2175-2266/? E/SEC_AAC_DEC: saacd_decode() failed ret_val: -5, Indata 0x 21 1b 94 a5, length : 1326
04-18 12:27:47.931 2175-2266/? E/SEC_AAC_DEC: ASI 0x 11, 90 00 00
04-18 12:27:47.931 32443-2244/com.uc.vmate E/ACodec: OMXCodec::onEvent, OMX_ErrorStreamCorrupt
04-18 12:27:47.936 2175-2266/? E/SEC_AAC_DEC: saacd_decode() failed ret_val: -5, Indata 0x 21 1b 94 bd, length : 1314
最后发现问题不是出在解码器上,而是出在MediaExtractor上,MediaExtractor使用的时候,内部可能出错,导致MediaExtractor解封装的时候给的数据存在异常。
视频解码时,获取输入输出Buffer始终为-1
在Oppo A37wf 5.1.1系统的手机上进行视频解码的时候,遇到了一个问题。同时解码两路1080p视频,结果一路正常,一路解码出一帧后,dequeueInputBuffer和dequeueOutputBuffer始终返回-1,无报错。而看grafika是可以同时解码的。对比了下我的使用和grafika中的示例,发现最终的原因是我在使用MediaCodec进行解码的时候,并不是dequeueOutputBuffer后就会releaseOutputBuffer,保证同时只会持有一帧数据。而是同时持有了两帧的outputBufer。
把代码改成只持有一个outputBuffer就正常了。回头再看了下Android cts中MediaCodec相关代码,并没有对同时多路持有多个Buffer进行测试,所以最终只能认命了,避免掉持有多帧不立即释放的情况。这里也就不得不提一个建议了,要想使用MediaCodec时,代码无bug,使用尽量不超出Android cts的范围,超出范围的使用就要做好面对一堆bug的准备了。
借助SurfaceTexture解码,图像方向不正确
MediaCodec解码视频可以直接将视频图像解码到Surface上,而Surface又可以通过SurfaceTexture来进行构建,也就是说MediaCodec可以直接将图像解码到SurfaceTexture上,当我们需要对解码后的视频进行图像处理时,通常会选择这样的方式。
对于带有旋转或者裁边信息的视频,我们通常需要在渲染SurfaceTexture的纹理时,将其纹理矩阵信息通过getTransformMatrix拿到,然后去做渲染处理。但是在一些情况下,我们通过getTransformMatrix并不能拿到正确的矩阵。依旧是在Oppo A37wf这个手机上,使用两路1080p视频解码,会遇到一路视频正常,一路视频的SurfaceTexture无法通过getTransformMatrix获得正确的Matrix的情况。在grafika上也存在同样的问题。
进一步跟进,发现在出错的那一路解码器中,codec.getOutputFormat()得到的Format中有一个using-sw-renderer字段被设为1了,所以根本原因就是这个手机用Surface的方式同时硬解两路1080p视频,会有一路渲染使用的软件渲染的方式进行渲染,而这个垃圾手机软件渲染又有bug。 在MediaCodec.cpp可以找到设置和处理相关源码,但是找到可以强制改回使用硬件渲染的方式。
我使用的解决方案是在发现解码使用的是软件渲染的OutputFormat时,对获取的矩阵进行判断,如果矩阵信息和OutputFormat中的信息不匹配的话,重新计算一个渲染矩阵出来,然后渲染时候使用重新计算的矩阵。计算方式可以参考native层源码GLConsumer.cpp中的计算。直接copy过来就能用了。
欢迎转载,转载请保留文章出处。湖广午王的博客[http://blog.csdn.net/junzia/article/details/106036509]
Android MediaCodec踩坑笔记相关推荐
- iphone se 一代 不完美越狱 14.6 视频壁纸教程(踩坑笔记)
iphone se 一代 不完美越狱 14.6 加 视频壁纸教程-踩坑笔记 越狱流程 1.爱思助手制作启动u盘 坑点: 2.越狱好后 视频壁纸软件 1.源 2.软件安装 越狱流程 1.爱思助手制作启动 ...
- Linux内核踩坑笔记
systemtap embedded C踩坑笔记戳这: https://blog.csdn.net/qq_41961459/article/details/103093912 task_struct的 ...
- Android applink 踩坑指南
Android applink 踩坑指南 原理 接入步骤 将链接与activity关联起来 加入meta data 生成身份验证JSON 真机测试 结论 官方文档 原理 与url scheme不同的地 ...
- 阿里云部署Tiny Tiny RSS踩坑笔记
阿里云部署Tiny Tiny RSS踩坑笔记 前言 入坑了RSS,之前的配置是阿里云部署RSSHub,配合Inoreader进行文章阅读,详情见RSS入坑指南.阿里云部署RSSHub踩坑笔记.在202 ...
- 「Java」基于Mirai的qq机器人开发踩坑笔记(其一)
目录 0. 前置操作 I. 安装MCL II. MCL自动登录配置 III. 安装IDEA插件 1. 新建Mirai项目 2. 编写主类 3. 添加外部依赖 4. IDEA运行 5. 插件打包 6. ...
- 「Java」基于Mirai的qq机器人开发踩坑笔记(其二)
目录 0. 配置机器人 1. onLoad方法 2. onEnable方法 3. 消息属性 4. 消息监听 I. 好友消息 II. 群聊消息 III. 无差别消息 5. 发送消息 I. 文本消息 II ...
- 昆仑通态触摸屏1003故障码,踩坑笔记
昆仑通态触摸屏1003故障码,踩坑笔记 第一次使用这个昆仑通态触摸屏,使用modbusRTU与金田变频器做通讯. 触摸屏在线后报1003通讯错误代码,现象是控制指令正常,但是读取不正常.读取变频器状态 ...
- EDUSOHO踩坑笔记之四十二:资讯
EDUSOHO踩坑笔记之四十二:资讯 获取资讯列表信息 GET /articles/{id} 权限 老API,需要认证 参数 字段 是否必填 描述 sort string 否 排序,'created' ...
- EDUSOHO踩坑笔记之三十三:班级
EDUSOHO踩坑笔记之三十三:班级 班级 班级 获取班级信息 获取班级列表 班级成员 获取班级计划 加入班级 营销平台加入班级 班级 班级 获取班级信息 GET /classrooms/{class ...
最新文章
- day9 线程与进程、队列
- mysql和java区别_java和mysql的length()区别及char_length()
- java 集合框架(一)
- Eclipse启动项目时,删除workspaces无用的工作区间
- mysql中的类型与java_mysql与java数据类型对应关系
- P2P之UDP穿透NAT的原理与实现(转)
- 如何在Windows中打开和使用命令提示符
- python读取txt文件每一行存为列表,从txt文件中读取一定数量的行,并以python方式转换为list...
- 韩顺平HTML5教程www.gis520.com
- 小样本点云深度学习库_NeurIPS2019 | MIT与上海交大提出新型点云深度学习框架Point-Voxel CNN...
- c#多线程thread实例详解
- HitPaw Watermark Remover for mac(视频图片去水印)
- asp毕业设计——基于asp+access的WEB网上留言板设计与实现(毕业论文+程序源码)——网上留言板
- windows 程序员计算器
- GAN (Generative Adversarial Nets 生成对抗网络)
- rasp 系统_RASP 类接口
- 二叉平衡树之AVL树【手动实现代码】
- 解决Win7笔记本下玩游戏的显示问题
- 〖Python自动化办公篇⑫〗- Excel 文件自动化 - 读取 excel 数据
- 【BP靶场portswigger-服务端4】操作系统命令注入-5个实验(全)