Android MediaCodec使用介绍
发布日期:2021-10-04 02:53:49 浏览次数:7 分类:技术文章

本文共 3489 字,大约阅读时间需要 11 分钟。

编解码器简单概念

MediaCodec用来使用底层多媒体编解码器。

宽泛讲编解码器处理输入数据生成输出数据,它的处理是异步的并且使用一系列输入输出buffer。简单层面来说,你请求或者获取空的输入buffer,装满输入之后发送到编解码器处理,在处理结束后编解码器再将数据转换到一个输出的空buffer。最后你请求或者获取装满数据的输出buffer,消耗完其内容数据之后将该buffer释放回编解码器。

1.支持的数据类型

编解码器支持三种数据:压缩的数据、原始的音频数据、原始的视频数据。所有的三种数据都可以通过使用ByteBuffers来处理,但是对于原始的视频数据可以使用Surface来提高编解码器的性能同时可以使用ImageReader获取视频的单个帧,即截图。

对于原始视频数据,当你使用ByteBuffers来处理时,其buffer的排列是依据他们的颜色格式。视频编解码器支持三种颜色格式:

  • native raw video format:通过COLOR_FormatSurface来标记,可以被用作输入或者输出Surface。

  • flexible YUV buffers(比如 COLOR_FormatYUV420Flexible):可以用作输入输出Surface以及ByteBuffers模式。

  • other, specific formats:这些只能使用ByteBuffers模式处理。

2.编解码器的状态

编解码器的理论状态是三种:停止、执行、释放。

停止状态由包含三个子状态:错误、为初始化、配置。

执行状态包含三个子状态:刷新、运行、结束流。

当使用工厂方法获得编解码器对象时,起处于未初始化状态。首先需要新建MMediaFormat对象,使用configure方法进行配置,此时处于配置状态。接着调用start方法此时进入执行状态。在这个状态可以通过缓冲buffer操作过程数据。

执行状态包含三个子状态。当调用start进入刷新子状态,该状态持有所有buffer。一旦第一个输入buffer出队列编解码器就进入运行子状态,这个状态最耗时。当你入队列一个输入buffer带有ENDOFSTREAM标记时,编解码器进入结束流子状态,在这个状态不在接收输入buffer,但依然生成输出buffer。

调用stop方法进入为初始化状态,一旦编解码器使用完成你必须调用release进行释放。

编解码器的使用

以下是如何通过代码使用编解码器。编解码器有两种使用方式:异步使用、同步使用。

1.异步使用

MediaCodec codec = MediaCodec.createByCodecName(name); MediaFormat mOutputFormat; // member variable codec.setCallback(new MediaCodec.Callback() {   @Override   void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);     // fill inputBuffer with valid data     …     codec.queueInputBuffer(inputBufferId, …);   }   @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, …);   }   @Override   void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {     // Subsequent data will conform to new format.     // Can ignore if using getOutputFormat(outputBufferId)     mOutputFormat = format; // option B   }   @Override   void onError(…) {     …   } }); codec.configure(format, …); mOutputFormat = codec.getOutputFormat(); // option B codec.start(); // wait for processing to complete codec.stop(); codec.release();

2.同步使用

MediaCodec codec = MediaCodec.createByCodecName(name);     codec.configure(format, …);     MediaFormat outputFormat = codec.getOutputFormat(); // option B     codec.start();     for (;;) {       int inputBufferId = codec.dequeueInputBuffer(timeoutUs);       if (inputBufferId >= 0) {         ByteBuffer inputBuffer = codec.getInputBuffer(…);         // fill inputBuffer with valid data         …         codec.queueInputBuffer(inputBufferId, …);       }       int outputBufferId = codec.dequeueOutputBuffer(…);       if (outputBufferId >= 0) {         ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);         MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A         // bufferFormat is identical to outputFormat         // outputBuffer is ready to be processed or rendered.         …         codec.releaseOutputBuffer(outputBufferId, …);       } 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();

附录参考

转载地址:https://blog.csdn.net/leif_/article/details/50971616 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android5.0以上使用MediaProjection截图和录屏
下一篇:Android invalidate()源码分析

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月02日 23时18分24秒