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 堆栈由三个层次组成:

  1. 异常头部 — 异常类型 + 描述信息。
  2. 堆栈帧列表 — 从异常抛出点向上回溯,每行格式为 at 包名.类名.方法名(文件:行号)。
  3. 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 异常堆栈解析核心流程 现象识别 数据采集 原因定位 ① 异常类型识别 ② 堆栈结构解析 ③ 关键行定位 修复动作 复测验证 预防策略 ▶ 关键决策: 异常类型决定排查方向 → 堆栈结构定位调用链 → 关键行锁定修复代码
章节要点:MediaCodec 异常堆栈解析应始终遵循“现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防”的闭环。堆栈头部定类型、第一帧定入口、Caused by 定根因、错误码定方向——这四步定位法将在后续各章中反复使用并逐层深化。