Most visited

Recently visited

Added in API level 16

MediaCodec

public final class MediaCodec
extends Object

java.lang.Object
   ↳ android.media.MediaCodec


MediaCodec类可用于访问低级媒体编解码器,即编码器/解码器组件。 它是Android低电平多媒体支持基础设施的一部分(通常与一起使用MediaExtractorMediaSyncMediaMuxerMediaCryptoMediaDrmImageSurface ,和AudioTrack )。

MediaCodec buffer flow diagram

广义而言,编解码器处理输入数据以生成输出数据。 它异步处理数据并使用一组输入和输出缓冲区。 在简单的层面上,您请求(或接收)一个空输入缓冲区,填充数据并将其发送到编解码器进行处理。 编解码器使用数据并将其转换为其空的输出缓冲区之一。 最后,您请求(或接收)一个填充的输出缓冲区,消耗其内容并将其释放回编解码器。

Data Types

编解码器对三种数据进行操作:压缩数据,原始音频数据和原始视频数据。 所有三种数据都可以使用ByteBuffers进行处理,但您应该使用Surface作为原始视频数据以提高编解码器的性能。 Surface使用本地视频缓冲区而不映射或将它们复制到ByteBuffers; 因此,它更有效率。 使用Surface时通常无法访问原始视频数据,但可以使用ImageReader类来访问不安全的已解码(原始)视频帧。 这可能仍然比使用ByteBuffers更高效,因为某些本地缓冲区可能映射到direct ByteBuffers中。 当使用ByteBuffer的模式,您可以使用访问原始视频帧Image类和getInput / OutputImage(int)

Compressed Buffers

根据format's type,输入缓冲器(用于解码器)和输出缓冲器(用于编码器)包含压缩数据。 对于视频类型,这是一个单一的压缩视频帧。 对于音频数据,这通常是单个访问单元(编码音频段通常包含由格式类型指示的几毫秒的音频),但是由于缓冲器可能包含多个编码的音频存取单元,所以这个要求稍微宽松。 无论哪种情况,缓冲区都不会以任意字节边界开始或结束,而是在帧/访问单元边界上开始或结束。

Raw Audio Buffers

原始音频缓冲区包含整个PCM音频数据帧,这是通道顺序中每个通道的一个样本。 每个样本都是16-bit signed integer in native byte order

 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;
 }

Raw Video Buffers

在ByteBuffer模式下,视频缓冲区按照其color format进行布局 您可以从getCodecInfo() . getCapabilitiesForType(…) . colorFormats获得支持的颜色格式。 视频编解码器可支持三种颜色格式:

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

Accessing Raw Video ByteBuffers on Older Devices

在支持 LOLLIPOPImage之前,需要使用 KEY_STRIDEKEY_SLICE_HEIGHT输出格式值来了解原始输出缓冲区的布局。

请注意,在某些设备上,切片高度被广告为0.这可能意味着切片高度与帧高度相同,或者切片高度是与某个值对齐的帧高度(通常是2)。 不幸的是,在这种情况下无法分辨实际的切片高度。 此外,平面格式的U平面的垂直跨度也未被指定或定义,尽管通常它是切片高度的一半。

KEY_WIDTHKEY_HEIGHT键指定视频帧的大小; 然而,对于大多数情况,视频(图片)只占据视频帧的一部分。 这由“裁剪矩形”表示。

您需要使用以下键从output format获取原始输出图像的裁剪矩形。 如果这些键不存在,则视频占据整个视频帧。 应用任何rotation 之前 ,在输出帧的上下文中理解裁剪矩形。

Format Key Type 描述
"crop-left" Integer The left-coordinate (x) of the crop rectangle
"crop-top" Integer The top-coordinate (y) of the crop rectangle
"crop-right" Integer The right-coordinate (x) MINUS 1 of the crop rectangle
"crop-bottom" Integer The bottom-coordinate (y) MINUS 1 of the crop rectangle
The right and bottom coordinates can be understood as the coordinates of the right-most valid column/bottom-most valid row of the cropped output image.

视频帧的大小(旋转之前)可以这样计算:

 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

在其生命周期中,编解码器概念上存在三种状态之一:停止,执行或释放。 停止的集体状态实际上是三种状态的集合:未初始化,已配置和错误,而执行状态在概念上通过三个子状态:刷新,运行和结束流。

MediaCodec state diagram

当您使用其中一种工厂方法创建编解码器时,编解码器处于未初始化状态。 首先,您需要通过configure(…)进行配置,使其进入Configured状态,然后调用start()将其移至Executing状态。 在这种状态下,您可以通过上述的缓冲区队列处理来处理数据。

执行状态有三个子状态:刷新,运行和结束流。 紧接在start()之后,编解码器处于Flushed子状态,它保存所有缓冲区。 只要第一个输入缓冲区出列,编解码器就会转移到运行子状态,在该状态下它大部分时间都在使用。 当您使用end-of-stream marker对输入缓冲区进行排队时 ,编解码器将转换为流结束子状态。 在这种状态下,编解码器不再接受进一步的输入缓冲器,但仍然产生输出缓冲器,直到输出端达到输出端。 您可以在处于Executing状态时使用flush()随时移回Flushed子状态。

调用stop()可将编解码器返回到未初始化状态,然后可再次进行配置。 当您完成使用编解码器时,您必须通过拨打release()来释放它。

在极少数情况下,编解码器可能会遇到错误并进入错误状态。 这是使用来自排队操作的无效返回值或有时通过异常传递的。 致电reset()以使编解码器再次可用。 您可以从任何状态调用它以将编解码器移回未初始化状态。 否则,请致电release()移至终端发布状态。

Creation

使用MediaCodecList为特定的MediaFormat创建MediaCodec。 解码文件或流时,您可以从MediaExtractor.getTrackFormat获得所需的格式。 使用MediaFormat.setFeatureEnabled注入要添加的任何特定功能,然后调用MediaCodecList.findDecoderForFormat以获取可以处理该特定媒体格式的编解码器的名称。 最后,使用createByCodecName(String)创建编解码器。

注意:LOLLIPOP ,该格式MediaCodecList.findDecoder / EncoderForFormat不得包含frame rate 使用format.setString(MediaFormat.KEY_FRAME_RATE, null)清除格式中的任何现有帧速率设置。

您还可以创建首选的编解码器使用特定的MIME类型createDecoder / EncoderByType(String) 但是,这不能用于注入功能,并且可能会创建无法处理特定所需媒体格式的编解码器。

Creating secure decoders

在版本KITKAT_WATCH和更早的版本上,安全编解码器可能不会在MediaCodecList列出,但仍可能在系统上可用。 通过将".secure"附加到常规编解码器的名称(所有安全编解码器的名称必须以".secure"结尾),可以通过名称仅实例化存在的安全编解码器。如果编解码器不存在于系统上, createByCodecName(String)将抛出IOException

LOLLIPOP开始,您应该使用媒体格式中的 FEATURE_SecurePlayback功能来创建安全解码器。

Initialization

创建编解码器后,如果要异步处理数据,可以使用setCallback设置回调。 然后, configure使用特定的媒体格式的编解码器。 这是您可以为视频制作者指定输出Surface生成原始视频数据的编解码器(例如视频解码器)。 这也是您可以设置安全编解码器的解密参数时的情况(请参阅MediaCrypto )。 最后,由于一些编解码器可以在多种模式下运行,因此您必须指定是否要将其用作解码器或编码器。

LOLLIPOP ,您可以在Configured状态下查询生成的输入和输出格式。 在启动编解码器之前,您可以使用它来验证生成的配置,例如颜色格式。

如果您想要使用视频使用者本地处理原始输入视频缓冲区 - 处理原始视频输入的编解码器(例如视频编码器) - 在配置后使用createInputSurface()为输入数据创建目标表面。 或者,建立了编解码器使用以前创建persistent input surface致电setInputSurface(Surface)

Codec-specific Data

某些格式,特别是AAC音频和MPEG4,H.264和H.265视频格式要求实际数据前缀包含设置数据或编解码器特定数据的多个缓冲区。 处理这种压缩格式时,必须在start()之后和任何帧数据之前将此数据提交给编解码器。 此类数据必须在致电queueInputBuffer使用标志BUFFER_FLAG_CODEC_CONFIG进行标记。

特定于编解码器的数据也可以包含在以“csd-0”,“csd-1”等键在ByteBuffer条目中传递给configure的格式中。这些键总是包含在从MediaFormat获得的轨道MediaExtractor 格式中的编解码器专用数据在start()自动提交给编解码器; 绝不能明确地提交这些数据。 如果格式不包含编解码器特定数据,则可以根据格式要求,选择使用指定数量的缓冲区以正确的顺序提交它。 在H.264 AVC的情况下,您还可以连接所有编解码器专用数据并将其作为单个编解码器配置缓冲区提交。

Android使用以下编解码器特定的数据缓冲区。 这些也需要设置为轨道格式以适合MediaMuxer轨道配置。 标有( * )的每个参数集和编码解码器特定数据部分必须以"\x00\x00\x00\x01"的起始码开始。

Format CSD buffer #0 CSD buffer #1 CSD buffer #2
AAC Decoder-specific information from ESDS* Not Used Not Used
VORBIS Identification header Setup header Not Used
OPUS Identification header Pre-skip in nanosecs
(unsigned 64-bit native-order integer.)
This overrides the pre-skip value in the identification header.
Seek Pre-roll in nanosecs
(unsigned 64-bit native-order integer.)
MPEG-4 Decoder-specific information from ESDS* Not Used Not Used
H.264 AVC SPS (Sequence Parameter Sets*) PPS (Picture Parameter Sets*) Not Used
H.265 HEVC VPS (Video Parameter Sets*) +
SPS (Sequence Parameter Sets*) +
PPS (Picture Parameter Sets*)
Not Used Not Used
VP9 VP9 CodecPrivate Data (optional) Not Used Not Used

注意:如果编解码器在启动之后立即刷新或在输出缓冲区或输出格式更改返回之前不久, 请注意 ,因为在刷新期间编解码器特定的数据可能会丢失。 在这种刷新之后,您必须使用标有BUFFER_FLAG_CODEC_CONFIG缓冲区重新提交数据,以确保正确的编解码器操作。

编码器(或生成压缩数据的编解码器)将在用codec-config flag标记的输出缓冲区中的任何有效输出缓冲区之前创建并返回编解码器特定数据。 包含编解码器专用数据的缓冲器没有有意义的时间戳。

Data Processing

每个编解码器都维护一组由API调用中的缓冲区ID引用的输入和输出缓冲区。 在成功调用start() ,客户端“拥有”既没有输入也没有输出缓冲区。 在同步模式中,呼叫dequeueInput / OutputBuffer(…)获得(获得的所有权)从编解码器的输入或输出缓冲区。 在异步模式下,您将自动通过接收可用缓冲区MediaCodec.Callback.onInput / OutputBufferAvailable(…)回调。

在获得输入缓冲区时,填充数据并使用queueInputBufferqueueSecureInputBuffer如果使用解密)将其提交给编解码器。 不要使用相同的时间戳提交多个输入缓冲区(除非它被标记为codec-specific data )。

编解码器将通过异步模式下的onOutputBufferAvailable回调或者响应同步模式下的dequeuOutputBuffer调用返回一个只读输出缓冲区。 输出缓冲区处理完毕后,调用其中一个releaseOutputBuffer方法将缓冲区返回给编解码器。

虽然您不需要立即重新提交/释放缓冲区到编解码器,但握住输入和/或输出缓冲区可能会使编解码器停顿,并且此行为取决于设备。 特别是,编解码器有可能在产生输出缓冲区之前暂缓,直到所有未完成的缓冲区被释放/重新提交。 因此,尽可能少地尝试保留可用的缓冲区。

根据API版本,您可以通过三种方式处理数据:

Processing Mode API version <= 20
Jelly Bean/KitKat
API version >= 21
Lollipop and later
Synchronous API using buffer arrays Supported 已过时的
Synchronous API using buffers Not Available Supported
Asynchronous API using buffers Not Available Supported

Asynchronous Processing using Buffers

由于LOLLIPOP ,首选方法是在调用configure之前通过设置回调来异步处理数据。 异步模式改变的状态转换咯,因为你必须调用start()flush()过渡编解码器的跑分状态,并开始接收输入缓冲器。 同样,在初始调用start ,编解码器将直接移至Running子状态,并通过回调开始传递可用的输入缓冲区。

MediaCodec state diagram for asynchronous operation

MediaCodec通常以异步模式使用:

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

Synchronous Processing using Buffers

由于LOLLIPOP ,你应该使用检索输入和输出缓冲器getInput / OutputBuffer(int)和/或getInput / OutputImage(int)使用同步模式编解码器也是如此。 这允许框架进行某些优化,例如在处理动态内容时。 如果调用此优化禁用getInput / OutputBuffers()

注意:不要混合同时使用缓冲区和缓冲区数组的方法。 具体而言,只调用getInput / OutputBuffers后直接start()或具有与出列的值的输出缓冲器ID后INFO_OUTPUT_FORMAT_CHANGED

MediaCodec通常以同步模式使用:

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

Synchronous Processing using Buffer Arrays (deprecated)

在版本KITKAT_WATCH和之前,输入和输出缓冲区组由ByteBuffer[]阵列表示。 成功调用后start() ,检索使用缓存阵列getInput / OutputBuffers() 如以下示例所示,使用缓冲区ID-s作为这些数组中的索引(非负数时)。 请注意,尽管数组大小提供了上限,但阵列大小与系统使用的输入和输出缓冲区数量之间没有固有的相关性。

 MediaCodec codec = MediaCodec.createByCodecName(name);
 codec.configure(format, …);
 codec.start();
 ByteBuffer[] inputBuffers = codec.getInputBuffers();
 ByteBuffer[] outputBuffers = codec.getOutputBuffers();
 for (;;) {
   int inputBufferId = codec.dequeueInputBuffer(…);
   if (inputBufferId >= 0) {
     // fill inputBuffers[inputBufferId] with valid data
     …
     codec.queueInputBuffer(inputBufferId, …);
   }
   int outputBufferId = codec.dequeueOutputBuffer(…);
   if (outputBufferId >= 0) {
     // outputBuffers[outputBufferId] is ready to be processed or rendered.
     …
     codec.releaseOutputBuffer(outputBufferId, …);
   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
     outputBuffers = codec.getOutputBuffers();
   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
     // Subsequent data will conform to new format.
     MediaFormat format = codec.getOutputFormat();
   }
 }
 codec.stop();
 codec.release();

End-of-stream Handling

当你到达输入数据的最后,你必须通过指定其信号编解码器BUFFER_FLAG_END_OF_STREAM呼叫标志queueInputBuffer 您可以在最后一个有效的输入缓冲区上执行此操作,或者通过提交一个额外的空输入缓冲区并设置流结束标志。 如果使用空缓冲区,时间戳将被忽略。

编解码器将继续返回输出缓冲区,直到它最终通过在MediaCodec.BufferInfo设置的dequeueOutputBuffer指定的相同流结束标志或通过onOutputBufferAvailable返回来发onOutputBufferAvailable输出流的结束。 这可以在最后一个有效的输出缓冲区上设置,或者在最后一个有效的输出缓冲区之后的空缓冲区上设置。 这个空缓冲区的时间戳应该被忽略。

除非编解码器已被刷新,停止或重新启动,否则在发出输入流结束信号后,请勿提交其他输入缓冲区。

Using an Output Surface

在使用输出Surface时,数据处理与ByteBuffer模式几乎相同; 但是,输出缓冲区将不可访问,并表示为null值。 例如getOutputBuffer / Image(int)将返回nullgetOutputBuffers()将返回仅含有一个数组null -s。

使用输出曲面时,可以选择是否渲染曲面上的每个输出缓冲区。 你有三个选择:

由于M ,默认时间戳是缓冲区的presentation timestamp (转换为纳秒)。 在此之前没有定义。

另外由于 M ,您可以使用 setOutputSurface动态更改输出曲面。

Transformations When Rendering onto Surface

If the codec is configured into Surface mode, any crop rectangle, rotation and video scaling mode will be automatically applied with one exception:

M版本之前,软件解码器在渲染到Surface上时可能未应用旋转。 不幸的是,没有办法识别软件解码器,或者如果他们应用轮换而不是通过尝试它。

也有一些警告。

请注意,将输出显示在Surface上时,不考虑像素纵横比。 这意味着如果您使用的是VIDEO_SCALING_MODE_SCALE_TO_FIT模式,则必须定位输出Surface,以使其具有适当的最终显示宽高比。 相反,对于正方形像素(像素宽高比或1:1)的内容,您只能使用VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING模式。

另请注意,从 N版本开始,对于旋转90度或270度的视频, VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING模式可能无法正常工作。

设置视频缩放模式时,请注意每次输出缓冲区更改后必须重置。 由于INFO_OUTPUT_BUFFERS_CHANGED事件已被弃用,因此每次输出格式更改后都可以这样做。

Using an Input Surface

当使用输入表面时,没有可访问的输入缓冲区,因为缓冲区会自动从输入表面传递到编解码器。 调用dequeueInputBuffer将抛出一个IllegalStateException ,并且getInputBuffers()返回一个不能写入的伪造的ByteBuffer[]数组。

致电signalEndOfInputStream()以表示流结束。 此通话后,输入表面将立即停止向编解码器提交数据。

Seeking & Adaptive Playback Support

视频解码器(以及一般使用压缩视频数据的编解码器)在搜索和格式更改方面表现不同,无论它们是否支持并配置为自适应播放。 您可以检查解码器支持adaptive playback通过CodecCapabilities.isFeatureSupported(String) 只有将编解码器配置为解码到Surface才会激活对视频解码器的自适应播放支持。

Stream Boundary and Key Frames

start()flush()之后的输入数据始于合适的流边界很重要:第一个帧必须是关键帧。 关键帧可以完全自行解码(对于大多数编解码器来说,这意味着I帧),并且在关键帧之后没有要显示的帧指的是关键帧之前的帧。

下表总结了各种视频格式的合适关键帧。

Format Suitable key frame
VP9/VP8 a suitable intraframe where no subsequent frames refer to frames prior to this frame.
(There is no specific name for such key frame.)
H.265 HEVC IDR or CRA
H.264 AVC IDR
MPEG-4
H.263
MPEG-2
a suitable I-frame where no subsequent frames refer to frames prior to this frame.
(There is no specific name for such key frame.)

For decoders that do not support adaptive playback (including when not decoding onto a Surface)

为了开始解码与先前提交的数据不相邻的数据(即,在寻找之后),您必须清空解码器。 由于所有输出缓冲区在冲洗点立即被撤销,因此您可能需要首先发出信号,然后等待数据流结束,然后再致电flush 冲洗后的输入数据始于合适的流边界/关键帧,这一点很重要。

注意:刷新后提交的数据格式不能改变; flush()不支持格式不连续; 为此,完整的stop() - configure(…) - start()周期是必要的。

另请注意:如果您在start()之后start()刷新编解码器 - 通常在收到第一个输出缓冲区或输出格式更改之前 - 您将需要重新提交编解码器特定数据到编解码器。 有关更多信息,请参阅codec-specific-data section

For decoders that support and are configured for adaptive playback

为了开始解码与先前提交的数据不相邻的数据(即,在寻找之后), 不需要刷新解码器; 然而,不连续性之后的输入数据必须从合适的流边界/关键帧开始。

对于某些视频格式(即H.264,H.265,VP8和VP9),也可以在中途更改图片大小或配置。 为此,您必须将全部新的编解码器专用配置数据与关键帧一起打包到单个缓冲区(包括任何启动代码)中,并将其作为常规输入缓冲区提交。

您将收到来自 dequeueOutputBufferINFO_OUTPUT_FORMAT_CHANGED返回值或 onOutputFormatChanged在图片大小更改发生后以及任何具有新大小的帧返回之前的回 INFO_OUTPUT_FORMAT_CHANGED值。

注意:就像编解码器专用数据的情况一样,在更改图片尺寸后不久请致电flush()时请小心。 如果您还没有收到图片尺寸更改的确认,则需要重新请求新图片尺寸。

Error handling

该工厂方法createByCodecNamecreateDecoder / EncoderByTypeIOException失败,你必须赶上或申报错过。 当方法从不允许的编解码器状态调用时,MediaCodec方法抛出IllegalStateException ; 这通常是由于不正确的应用程序API使用。 涉及安全缓冲区的方法可能会抛出MediaCodec.CryptoException ,它具有可从getErrorCode()获得的更多错误信息。

内部编解码器错误导致MediaCodec.CodecException ,这可能是由于媒体内容损坏,硬件故障,资源耗尽等等,即使应用程序正确使用API。 通过拨打isRecoverable()isTransient()可以确定收到CodecException时的建议操作:

isRecoverable()isTransient()都不会同时返回true。

Valid API Calls and API History

本部分总结了每种状态下有效的API调用和MediaCodec类的API历史记录。 有关API版本号,请参阅Build.VERSION_CODES

Symbol Meaning
Supported
Semantics changed
Experimental support
[ ] 已过时的
Restricted to surface input mode
Restricted to surface output mode
Restricted to ByteBuffer input mode
Restricted to synchronous mode
Restricted to asynchronous mode
( ) Can be called, but shouldn't
Uninitialized
Configured
Flushed
Running
End of Stream
Error
Released
SDK Version
State 方法 16 17 18 19 20 21 22 23
createByCodecName
createDecoderByType
createEncoderByType
createPersistentInputSurface
16+ - - - - - - configure
- 18+ - - - - - createInputSurface
- - 16+ 16+ (16+) - - dequeueInputBuffer ⁕▧↩ ▧↩ ▧↩
- - 16+ 16+ 16+ - - dequeueOutputBuffer ⁕↩
- - 16+ 16+ 16+ - - flush
18+ 18+ 18+ 18+ 18+ 18+ - getCodecInfo
- - (21+) 21+ (21+) - - getInputBuffer
- - 16+ (16+) (16+) - - getInputBuffers [⁕↩] [↩] [↩]
- 21+ (21+) (21+) (21+) - - getInputFormat
- - (21+) 21+ (21+) - - getInputImage
18+ 18+ 18+ 18+ 18+ 18+ - getName
- - (21+) 21+ 21+ - - getOutputBuffer
- - 16+ 16+ 16+ - - getOutputBuffers [⁕↩] [↩] [↩]
- 21+ 16+ 16+ 16+ - - getOutputFormat()
- - (21+) 21+ 21+ - - getOutputFormat(int)
- - (21+) 21+ 21+ - - getOutputImage
- - - 16+ (16+) - - queueInputBuffer
- - - 16+ (16+) - - queueSecureInputBuffer
16+ 16+ 16+ 16+ 16+ 16+ 16+ release
- - - 16+ 16+ - - releaseOutputBuffer(int, boolean)
- - - 21+ 21+ - - releaseOutputBuffer(int, long)
21+ 21+ 21+ 21+ 21+ 21+ - reset
21+ - - - - - - setCallback
- 23+ - - - - - setInputSurface
23+ 23+ 23+ 23+ 23+ (23+) (23+) setOnFrameRenderedListener ○ ⎆
- 23+ 23+ 23+ 23+ - - setOutputSurface
19+ 19+ 19+ 19+ 19+ (19+) - setParameters
- (16+) (16+) 16+ (16+) (16+) - setVideoScalingMode
- - 18+ 18+ - - - signalEndOfInputStream
- 16+ 21+(⇄) - - - - start
- - 16+ 16+ 16+ - - stop

Summary

Nested classes

class MediaCodec.BufferInfo

每个缓冲区元数据包括指定相关编解码器(输出)缓冲区中有效数据范围的偏移量和大小。

class MediaCodec.Callback

MediaCodec回调接口。

class MediaCodec.CodecException

内部编解码器错误发生时抛出。

class MediaCodec.CryptoException

排队安全输入缓冲区时发生加密错误时抛出。

class MediaCodec.CryptoInfo

描述(至少部分)加密的输入样本结构的元数据。

interface MediaCodec.OnFrameRenderedListener

在输出表面上渲染输出帧时调用侦听器

Constants

int BUFFER_FLAG_CODEC_CONFIG

这表明标记为这样的缓冲区包含编解码器初始化/编解码器特定数据而不是媒体数据。

int BUFFER_FLAG_END_OF_STREAM

这表示流的结束,即

int BUFFER_FLAG_KEY_FRAME

这表示标记为(编码)的缓冲区包含关键帧的数据。

int BUFFER_FLAG_SYNC_FRAME

此常数在API级别21中已弃用。请改为使用BUFFER_FLAG_KEY_FRAME

int CONFIGURE_FLAG_ENCODE

如果此编解码器要用作编码器,请传递此标志。

int CRYPTO_MODE_AES_CBC

int CRYPTO_MODE_AES_CTR

int CRYPTO_MODE_UNENCRYPTED

int INFO_OUTPUT_BUFFERS_CHANGED

此常数在API级别21中已弃用。由于getOutputBuffers()已被弃用,因此可以忽略此返回值。 每次出队时,客户端都应该使用get-buffer或get-image方法的on命令来请求当前缓冲区。

int INFO_OUTPUT_FORMAT_CHANGED

输出格式已更改,后续数据将采用新格式。

int INFO_TRY_AGAIN_LATER

如果在 dequeueOutputBuffer(MediaCodec.BufferInfo, long)的呼叫中指定了非负超时,则表示呼叫超时。

String PARAMETER_KEY_REQUEST_SYNC_FRAME

请求编码器“很快”产生一个同步帧。

String PARAMETER_KEY_SUSPEND

临时挂起/恢复输入数据的编码。

String PARAMETER_KEY_VIDEO_BITRATE

即时更改视频编码器的目标比特率。

int VIDEO_SCALING_MODE_SCALE_TO_FIT

内容缩放到表面尺寸

int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING

内容被缩放,保持其宽高比,整个表面区域被使用,内容可能被裁剪。

Public methods

void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags)

配置组件。

static MediaCodec createByCodecName(String name)

如果您知道要实例化的组件的确切名称,请使用此方法将其实例化。

static MediaCodec createDecoderByType(String type)

实例化支持给定MIME类型的输入数据的首选解码器。

static MediaCodec createEncoderByType(String type)

实例化支持给定MIME类型的输出数据的首选编码器。

final Surface createInputSurface()

请求Surface用作编码器的输入,以代替输入缓冲区。

static Surface createPersistentInputSurface()

创建可与通常具有输入表面的编解码器一起使用的持久输入表面,例如视频编码器。

final int dequeueInputBuffer(long timeoutUs)

返回要用有效数据填充的输入缓冲区的索引,如果当前没有可用的缓冲区,则返回-1。

final int dequeueOutputBuffer(MediaCodec.BufferInfo info, long timeoutUs)

出队输出缓冲区,最多阻止“timeoutUs”微秒。

final void flush()

冲洗组件的输入和输出端口。

MediaCodecInfo getCodecInfo()

获取编解码器信息。

ByteBuffer getInputBuffer(int index)

返回一个 cleared可写的ByteBuffer对象,用于包含输入数据的出列输入缓冲区索引。

ByteBuffer[] getInputBuffers()

此方法在API级别21中已弃用。每次输入缓冲区出列时,请使用新的getInputBuffer(int)方法。 注意:从API 21开始,出队输入缓冲区自动为cleared 如果使用输入表面,请勿使用此方法。

final MediaFormat getInputFormat()

configure(MediaFormat, Surface, MediaCrypto, int)成功返回以获取编解码器接受的输入格式后调用此 configure(MediaFormat, Surface, MediaCrypto, int)

Image getInputImage(int index)

返回出队输入缓冲区索引的可写Image对象,以包含原始输入视频帧。

final String getName()

获取组件名称。

ByteBuffer getOutputBuffer(int index)

返回出队输出缓冲区索引的只读ByteBuffer。

ByteBuffer[] getOutputBuffers()

此方法在API级别21中已弃用。每次输出缓冲区出列时,请使用新的getOutputBuffer(int)方法。 如果编解码器配置为异步模式,则不支持此方法。 注意:从API 21开始,出队的输出缓冲区的位置和限制将被设置为有效的数据范围。 如果使用输出表面,请勿使用此方法。

final MediaFormat getOutputFormat(int index)

返回特定输出缓冲区的输出格式。

final MediaFormat getOutputFormat()

在dequeueOutputBuffer通过返回 INFO_OUTPUT_FORMAT_CHANGED表示格式更改后调用此 INFO_OUTPUT_FORMAT_CHANGED

Image getOutputImage(int index)

返回包含原始视频帧的出列输出缓冲区索引的只读Image对象。

final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags)

在指定索引处填充输入缓冲区的范围后,将其提交给组件。

final void queueSecureInputBuffer(int index, int offset, MediaCodec.CryptoInfo info, long presentationTimeUs, int flags)

类似于 queueInputBuffer但提交可能加密的缓冲区。

final void release()

释放编解码器实例使用的资源。

final void releaseOutputBuffer(int index, boolean render)

如果完成了缓冲区,则使用此调用将缓冲区返回给编解码器或将其呈现在输出表面上。

final void releaseOutputBuffer(int index, long renderTimestampNs)

如果已完成缓冲区,则使用此调用更新其表面时间戳并将其返回给编解码器以在输出表面上呈现它。

final void reset()

将编解码器返回到其初始(未初始化)状态。

void setCallback(MediaCodec.Callback cb, Handler handler)

为可操作的MediaCodec事件设置异步回调。

void setCallback(MediaCodec.Callback cb)

为默认循环中的可操作MediaCodec事件设置异步回调。

void setInputSurface(Surface surface)

配置编解码器(例如

void setOnFrameRenderedListener(MediaCodec.OnFrameRenderedListener listener, Handler handler)

注册在输出表面上呈现输出帧时要调用的回调。

void setOutputSurface(Surface surface)

动态设置编解码器的输出表面。

final void setParameters(Bundle params)

将其他参数更改传递给组件实例。

final void setVideoScalingMode(int mode)

如果先前调用 configure(MediaFormat, Surface, MediaCrypto, int)指定了 configure(MediaFormat, Surface, MediaCrypto, int)指定要使用的缩放模式。

final void signalEndOfInputStream()

输入信号结束码。

final void start()

成功配置组件后,请致电 start

final void stop()

完成解码/编码会话,注意,编解码器实例保持活跃,且已可 start()再编。

Protected methods

void finalize()

当垃圾收集确定没有更多对该对象的引用时,由对象上的垃圾回收器调用。

Inherited methods

From class java.lang.Object

Constants

BUFFER_FLAG_CODEC_CONFIG

Added in API level 16
int BUFFER_FLAG_CODEC_CONFIG

这表明标记为这样的缓冲区包含编解码器初始化/编解码器特定数据而不是媒体数据。

常量值:2(0x00000002)

BUFFER_FLAG_END_OF_STREAM

Added in API level 16
int BUFFER_FLAG_END_OF_STREAM

这表示流的结束,即在此之后没有缓冲区可用,除非 flush()

常量值:4(0x00000004)

BUFFER_FLAG_KEY_FRAME

Added in API level 21
int BUFFER_FLAG_KEY_FRAME

这表示标记为(编码)的缓冲区包含关键帧的数据。

常数值:1(0x00000001)

BUFFER_FLAG_SYNC_FRAME

Added in API level 16
int BUFFER_FLAG_SYNC_FRAME

此常数在API级别21中已弃用。
改为使用BUFFER_FLAG_KEY_FRAME

这表示标记为(编码)的缓冲区包含关键帧的数据。

常数值:1(0x00000001)

CONFIGURE_FLAG_ENCODE

Added in API level 16
int CONFIGURE_FLAG_ENCODE

如果此编解码器要用作编码器,请传递此标志。

常数值:1(0x00000001)

CRYPTO_MODE_AES_CBC

Added in API level 24
int CRYPTO_MODE_AES_CBC

常量值:2(0x00000002)

CRYPTO_MODE_AES_CTR

Added in API level 16
int CRYPTO_MODE_AES_CTR

常数值:1(0x00000001)

CRYPTO_MODE_UNENCRYPTED

Added in API level 16
int CRYPTO_MODE_UNENCRYPTED

常量值:0(0x00000000)

INFO_OUTPUT_BUFFERS_CHANGED

Added in API level 16
int INFO_OUTPUT_BUFFERS_CHANGED

此常数在API级别21中已弃用。
这个返回值可以被忽略,因为getOutputBuffers()已被弃用。 每次出队时,客户端都应该使用get-buffer或get-image方法的on命令来请求当前缓冲区。

输出缓冲区已更改,客户端必须参考 getOutputBuffers()getOutputBuffers()返回的新输出缓冲区集。

此外,此事件表示视频缩放模式可能已重置为默认值。

常量值:-3(0xfffffffd)

INFO_OUTPUT_FORMAT_CHANGED

Added in API level 16
int INFO_OUTPUT_FORMAT_CHANGED

输出格式已更改,后续数据将采用新格式。 getOutputFormat()返回新的格式。 请注意,您也可以使用新的getOutputFormat(int)方法获取特定输出缓冲区的格式。 这使您无需跟踪输出格式更改。

常量值:-2(0xfffffffe)

INFO_TRY_AGAIN_LATER

Added in API level 16
int INFO_TRY_AGAIN_LATER

如果在 dequeueOutputBuffer(MediaCodec.BufferInfo, long)的呼叫中指定了非负超时,则表示呼叫超时。

常量值:-1(0xffffffff)

PARAMETER_KEY_REQUEST_SYNC_FRAME

Added in API level 19
String PARAMETER_KEY_REQUEST_SYNC_FRAME

请求编码器“很快”产生一个同步帧。 提供值为0的整数。

常量值:“请求同步”

PARAMETER_KEY_SUSPEND

Added in API level 19
String PARAMETER_KEY_SUSPEND

临时挂起/恢复输入数据的编码。 暂停的输入数据被有效地丢弃,而不是被送入编码器。 该参数对于在“表面输入”模式下使用编码器确实非常有意义,因为在这种情况下客户端代码无法控制编码器的输入端。 该值是一个Integer对象,其中包含暂挂值1或要恢复的值0。

常量值:“drop-input-frames”

PARAMETER_KEY_VIDEO_BITRATE

Added in API level 19
String PARAMETER_KEY_VIDEO_BITRATE

即时更改视频编码器的目标比特率。 该值是包含bps新比特率的Integer对象。

常数值:“视频比特率”

VIDEO_SCALING_MODE_SCALE_TO_FIT

Added in API level 16
int VIDEO_SCALING_MODE_SCALE_TO_FIT

内容缩放到表面尺寸

常数值:1(0x00000001)

VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING

Added in API level 16
int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING

内容被缩放,保持其宽高比,整个表面区域被使用,内容可能被裁剪。

此模式仅适用于1:1像素长宽比的内容,因为您无法配置 Surface的像素宽高比。

N版本开始,如果视频是 rotated 90或270度,则此模式可能不起作用。

常量值:2(0x00000002)

Public methods

configure

Added in API level 16
void configure (MediaFormat format, 
                Surface surface, 
                MediaCrypto crypto, 
                int flags)

配置组件。

Parameters
format MediaFormat: The format of the input data (decoder) or the desired format of the output data (encoder). Passing null as format is equivalent to passing an an empty mediaformat.
surface Surface: Specify a surface on which to render the output of this decoder. Pass null as surface if the codec does not generate raw video output (e.g. not a video decoder) and/or if you want to configure the codec for ByteBuffer output.
crypto MediaCrypto: Specify a crypto object to facilitate secure decryption of the media data. Pass null as crypto for non-secure codecs.
flags int: Specify CONFIGURE_FLAG_ENCODE to configure the component as an encoder.
Throws
IllegalArgumentException if the surface has been released (or is invalid), or the format is unacceptable (e.g. missing a mandatory key), or the flags are not set properly (e.g. missing CONFIGURE_FLAG_ENCODE for an encoder).
IllegalStateException if not in the Uninitialized state.
MediaCodec.CryptoException upon DRM error.
MediaCodec.CodecException upon codec error.

createByCodecName

Added in API level 16
MediaCodec createByCodecName (String name)

如果您知道要实例化的组件的确切名称,请使用此方法将其实例化。 谨慎使用。 可能与从MediaCodecList获得的信息一起使用

Parameters
name String: The name of the codec to be instantiated.
Returns
MediaCodec
Throws
IOException if the codec cannot be created.
IllegalArgumentException if name is not valid.
NullPointerException if name is null.

createDecoderByType

Added in API level 16
MediaCodec createDecoderByType (String type)

实例化支持给定MIME类型的输入数据的首选解码器。 以下是定义的MIME类型及其语义的部分列表:

  • "video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm)
  • "video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm)
  • "video/avc" - H.264/AVC video
  • "video/hevc" - H.265/HEVC video
  • "video/mp4v-es" - MPEG4 video
  • "video/3gpp" - H.263 video
  • "audio/3gpp" - AMR narrowband audio
  • "audio/amr-wb" - AMR wideband audio
  • "audio/mpeg" - MPEG1/2 audio layer III
  • "audio/mp4a-latm" - AAC audio (note, this is raw AAC packets, not packaged in LATM!)
  • "audio/vorbis" - vorbis audio
  • "audio/g711-alaw" - G.711 alaw audio
  • "audio/g711-mlaw" - G.711 ulaw audio
Note: It is preferred to use findDecoderForFormat(MediaFormat) and createByCodecName(String) to ensure that the resulting codec can handle a given format.

Parameters
type String: The mime type of the input data.
Returns
MediaCodec
Throws
IOException if the codec cannot be created.
IllegalArgumentException if type is not a valid mime type.
NullPointerException if type is null.

createEncoderByType

Added in API level 16
MediaCodec createEncoderByType (String type)

实例化支持给定MIME类型的输出数据的首选编码器。 注意:最好使用findEncoderForFormat(MediaFormat)createByCodecName(String)来确保生成的编解码器可以处理给定的格式。

Parameters
type String: The desired mime type of the output data.
Returns
MediaCodec
Throws
IOException if the codec cannot be created.
IllegalArgumentException if type is not a valid mime type.
NullPointerException if type is null.

createInputSurface

Added in API level 18
Surface createInputSurface ()

请求Surface用作编码器的输入,以代替输入缓冲区。 这只能在configure(MediaFormat, Surface, MediaCrypto, int)之后和start()之前start()

应用程序负责在完成时调用Surface上的release()。

Surface必须使用硬件加速API(如OpenGL ES)进行渲染。 lockCanvas(android.graphics.Rect)可能会失败或产生意想不到的结果。

Returns
Surface
Throws
IllegalStateException if not in the Configured state.

createPersistentInputSurface

Added in API level 23
Surface createPersistentInputSurface ()

创建可与通常具有输入表面的编解码器一起使用的持久输入表面,例如视频编码器。 持续输入可以被后续的MediaCodecMediaRecorder实例重复使用,但最多只能同时使用一个编解码器或记录器实例。

应用程序负责在完成时调用Surface上的release()。

Returns
Surface an input surface that can be used with setInputSurface(Surface).

dequeueInputBuffer

Added in API level 16
int dequeueInputBuffer (long timeoutUs)

返回要用有效数据填充的输入缓冲区的索引,如果当前没有可用的缓冲区,则返回-1。 如果timeoutU == 0,此方法将立即返回,如果timeoutU <0,则无限期等待输入缓冲区的可用性;如果timeoutUs> 0,则等待“timeoutUs”微秒。

Parameters
timeoutUs long: The timeout in microseconds, a negative timeout indicates "infinite".
Returns
int
Throws
IllegalStateException if not in the Executing state, or codec is configured in asynchronous mode.
MediaCodec.CodecException upon codec error.

dequeueOutputBuffer

Added in API level 16
int dequeueOutputBuffer (MediaCodec.BufferInfo info, 
                long timeoutUs)

出队输出缓冲区,最多阻止“timeoutUs”微秒。 返回已成功解码的输出缓冲区的索引或其中一个INFO_ *常量。

Parameters
info MediaCodec.BufferInfo: Will be filled with buffer meta data.
timeoutUs long: The timeout in microseconds, a negative timeout indicates "infinite".
Returns
int
Throws
IllegalStateException if not in the Executing state, or codec is configured in asynchronous mode.
MediaCodec.CodecException upon codec error.

flush

Added in API level 16
void flush ()

冲洗组件的输入和输出端口。

返回后,以前通过调用 dequeueInputBufferdequeueOutputBuffer返回的所有索引或通过 onInputBufferAvailableonOutputBufferAvailable回调获得的 onInputBufferAvailable变为无效,并且所有缓冲区都归编解码器所有。

如果编解码器配置为异步模式,则返回flush以恢复编解码器操作后调用start() 在这种情况发生之前,编解码器不会请求输入缓冲器。 但请注意,在致电flush之前,可能仍有未完成的onOutputBufferAvailable回调。 通过这些回调返回的指数在拨打flush后也会失效,应该丢弃。

如果编解码器配置为同步模式,则编解码器将在配置输入表面时自动恢复。 否则,将在dequeueInputBuffer被调用时恢复。

Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

getCodecInfo

Added in API level 18
MediaCodecInfo getCodecInfo ()

获取编解码器信息。 如果编解码器是由createDecoderByType或createEncoderByType创建的,则选择哪个组件并不是事先知道的,因此调用者没有MediaCodecInfo。

Returns
MediaCodecInfo
Throws
IllegalStateException if in the Released state.

getInputBuffer

Added in API level 21
ByteBuffer getInputBuffer (int index)

返回一个cleared可写的ByteBuffer对象,用于包含输入数据的出列输入缓冲区索引。 在调用这个方法之后,必须不再使用先前为相同输入索引返回的任何ByteBuffer或Image对象。

Parameters
index int: The index of a client-owned input buffer previously returned from a call to dequeueInputBuffer(long), or received via an onInputBufferAvailable callback.
Returns
ByteBuffer the input buffer, or null if the index is not a dequeued input buffer, or if the codec is configured for surface input.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

getInputBuffers

Added in API level 16
ByteBuffer[] getInputBuffers ()

此方法在API级别21中已弃用。
每次输入缓冲区出列时,请使用新的getInputBuffer(int)方法。 注意:从API 21开始,出队输入缓冲区自动为cleared 如果使用输入表面,请勿使用此方法。

检索一组输入缓冲区。 在start()返回后调用它。 在调用这个方法之后,之前由这个方法调用返回的ByteBuffers必须不再被使用。

Returns
ByteBuffer[]
Throws
IllegalStateException if not in the Executing state, or codec is configured in asynchronous mode.
MediaCodec.CodecException upon codec error.

getInputFormat

Added in API level 21
MediaFormat getInputFormat ()

configure(MediaFormat, Surface, MediaCrypto, int)成功返回以获取编解码器接受的输入格式后调用此configure(MediaFormat, Surface, MediaCrypto, int) 这样做可以确定编解码器支持哪些可选的配置参数。

Returns
MediaFormat
Throws
IllegalStateException if not in the Executing or Configured state.
MediaCodec.CodecException upon codec error.

getInputImage

Added in API level 21
Image getInputImage (int index)

返回出队输入缓冲区索引的可写Image对象,以包含原始输入视频帧。 在调用这个方法之后,必须不再使用先前为相同输入索引返回的任何ByteBuffer或Image对象。

Parameters
index int: The index of a client-owned input buffer previously returned from a call to dequeueInputBuffer(long), or received via an onInputBufferAvailable callback.
Returns
Image the input image, or null if the index is not a dequeued input buffer, or not a ByteBuffer that contains a raw image.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

getName

Added in API level 18
String getName ()

获取组件名称。 如果编解码器是由createDecoderByType或createEncoderByType创建的,则选择的组件是事先不知道的。

Returns
String
Throws
IllegalStateException if in the Released state.

getOutputBuffer

Added in API level 21
ByteBuffer getOutputBuffer (int index)

返回出队输出缓冲区索引的只读ByteBuffer。 返回的缓冲区的位置和限制被设置为有效的输出数据。 在调用这个方法之后,必须不再使用先前为相同输出索引返回的任何ByteBuffer或Image对象。

Parameters
index int: The index of a client-owned output buffer previously returned from a call to dequeueOutputBuffer(MediaCodec.BufferInfo, long), or received via an onOutputBufferAvailable callback.
Returns
ByteBuffer the output buffer, or null if the index is not a dequeued output buffer, or the codec is configured with an output surface.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

getOutputBuffers

Added in API level 16
ByteBuffer[] getOutputBuffers ()

此方法在API级别21中已弃用。
每次输出缓冲区出列时,请改用新的getOutputBuffer(int)方法。 如果编解码器配置为异步模式,则不支持此方法。 注意:从API 21开始,出队的输出缓冲区的位置和限制将被设置为有效的数据范围。 如果使用输出表面,请勿使用此方法。

检索一组输出缓冲区。 在start()返回并且每当dequeueOutputBuffer通过返回INFO_OUTPUT_BUFFERS_CHANGED输出缓冲区更改时调用此INFO_OUTPUT_BUFFERS_CHANGED 在调用这个方法之后,之前由这个方法调用返回的ByteBuffers必须不再被使用。

Returns
ByteBuffer[]
Throws
IllegalStateException if not in the Executing state, or codec is configured in asynchronous mode.
MediaCodec.CodecException upon codec error.

getOutputFormat

Added in API level 21
MediaFormat getOutputFormat (int index)

返回特定输出缓冲区的输出格式。

Parameters
index int: The index of a client-owned input buffer previously returned from a call to dequeueInputBuffer(long).
Returns
MediaFormat the format for the output buffer, or null if the index is not a dequeued output buffer.

getOutputFormat

Added in API level 16
MediaFormat getOutputFormat ()

在dequeueOutputBuffer通过返回INFO_OUTPUT_FORMAT_CHANGED表示格式更改后调用此INFO_OUTPUT_FORMAT_CHANGED 您也可以在configure(MediaFormat, Surface, MediaCrypto, int)成功返回以获取最初为编解码器配置的输出格式后调用此configure(MediaFormat, Surface, MediaCrypto, int) 这样做可以确定编解码器支持哪些可选的配置参数。

Returns
MediaFormat
Throws
IllegalStateException if not in the Executing or Configured state.
MediaCodec.CodecException upon codec error.

getOutputImage

Added in API level 21
Image getOutputImage (int index)

返回包含原始视频帧的出列输出缓冲区索引的只读Image对象。 在调用这个方法之后,必须不再使用先前为相同输出索引返回的任何ByteBuffer或Image对象。

Parameters
index int: The index of a client-owned output buffer previously returned from a call to dequeueOutputBuffer(MediaCodec.BufferInfo, long), or received via an onOutputBufferAvailable callback.
Returns
Image the output image, or null if the index is not a dequeued output buffer, not a raw video frame, or if the codec was configured with an output surface.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

queueInputBuffer

Added in API level 16
void queueInputBuffer (int index, 
                int offset, 
                int size, 
                long presentationTimeUs, 
                int flags)

在指定索引处填充输入缓冲区的范围后,将其提交给组件。 一旦输入缓冲区排队等待编码解码器,它就不能使用,直到它被getInputBuffer(int)响应dequeueInputBuffer(long)返回值或onInputBufferAvailable(MediaCodec, int)回调onInputBufferAvailable(MediaCodec, int)

许多解码器要求实际压缩数据流在“编解码器特定数据”之前,即用于初始化编解码器的设置数据,例如在AVC视频情况下为PPS / SPS或在vorbis音频情况下为代码表。 MediaExtractor在名为“csd-0”,“csd-1”的条目中提供编解码器特定数据作为返回轨道格式的一部分...

通过指定标志BUFFER_FLAG_CODEC_CONFIG可以在start()flush()之后直接提交这些缓冲区。 但是,如果您使用包含这些密钥的MediaFormat配置编解码器,则它们将在启动后直接由MediaCodec自动提交。 因此,不鼓励使用BUFFER_FLAG_CODEC_CONFIG标志,并且仅建议高级用户使用。

为了表明这是最后一段输入数据(或者说,除非解码器随后被刷新,否则不再有输入数据),则指定标志 BUFFER_FLAG_END_OF_STREAM

注意:M之前, presentationTimeUs未传播到(呈现的)曲面输出缓冲区的帧时间戳,并且结果帧时间戳未定义。 使用releaseOutputBuffer(int, long)来确保设置了特定的帧时间戳。 同样,由于帧时间戳可以被目标表面用于渲染同步,因此必须注意使presentationTimeUs正常化,以便不会误认为系统时间。 (见SurfaceView specifics )。

Parameters
index int: The index of a client-owned input buffer previously returned in a call to dequeueInputBuffer(long).
offset int: The byte offset into the input buffer at which the data starts.
size int: The number of bytes of valid input data.
presentationTimeUs long: The presentation timestamp in microseconds for this buffer. This is normally the media time at which this buffer should be presented (rendered). When using an output surface, this will be propagated as the timestamp for the frame (after conversion to nanoseconds).
flags int: A bitmask of flags BUFFER_FLAG_CODEC_CONFIG and BUFFER_FLAG_END_OF_STREAM. While not prohibited, most codecs do not use the BUFFER_FLAG_KEY_FRAME flag for input buffers.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.
MediaCodec.CryptoException if a crypto object has been specified in configure(MediaFormat, Surface, MediaCrypto, int)

queueSecureInputBuffer

Added in API level 16
void queueSecureInputBuffer (int index, 
                int offset, 
                MediaCodec.CryptoInfo info, 
                long presentationTimeUs, 
                int flags)

类似于queueInputBuffer但提交可能被加密的缓冲区。 请查看queueInputBuffer进一步说明。

Parameters
index int: The index of a client-owned input buffer previously returned in a call to dequeueInputBuffer(long).
offset int: The byte offset into the input buffer at which the data starts.
info MediaCodec.CryptoInfo: Metadata required to facilitate decryption, the object can be reused immediately after this call returns.
presentationTimeUs long: The presentation timestamp in microseconds for this buffer. This is normally the media time at which this buffer should be presented (rendered).
flags int: A bitmask of flags BUFFER_FLAG_CODEC_CONFIG and BUFFER_FLAG_END_OF_STREAM. While not prohibited, most codecs do not use the BUFFER_FLAG_KEY_FRAME flag for input buffers.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.
MediaCodec.CryptoException if an error occurs while attempting to decrypt the buffer. An error code associated with the exception helps identify the reason for the failure.

release

Added in API level 16
void release ()

释放编解码器实例使用的资源。 确保在你完成释放任何打开的组件实例时调用它,而不是依赖垃圾回收器在将来的某个时刻为你做这件事。

releaseOutputBuffer

Added in API level 16
void releaseOutputBuffer (int index, 
                boolean render)

如果完成了缓冲区,则使用此调用将缓冲区返回给编解码器或将其呈现在输出表面上。 如果您使用输出表面配置编解码器, render true设置为true将首先将缓冲区发送到该输出表面。 一旦不再使用/显示,表面就会将缓冲区释放回编解码器。 一旦输出缓冲区被释放到编解码器,它就不能被使用,直到它被getOutputBuffer(int)响应dequeueOutputBuffer(MediaCodec.BufferInfo, long)返回值或onOutputBufferAvailable(MediaCodec, int, MediaCodec.BufferInfo)回调后来检索。

Parameters
index int: The index of a client-owned output buffer previously returned from a call to dequeueOutputBuffer(MediaCodec.BufferInfo, long).
render boolean: If a valid surface was specified when configuring the codec, passing true renders this output buffer to the surface.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

releaseOutputBuffer

Added in API level 21
void releaseOutputBuffer (int index, 
                long renderTimestampNs)

如果已完成缓冲区,则使用此调用更新其表面时间戳并将其返回给编解码器以在输出表面上呈现它。 如果您在配置此视频编解码器时尚未指定输出界面,则此调用将简单地将缓冲区返回给编解码器。

时间戳根据目的地表面可能有特殊含义。

SurfaceView specifics
If you render your buffer on a SurfaceView, you can use the timestamp to render the buffer at a specific time (at the VSYNC at or after the buffer timestamp). For this to work, the timestamp needs to be reasonably close to the current nanoTime(). Currently, this is set as within one (1) second. A few notes:
  • the buffer will not be returned to the codec until the timestamp has passed and the buffer is no longer used by the Surface.
  • buffers are processed sequentially, so you may block subsequent buffers to be displayed on the Surface. This is important if you want to react to user action, e.g. stop the video or seek.
  • if multiple buffers are sent to the Surface to be rendered at the same VSYNC, the last one will be shown, and the other ones will be dropped.
  • if the timestamp is not "reasonably close" to the current system time, the Surface will ignore the timestamp, and display the buffer at the earliest feasible time. In this mode it will not drop frames.
  • for best performance and quality, call this method when you are about two VSYNCs' time before the desired render time. For 60Hz displays, this is about 33 msec.
Once an output buffer is released to the codec, it MUST NOT be used until it is later retrieved by getOutputBuffer(int) in response to a dequeueOutputBuffer(MediaCodec.BufferInfo, long) return value or a onOutputBufferAvailable(MediaCodec, int, MediaCodec.BufferInfo) callback.

Parameters
index int: The index of a client-owned output buffer previously returned from a call to dequeueOutputBuffer(MediaCodec.BufferInfo, long).
renderTimestampNs long: The timestamp to associate with this buffer when it is sent to the Surface.
Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

reset

Added in API level 21
void reset ()

将编解码器返回到其初始(未初始化)状态。 如果在创建之后发生unrecoverable错误以将编解码器重置为其初始状态,请调用此unrecoverable

Throws
MediaCodec.CodecException if an unrecoverable error has occured and the codec could not be reset.
IllegalStateException if in the Released state.

setCallback

Added in API level 23
void setCallback (MediaCodec.Callback cb, 
                Handler handler)

为可操作的MediaCodec事件设置异步回调。 如果客户打算以异步模式使用组件,则应在configure(MediaFormat, Surface, MediaCrypto, int)之前提供有效的回调。 当启用异步回调,客户端应该不叫getInputBuffers()getOutputBuffers()dequeueInputBuffer(long)或者dequeueOutputBuffer(BufferInfo, long)

另外,在异步模式下, flush()行为不同。 在调用flush后,即使创建了输入曲面,也必须调用start()以“恢复”接收输入缓冲区。

Parameters
cb MediaCodec.Callback: The callback that will run. Use null to clear a previously set callback (before configure is called and run in synchronous mode).
handler Handler: Callbacks will happen on the handler's thread. If null, callbacks are done on the default thread (the caller's thread or the main thread.)

setCallback

Added in API level 21
void setCallback (MediaCodec.Callback cb)

为默认循环中的可操作MediaCodec事件设置异步回调。

与处理程序设置为null的 setCallback(Callback, Handler)相同。

Parameters
cb MediaCodec.Callback: The callback that will run. Use null to clear a previously set callback (before configure is called and run in synchronous mode).

也可以看看:

setInputSurface

Added in API level 23
void setInputSurface (Surface surface)

将编解码器(例如编码器)配置为使用持久输入表面代替输入缓冲器。 这只能在configure(MediaFormat, Surface, MediaCrypto, int)之后和start()之前start() ,以代替createInputSurface()

Parameters
surface Surface: a persistent input surface created by createPersistentInputSurface()
Throws
IllegalStateException if not in the Configured state or does not require an input surface.
IllegalArgumentException if the surface was not created by createPersistentInputSurface().

setOnFrameRenderedListener

Added in API level 23
void setOnFrameRenderedListener (MediaCodec.OnFrameRenderedListener listener, 
                Handler handler)

注册在输出表面上呈现输出帧时要调用的回调。

可以在任何编解码器状态中调用此方法,但仅对于将缓冲区呈现到输出表面的编解码器在执行状态中起作用。

注意:此回调仅用于提供信息:获取精确的渲染时间采样,并且可以显着延迟和批处理。 即使没有生成回调,某些帧可能已经被渲染。

Parameters
listener MediaCodec.OnFrameRenderedListener: the callback that will be run
handler Handler: the callback will be run on the handler's thread. If null, the callback will be run on the default thread, which is the looper from which the codec was created, or a new thread if there was none.

setOutputSurface

Added in API level 23
void setOutputSurface (Surface surface)

动态设置编解码器的输出表面。

这只能在编解码器配置有输出表面时才能使用。 新的输出表面应与原始输出表面具有兼容的使用类型。 例如编解码器可能不支持从SurfaceTexture(GPU可读)输出切换到ImageReader(软件可读)输出。

Parameters
surface Surface: the output surface to use. It must not be null.
Throws
IllegalStateException if the codec does not support setting the output surface in the current state.
IllegalArgumentException if the new surface is not of a suitable type for the codec.

setParameters

Added in API level 19
void setParameters (Bundle params)

将其他参数更改传递给组件实例。 注意:其中一些参数更改可能无法应用。

Parameters
params Bundle: The bundle of parameters to set.
Throws
IllegalStateException if in the Released state.

setVideoScalingMode

Added in API level 16
void setVideoScalingMode (int mode)

如果先前调用configure(MediaFormat, Surface, MediaCrypto, int)指定了configure(MediaFormat, Surface, MediaCrypto, int)指定要使用的缩放模式。 默认值是“适合缩放”。

缩放模式可被每次时间重置为默认 INFO_OUTPUT_BUFFERS_CHANGED时从编解码器接收的事件; 因此,客户端必须在每次缓冲区更改事件后(并且在释放第一个输出缓冲区以进行渲染之前)调用此方法,以确保一致的缩放模式。

由于 INFO_OUTPUT_BUFFERS_CHANGED事件已被弃用,因此也可以在每个 INFO_OUTPUT_FORMAT_CHANGED事件之后完成。

Parameters
mode int
Throws
IllegalArgumentException if mode is not recognized.
IllegalStateException if in the Released state.

signalEndOfInputStream

Added in API level 18
void signalEndOfInputStream ()

输入信号结束码。 相当于提交一个BUFFER_FLAG_END_OF_STREAM集的空缓冲区。 这只能用于接收来createInputSurface()创建的Surface的输入的编码器。

Throws
IllegalStateException if not in the Executing state.
MediaCodec.CodecException upon codec error.

start

Added in API level 16
void start ()

成功配置组件后,请致电 start

如果编解码器配置为异步模式,并且刚被刷新,则可以调用 start以恢复请求输入缓冲区。

Throws
IllegalStateException if not in the Configured state or just after flush() for a codec that is configured in asynchronous mode.
MediaCodec.CodecException upon codec error. Note that some codec errors for start may be attributed to future method calls.

stop

Added in API level 16
void stop ()

完成解码/编码会话,注意,编解码器实例保持活跃,且已可start()再编。 为了确保它可以被其他客户端调用release()并且不只是依靠垃圾收集来最终为你做到这一点。

Throws
IllegalStateException if in the Released state.

Protected methods

finalize

Added in API level 16
void finalize ()

当垃圾收集确定没有更多对该对象的引用时,由对象上的垃圾回收器调用。 子类会覆盖finalize方法以处置系统资源或执行其他清理。

的常规协定finalize是,它被调用,如果当在Java TM虚拟机已确定不再有由该目的可以通过还没有死亡,除了作为一个动作的结果的任何线程访问的任何手段取决于某些其他可以完成的对象或类别的最终定稿。 方法finalize可以采取任何行动,包括使这个对象再次可用于其他线程; 然而, finalize的通常目的是在对象被不可撤销地丢弃之前执行清理操作。 例如,表示输入/输出连接的对象的finalize方法可能会执行显式I / O事务,以在永久丢弃该对象之前中断连接。

finalize方法Object执行特殊的操作; 它只是正常返回。 Object子类可能会覆盖此定义。

Java编程语言不保证哪个线程将为任何给定对象调用finalize方法。 但是,保证调用finalize的线程在调用finalize时不会保留任何用户可见的同步锁。 如果finalize方法引发未捕获的异常,则忽略该异常,并终止该对象的终止。

在为对象调用 finalize方法后,不会采取进一步的操作,直到Java虚拟机再次确定不再有任何途径可以通过任何尚未死亡的线程访问此对象,包括可能的操作通过准备完成的其他对象或类别,此时该对象可能被丢弃。

对于任何给定的对象,Java虚拟机不会多次调用 finalize方法。

finalize方法抛出的任何异常 finalize导致此对象的终止被暂停,但是会被忽略。

Hooray!