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思路写代码,建议尽快升级。
1.2 MediaCodec核心概念
MediaCodec是Android硬解码的核心API。它有两种工作模式:
- 同步模式:dequeueInputBuffer/dequeueOutputBuffer 来回调用。代码写起来直观,但容易阻塞。
- 异步模式:通过回调处理数据。我个人更推荐这种方式,尤其在高帧率场景下。
我记得刚开始用MediaCodec时,总搞不清它的状态机。其实就三种状态:
- Stopped:初始状态,还没开始干活。
- Executing:正在解码中。又细分为Flushed、Running、End-of-Stream。
- 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