MediaCodec 概述:定义、应用场景与角色
熟悉我的同学都知道,我做了好多年的 Android 多媒体底层优化。今天聊的 MediaCodec,说白了就是个硬件编解码的官方接口。你想想看,手机要拍视频、播视频、做直播,底层谁在干活?不是 CPU,而是 GPU、DSP 这些专用硬件。MediaCodec 就是帮我们跟这些硬件打交道的。
一句话定义:MediaCodec 是 Android 提供的底层音视频编解码 API,用于访问设备上的硬件或软件编解码器。
它到底长什么样?
不说虚的。MediaCodec 本质上是一个状态机,有四个状态:Stopped、Executing、Flushed、EndOfStream。我们平时调用的 createByCodecName()、configure()、start() 就是在不同状态间跳转。
给我印象最深的是实例化阶段——就是 createByCodecName() 和 configure() 这两步。为什么单独拿出来做一节课?因为我在项目里吃过亏:线上视频通话卡顿,查了半天,发现每次建立通话前 MediaCodec 实例化居然要 200ms+。嗯,这个时间对用户来说就是「转圈圈」。
应用场景有哪些?
我按自己接触过的项目总结一下:
- 直播推流:把摄像头采集的画面用 H.264/H.265 编码,推给 CDN。
- 视频播放:解码本地或网络的视频文件。
- 视频编辑:裁剪、拼接、转码,比如抖音的滤镜处理。
- 实时通信:WebRTC 场景,编码后通过 RTP 传出去。
- 屏录/投屏:把屏幕内容编码成流。
你留意到没?这些场景里 MediaCodec 实例化都会被频繁调用。比如直播切后台再回来、切换摄像头、分辨率变化——每次都得重新创建编解码器。所以优化实例化阶段的耗时,直接影响用户体验的流畅度。
在 Android 多媒体框架里的角色
我们可以把 Android 多媒体框架想象成三层结构:
| 层级 | 组件 | 我的理解 |
|---|---|---|
| 应用层 | MediaCodec, MediaMuxer, MediaExtractor | 咱们开发者直接用的 API,封装了底层细节 |
| 框架层 | Stagefright、NuPlayer、ACodec | 状态管理、缓冲池、编解码器路由 |
| 硬件抽象层 | OMX(OpenMAX IL)、Codec2 | 跟具体芯片对接,高通、联发科各有一套实现 |
MediaCodec 就坐在应用层,但它实际干活时是一路往下走。你调 createByCodecName("OMX.qcom.video.encoder.avc"),框架会去 HAL 层找对应的 OMX 组件,加载驱动,分配内存。
核心知识结构图
下面这张图我把 MediaCodec 实例化涉及的核心节点画出来,方便你理解全局。
为什么实例化阶段值得单独拿出来讲?
我直接给你看个真实数据。某款中端手机,使用软件编解码器时实例化大概 30ms,但用硬件编解码器(OMX)时却要 200-400ms,其中 createByCodecName 占了 80ms,configure 占了 150ms。
关键结论:硬件编解码器的实例化时间远高于软件编解码器,且主要瓶颈在 createByCodecName 和 configure 内部。
你可能会问:为什么硬件编解码器反而慢?原因有很多:
- 组件查找时需要在 /vendor/lib 下加载动态库,I/O 耗时
- 驱动需要初始化硬件状态、申请 DMA-BUF 内存
- 跨进程通信(Binder)也会增加额外延迟
嗯,这些都是后面课程会细讲的内容。这里先建立个整体认知就好。
一个小总结
MediaCodec 实例化阶段就像「开工厂」:先找厂房(createByCodecName),再配置流水线(configure),然后启动机器(start)。我们后面的优化案例,就是解决每一环节的「开机慢」问题。
个人建议:在做多媒体 App 性能分析时,先把 MediaCodec 实例化阶段单独 profiling 一次。习惯用 Trace.beginSection() 打点,抓 systrace 看耗时分布。曾经有个同事调了一个月的编码延迟,结果发现只是每次创建编码器时日志输出太多导致的 I/O 阻塞……