Android Multimedia框架总结(二十)MediaCodec状态周期及Codec与输入/输出Buffer过程(附实例)
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718
前言:前面几节都是介绍Camera2相关,对于Camera2预览把图像显示在SurfaceView上,还有录像时,时时刷新当前图像区域。追溯到最早介绍的MediaPlayer播放视频,这些都离不开重要角色MediaCodec,今天介绍MediaCodec,看下Agenda:
- MediaCodec是什么?
- codec操作的数据类型
- 压缩buffer
- 原始音频buffer
- 原始视频buffer
- MediaCodec状态周期图
- Codec-specific数据
- Codec数据处理过程
- MediaCodec案例
MediaCodec是什么?
MediaCodec类可以访问底层媒体编解码器框架(StageFright或openMAX),即编码器/解码器组件。这是Android low-level多媒体支持基础设施的一部分(通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, and AudioTrack.一起使用))。
从广义上讲,codec处理输入数据产生输出数据。异步处理数据,并使用一组输入和输出buffer。在简单的层面,请求(或接收)空输入缓冲区,加满数据并将其发送到codec进行处理。codec使用的数据转换成一个空的输出缓冲区。最后,请求(或接收)输出buffer,消耗其内容并释放它回codec。
codec操作的数据类型
codec操作三种数据:压缩数据,原始音频数据和原始的视频数据。所有这三种数据可以使用ByteBuffers处理,应该对原始视频数据使用一个Surface来提高编码性能。Surface使用native视频的buffers没有映射或复制他们ByteBuffers;因此,它更高效。通常不能访问原始视频数据使用一个Surface时,可以使用ImageReader类访问未固定的解码视频帧(原生)。比起使用ByteBuffers的话,这可能会更有效的,一些native 的buffers可能直接映射到ByteBuffers。当使用ByteBuffer模式中,您可以使用Image类及getInput / OutputImage(int)访问原始视频帧。
压缩buffer
输入缓冲区(解码器)和输出缓冲区(编码器)包含压缩数据格式的类型。对于视频类型,这是一个压缩的视频帧。对于音频数据,这通常是一个单一的访问单元(一个音频段通常包含几毫秒的音频编码格式决定的类型),但这个需求略有放松,缓冲区可能包含多个接入单位的音频编码。在这两种情况下,在任意字byte边界上,buffer不会start和end,直到在(帧/访问)unit边界上。
原始音频buffer
原始音频缓冲区包含整个PCM音频帧数据,下面是一个示例为每个通道的通道顺序。每一个样例都是16位带符号整数在native byte通道中。
short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
MediaFormat format = codec.getOutputFormat(bufferId);
ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
int numChannels = formet.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
if (channelIx < 0 || channelIx >= numChannels) {
return null;
}
short[] res = new short[samples.remaining() / numChannels];
for (int i = 0; i < res.length; ++i) {
res[i] = samples.get(i * numChannels + channelIx);
}
return res;
}
原始视频buffer
ByteBuffer模式视频缓冲区根据他们的颜色格式布局。你可以从getCodecInfo().getCapabilitiesForType .colorFormats(…)得到支持的颜色格式数组。视频编解码器支持三种颜色格式:
- native raw video format: 带有COLOR_FormatSurface标记,并用于输入/输出到Surface.
- flexible YUV buffers (带有COLOR_FormatYUV420Flexible): 当在 ByteBuffer 模式下,通过getInput/OutputImage(int)方法,也用于输入/输出到Surface.
- specific formats: 这些都是通常只支持ByteBuffer模式,一些特定于供应商的颜色格式,其他人则MediaCodecInfo.CodecCapabilities中定义,对于color formats ,相当于一个灵活的格式,你依旧可以使用getInput/OutputImage(int)
自LOLLIPOP_MR1开始,所有视频编解码器支持灵活的YUV 4:2:0的buffer
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718
MediaCodec状态
在codec的生命周期的概念上存在三种状态之一:Stopped, Executing or Released. 。停止所有状态实际上是聚集的三种状态:Uninitialized, Configured and Error,而执行状态概念上的进展通过三个子状态:Flushed, Running and End-of-Stream。
当您使用一个工厂方法创建一个codec时,codec处于未初始化的状态。首先,您需要配置它通过configue(…),这让它处于配置的状态,然后调用start()方法将它移动到Executing状态。在这种状态下你可以通过上述缓冲队列操作过程数据。
执行状态有三个子状态:Flushed, Running and End-of-Stream。在start()方法调用后,codec会立刻刷新子状态,它拥有所有的buffer。一旦第一个输入buffer从列中移除,codec将花费比较长的时间移动到正在运行的子状态上。当你队列的输入buffer带有end-of-stream标记,codec将转换到end-of-stream子状态。在这种状态下的codec不再接受进一步输入buffer,但仍然生成输出缓冲区,直到达到end-of-stream输出。你可以移回到Flushed子状态在任何时候当在Executing 状态时使用flush()方法。
调用stop()方法返回的codec未初始化(Uninitialized)状态,因为它可能是再次被配置了。当你再使用一个编解码器(codec),你必须释放它通过调用release()方法。
在极少数情况下的codec可能会遇到一个错误,Error状态。这是沟通使用无效的返回值从一个队列操作,或者通过一个例外。调用reset()方法让编解码器(codec)能再次可用。你可以调用它 把当前的任何状态转移到Uninitialized状态,否则,调用release()方法,回到终端Released状态。
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718
Codec-specific数据
一些格式,特别是AAC音频和MPEG4,H.264和H.265视频格式需要通过大量的buffer包含设置数据,或codec特定数据来作为真实数据的开头。在处理这样的压缩格式时,在任意帧数据开始前,调用start方法后,这个数据必须提交给codec。当在调用queueInputBuffer时,这些数据必须使用flag:BUFFER_FLAG_CODEC_CONFIG。
Codec-specific数据也可以包含在ByteBuffer条目的格式传递给配置钥匙“csd-0”、“csd-1”,等等。这些钥匙总是包含在跟踪MediaFormat从MediaExtractor获得。Codec-specific数据格式自动提交给codec在start调用;你不能明确地提交这些数据。如果不包含编码特定的数据格式,你可以选择提交使用指定的缓冲区以正确的顺序,按照格式要求。对于H.264 AVC,您还可以连接所有codec-specific数据并提交它作为单个codec-config缓冲区。
Android使用以下codec-specific数据缓冲区。这些也需要跟踪格式中设置适当的MediaMuxer track 配置。每个参数设置和codec-specific-data部分标注(*)必须从以”\x00\x00\x00\x01”开始。
注意:必须注意codec在start之后马上刷新,在任何output buffer或输出格式被改变被返回之前, codec specific data也许会丢失在刷新过程中。在这种刷新时,要确保合适的codec操作不出问题,必须要重提交data,使用带BUFFER_FLAG_CODEC_CONFIG标志的buffers。
在任意有效的output buffers输出的buffer带有codec-config 标志前,编码器(或codec生成压缩数据)将创建并返回编码特定的数据。buffer包含codec-specific-data没有意义的时间戳。
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718
Codec数据处理过程
每个codec维护的一组输入和输出buffer被指向在API调用的buffer-ID。成功调用start()方法后,client“拥有”输入和输出buffer。在同步模式下,调用dequeueInput / OutputBuffer(…)来获得(所有权)codec的输入或输出buffer。在异步模式下,您通过MediaCodec.Callback.onInput / OutputBufferAvailable(…)回调方法将自动接收buffer。
在获得一个输入缓冲区,填入数据并提交它的codec使用queueInputBuffer——或者queueSecureInputBuffer如果使用解密。不要使用相同的时间戳提交多个输入buffer(除非codec-specific数据被标记为)。
codec在异步模式下通过onOutputBufferAvailable回调方法将返回一个只读输出buffer,或在同步模式下响应dequeuOutputBuffer调用。在输出buffer被处理后,调用一个releaseOutputBuffer方法返回codec的buffer。
当你不需要重新提交/立即释放codec的buffer,抓住输入和/或输出buffer可能在codec中延后,这种情况和设备相关。具体地说,codec可能暂缓生成输出buffer,直到所有buffer的未发布/重新提交。因此,试图得到可用buffer尽可能少。
根据API版本,您可以在三个方面:处理数据
异步处理使用缓冲区
自LOLLIPOP开始,首选的方法处理异步过程数据是通过设置一个回调在调用配置之前。异步模式改变了状态转换,因为刷新后必须调用start()方法的codec过渡到正在运行的子状态,开始接收输入buffer。同样,在一个初始直接调用开始后,codec将正在运行的子状态,开始通过回调传递可用的输入buffer。
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718
案例
此前我们曾用MediaPlayer播放网络视频及本地视频,今天不用MediaPlayer,转而用MediaCodec来Codec一个视频到SurfaceView上,下面看代码:
效果图
案例工程已上传到github:https://github.com/hejunlin2013/MultiMediaSample,之前其他多媒体框架相关案例也在此仓库中。
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
Android Multimedia框架总结(二十)MediaCodec状态周期及Codec与输入/输出Buffer过程(附实例)的更多相关文章
- Android Multimedia框架总结(十五)Camera框架之Camera2补充
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...
- Android Multimedia框架总结(十二)CodeC部分之OMXCodec与OMX事件回调流程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629449 前言:上篇文中分析 ...
- Android Multimedia框架总结(十)Stagefright框架之音视频输出过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012 前言:上篇文中最后 ...
- Android Multimedia框架总结(十九)Camera2框架C/S模型之CameraService启动及与Client连接过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53150322 Agenda: 一 ...
- Android Multimedia框架总结(十六)Camera2框架之openCamera及session过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52942533 前言:前一篇介绍了 ...
- Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...
- Android Multimedia框架总结(十八)Camera2框架从Java层到C++层类关系
Agenda: getSystemService(Context.CAMERA_SERVICE) CameraManager.getCameraIdList() ICameraService.aidl ...
- Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882 前言:上篇文< ...
- Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085 不知不觉到第九篇了,感觉还有 ...
随机推荐
- java面试2(java技术栈和Hollis面试内容分享)
1.什么是java虚拟机? java虚拟机(JVM)是一个可执行java字节码的虚拟机进程,java源文件被编译成能被java虚拟机可执行的字节码文件. 2.什么是平台无关性,java是如何做到平台无 ...
- 视觉slam学习之路(一)看高翔十四讲所遇到的问题
目前实验室做机器人,主要分三个方向,定位导航,建图,图像识别,之前做的也是做了下Qt上位机,后面又弄红外识别,因为这学期上课也没怎么花时间在项目,然后导师让我们确定一个方向来,便于以后发论文什么. ...
- [SDOI 2010]外星千足虫
Description 题库链接 给出 \(m\) 个 \(n\) 元的 \(0,1\) 方程,即系数非 \(0\) 即 \(1\) ,方程的结果为奇偶性. \(1\leq n\leq 1000,1\ ...
- [HAOI2009]逆序对数列
题目描述 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样 ...
- UVA11795 Mega Man's Mission
状压dp #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> ...
- 【LSGDOJ 2015】数页码
题目描述 一本书的页码是从 1-n 编号的连续整数:1, 2, 3, ... , n.请你求出全部页码中所有单个数字的和,例如第 123 页,它的和就是 1+2+3=6. 输入 一行为 n(1 < ...
- 【LSGDOJ 1351】关灯
题目描述 多瑞卡得到了一份有趣而高薪的工作.每天早晨他必须关掉他所在村庄的街灯.所有的街灯都被设置在一条直路的同一侧. 多瑞卡每晚到早晨 5 点钟都在晚会上,然后他开始关灯.开始时,他站在某一盏路灯的 ...
- ●BZOJ 4826 [Hnoi2017]影魔
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4826 题解: 主席树,单调栈 以前还没做过这种维护信息的题,感觉好奇妙. 每对相邻的两个数所 ...
- hdu 5592 BestCoder Round #65(树状数组)
题意: ZYB有一个排列PP,但他只记得PP中每个前缀区间的逆序对数,现在他要求你还原这个排列. (i,j)(i < j)(i,j)(i<j)被称为一对逆序对当且仅当A_i>A_jA ...
- [BZOJ]1045 糖果传递(HAOI2008)
放一道数学题. Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数n<=1000000,表示 ...