FFmpeg Android 硬件编解码现状及展望

一、功能特性

自FFmpeg 6.0版本开始,FFmpeg对Android硬件编解码的支持逐步完善了,当前支持的功能特性包括:

  • 通过JNI调用Java MediaCodec

  • 直接调用NDK MediaCodec

  • 解码:H264、H265、MPEG2、MPEG4、VP8、VP9、AV1

  • 编码:H264、H265、MPEG4、VP8、VP9、AV1

  • 输入输出方式

    • Surface/ANativeWindow作为编码器输入,作为解码器输出

    • Buffer输入输出:YUV420P/NV12格式的AVFrame

值得一提的是,Java MediaCodec和NDK MediaCodec两套编解码的实现是共存的,运行时可以通过参数控制选择用哪一个,并且在获取不到JVM时,自动选择NDK MediaCodec的实现。

基于NDK MediaCodec的实现一方面性能更好,另一方面是可以脱离JVM环境运行:

  1. 你可以在adb命令行里执行FFmpeg命令做硬件编解码,做推流

  2. 你也可以在App程序里直接调用FFmpeg命令行

Android上运行FFmpeg命令行,当前有两大热门的应用场景:

  1. termux https://github.com/termux/termux-app

  2. ffmpeg-kit https://github.com/arthenica/ffmpeg-kit

二、亮点功能

做Android音视频开发的同学熟悉,MediaCodec编码器对非16整数倍分辨率的视频有兼容性问题,特别是早期华为麒麟的芯片,容易crash。我在FFmpeg里实现MediaCodec硬件编码时,通过FFmpeg自带的bsf(bit stream filter)解决了和分辨率相关的兼容性问题。简单来说,就是自动做align,再通过bsf修改输出的码流,修改SPS中的crop部分,裁切掉多余的padding。

三、已知缺陷

当前编码器支持YUV420P和NV12两种pixel format输入。但是,某些芯片只支持NV12格式,配置YUV420P格式会报错。

1、设备支持哪种pixel format,Android只提供了Java的API,没有NDK API,没有JVM时就没法查询

2、即使能够查询,也得要知道MediaCodec编码器的名字,知道MediaCodec编码器的名字是在avcodec open之后,设置pixel format是在avcodec open之前

3、编码器的pixel format是用户设定的,不像解码器有个get_format回调能够协商

以上种种困难导致的后果就是,如果你设置编码器输入格式是YUV420P,打开编码器可能失败。

NV12基本都支持,一般建议用NV12格式。之所以提供YUV420P作为一个选项,是在输入图像本身是YUV420P的情况下,省去一道YUV420P到NV12的转换,提升性能。

最近发现的另一个问题是:有个Vivo手机,用的联发科天玑9000的CPU,AMediaFormat_getRect返回图像的right/bottom信息错乱了,结果是解码正常,但是按照crop信息输出,图像只剩一小块了。可能要加黑名单,忽略掉联发科芯片返回的crop信息。

四、展望

未来我会重点放在NDK MediaCodec上,通过JNI调用Java MediaCodec实在繁琐,只做基本维护,不做开发了。

高版本Android提供了异步的NDK MediaCodec接口,我在编码器上实现了一个版本,性能提升挺明显的,patch还没合并到FFmpeg仓库里,打算再多做些测试。解码器也会加上异步方式,只是原有的解码器实现比较乱,收拾起来要花更多时间。

等给FFmpeg MediaCodec加上异步的支持之后,再支持鸿蒙的硬件编解码基本水到渠成了,因为看公开的API,基本上只是把Android MediaCodec的API换了个鸿蒙的前缀。现在没有开发测试环境,等有条件再说吧!

关于10bit的编解码支持,当前可以用Surface/ANativeWindows做输入输出来实现,Android没提供可用的10bit的pixel format。HDR编码的支持,看Android API情况和应用场景而定,对我而言优先级不高。类似的还有tunneled 模式,支持起来也许不难,但是构造测试场景麻烦。

肯定还有其他场景我没考虑到的,欢迎来聊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用ffmpeg进行多次编解码时,可能会出现失真的情况。这种失真可能是由于编解码引擎的算法问题、位深度转换引起的数据损失、颜色空间转换带来的图像质量下降,以及数据压缩引起的信息丢失等多种因素导致的。 首先,编解码引擎的算法问题可能会导致失真。编解码算法的质量和效率取决于具体的实现方式,不同的实现可能会有不同的性能表现。如果使用ffmpeg版本或配置不够稳定或优化不良,就有可能出现失真的情况。 其次,位深度转换可能导致数据损失。在多次编解码过程中,可能会对图像的位深度进行转换,例如从8位转换为10位。这种位深度的转换会引起信息损失,从而导致失真。 此外,颜色空间的转换也可能引起图像质量的下降。在多次编解码过程中,可能会对图像的颜色空间进行转换,例如从RGB转换为YUV。这种转换会导致色彩信息的损失,进而造成失真。 最后,数据压缩也可能导致信息丢失。在多次编解码过程中,可能会对数据进行压缩,以减小文件大小或传输带宽。然而,数据的压缩会导致信息的丢失,从而引起失真。 为了避免在ffmpeg多次编解码时出现失真,可以尝试以下方法:选择合适的ffmpeg版本和配置,保证编解码算法的质量和效率;尽量避免位深度和颜色空间的转换;限制数据压缩的程度,以减少信息丢失。此外,如果对图像质量要求较高,也可以考虑减少编解码的次数,以减少因多次编解码而引起的潜在失真。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值