android 媒体框架之MediaCodec
一、MediaCodec 整体架构与设计思想
MediaCodec 是 Android 底层多媒体框架的核心组件,负责高效处理音视频编解码任务。其架构采用 生产者-消费者模型,通过双缓冲区队列(输入/输出)实现异步数据处理:
- 输入缓冲区队列:存放待编码/解码的原始数据(如 YUV 视频帧或 PCM 音频)。
- 输出缓冲区队列:存储处理后的数据(如 H.264 流或解码后的原始帧)。
- 硬件加速支持:优先调用设备专属编解码器(如高通 DSP),显著降低 CPU 负载。
二、核心组件与关键 API 详解
1. 编解码器实例(MediaCodec)
- 创建方式:
支持通过 MIME 类型(如// 创建解码器(H.264 示例) MediaCodec decoder = MediaCodec.createDecoderByType("video/avc"); // 创建编码器(AAC 音频示例) MediaCodec encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
video/avc
)或硬件编解码器名称创建。
2. 缓冲区管理
- 输入缓冲区:
dequeueInputBuffer(timeoutUs)
:获取空闲缓冲区索引。getInputBuffer(index)
:通过索引获取ByteBuffer
对象填充数据。queueInputBuffer(...)
:提交数据给编解码器处理。
- 输出缓冲区:
dequeueOutputBuffer(BufferInfo, timeoutUs)
:获取处理完成的缓冲区索引及元数据。getOutputBuffer(index)
:读取编解码后数据。releaseOutputBuffer(index, render)
:释放缓冲区(若为视频,render=true
可触发渲染)。
3. 配置与状态控制
- 配置参数(MediaFormat):
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000); // 码率 format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 帧率 format.setInteger(KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible); // 颜色空间 codec.configure(format, surface, null, 0); // surface 用于视频渲染
- 生命周期控制:
start()
→ 进入运行状态(Running
)。stop()
→ 回到未初始化状态(Uninitialized
)。release()
→ 释放资源。
三、核心类 MediaCodec.BufferInfo
深度解析
BufferInfo
是描述输出缓冲区元数据的关键类,包含以下字段:
字段 | 类型 | 作用 |
---|---|---|
offset | int | 有效数据在缓冲区中的起始偏移(字节)。通常为 0,表示从缓冲区头部开始读取。 |
size | int | 有效数据长度(字节)。若为 0 且含 BUFFER_FLAG_END_OF_STREAM ,表示流结束。 |
presentationTimeUs | long | 呈现时间戳(微秒),用于音视频同步(如视频帧的渲染时机)。 |
flags | int | 缓冲区标志位(位掩码),关键值包括: |
(0) : B or P 帧 | ||
- BUFFER_FLAG_KEY_FRAME (1):关键帧(I帧)。 | ||
- BUFFER_FLAG_END_OF_STREAM (4):流结束标记(EOS)。 | ||
- BUFFER_FLAG_CODEC_CONFIG (2):编解码配置数据(如 SPS/PPS)。 |
典型使用场景:
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputIndex = codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
if (outputIndex >= 0) {ByteBuffer outputBuffer = codec.getOutputBuffer(outputIndex);byte[] data = new byte[bufferInfo.size];outputBuffer.position(bufferInfo.offset);outputBuffer.get(data, 0, bufferInfo.size);// 关键帧处理if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {saveKeyFrame(data); // 存储关键帧用于错误恢复}codec.releaseOutputBuffer(outputIndex, true);
}
四、工作流程与状态机
- 关键状态:
- Flushed:启动后初始状态,缓冲区为空。
- Running:持续处理数据(90% 时间处于此状态)。
- End-of-Stream:输入流结束,等待输出剩余数据。
五、注意
-
同步 vs 异步模式:
- 同步模式:简单但易阻塞主线程,适合低复杂度场景。
- 异步模式:通过
setCallback()
监听事件,高效但需处理线程安全。
-
缓冲区复用:避免频繁申请内存,提升性能(尤其高清视频)。
-
设备兼容性:
- 使用
MediaCodecList
检查编解码器支持情况。 - 某些设备对
COLOR_FORMAT
支持有限,需动态适配。
- 使用
-
MediaCodec 通过双缓冲区队列和状态机控制实现高效编解码,核心在于:
缓冲区管理:dequeueInputBuffer
/queueInputBuffer
与dequeueOutputBuffer
/releaseOutputBuffer
的配对使用。 -
元数据解析:
BufferInfo
的flags
和presentationTimeUs
是同步与错误恢复的关键。 -
硬件加速:优先选择设备专属编解码器(如
OMX.qcom.
前缀)以优化性能。