Android MediaCodec 图片转视频实战:从编码原理到性能优化
在移动端开发中,将图片序列转换为视频是一个常见需求,比如生成动态相册、制作短视频等场景。传统方案使用FFmpeg虽然功能强大,但在Android平台上存在包体积大、性能开销高的缺点。而Android原生的MediaCodec API则提供了更高效的硬件加速方案,下面分享我的实战经验。

一、为什么选择MediaCodec?
- 性能优势:直接调用硬件编码器(如高通/MTK芯片组的H.264编码模块)
- 体积优势:无需集成第三方库,APK体积可减少5-10MB
- 功耗控制:比软件编码节省30%以上电量(实测红米Note11 Pro编码1080P视频)
但要注意几个常见坑点: 1. 帧率不稳定导致视频卡顿 2. 内存泄漏风险(特别是Android 9以下版本) 3. 不同厂商设备编码器支持差异
二、核心实现四步走
-
初始化编码器(关键参数示例)
val format = MediaFormat.createVideoFormat("video/avc", width, height).apply { setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) setInteger(MediaFormat.KEY_BIT_RATE, 2500_000) // 2.5Mbps setInteger(MediaFormat.KEY_FRAME_RATE, 30) setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2) // 关键帧间隔 } val encoder = MediaCodec.createEncoderByType("video/avc") encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE) val surface = encoder.createInputSurface() // 用于接收图像数据 -
帧数据输入技巧
- 使用OpenGL ES将Bitmap渲染到Surface(避免直接内存拷贝)
-
时间戳计算公式:
presentationTimeUs = 1000000L * frameIndex / frameRate -
输出缓冲区处理
val bufferInfo = MediaCodec.BufferInfo() when (val status = encoder.dequeueOutputBuffer(bufferInfo, 10000)) { >= 0 -> { val outputBuffer = encoder.getOutputBuffer(status) // 写入MP4容器(建议用MediaMuxer) muxer.writeSampleData(trackIndex, outputBuffer, bufferInfo) encoder.releaseOutputBuffer(status, false) } MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> trackIndex = muxer.addTrack(encoder.outputFormat) }

三、性能优化实战
内存优化三原则: 1. 复用Texture和Surface(避免每帧创建/销毁) 2. 使用BITMAP_RECYCLE及时回收Bitmap 3. 限制待编码帧队列长度(建议<5帧)
编码速度提升技巧: - 预生成所有Bitmap的时间戳(减少实时计算开销) - 对于720P视频,设置KEY_PROFILE为CodecProfileLevel.AVCProfileBaseline - 启用异步模式(API 21+)
四、避坑指南
高频异常处理:
try {
// 编码操作
} catch (e: IllegalStateException) {
// 常见于编码器状态错误
encoder.reset()
} catch (e: MediaCodec.CodecException) {
// 检查设备支持的color format
val caps = encoder.codecInfo.getCapabilitiesForType("video/avc")
caps.colorFormats.forEach { Log.d("SupportedFormat", "$it") }
}
版本兼容方案: - Android 4.3以下:降级到H.263编码 - Android 5.0+:优先使用createPersistentInputSurface() - Android 12+:注意HardwareBuffer的使用限制
五、完整代码示例
GitHub代码片段 包含: 1. Bitmap到YUV的转换工具类 2. 带进度回调的编码封装 3. 帧率自适应算法
最后建议结合JobScheduler实现后台编码任务管理,避免ANR。通过合理配置MediaCodec参数,在我的Redmi K40上实现1080P@30fps视频编码仅需原图序列处理时间的1.2倍,内存占用稳定在50MB以内。
更多推荐


所有评论(0)