MediaCodec基本原理及使用「建议收藏」

MediaCodec基本原理及使用「建议收藏」MediaCodec类Android提供的用于访问低层多媒体编/解码器接口,它是Android低层多媒体架构的一部分,通常与MediaExtractor、MediaMuxer、AudioTrack结合使用,能够编解码诸如H.264、H.265、AAC、3gp等常见的音视频格式。广义而言,MediaCodec的工作原理就是处理输入数据以产生输出数据。具体来说,MediaCodec在编解码的过程中使用了一组输入/输出缓存区来同步或异步处理数据:首先,客户端向获取到的编解码器输入缓存区写入要编解码的数据并将其提交

大家好,又见面了,我是你们的朋友全栈君。

MediaCodec工作原理

MediaCodec类Android提供的用于访问低层多媒体编/解码器接口,它是Android低层多媒体架构的一部分,通常与MediaExtractor、MediaMuxer、AudioTrack结合使用,能够编解码诸如H.264、H.265、AAC、3gp等常见的音视频格式。广义而言,MediaCodec的工作原理就是处理输入数据以产生输出数据。具体来说,MediaCodec在编解码的过程中使用了一组输入/输出缓存区来同步或异步处理数据:首先,客户端向获取到的编解码器输入缓存区写入要编解码的数据并将其提交给编解码器,待编解码器处理完毕后将其转存到编码器的输出缓存区,同时收回客户端对输入缓存区的所有权;然后,客户端从获取到编解码输出缓存区读取编码好的数据进行处理,待处理完毕后编解码器收回客户端对输出缓存区的所有权。不断重复整个过程,直至编码器停止工作或者异常退出。

MediaCodec基本原理及使用「建议收藏」

通过上图可以看出,mediacodec的作用是处理输入的数据生成输出数据。首先生成一个输入数据缓冲区,将数据填入缓冲区提供给codec,codec会采用异步的方式处理这些输入的数据,然后将填满输出缓冲区提供给消费者,消费者消费完后将缓冲区返还给codec。

MediaCodec编码过程

在整个编解码过程中,MediaCodec的使用会经历配置、启动、数据处理、停止、释放几个过程,相应的状态可归纳为停止(Stopped),执行(Executing)以及释放(Released)三个状态,而Stopped状态又可细分为未初始化(Uninitialized)、配置(Configured)、异常( Error),Executing状态也可细分为读写数据(Flushed)、运行(Running)和流结束(End-of-Stream)。MediaCodec整个状态结构图如下:

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 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 < 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;
 }

(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); 

以上代码是在编码H.264时的配置方法,createVideoFormat(“video/avc”, 640 ,480)为”video/avc”类型(即H.264)编码器的MediaFormat对象,需要指定视频数据的宽高,如果编解码音频数据,则调用MediaFormat的createAudioFormat(String mime, int sampleRate,int channelCount)的方法。除了一些诸如视频帧率、音频采样率等配置参数,这里需要着重讲解一下MediaFormat.KEY_COLOR_FORMAT配置属性,该属性用于指明video编码器的颜色格式,具体选择哪种颜色格式与输入的视频数据源颜色格式有关。比如,我们都知道Camera预览采集的图像流通常为NV21或YV12,那么编码器需要指定相应的颜色格式,否则编码得到的数据可能会出现花屏、叠影、颜色失真等现象。MediaCodecInfo.CodecCapabilities.存储了编码器所有支持的颜色格式,常见颜色格式映射如下:

原始数据 编码器 
NV12(YUV420sp) ———> COLOR_FormatYUV420PackedSemiPlanar 
NV21 ———-> COLOR_FormatYUV420SemiPlanar 
YV12(I420) ———-> COLOR_FormatYUV420Planar 

当编解码器配置完毕后,就可以调用MediaCodec的start()方法,该方法会调用低层native_start()方法来启动编码器,并调用低层方法ByteBuffer[] getBuffers(input)来开辟一系列输入、输出缓存区。start()方法源码如下:

public final void start() {
        native_start();
        synchronized(mBufferLock) {
            cacheBuffers(true /* input */);
            cacheBuffers(false /* input */);
        }
 }

(3) 数据处理

MediaCodec支持两种模式编解码器,即同步synchronous、异步asynchronous,所谓同步模式是指编解码器数据的输入和输出是同步的,编解码器只有处理输出完毕才会再次接收输入数据;而异步编解码器数据的输入和输出是异步的,编解码器不会等待输出数据处理完毕才再次接收输入数据。这里,我们主要介绍下同步编解码,因为这种方式我们用得比较多。我们知道当编解码器被启动后,每个编解码器都会拥有一组输入和输出缓存区,但是这些缓存区暂时无法被使用,只有通过MediaCodec的dequeueInputBuffer/dequeueOutputBuffer方法获取输入输出缓存区授权,通过返回的ID来操作这些缓存区。下面我们通过一段官方提供的代码,进行扩展分析:

MediaCodec codec = MediaCodec.createByCodecName(name);
 codec.configure(format, …);
 MediaFormat outputFormat = codec.getOutputFormat(); // option B
 codec.start();
 for (;;) { 
   
   int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
   if (inputBufferId >= 0) {
     ByteBuffer inputBuffer = codec.getInputBuffer(…);
     // fill inputBuffer with valid data
     …
     codec.queueInputBuffer(inputBufferId, …);
   }
   int outputBufferId = codec.dequeueOutputBuffer(…);
   if (outputBufferId >= 0) {
     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
     MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
     // bufferFormat is identical to outputFormat
     // outputBuffer is ready to be processed or rendered.
     …
     codec.releaseOutputBuffer(outputBufferId, …);
   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
     // Subsequent data will conform to new format.
     // Can ignore if using getOutputFormat(outputBufferId)
     outputFormat = codec.getOutputFormat(); // option B
   }
 }
 codec.stop();
 codec.release();

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

参考资料

Android MediaCodec实现多段音视频的截取与拼接
http://qkxue.net/info/170238/Android-MediaCodec

安卓解码器MediaCodec解析
https://rangaofei.github.io/2018/03/09/%E5%AE%89%E5%8D%93%E8%A7%A3%E7%A0%81%E5%99%A8MediaCodec%E8%A7%A3%E6%9E%90/

Android直播开发之旅(8):Android硬编解码接口MediaCodec原理剖析
https://blog.csdn.net/andrexpert/article/details/79578149

Android MediaCodec编解码详解及demo
https://www.jianshu.com/p/e6c683d6dbbe

Android 音视频开发(六): MediaCodec API 详解
https://www.cnblogs.com/renhui/p/7478527.html

Android 音视频开发(五):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件
https://www.cnblogs.com/renhui/p/7474096.html

Android硬编解码接口MediaCodec使用完全解析(一)
https://blog.csdn.net/u013028621/article/details/62417181/

android中MediaCodec类解析
https://www.jianshu.com/p/14da1baaf08f

Android音视频开发-入门(四):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件
https://www.jianshu.com/p/26c5305da513

Android分离合成音视频(用MediaExtractor和MediaMuxer)
https://blog.csdn.net/k_bb_666/article/details/79175510

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125018.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 关于数据库tinyint 字段的值范围「建议收藏」

    关于数据库tinyint 字段的值范围「建议收藏」tinyint从-2^7(-128)到2^7-1(123)的整型数据。存储大小为1个字节。unsigned是从0到255的整型数据。所以建表的时候只能是tinyint(3),哪怕你建tinyint(100),他最大还是3位这么多。转载于:https://www.cnblogs.com/jinhaidong/p/5944554.html…

  • 前端开发经验总结_前端开发实训总结报告

    前端开发经验总结_前端开发实训总结报告一、前端开发经验总结开发前与产品经理/UI对接需要注意:配色,字体,弹框/消息提示,响应式操作,设备屏幕比例,间距,是否多个主题,icon或者svg图标给出方式,图片大小,表格表单等等组件,页面注释便于理解和记录。最好有设计规范先出来再开始设计。开发前与后端对接需要注意:是否具有需求文档,返回的状态处理,容错处理,接口提交类型(get、post等)能否统一设置,参数类型设置,能否合理安排工期,能否又便捷的接口呈现方式(借用工具还是文档标注)。选择框架要慎重。搭框架包括:状态管理,网络管理,样式处理

  • C语言和JAVA的区别[通俗易懂]

    C语言和JAVA的区别[通俗易懂]java语言和c语言的区别:un公司推出的Java是面向对象程序设计语言,其适用于Internet应用的开发,称为网络时代重要的语言之一。Java可以用认为是C的衍生语言,与C在大量元以内成分保持相同,例如此法结构、表达式语句、运算符等与C基本一致:但Java更简洁,没有C中冗余以及容易引起异常的功能成分,并且增加了多线程、异常处理、网络编程等方面的支持功能。本文从多角度对Java与C进行对比分析,为C与Java语言的学习提高一些借鉴。1、调法结构C与Java的词法结构很相似,针对程

  • css3动画特效_css3动画效果大全

    css3动画特效_css3动画效果大全CSS3为我们带来了令人惊叹的新特性,而最有趣的就是CSS动画。今天彬Go向大家推荐这50个CSS动画集合可以让你通过使用JavaScript函数来让动画更生动。为了能够预览到这些惊人的CSS3技术带

  • 2023电子科技大学计算机考研信息汇总及答案_计算机考研难度排行榜

    2023电子科技大学计算机考研信息汇总及答案_计算机考研难度排行榜N诺小程序-计算机学习考研必备神器电子科技大学计算机科学与工程学院电子科技大学信息与软件工程学院电子科技大学基础与前沿研究院电子科技大学电子科学技术研究院电子科技大学通信抗干扰技术国家级重点实验室电子科技大学数学科学学院电子科技大学(UniversityofElectronicScienceandTechnologyofChina)坐落于四川省会成都市,直属中华人民共和国教育部,由教育部、工业和信息化部、四川省和成都市共建。是国家“…

  • java教程安装_java 安装教程

    java教程安装_java 安装教程直接运行exe可执行程序,默认安装即可;备注:路径可以选其他盘符,不建议路径包含中文名及特殊符号。3、配置环境变量1)新建变量名:JAVA_HOME,变量值:C:\ProgramFiles\Java\jdk1.8.0_112)打开PATH,添加变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin3)新建变量名:CLASSPATH,变量值:.;%JAVA_HOME%…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号