#.MedaiCodec简介
MediaCodec是Android中提供的音视频编码、解码工具。它主要是完成上层接口的封装,提供给开发者使用,编解码功能实际是在native底层服务中完成的。
#.MediaCodec工作的宏观流程:
##.包换两个缓冲区队列
一个输入缓冲区队列,包含一组输入缓冲区(格式ByteBuffer);
一个输出缓冲区队列,包含一组输出缓冲区(格式ByteBuffer);
##.使用中,需要不断重复以下过程:
1.把原始数据放入输入缓冲区队列中一个空缓冲区上;2.编/解码器从输入缓冲队列中获取缓冲区上数据,进行编码处理,结果存放到输出缓冲区上一个空缓冲区上,处理完毕后,释放该输入缓冲区,它会被重新放回输入缓冲区队列,以便下次重复使用;3.对输出缓冲区上数据做自己需要的业务处理处理,处理完毕后,释放该输出缓冲区,它会被重新放回输出缓冲区队列,以便下次重复使用。
##.当对视频帧进行编/解码时,一般会用编码器创建一个输入Surface或为编码器设置一个输出Surface,在这里Surface充当着数据缓冲区的角色。使用Surface可以提高编/解码器的性能,Surface直接使用native视频数据缓存,没有映射或复制它们到ByteBuffers,这种方式会更加高效。
#.内部的状态机和处理流程
##.状态机,三类状态:
1.停止态(Stopped):1.1 未初始化状态(Uninitialized)1.2 配置状态(Configured)1.3 错误状态(Error)2.执行态(Executing):2.1 刷新状态(Flushed)2.2 运行状态( Running)2.3 流结束状态(End-of-Stream)3.释放态(Released)
##.操作流程:
1.一般流程为创建编/解码器,此时处于未初始化状态(Uninitialized);2.调用configure(…)方法对编解码器进行配置,使编解码器转入配置状态(Configured);3.调用start()方法,使其转入执行刷新状态(Flushed);4.此时编解码器已经拥有其输入/输出缓存,当第一个输入缓存区被移出队列,编解码器转入运行状态( Running);5.在运行状态( Running)中,编解码器不断对输入缓冲区中数据做编解码操作,结果存到输出缓冲区;6.当一个带有end-of-stream标记的输入缓存入队列时,编解码器将转入流结束状态(End-of-Stream)。在这种状态下,编解码器不再接收新的输入缓存,但它仍然产生输出缓存。直到7.当输入缓存中所有数据都被处理完,带有end-of-stream标记的数据帧到达输出缓存后,转入释放态(Released)。当我们处理完输出数据后,在此状态下可以用release()进行相关资源的释放。
##.状态转化其它相关要点:
1.在执行状态(Executing)下的任何时候,通过调用flush()方法使编解码器重新返回到刷新子状态(Flushed);2.通过调用stop()方法使编解码器返回到未初始化状态(Uninitialized),此时这个编解码器可以再次重新配置;3.编解码器遇到错误时会进入错误状态(Error),此时应调用reset()方法使编解码器再次可用。4.任何状态下调用reset()方法使编解码器返回到未初始化状态(Uninitialized)
##.MediaCodec相关API介绍:
createDecoderByType:获取解码器对象createEncoderBytype:获取编码器对象configure:对编解码器进行配置,使编解码器转入配置状态start:使编码器转入执行刷新状态stop:结束并返回到未初始化状态release:释放实例资源createInputSurface:创建输入缓冲SurfacesetOutputSurface:设置输出缓冲SurfacegetInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组queueInputBuffer:输入流入队列dequeueInputBuffer:从输入流队列中取数据进行编码操作getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组dequeueOutputBuffer:从输出队列中取出编码操作之后的数据releaseOutputBuffer:处理完成,释放ByteBuffer数据
##.MediaCodec的两种工作方式
1.同步方式:数据输入和数据输出依次进行。要等待上一次数据输入后,才能数据输出;等待上一次数据输出后,才能再次进行数据输入。2.异步方式:数据输入和数据输出操作顺序相互独立。是底层服务来判断何时输入/输出可以进行,然后进行相应回调,开发者在回调中进行数据输入/输出处理。
//异步处理方式时,需要设置回调接口。
//在回调中进行数据处理
mEncoder.setCallback(new MediaCodec.Callback() {
//有可用的输入缓冲区时回调
@Override
public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
}
//有可用的输出缓冲区时回调
@Override
public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
}
//输出格式变化时回调
@Override
public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
}
//出错时回调
@Override
public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
}
});