1. MediaCodec异常堆栈概览:识别常见异常类型、堆栈结构、关键行定位
现象识别
MediaCodec 异常发生时,应用通常表现为视频播放黑屏、编码卡死、录制中断或直接闪退。Logcat 中会输出包含 MediaCodec 关键词的异常堆栈,堆栈头部明确定义了异常类型与错误描述。
现场第一信号:异常堆栈头部的前两行通常直接指明异常大类(如 CodecException、IllegalStateException)和触发场景(如 start()、dequeueOutputBuffer())。抓住这两行,就能确定排查方向。
数据采集
通过 adb logcat -s MediaCodec 或 adb logcat -b crash 过滤出 MediaCodec 相关堆栈。建议同时采集 MediaCodec、MediaFormat、ACodec 三个 TAG 的日志,以便还原异常触发前的状态。
采集重点:
- 异常时间戳:与操作时间点对齐。
- 异常类型全称:如
android.media.MediaCodec$CodecException。 - 完整堆栈帧:至少采集从异常抛出点到应用入口的全部 15~30 行。
- 进程与线程 ID:确认异常发生在主线程还是 Binder 线程。
# 示例采集命令
adb logcat -b crash -b main -v threadtime | grep -E "MediaCodec|ACodec|MediaFormat" > mediacodec_crash.log
原因定位
常见异常类型速查表
| 异常类型 | 堆栈头部特征 | 典型触发场景 |
|---|---|---|
| CodecException | android.media.MediaCodec$CodecException |
configure()/start()/flush() 时编解码器内部错误 |
| IllegalStateException | java.lang.IllegalStateException |
在错误状态调用 dequeueOutputBuffer()、release() |
| MediaFormatException | android.media.MediaFormatException |
关键格式参数缺失或类型不匹配 |
| Surface 异常 | android.view.Surface$InvalidSurfaceException |
Surface 已释放或尺寸为 0 时送入解码器 |
| 资源耗尽 | java.lang.RuntimeException + Resource unavailable |
同时打开过多编解码器实例 |
堆栈结构解析规则
一个标准的 MediaCodec 堆栈由三个层次组成:
- 异常头部 — 异常类型 + 描述信息。
- 堆栈帧列表 — 从异常抛出点向上回溯,每行格式为
at 包名.类名.方法名(文件:行号)。 - Caused by 链 — 根因异常,通常指向 Native 层或底层驱动。
// 典型 MediaCodec 异常堆栈示例
android.media.MediaCodec$CodecException: Error 0x80000001
at android.media.MediaCodec.native_start(Native Method)
at android.media.MediaCodec.start(MediaCodec.java:2840)
at com.example.video.MediaCodecHelper.startCodec(MediaCodecHelper.java:105)
at com.example.video.PlayerActivity.onSurfaceCreated(PlayerActivity.java:78)
... 12 more
Caused by: android.media.MediaCodec$CodecException: init failed: resource busy
at android.media.MediaCodec.native_configure(Native Method)
... 9 more
关键行定位三原则
- 原则一:找第一个 at 自己代码的帧。 该帧是应用层触发异常的起点。
- 原则二:找 Native 层线索。
native_start、native_configure等帧后的错误码(如0x80000001)指示底层失败原因。 - 原则三:追踪 Caused by 链。 最后一层 Caused by 通常是问题的根本原因。
定位口诀:头部定类型,第一帧定入口,Caused by 定根因,错误码定方向。
修复动作
针对本章覆盖的常见异常类型,修复动作可初步归纳如下(后续章节将逐一深入):
- CodecException — 检查编解码器是否支持当前 MIME 类型;确认设备媒体资源未被耗尽。
- IllegalStateException — 严格按照
Stopped → Configured → Executing → Released状态机调用 API。 - MediaFormatException — 确保设置了
KEY_WIDTH、KEY_HEIGHT、KEY_MIME三个必填键。 - Surface 异常 — 在送入解码器前校验 Surface.isValid() 和尺寸。
- 资源耗尽 — 使用
MediaCodecList查询可用实例数;及时 release() 不再使用的编解码器。
复测
修复后需验证以下场景:
- 异常不再复现,连续播放/录制 30 分钟无崩溃。
- Logcat 中不再出现对应异常类型的堆栈输出。
- 快速切换前后台、旋转屏幕、切换分辨率等边界操作均通过。
预防
- 在
configure()前调用MediaCodecList.findDecoder/EncoderForFormat()确认设备支持。 - 建立统一的
MediaCodecLifecycleManager管理状态转换,避免手动状态错乱。 - 在全局异常捕获器中增加
MediaCodec.CodecException的定向采集与上报。 - 为每台设备建立编解码器资源池上限,运行时动态监控已分配实例数。
本章知识图谱:MediaCodec 异常堆栈解析流程
章节要点:MediaCodec 异常堆栈解析应始终遵循“现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防”的闭环。堆栈头部定类型、第一帧定入口、Caused by 定根因、错误码定方向——这四步定位法将在后续各章中反复使用并逐层深化。