实现音视频编解码工具 MediaCodec 创建解码器

2022-08-30  本文已影响0人  程序老秃子

前言

Android 开发中提供了实现音视频编解码工具 MediaCodec针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作

MediaCodec

MediaCodec 所支持的数据类型:压缩的音视频数据、原始音频数据和原始视频数据;首先 show 代码,紧接着之前 MediaExtactor 提取资源, MediaCodecList 遍历支持格式,确认设置支持该资源格式后通过 MediaCodec 创建解码器(这里是做视频解码播放)

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可以处理具体的视频流,主要有这几个方法:

基本使用

所有的同步模式的 MediaCodec API都遵循一个模式:

(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 < numCodecs; i++) {
        // 编解码器相关性信息存储在MediaCodecInfo中
         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
         // 判断是否为编码器
         if (!codecInfo.isEncoder()) {
             continue;
         }
        // 获取编码器支持的MIME类型,并进行匹配
         String[] types = codecInfo.getSupportedTypes();
         for (int j = 0; j < types.length; j++) {
             if (types[j].equalsIgnoreCase(mimeType)) {
                 return codecInfo;
             }
         }
     }
     return null;
 }
123456789101112131415161718192021

(2) 配置、启动编/解码器

编解码器配置使用的是 MediaCodec 的 configure 方法,该方法首先对 MediaFormat 存储的数据 map 进行提取,然后调用本地方法 native-configure 实现对编解码器的配置工作

在配置时,configure 方法需要传入format、surface、crypto、flags 参数,其中 format 为 MediaFormat 的实例,它使用 ”key-value” 键值对的形式存储多媒体数据格式信息; surface 用于指明解码器的数据源来自于该 surface

crypto 用于指定一个 MediaCrypto 对象,以便对媒体数据进行安全解密;flags指明配置的是编码器(CONFIGURE_FLAG_ENCODE)

MediaFormat mFormat = MediaFormat.createVideoFormat("video/avc", 640 ,480);     // 创建MediaFormat
mFormat.setInteger(MediaFormat.KEY_BIT_RATE,600);       // 指定比特率
mFormat.setInteger(MediaFormat.KEY_FRAME_RATE,30);  // 指定帧率
mFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,mColorFormat);  // 指定编码器颜色格式  
mFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,10); // 指定关键帧时间间隔
mVideoEncodec.configure(mFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE); 
1234567

从上面代码可知,当编解码器 start 后,会进入一个 for(;;)循环,该循环是一个死循环,以实现不断地去从编解码器的输入缓存池中获取包含数据的一个缓存区,然后再从输出缓存池中获取编解码好的输出数据

尽可能实际地,由类定义的 hashCode 方法 Object 为不同的对象返回不同的整数(这通常是通过将对象的内部地址转换成整数来实现的,但是Java编程语言并不要求这种实现技术)

本文 全面介绍了 LiveData 的生命周期是如何变化的 希望大家在开发时尽量避免出现 因生命周期变化而出现的问题

为了是大家能够更好的学习 音视频开发, 在这里特别提供一份 高级音视频开发学习笔记;里面包含了这些年学习 音视频开发所遇到的难题及其解决方案; 有需要这份 高级音视频开发学习笔记 的朋友: 可以简信 发送 “笔记” 即可 免费获取; 希望大家阅读过后,能够 查漏补缺;早日成为高级音视频开发者

内容展示如下:

高级音视频开发学习笔记目录

H264 编码基础 06 -- 编码标准之战

H264 编码基础 01 帧与场

有需要完整版高级音视频开发学习笔记的朋友:可以 简信 发送 “笔记” 即可 免费获取

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

加油!让我们早日成为音视频高级开发者

上一篇下一篇

猜你喜欢

热点阅读