*由于工作需要,需要利用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 @OverrIDe13 voID oninputBufferAvailable(MediaCodec mc,int inputBufferID) {14 ByteBuffer inputBuffer = codec.getinputBuffer(inputBufferID);15 fill inputBuffer with valID data16 …17 codec.queueinputBuffer(inputBufferID,…);18 }19 20 21 * 在onOutputBufferAvailable回调方法中,MediaCodec会通知什么时候output22 * 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 A31 bufferFormat is equivalent to mOutputFormat32 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 B44 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 complete57 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 buffer10 if (inputBufferID >= 0) {11 ByteBuffer inputBuffer = codec.getinputBuffer(...); 获取input buffer12 13 ...14 codec.queueinputBuffer(inputBufferID,...); 提交数据给Codec15 }16 int outputBufferID = codec.dequeueOutputBuffer(...); 请求是否有可用的output buffer17 if (outputBufferID >= 018 ByteBuffer outputBuffer = codec.getoutputBuffer(outputBufferID); 获取output buffer19 MediaFormat bufferFormat = codec.getoutputFormat(outputBufferID); 20 bufferFormat is IDentical to outputFormat21 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的数据处理方式分析所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)