Android MediaCodec使用介绍

编解码器简单概念

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();

附录参考

官方文档

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值