*由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不恰当之处,望批评指正。

*转载请注明出处:http://www.cnblogs.com/roger-yu/

概述

Android MediaCodec可以访问底层的media codecs,我们很容易利用MediaCodec来构建encoder或decoder来实现音视频编码和音视频解码的功能。

简单点儿理解,一个Codec(可以认为是一个MediaCodec的实例对象)就相当于一个“处理器”:处理输入数据,并产生输出数据。

如下图所示,每一个Codec都维护着一组 input buffers 和 output buffers。开始时Codec拥有所有buffers的所有权,Client(可以暂且理解为MediaCodec之外写的程序)无法向 input buffer 写入数据,也无法读取 output buffer 中的数据。数据处理开始后,Client向Codec请求一个(同步模式)或者接收到(异步模式)一个空的 input buffer,将要处理的数据写入到该buffer中,然后提交给Codec处理,Codec处理完数据后会将处理的结果写入到一个空的 output buffer 中,之后Client就可以请求或接收到这个存有结果的 output buffer,Client对结果使用完毕后就可以release这个output buffer,Codec就可以再次使用这个buffer,如此过程完成整个的处理。

Android MediaCodec主要有3种数据处理的方式:

  1. 使用Buffers的异步处理方式(Asynchronous Processing using Buffers)

  2. 使用Buffers的同步处理方式(Synchronous Processing using Buffers)

  3. 使用Buffer数组的同步处理方式(Synchronous Processing using Buffer Arrays (deprecated))

依据Android版本不同可以采用不同的方式,如下图:

目前最常用的是前两种模式,故接下来重点讲解。

使用Buffers的异步处理方式(Asynchronous Processing using Buffers)

基本处理流程:

注意:

  1. 在调用configure配置MediaCodec之前需要为MediaCodec设置callback,需要实现MediaCodec.Callback接口并重写其中的方法:onInputBufferAvailable 、onOutputBufferAvailable、onOutputFormatChanged、onError,工作时MediaCodec会利用    这四个回调方法来自动的通知Client什么时候input buffer有效,什么时候output buffer有效,什么时候media format发生变化,什么时候运行出错,也是在这些方法中Client向Codec送入数据并得到处理的结果及获取Codec的一些其他信息。

  2. 异步模式下MediaCodec的状态转换会有些许不同,在调用start方法后会直接进入Running状态;

  异步处理模式下,调用MediaCodec.start()后Codec 立即进入Running子状态,通过设置的callback中的回调方法onInputBufferAvailable()会自动收到可用(empty)的input buffer,此时可以根据input buffer id调用getInputBuffer(id)得到这个buffer,并将需要的处理的数据写入该buffer中,最后调用queueInputBuffer(id, ...)将该buffer提交给Codec处理;Codec每处理完一帧数据就会将处理结果写入一个空的output buffer,并通过回调函数onOutputBufferAvailable来通知Client来读取结果,Client可以根据output bufffer id调用getOutputBuffer(id)获取该buffer并读取结果,完毕后可以调用releaseOutputBuffer(id, ...)释放该buffer给Codec再次使用。

典型的代码设计:

 MediaCodec codec = MediaCodec.createByCodecName(name);
MediaFormat mOutputFormat; // member variable
// 异步模式下需要在configure之前设置callback
codec.setCallback(new MediaCodec.Callback() { /**
* 在onInputBufferAvailable回调方法中,MediaCodec会通知什么时候input
* buffer有效,根据buffer id,调用getInputBuffer(id)可以获得这个buffer,
* 此时就可以向这个buffer中写入数据,最后调用queueInputBuffer(id, …)提交
* 给MediaCodec处理。
*/
@Override
void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
// fill inputBuffer with valid data

codec.queueInputBuffer(inputBufferId, …);
} /**
* 在onOutputBufferAvailable回调方法中,MediaCodec会通知什么时候output
* buffer有效,根据buffer id,调用getOutputBuffer(id)可以获得这个buffer,
* 此时就可以读取这个buffer中的数据,最后调用releaseOutputBuffer(id, …)释放
* 给MediaCodec再次使用。
*/ @Override
void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
// bufferFormat is equivalent to mOutputFormat
// outputBuffer is ready to be processed or rendered.

codec.releaseOutputBuffer(outputBufferId, …);
}
  /**
* 当MediaCodec的output format发生变化是会回调该方法,一般在start之后都会首先回调该方法
*/
@Override
void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
mOutputFormat = format; // option B
}
/**
* MediaCodec运行发生错误时会回调该方法
*/
@Override
void onError(…) {

}
});
codec.configure(format, …);
mOutputFormat = codec.getOutputFormat(); // option B
codec.start(); // start 之后MediaCodec立即进入Running子状态,并会回调callback中的方法
// wait for processing to complete
codec.stop(); // stop后MediaCodec进入Uninitialized子状态
codec.release(); //使用完毕要释放掉MediaCdoec占用的资源

使用Buffers的同步处理方式(Synchronous Processing using Buffers)

基本处理流程:

  同步模式下,MediaCodec调用start()方法后会进入Flushed子状态,然后第一次调用dequeueInputBuffer()后才会进入Running子状态。

  这种模式下,程序需要在一个无限循环中通过调用dequeueInputBuffer(...)和dequeueOutputBuffer(...)来不断地请求Codec是否有可用的input buffer 或 output buffer:

      > 如果有可用的input buffer:根据得到的buffer id,调用getInputBuffer(id)获取该buffer,并向其中写入待处理的数据,然后调用queueInputBuffer(id,..)提交到Codec进行处理

      > 如果有可用的output buffer: 根据得到的buffer id,调用getOutputBuffer(id)获取该buffer,读取其中的处理结果,然后调用releaseOutputBuffer(id,..)释放该buffer供Codec再次使用

      > 处理过程中还可能受到一些特殊标记的buffer id,比如MediaCodec.INFO_OUTPUT_FORMAT_CHANGED,要作出恰当处理

典型的代码设计:

  MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, ...);
MediaFormat outputFormat = codec.getOutputFormat(); // option B
codec.start(); // start()方法后会进入Flushed子状态
/**
* 在一个无限循环中不断地请求Codec是否有可用的input buffer 或 output buffer
*/
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(timeoutUs); // 请求是否有可用的input buffer
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = codec.getInputBuffer(...); // 获取input buffer
// fill inputBuffer with valid data
...
codec.queueInputBuffer(inputBufferId, ...); // 提交数据给Codec
}
int outputBufferId = codec.dequeueOutputBuffer(...); // 请求是否有可用的output buffer
if (outputBufferId >= 0) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId); // 获取output buffer
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
// bufferFormat is identical to outputFormat
// outputBuffer is ready to be processed or rendered.
...
codec.releaseOutputBuffer(outputBufferId, ...); // 释放output buffer供Codec再次使用
} 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(); //释放资源

异步模式与同步模式的区别在于:

  》异步模式下通过回调函数来自动的传递可用的input buffer 或 output buffer

  》同步模式下需要通过dequeueInputBuffer(...)或dequeueOutputBuffer(...)来请求获取可用的input buffer 或 output buffer

微信扫一扫,关注玖零日记,获取更多相关资讯及源码 -- 虽无面朝大海,依旧春暖花开

Android MediaCodec的数据处理方式分析的更多相关文章

  1. Android MediaCodec 状态(States)转换分析

    *由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不 ...

  2. Android WebView的缓存方式分析

    WebView的缓存可以分为(1)页面缓存和(2)数据缓存. 页面缓存是指当WebView加载一个网页时的html.JS.CSS等页面或者资源数据.这些缓存资源是由于浏览器的行为而产生,开发者只能通过 ...

  3. Android笔记:触摸事件的分析与总结----TouchEvent处理机制

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://glblong.blog.51cto.com/3058613/1559320   ...

  4. OpenGL—Android 开机动画源码分析一

    .1 Android开机动画实现方式目前实现Android开机动画的方式主要是逐帧动画和OpenGL动画. ?逐帧动画 逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的 ...

  5. 第四次作业——关于石墨文档(Android)客户端的案例分析

    关于石墨文档(Android)客户端的案例分析 作业地址:[https://edu.cnblogs.com/campus/nenu/2016CS/homework/2505] 第一部分调研,评测 1. ...

  6. 理解Android绘制视图的方式

    在创建自定义ViewGroup前,读者首先需要理解Android绘制视图的方式.我不会涉及过多细节,但是需要读者理解Android开发文档(见3.5节)中的一段话,这段话解释如何绘制一个布局.内容如下 ...

  7. Android:日常学习笔记(2)——分析第一个Android应用程序

    Android:日常学习笔记(2)——分析第一个Android应用程序 Android项目结构 整体目录结构分析 说明: 除了APP目录外,其他目录都是自动生成的.APP目录的下的内容才是我们的工作重 ...

  8. Wps 2013 拼音标注两种方式分析

    Wps 2013 拼音标注两种方式分析 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转 ...

  9. Android A/B System OTA分析(一)概览【转】

    本文转载自:https://blog.csdn.net/guyongqiangx/article/details/71334889 Android从7.0开始引入新的OTA升级方式,A/B Syste ...

随机推荐

  1. charles mock方法及问题

    一. 抓包后修改返回数据1.生成一个完成的请求返回信息1.charles抓取一个完整的请求,返回数据2.然后找到该请求,右键“save response”,将该完整请求返回文件保存至本地3.修改本地需 ...

  2. WAP网页中点击链接直接拨打电话的方法

    主要方法有两种: 第一种: 这种也是最简单的. 示例代码: <a href="tel:+18790853577">点击拨打</a> 第二种: <a h ...

  3. Spring IOC 低级容器解析

    1.IOC是什么 IOC-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...

  4. poj12482 扫描线+lazy-tag

    采用扫描线的思想,其实是区间更新的题目 题解链接https://blog.csdn.net/shiqi_614/article/details/7819232 注意处理细节:1)因为边框上的点不算,所 ...

  5. IntelliJ IDEA像Eclipse一样打开多个项目(转)

    转自: 海涛zht666   IntelliJ IDEA像Eclipse一样打开多个项目 我们做项目实际中经常会遇到这样的情况,创建一个common项目(Maven项目)作为公用项目,common中有 ...

  6. 注解工具ButterKnife用法和注意点

    // implementation 'com.android.support:appcompat-v7:28.0.0-Beta1' // implementation 'com.android.sup ...

  7. SG 大法(Sprague-Grundy函数)

    SG函数的定义: g(x) = mex ( sg(y) |y是x的后继结点 ) 其中mex(x)(x是一个自然是集合)函数是x关于自然数集合的补集中的最小值,比如x={0,1,2,4,6} 则mex( ...

  8. NodeMCU入门(1):刷入At固件,透传数据到TcpServer和Yeelink平台

    准备工作 1. NodeMCU  LUA ESP8266 CP2102  WIFI Internet Development Board,仔细看背面可以看出自带cp2102模块,可以通过普通的手机充电 ...

  9. 3.Django| 视图层| 模板层

    1.视图函数 文件在view_demo 一个视图函数简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XM ...

  10. Qt学习之信号与槽(一)

    Qt学习之信号与槽(一) 目录 QT的信号与槽机制 在窗口的UI设计中操作添加信号和槽     QT的信号与槽机制   QT的两种机制 在Qt和PyQt中有两种通信机制: 低级事件处理机制(low-l ...