MediaCodec API笔记

MediaCodec介绍

MediaCodec类可以访问基础的媒体编解码器,即编码器/解码器组件。它是Android基础多媒体支持基础架构的一部分(通常跟MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、MediaDrm、Image、Surface和AudioTrack一起使用)。

从广义上讲,一个编解码器可以处理输入数据来产生输出数据。它使用一组输入和输出缓冲器异步处理数据。简单来说,你请求(或者接收)一个空的输入缓冲区,填充数据后发送到编解码器进行处理。编解码器使用这些数据进行转换,并输出到它其中一个输出缓冲器中。最后你请求(或接收)一个填充的输出缓冲器,消费掉里面的数据后释放回编解码器。其流程如下:
在这里插入图片描述

数据类型 (Data Types)

编解码器可处理三种数据:压缩数据、原始音频数据、原始视频数据。可以使用ByteBuffers处理这三种数据,但是你在处理原始视频数据时需要使用Surface来提升编解码的性能。Surface使用的是本地缓冲区,它不会映射或拷贝到ByteBuffers;所以,效率更高。在使用Surface时通常无法访问原始视频数据,但是你可以使用ImageReader类来访问不安全的解码(原始)视频帧。这可能仍然比使用ByteBuffers更有效率,因为一些本地缓冲区可能会直接映射到ByteBuffers。使用ByteBuffers模式时,你可以使用Image类和getInput/OutputImage(int)来访问原始视频帧。

缓冲区的压缩

输入缓冲区(用于解码器)和输出缓冲区(用于编码器)包含各种格式类型的压缩数据。对于视频这通常是一个压缩的视频帧,对于音频它通常是一个可访问的单元(一个编码音频段通常包含格式类型所指定的几毫秒音频),但是这个要求会适当放宽一点,如果一个缓冲区包含多个可访问的编码音频单元。在任何情况下,缓冲区不会在任意字节边界开始或结束,而是在帧/访问单元边界,除非使用了BUFFER_FLAG_PARTIAL_FRAME标记。

原始音频缓冲区

原始音频缓冲区包含所有的PCM音频数据帧,它是通道顺序中每个通道的一个样本。每个样本都是本机字节顺序的16位有符号整数。下面的示例是如何获取一个通道样本:

 short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
   ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
   MediaFormat format = codec.getOutputFormat(bufferId);
   ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
   int numChannels = formet.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
   if (channelIx < 0 || channelIx >= numChannels) {
     return null;
   }
   short[] res = new short[samples.remaining() / numChannels];
   for (int i = 0; i < res.length; ++i) {
     res[i] = samples.get(i * numChannels + channelIx);
   }
   return res;
 }
原始视频缓冲区

ByteBuffers模式下,视频缓冲区根据其颜色格式进行布局。你可以从getCodecInfo().getCapabilitiesForType(…).colorFormats获取支持的颜色格式作为数组。视频编解码器可支持三种颜色格式。

  • 本地原始视频格式: 它由MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface标记,并且它可以和输入输出Surface一起使用。
  • 灵活的YUV缓冲区(如MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible): 它们可以与输入/输出Surface一起使用,跟ByteBuffers模式使用getInput/OutputImage(int)一样。
  • 其他特定的格式: 这些格式通常只支持在ByteBuffers模式下使用。一些颜色格式是供应商特定的,其他的在MediaCodecInfo.CodecCapabilities中定义。对于等同于灵活格式的颜色格式,仍然可以使用getInput/OutputImage(int)。

自Build.VERSION_CODES.LOLLIPOP_MR1以来,所有的视频编解码器都支持灵活的YUV 4:2:0 缓冲区。

在旧的设备上访问原始视频缓冲区

在支持 Build.VERSION_CODES.LOLLIPOP 和Image 之前,你需要使用 MediaFormat.KEY_STRIDE 和MediaFormat.KEY_SLICE_HEIGHT 输出格式值来了解原始输出缓冲区的布局。

MediaFormat.KEY_WIDTH和MediaFormat.KEY_HEIGHT键指定视频帧的大小;然而,对于大多数内容,视频(图片)仅占据视频帧的一部分。这由“裁剪矩形”表示

你需要使用以下键从输出格式获取原始输出图像的裁剪矩形。如果这些键不存在,则视频占据整个视频帧。在应用任何旋转之前,在输出帧的上下文中理解裁剪矩形。
在这里插入图片描述
计算视频帧的大小(旋转之前):

 MediaFormat format = decoder.getOutputFormat(…);
 int width = format.getInteger(MediaFormat.KEY_WIDTH);
 if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
     width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
 }
 int height = format.getInteger(MediaFormat.KEY_HEIGHT);
 if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
     height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
 }
 

另请注意,BufferInfo.offset的含义在各设备之间并不一致。在某些设备上,偏移量指向裁剪矩形的左上角像素,而在大多数设备上,它指向整个帧的左上角像素

状态(States)

在其生命周期中,编解码器存在三种状态:Stopped, Executing 和 Released。Stopped状态也分为三个子状态:Uninitialized, Con

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值