MediaCodec 基础:什么是 MediaCodec,作用,使用场景
什么是 MediaCodec?
MediaCodec,说白了就是 Android 系统里专门用来处理音视频编解码的底层 API。它不是第三方库,而是系统自带的核心组件。我刚开始做多媒体开发时,总觉得它像个“黑盒子”——输入原始数据,输出解码后的画面,中间怎么跑的,完全不清楚。
但干这行久了,你就得跟它打交道。MediaCodec 直接调用硬件编解码器(比如高通、联发科芯片里的硬解模块),比软件解码(比如 FFmpeg 的软解)快得多,功耗也低得多。
MediaCodec 的核心作用
它的作用其实就两件事:编码 和 解码。
- 解码:把压缩过的视频流(H.264、H.265、VP9 等)转成原始 YUV 或 RGB 帧,再交给 Surface 或纹理渲染。
- 编码:把原始帧压缩成指定格式,比如录制视频或推流时用的 H.264。
你可能想问:那和 MediaPlayer 有什么区别?MediaPlayer 是上层封装,内部也在用 MediaCodec。如果你只做播放器,用 MediaPlayer 省事;但要自己做音视频处理、低延迟渲染、或自定义解码策略,MediaCodec 就是绕不开的东西。
MediaCodec 的工作模式
MediaCodec 提供两种工作模式,我用表格帮你理清:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| 同步模式(Buffer 模式) | 手动调用 dequeueInputBuffer/dequeueOutputBuffer,线程阻塞 | 简单解码,容易控制 |
| 异步模式(Callback 模式) | 设置回调,编解码完成后自动通知 | 高性能场景,避免空转轮询 |
我个人建议,新项目优先用异步模式。为什么呢?曾经我在一个播放器项目里用了同步轮询,导致主线程频繁卡顿,后来改成回调才解决。异步模式下,系统把数据流管理得更好,你只需关心回调里的数据。
典型使用场景
- 本地视频播放:解码 H.264 视频流,配合 SurfaceView/TextureView 显示。
- 视频录制:从 Camera 拿到预览帧,编码成 H.264/H.265 存文件。
- 视频转码:把一个视频的格式、分辨率、码率转成另一种,比如压缩体积。
- 实时音视频通信:WebRTC 底层也依赖 MediaCodec 做硬编硬解。
- 截图/滤镜处理:解码后拿到原始帧,经过 OpenGL 处理再编码或者显示。
你想想看,上面这些场景,哪个不需要启动速度?尤其是实时通信和录屏,用户点开就要立即看到画面,一旦 MediaCodec 启动慢了,卡顿感就扑面而来。这就是我们这门课要解决的核心问题。
MediaCodec 能做什么,不能做什么
- 能:批量输入输出,支持 seek、关键帧控制、动态码率调整。
- 不能:它不负责网络协议、文件解析、音画同步。这些需要你配合 MediaExtractor、MediaMuxer 等来搞定。
启动卡顿从哪来?
既然我们要排查启动卡顿,就得先明白 MediaCodec 在启动时干了什么。调用 configure()、start() 之后,系统需要做硬件资源分配、Codec 实例化、首帧解码等等。这一步如果慢了,播放器就黑屏等待。
我遇到过最典型的情况:某机型在 configure() 阶段耗时 200ms,原因是后台还在跑其他 Codec 实例,资源被占满了。当时我们加了实例数限制和预热策略,才把启动时间压到 50ms 以内。
MediaCodec.createByCodecName() 之前,可以用 MediaCodecList 枚举所有支持的编码器,避免硬编码 codec 名字造成异常。
章节小结
MediaCodec 是一切多媒体底层操作的基础。理解它的作用、工作模式、使用场景,你才能知道卡顿出现在哪个环节。下一章我们就会深入启动流程,逐一拆解每个 API 调用到底干了些什么。
记住:不搞清楚基础,优化就是瞎蒙。