简介
应用程序对音频和视频数据进行编码(压缩)和解码(解压缩)。通过MediaCodec,开发者可以直接访问底层的编解码器,实现更高效的音视频处理,并支持硬件加速,从而提高编解码的性能。
工作原理
MediaCodec采用异步的方式处理两路数据流:输入流(input)和输出流(output)。输入流用于接收待解码或待编码的数据,而输出流则用于输出已解码或已编码的数据。
- 在编码过程中,MediaCodec不断从输入缓冲区中读取原始数据(如YUV格式的视频帧),经过编码后,从输出缓冲区获取压缩后的数据(如H.264格式的视频流)。
- 解码过程则相反,MediaCodec从输入缓冲区读取压缩后的数据,解码后输出原始数据到输出缓冲区。
生命周期
MediaCodec在不同的数据处理模式下,其状态会有所不同。MediaCodec的三种主要状态包括:停止态(Stopped)、执行态(Executing)和释放态(Released)。其中,停止态和执行态又分别包含多个子状态:
- 未初始化状态(Uninitialized):MediaCodec对象刚被创建,尚未进行配置。
- 配置状态(Configured):MediaCodec已经通过configure()方法进行了配置,但尚未启动。
- 错误状态(Error):MediaCodec在编解码过程中遇到错误,需要重置或释放。
- 刷新状态(Flushed):MediaCodec已经启动,但尚未处理任何数据,或者已经通过flush()方法被清空。
- 运行状态(Running):MediaCodec正在处理数据,可以从输入缓冲区读取数据,并向输出缓冲区写入数据。
- 流结束状态(End-of-Stream):MediaCodec已经处理完所有输入数据,不再有新的数据输入。
使用
//创建MediaCodec
MediaCodec codec = MediaCodec.createEncoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
//码率
format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000);
//帧率
format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
//关键帧
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
//颜色空间
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
//把待解码或待编码的数据放入MediaCodec的缓冲区中
int index = mediaCodec.dequeueInputBuffer(timeoutUs);
if (index >= 0) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
inputBuffer.clear();
inputBuffer.put(buffer);
//填充的数据加入队列
mediaCodec.queueInputBuffer(index, 0,
buffer.length, System.nanoTime() / 1000, 0);
}
//获取已解码或已编码的数据
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int encode = mediaCodec.dequeueOutputBuffer(bufferInfo, timeoutEn);
if (encode >= 0) {
ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(encode);
MediaFormat bufferFormat = mediaCodec.getOutputFormat(encode);
mediaCodec.releaseOutputBuffer(encode,false);
}
常用的API
//获取解码器对象。
public static MediaCodec createDecoderByType(String type)
//获取编码器对象。
public static MediaCodec createEncoderByType(String type)
//开始
public void start()
//结束
public void stop()
//创建输入缓冲Surface(用于视频编码)。
public native Surface createInputSurface()
//设置输出缓冲Surface(用于视频解码)。
public void setOutputSurface(@NonNull Surface surface)
// 获取可用的输入缓冲区的索引
public int dequeueInputBuffer (long timeoutUs)
// 获取输入缓冲区
public ByteBuffer getInputBuffer(int index)
// 将填满数据的inputBuffer提交到编码队列
public final void queueInputBuffer(int index,int offset, int size, long presentationTimeUs, int flags)
// 获取已成功编解码的输出缓冲区的索引
public final int dequeueOutputBuffer(BufferInfo info, long timeoutUs)
// 获取输出缓冲区
public ByteBuffer getOutputBuffer(int index)
// 释放输出缓冲区
public final void releaseOutputBuffer(int index, boolean render)