Android MediaCodec的数据处理方式分析

编程之家收集整理的这篇文章主要介绍了Android MediaCodec的数据处理方式分析编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

 

*由于工作需要,需要利用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再次使用。

典型的代码设计:

 1 MediaCodec codec = MediaCodec.createByCodecName(name);
 2 MediaFormat mOutputFormat; // member variable
 3  异步模式下需要在configure之前设置callback
 4 codec.setCallback(new MediaCodec.Callback() {
 5 
 6     /**
 7      * 在onInputBufferAvailable回调方法中,MediaCodec会通知什么时候input
 8      * buffer有效,根据buffer id,调用getInputBuffer(id)可以获得这个buffer,
 9      * 此时就可以向这个buffer中写入数据,最后调用queueInputBuffer(id,…)提交
10      * 给MediaCodec处理。
11      */
12     @Override
13     void onInputBufferAvailable(MediaCodec mc,int inputBufferId) {
14     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
15      fill inputBuffer with valid data
16 17     codec.queueInputBuffer(inputBufferId,…);
18     }
19 
20     21      * 在onOutputBufferAvailable回调方法中,MediaCodec会通知什么时候output
22      * buffer有效,根据buffer id,调用getOutputBuffer(id)可以获得这个buffer,
23      * 此时就可以读取这个buffer中的数据,最后调用releaSEOutputBuffer(id,…)释放
24      * 给MediaCodec再次使用。
25      26 
27 28     void onOutputBufferAvailable(MediaCodec mc,1)"> outputBufferId,…)     {
29         ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
30         MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId);  option A
31          bufferFormat is equivalent to mOutputFormat
32          outputBuffer is ready to be processed or rendered.
33 34         codec.releaSEOutputBuffer(outputBufferId,1)">35 36   37     * 当MediaCodec的output format发生变化是会回调该方法,一般在start之后都会首先回调该方法
38     39 40     void onOutputFormatChanged(MediaCodec mc,MediaFormat format) {
41          Subsequent data will conform to new format.
42          Can ignore if using getOutputFormat(outputBufferId)
43         mOutputFormat = format;  option B
44 45     46      * MediaCodec运行发生错误时会回调该方法
47      48 49      onError(…) {
50 51 52 });
53 codec.configure(format,1)">54 mOutputFormat = codec.getOutputFormat(); 55 codec.start();  start 之后MediaCodec立即进入Running子状态,并会回调callback中的方法
56  wait for processing to complete
57 codec.stop();   stop后MediaCodec进入Uninitialized子状态
58 codec.release(); 使用完毕要释放掉MediaCdoec占用的资源                   
View Code

 

 使用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,要作出恰当处理

典型的代码设计:

 

 1  MediaCodec codec = 2  codec.configure(format,...);
 3  MediaFormat outputFormat = codec.getOutputFormat();  4  codec.start();   start()方法后会进入Flushed子状态
 5   6   * 在一个无限循环中不断地请求Codec是否有可用的input buffer 或 output buffer
 7    8  for (;;) {
 9      int inputBufferId = codec.dequeueInputBuffer(timeoutUs);  请求是否有可用的input buffer
10      if (inputBufferId >= 0) {
11          ByteBuffer inputBuffer = codec.getInputBuffer(...);  获取input buffer
12          13          ...
14          codec.queueInputBuffer(inputBufferId,...);  提交数据给Codec
15      }
16      int outputBufferId = codec.dequeueOutputBuffer(...);  请求是否有可用的output buffer
17      if (outputBufferId >= 018          ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);  获取output buffer
19          MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); 20           bufferFormat is identical to outputFormat
21          23          codec.releaSEOutputBuffer(outputBufferId,1)"> 释放output buffer供Codec再次使用
24      } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
25          26          27          outputFormat = codec.getOutputFormat(); 28 29   }
30   codec.stop(); 
31   codec.release(); 释放资源
View Code

 

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

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

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

 

 

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

 

 

 

总结

以上是编程之家为你收集整理的Android MediaCodec的数据处理方式分析全部内容,希望文章能够帮你解决Android MediaCodec的数据处理方式分析所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢寻找一群志同道合、互帮互助的学习伙伴,可以点击下方链接加入:
编程之家官方1群
编程之家官方2群
编程之家官方3群
编程之家官方4群

相关文章

猜你在找的Android相关文章

为防止盗链,本文首发于于果的博客,转载请注明出处!原文链接:https://www.cnblogs.com/yuxiuyan/p/14524302.html, 前语 最近,Android手机上的手机管
︿( ̄︶ ̄)︿ 子曰:溫故而知新,可以為師矣。《論語》 学习技术也一样,对于技术文档或者经典的技术书籍来说,指望看一遍就完全掌握,那基本不大可能,所以我们需要经常回过头再仔细研读几遍,以领悟到作者的思
基本概念: I frame :帧内编码帧 又称intra picture,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。
本文系作者自己学习之所用,文章内容仅出自作者拙劣之思考,问题之处烦请不吝指教。 MediaPlayer 能被用来控制音/视频文件或流媒体的回放。Android中以MediaPlayer类作为音视频播放
*由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不
在Android中可以使用MediaPlayer+SurfaceView来实现一个简单的多媒体播放器。 一 构造函数 java MediaPlayer class 的源码位置:frameworksb
前言 最近Android对于文件的许多方法进行了修改,网络上又没有对Android4到Android11关于系统相机、系统相册和系统裁剪的适配方案,我花了几天事件总结了一下,先上源码 DEMO源码 先
本文主要介绍了适配Android10调用系统相册,系统相机,系统裁剪和对应上传操作
微信公众号搜索 “ 程序精选 ” ,选择关注!
微信公众号搜 "程序精选"关注