1. 编解码器基础与碎片化背景
1.1 MediaCodec 框架概述
Android 的媒体编解码能力由 android.media.MediaCodec 类集中提供,它是 NDK 与 SDK 两套 API 的底层核心。应用通过 MediaCodec 可以访问设备硬件加速的编码器与解码器,而无需直接操作 OpenMAX IL 或 Codec2 HAL 层。
| 属性 | 说明 |
|---|---|
| 输入/输出缓冲区 | 应用从输入队列提交 ByteBuffer,从输出队列获取已解码/编码的帧 |
| 状态机 | Stopped → Executing → Flushed → End-of-Stream 等状态切换 |
| Codec vs Codec2 | Android 10 起 Codec2 逐步替代旧 MediaCodec,但仍需同时兼容 |
| 异步/同步模式 | 同步:dequeueInputBuffer + queueInputBuffer;异步:setCallback + 回调线程 |
典型初始化流程(同步模式):
MediaCodec codec = MediaCodec.createDecoderByType(mimeType);
MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
codec.configure(format, surface, null, 0);
codec.start();
// 循环:dequeueInputBuffer -> 填入数据 -> queueInputBuffer -> dequeueOutputBuffer -> 释放
1.2 厂商差异:HAL 栈实现分裂
Android 编解码器 HAL 存在两套历史实现:
- OMX(OpenMAX IL) – 早期标准,高通、MTK、三星各自适配,Bug 多
- Codec2(C2) – Android 10+ 推荐的模块化架构,但旧设备仍使用 OMX
不同 SoC 厂商对 H.264, H.265, VP9, AV1 的支持深度完全不同,即使同样是 H.264,分辨率上限、B‑frame 数量、profile/level 也存在差异。
典型碎片化表现: 一款手机支持 4K H.264 硬解,另一款只能到 1080p;同一台设备在 Android 9 上可正常硬解,升级 Android 11 后偶发解码黑屏。
1.3 碎片化典型表现
| 分类 | 具体问题 | 影响范围 |
|---|---|---|
| 编解码器列表差异 | getCodecInfo() 返回不同数量、不同名称的解码器 | 播放器/录制器选型报错 |
| 分辨率/帧率上限 | 部分厂商限制 4K 解码仅支持 30fps,或 1080p 编码最高 48fps | 直播推流、本地回放花屏 |
| 颜色格式不兼容 | COLOR_FormatYUV420Planar vs COLOR_FormatYUV420SemiPlanar 混用 | 纹理上传、GPU 滤镜崩溃 |
| H.265 / VP9 缺失 | 低端机型没有硬件 HEVC/VP9 解码器 | 视频无法播放或回退软解卡顿 |
| B‑frame 排序异常 | OMX 实现输出解码帧顺序不保证按 PTS 递增 | timedText 字幕错位 |
| 回调线程死锁 | 异步模式下 onOutputBufferAvailable 中调用 releaseOutputBuffer 超时 | 界面无响应 |
避坑: 不要依赖
MediaCodecList.getCodecInfoAt() 返回的顺序;部分国产机型会隐藏自适应解码器(Adaptive Playback),仅暴露“OMX.google.*”软解,导致硬解降级。
1.4 调试手段:获取设备编解码器能力
使用 adb shell dumpsys media.codec 可以列出所有注册的 Codec 以及每个 Codec 支持的 MIME、分辨率、帧率范围。从 Android 10 开始推荐使用 MediaCodecList.getDetailedCapabilities() 获取更精确的能力。
adb shell dumpsys media.codec
# 输出片段示例:
# OMX.qcom.video.decoder.avc:
# Component: OMX.qcom.video.decoder.avc
# Supports: video/avc
# Max resolution: 4096x2176
# Max framerate: 60 (per resolution: 1920x1080@60)
# Color formats: 21, 2130708362
最佳实践: 在应用启动时遍历
MediaCodecList,将支持的编解码器及其能力上报至远端日志中心,用于灰度监控兼容性问题。
1.5 常见错误清单(起步必读)
- MediaCodec.CodecException(错误码 0xFFFFFFEA): 硬件资源不足,尝试回退软解或降低分辨率
- IllegalStateException(”No such codec”): MIME 类型不匹配或设备未注册,优先使用
findDecoderForFormat查询 - 输出缓冲区格式突变: 更新后的 Android 版本可能改变颜色格式,需在
onOutputFormatChanged中重建纹理 - dequeueOutputBuffer 返回 INFO_OUTPUT_FORMAT_CHANGED 后未正确处理: 导致后续帧全部失败
性能起点: 在开发阶段启用
MediaCodec.MetricsConstants 收集编解码耗时,定位厂商特定硬编/硬解瓶颈。
掌握以上基础后,第 2 章将深入 MediaCodec 状态机与同步/异步模式的选择策略,直接指导工程实现。