限时福利领取


在移动端处理音视频时,MediaCodec是Android系统提供的底层编解码利器。相比跨平台的FFmpeg,它直接调用硬件加速,效率能提升3-5倍。今天记录下最近实现的转码Demo,分享关键实现和踩坑经验。

MediaCodec工作流程

一、为什么选择MediaCodec?

  1. 硬件加速优势:直接调用芯片的DSP单元,H.264编码速度是软件方案的4倍
  2. 系统级集成:自动处理安卓版本兼容性问题,API Level 16+全支持
  3. 低延迟特性:直播推流场景下延迟可控制在200ms内

对比FFmpeg虽然功能全面,但在Android上需要NDK交叉编译,且CPU占用率高。实测转码1080P视频:

// 性能对比数据(Pixel 4 XL测试)
MediaCodec: 45fps  CPU占用12%
FFmpeg:   18fps  CPU占用65%

二、核心实现四步走

  1. 初始化编解码器 关键点在于选择合适的MIME类型和颜色格式:
val codec = MediaCodec.createDecoderByType("video/avc") 
val format = MediaFormat.createVideoFormat("video/avc", width, height)
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)
codec.configure(format, surface, null, 0)
  1. 输入输出缓冲区管理 采用异步回调更高效,注意处理BUFFER_FLAG_END_OF_STREAM:
codec.setCallback(object : MediaCodec.Callback() {
    override fun onInputBufferAvailable(codec: MediaCodec, index: Int) {
        val buffer = codec.getInputBuffer(index)
        // 填充原始数据
        codec.queueInputBuffer(index, ...)
    }

    override fun onOutputBufferAvailable(...) {
        // 处理转码后数据
        codec.releaseOutputBuffer(index, ...)
    }
})
  1. 数据格式转换 YUV420P转NV21的优化写法:
void convertYUV420ToNV21(byte[] yuv420, byte[] nv21, int width, int height) {
    // Y分量直接复制
    System.arraycopy(yuv420, 0, nv21, 0, width*height);

    // UV分量交错处理
    for (int i=0; i<width*height/4; i++) {
        nv21[width*height + i*2] = yuv420[width*height + i]; // U
        nv21[width*height + i*2 +1] = yuv420[width*height*5/4 + i]; // V
    }
}
  1. 异常处理三板斧
  2. 解码器不支持时fallback到其他MIME类型
  3. 配置失败检查是否缺少CSD(Codec Specific Data)
  4. 输出画面绿屏检查颜色格式是否匹配

转码流程示意图

三、性能优化实战技巧

  1. 缓冲区黄金法则
  2. 输入缓冲区:根据帧率计算,如30fps视频设15帧缓存
  3. 输出缓冲区:参考分辨率,1080P建议≥2MB

  4. 异步模式陷阱: 必须处理callback的时序问题,建议用HandlerThread+同步锁:

val handlerThread = HandlerThread("CodecCallback")
handlerThread.start()
codec.setCallback(callback, Handler(handlerThread.looper))
  1. 硬件加速秘籍: 在Manifest声明硬件加速,并检测设备支持情况:
<application android:hardwareAccelerated="true">

四、常见坑位排查表

| 现象 | 原因 | 解决方案 | |-------|-------|-------| | 初始化崩溃 | 不支持的color format | 改用COLOR_FormatYUV420Flexible | | 输出花屏 | 未设置CSD数据 | 添加sps/pps到format | | 编码延迟高 | 未启用BITRATE_MODE_CBR | 设置目标码率和模式 |

五、扩展方向建议

  1. 动态码率调整:根据网络状况实时修改KEY_BITRATE
  2. 多轨道处理:音频同步用presentationTimeUs对齐
  3. 滤镜集成:结合GLSurfaceView实现实时特效

完整Demo已上传GitHub,包含如下模块:

app/
├── src/main/
│   ├── java/com/example/transcoder/
│   │   ├── VideoTranscoder.kt  # 核心转码逻辑
│   │   └── Utils.kt           # YUV转换工具
│   └── assets/test.mp4        # 测试视频

通过这次实践,深刻体会到MediaCodec就像精准的手术刀——用对地方威力无穷,但需要严格遵循操作规范。建议新手从官方CTS测试用例学起,逐步掌握这个强大的工具。

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐