一,MediaCodec工作原理
MediaCodec类Android提供的用于访问低层多媒体编/解码器接口,它是Android低层多媒体架构的一部分,通常与MediaExtractor、MediaMuxer、AudioTrack结合使用,能够编解码诸如H.264、H.265、AAC、3gp等常见的音视频格式。
广义而言,MediaCodec的工作原理就是处理输入数据以产生输出数据。具体来说,MediaCodec在编解码的过程中使用了一组输入/输出缓存区来同步或异步处理数据:首先,客户端向获取到的编解码器输入缓存区写入要编解码的数据并将其提交给编解码器,待编解码器处理完毕后将其转存到编码器的输出缓存区,同时收回客户端对输入缓存区的所有权;然后,客户端从获取到编解码输出缓存区读取编码好的数据进行处理,待处理完毕后编解码器收回客户端对输出缓存区的所有权。不断重复整个过程,直至编码器停止工作或者异常退出。
mediacodec的作用是处理输入的数据生成输出数据。首先生成一个输入数据缓冲区,将数据填入缓冲区提供给codec,codec会采用异步的方式处理这些输入的数据,然后将填满输出缓冲区提供给消费者,消费者消费完后将缓冲区返还给codec。
二,MediaCodec编码过程
在整个编解码过程中,MediaCodec的使用会经历配置、启动、数据处理、停止、释放几个过程,相应的状态可归纳为停止(Stopped),执行(Executing)以及释放(Released)三个状态,而Stopped状态又可细分为未初始化(Uninitialized)、配置(Configured)、异常( Error),Executing状态也可细分为读写数据(Flushed)、运行(Running)和流结束(End-of-Stream)。
MediaCodec整个状态结构图如下:
从上图可知,当MediaCodec被创建后会进入未初始化状态,待设置好配置信息并调用start()启动后,MediaCodec会进入运行状态,并且可进行数据读写操作。如果在这个过程中出现了错误,MediaCodec会进入Stopped状态,我们就是要使用reset方法来重置编解码器,否则MediaCodec所持有的资源最终会被释放。当然,如果MediaCodec正常使用完毕,我们也可以向编解码器发送EOS指令,同时调用stop和release方法终止编解码器的使用。
三,MediaCodec API 说明
MediaCodec可以处理具体的视频流,主要有这几个方法:
- getInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组
- queueInputBuffer:输入流入队列
- dequeueInputBuffer:从输入流队列中取数据进行编码操作
- getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组
- dequeueOutputBuffer:从输出队列中取出编码操作之后的数据
- releaseOutputBuffer:处理完成,释放ByteBuffer数据
四,MediaCodec基本使用
所有的同步模式的 MediaCodec API都遵循一个模式:
创建并配置一个 MediaCodec 对象循环直到完成:如果输入缓冲区就绪,读取一个输入块,并复制到输入缓冲区中如果输出缓冲区就绪,复制输出缓冲区的数据释放 MediaCodec 对象
(1) 创建编/解码器
MediaCodec主要提供了createEncoderByType(String type)、createDecoderByType(String type)两个方法来创建编解码器,它们均需要传入一个MIME类型多媒体格式。常见的MIME类型多媒体格式如下:● “video/x-vnd.on2.vp8” - VP8 video (i.e. video in .webm)● “video/x-vnd.on2.vp9” - VP9 video (i.e. video in .webm)● “video/avc” - H.264/AVC video● “video/mp4v-es” - MPEG4 video● “video/3gpp” - H.263 video● “audio/3gpp” - AMR narrowband audio● “audio/amr-wb” - AMR wideband audio● “audio/mpeg” - MPEG1/2 audio layer III● “audio/mp4a-latm” - AAC audio (note, this is raw AAC packets, not packaged in LATM!)● “audio/vorbis” - vorbis audio● “audio/g711-alaw” - G.711 alaw audio● “audio/g711-mlaw” - G.711 ulaw audio当然,MediaCodec还提供了一个createByCodecName (String name)方法,支持使用组件的具体名称来创建编解码器。但是该方法使用起来有些麻烦,且官方是建议最好是配合MediaCodecList使用,因为MediaCodecList记录了所有可用的编解码器。当然,我们也可以使用该类对传入的minmeType参数进行判断,以匹配出MediaCodec对该mineType类型的编解码器是否支持。
以指定MIME类型为“video/avc”为例,代码如下:
private static MediaCodecInfo selectCodec(String mimeType) { // 获取所有支持编解码器数量 int numCodecs = MediaCodecList.getCodecCount(); for (int i = 0; i