1. 硬解码基础:Android多媒体架构概览

做Android视频开发这些年,我最大的感触就是——硬解码这块,光看文档真不够。你得真正踩过坑,才知道MediaCodec到底怎么用才顺手。今天咱们就从最基础的东西聊起。

1.1 Android多媒体架构概览

先说说Android的多媒体架构长什么样。说白了,它分三层:

  • 应用层:你写的播放器、相机App都在这一层。调用MediaCodec、MediaPlayer这些API。
  • 框架层:Java层的MediaCodec、MediaExtractor等,负责把上层请求转给底层。
  • 底层:Stagefright、NuPlayer、OMX组件、Codec2。真正的解码工作在这里完成。

我个人习惯把这三层想象成「点菜-传菜-做菜」的关系。应用层点菜,框架层传菜,底层的大厨(硬件编解码器)负责把菜做出来。

核心要点:Android从8.0开始逐步用Codec2替代OMX,到Android 12基本完成过渡。如果你还在用老旧的OMX思路写代码,建议尽快升级。

应用层 MediaPlayer | MediaCodec | 自定义播放器 框架层 MediaExtractor | MediaMuxer | Surface 底层 Codec2 / OMX | 硬件编解码器 | 驱动层

1.2 MediaCodec核心概念

MediaCodec是Android硬解码的核心API。它有两种工作模式:

  • 同步模式:dequeueInputBuffer/dequeueOutputBuffer 来回调用。代码写起来直观,但容易阻塞。
  • 异步模式:通过回调处理数据。我个人更推荐这种方式,尤其在高帧率场景下。

我记得刚开始用MediaCodec时,总搞不清它的状态机。其实就三种状态:

  1. Stopped:初始状态,还没开始干活。
  2. Executing:正在解码中。又细分为Flushed、Running、End-of-Stream。
  3. Released:资源释放完毕。

小技巧:调用start()后,MediaCodec会进入Flushed状态。这时候别急着往里塞数据,先等它准备好。我见过不少新手在这踩坑。

1.3 硬解码与软解码对比

这个问题我经常被问到。直接上对比表:

对比项 硬解码 软解码
功耗 低(专用硬件) 高(CPU全速运转)
性能 高,轻松4K@60fps 低,1080p可能就卡
兼容性 因芯片而异 统一,FFmpeg通吃
发热 高,手机能煎鸡蛋
色彩格式 YUV为主 RGB为主

你想想看,为什么现在手机都能轻松播放4K视频?全靠硬解码。软解码跑4K,CPU直接拉满,电池撑不过半小时。

避坑指南:我曾经在一个项目里全用硬解码,结果某款老机型不支持H.265硬解,画面直接黑屏。后来我加了软解回退逻辑,才解决问题。记住:永远要有Plan B。

1.4 YUV与RGB色彩空间

说到色彩空间,这是硬解码绕不开的坎。MediaCodec输出的原始数据,绝大多数是YUV格式。为什么?因为YUV天生适合视频压缩。

简单理解:

  • Y:亮度信息,人眼最敏感的部分。
  • U/V:色度信息,人眼没那么敏感,可以压缩。

常见的YUV格式有:

  • NV12:先存Y,再交错存UV。Android相机默认输出格式之一。
  • NV21:先存Y,再交错存VU。老机型常见。
  • YUV420P:三个平面分开存。FFmpeg里常用。

而RGB呢?每个像素都包含完整的红绿蓝信息。显示器和UI层喜欢RGB,但视频编码器不喜欢——太占带宽了。

实战经验:我做过一个项目,需要把MediaCodec输出的NV12转成RGB再渲染。直接用CPU转,1080p@30fps就把CPU吃掉了30%。后来改用OpenGL Shader做色彩转换,CPU占用直接降到5%以下。嗯,这里要注意:能用GPU干的活,别让CPU干。

色彩转换的公式其实不复杂:

// YUV转RGB(简化版)
R = Y + 1.402 * (V - 128)
G = Y - 0.344 * (U - 128) - 0.714 * (V - 128)
B = Y + 1.772 * (U - 128)

但实际项目中,我建议直接用现成的库或者Shader。自己手写转换,容易踩精度和性能的坑。

小结

这一章我们聊了Android多媒体架构的三层结构,MediaCodec的核心状态机,硬解码和软解码的取舍,以及YUV和RGB的区别。这些都是硬解码的基石。下一章我们会深入MediaCodec的具体用法,包括怎么配置、怎么处理数据流。

公众号:蓝海资料掘金营,微信deep3321