转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiophttp://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过程(附实例)的更多相关文章

  1. Android Multimedia框架总结(十五)Camera框架之Camera2补充

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...

  2. Android Multimedia框架总结(十二)CodeC部分之OMXCodec与OMX事件回调流程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629449 前言:上篇文中分析 ...

  3. Android Multimedia框架总结(十)Stagefright框架之音视频输出过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012 前言:上篇文中最后 ...

  4. Android Multimedia框架总结(十九)Camera2框架C/S模型之CameraService启动及与Client连接过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53150322 Agenda: 一 ...

  5. Android Multimedia框架总结(十六)Camera2框架之openCamera及session过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52942533 前言:前一篇介绍了 ...

  6. Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...

  7. Android Multimedia框架总结(十八)Camera2框架从Java层到C++层类关系

    Agenda: getSystemService(Context.CAMERA_SERVICE) CameraManager.getCameraIdList() ICameraService.aidl ...

  8. Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882 前言:上篇文< ...

  9. Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085 不知不觉到第九篇了,感觉还有 ...

随机推荐

  1. python 作业 编写登陆接口

    # -*- coding:utf-8 -*-import os,sysfor i in range(3):#进行3次循环 blacklist = open(r"C:\Users\Pc4\De ...

  2. javascript的基础(2)--数据类型介绍

    1. number数据类型 所有的数字都是Number数据类型 利用typeof运算符可以返回当前数据的数据类型 特殊值:NaN not a number 不是一个数字 注意 :小数的计算可能产生丢失 ...

  3. [HNOI2003]激光炸弹

    Description 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标.现在地图上有n个目标,用整数,表示目标在地图上的位置,每个目标都有一个价值.激光炸弹的投放是通过卫星定位的,但其 ...

  4. [Ahoi2005]LANE 航线规划

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  5. hdu 5442 (后缀数组)

    稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题).  /*推荐 <后缀数组——处理字符串的有力工具>— ...

  6. [Codeforces Round#417 Div.2]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 有毒的一场div2 找了个1300的小号,结果B题题目看错没交  D题题目剧毒 E题差了10秒钟没交上去. 233 ------- A.Sag ...

  7. QSDK下驱动AR8035

    0 概述 QSDK平台中,我所接触到的版本,能支持MIPS架构的,是基于Openwrt AA版本:虽然CC版本上就已经能很好地支持AR8035了,可是AA版本它本身是不支持的,于是不断有人要求提供补丁 ...

  8. Java面试题—初级(8)

    基本表结构:  student(sno,sname,sage,ssex)学生表        course(cno,cname,tno) 课程表        sc(sno,cno,score) 成绩 ...

  9. java开发笔记——表映射实体类代码示例

    package com.special.ipmsdm; import java.io.Serializable; import javax.persistence.Column; import jav ...

  10. C语言中如何调用另一个源文件里的函数

    在开发大型项目时,我们常常需要将一份源码分成多个源文件来进行编写,这样可以方便后期的维护.下面就介绍如何从一个源文件里调用另一个源文件的函数. 在源文件A1.c中调用A2.c 中的函数有两种方法: 1 ...