MediaCodec 基础:什么是 MediaCodec,作用,使用场景

什么是 MediaCodec?

MediaCodec,说白了就是 Android 系统里专门用来处理音视频编解码的底层 API。它不是第三方库,而是系统自带的核心组件。我刚开始做多媒体开发时,总觉得它像个“黑盒子”——输入原始数据,输出解码后的画面,中间怎么跑的,完全不清楚。

但干这行久了,你就得跟它打交道。MediaCodec 直接调用硬件编解码器(比如高通、联发科芯片里的硬解模块),比软件解码(比如 FFmpeg 的软解)快得多,功耗也低得多。

核心一句话:MediaCodec 是 Android 硬解/硬编的入口,想做流畅播放、低延迟推流,都得用它。

MediaCodec 的核心作用

它的作用其实就两件事:编码 和 解码。

  • 解码:把压缩过的视频流(H.264、H.265、VP9 等)转成原始 YUV 或 RGB 帧,再交给 Surface 或纹理渲染。
  • 编码:把原始帧压缩成指定格式,比如录制视频或推流时用的 H.264。

你可能想问:那和 MediaPlayer 有什么区别?MediaPlayer 是上层封装,内部也在用 MediaCodec。如果你只做播放器,用 MediaPlayer 省事;但要自己做音视频处理、低延迟渲染、或自定义解码策略,MediaCodec 就是绕不开的东西。

MediaCodec 的工作模式

MediaCodec 提供两种工作模式,我用表格帮你理清:

模式特点适用场景
同步模式(Buffer 模式)手动调用 dequeueInputBuffer/dequeueOutputBuffer,线程阻塞简单解码,容易控制
异步模式(Callback 模式)设置回调,编解码完成后自动通知高性能场景,避免空转轮询

我个人建议,新项目优先用异步模式。为什么呢?曾经我在一个播放器项目里用了同步轮询,导致主线程频繁卡顿,后来改成回调才解决。异步模式下,系统把数据流管理得更好,你只需关心回调里的数据。

典型使用场景

  1. 本地视频播放:解码 H.264 视频流,配合 SurfaceView/TextureView 显示。
  2. 视频录制:从 Camera 拿到预览帧,编码成 H.264/H.265 存文件。
  3. 视频转码:把一个视频的格式、分辨率、码率转成另一种,比如压缩体积。
  4. 实时音视频通信:WebRTC 底层也依赖 MediaCodec 做硬编硬解。
  5. 截图/滤镜处理:解码后拿到原始帧,经过 OpenGL 处理再编码或者显示。

你想想看,上面这些场景,哪个不需要启动速度?尤其是实时通信和录屏,用户点开就要立即看到画面,一旦 MediaCodec 启动慢了,卡顿感就扑面而来。这就是我们这门课要解决的核心问题。

MediaCodec 能做什么,不能做什么

  • 能:批量输入输出,支持 seek、关键帧控制、动态码率调整。
  • 不能:它不负责网络协议、文件解析、音画同步。这些需要你配合 MediaExtractor、MediaMuxer 等来搞定。
注意:MediaCodec 对编码器实例数量有限制(一般 2~4 个),不要频繁创建释放,否则会触发 Camera 或 Surface 的时序冲突,我遇到过创建第三个解码器直接抛 IllegalStateException 的例子。

MediaCodec 知识体系 MediaCodec 基础 作用:硬编硬解 工作模式:同步/异步 典型场景(4类) 注意事项 & 避坑 说明:异步模式更推荐,同步模式适合简单调试。

启动卡顿从哪来?

既然我们要排查启动卡顿,就得先明白 MediaCodec 在启动时干了什么。调用 configure()、start() 之后,系统需要做硬件资源分配、Codec 实例化、首帧解码等等。这一步如果慢了,播放器就黑屏等待。

我遇到过最典型的情况:某机型在 configure() 阶段耗时 200ms,原因是后台还在跑其他 Codec 实例,资源被占满了。当时我们加了实例数限制和预热策略,才把启动时间压到 50ms 以内。

小技巧:在 MediaCodec.createByCodecName() 之前,可以用 MediaCodecList 枚举所有支持的编码器,避免硬编码 codec 名字造成异常。

章节小结

MediaCodec 是一切多媒体底层操作的基础。理解它的作用、工作模式、使用场景,你才能知道卡顿出现在哪个环节。下一章我们就会深入启动流程,逐一拆解每个 API 调用到底干了些什么。

记住:不搞清楚基础,优化就是瞎蒙。