Android MediaCodec踩坑笔记

Android MediaCodec踩坑笔记关于编解码 FFMpeg 不香吗 为什么要吊死在 Android 的 MediaCodec 上 对于这个问题 我也很无奈 FFMpeg 很香 但是因为包体积 效率等问题引发的工作业务的需要 使我不得不在 AndroidMedia 的摧残下苟且偷生 MediaCodec 的 api 比较简单 用来写 demo 毫无难度 让人痛不欲生的是它的兼容性问题 使用 MediaCodec 遇到的问题 往往都是和机型 版本 某类媒体文件相关的问题 从开始使用 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/]


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233064.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • -2147467259 mysql_我点了帮助,提示说是:连接数据库错误,错误号:-2147467259,怎么回事?望帮我解答。谢谢!…

    -2147467259 mysql_我点了帮助,提示说是:连接数据库错误,错误号:-2147467259,怎么回事?望帮我解答。谢谢!…展开全部有几个主要的错误原因:这个错误发生在当自己的程序试图执行更新数据库或其它类似操作时。这是因为636f70793231313335323631343130323136353331333433623762:1、最普遍的原因是匿名用户帐号(IUSR_MACHINE)对该数据库文件没有写权限。要解决这个问题,在管理器中调整数据库文件的属性,让匿名用户有正确的权限。当使用ACCESS数据库时,…

    2022年7月13日
    15
  • 用C#编程的建议建议收藏

    1.如果可能尽量使用接口来编程.NET框架包括类和接口,在编写程序的时候,你可能知道正在用.NET的哪个类。然而,在这种情况下如果你用.NET支持的接口而不是它的类来编程时,代码会变得更加稳定、可用

    2021年12月21日
    43
  • OSPF报文类型

    OSPF报文类型OSPF 报文头格式 OSPF 用 IP 报文直接封装协议报文 协议号为 89 OSPF 分为 5 种报文 Hello 报文 DD 报文 LSR 报文 LSU 报文和 LSAck 报文 OSPF 这五种报文具有相同的报文头格式 长度为 24 字节 报文格式 字段解释 Version1 字节版本 OSPF 的版本号 对于 OSPFv2 来说 其值为 2 字段长度含义

    2025年11月30日
    3
  • importerror cannot import name_cannot resolve plugin org.apache

    importerror cannot import name_cannot resolve plugin org.apache今天测试一款轻量级的爬虫库:[RoboBrowser]。(https://github.com/jmcarp/robobrowser)github上的介绍是这样的:结合使用了Requests和BeautifulSoup,具体就不介绍了,这里主要是提一下碰到的问题:cannotimportname‘cached_property’from‘werkzeug’(C:\Users\79229\AppData\Local\Programs\Python\Python38\lib\site

    2022年10月7日
    5
  • linux安装rabbitmq教程(rabbitmq中文文档)

    一、准备依赖包yuminstallbuild-essentialopensslopenssl-develunixODBCunixODBC-develmakegccgcc-c++kernel-develm4ncurses-develtktcxz二、下载erlang-18.3-1wgetwww.rabbitmq.com/releases/erlang…

    2022年4月11日
    139
  • phpstorm激活码 3月最新注册码

    phpstorm激活码 3月最新注册码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    49

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号