public final class MediaCodec
extends Object
java.lang.Object | |
↳ | android.media.MediaCodec |
MediaCodec类可用于访问低级媒体编解码器,即编码器/解码器组件。 它是Android低电平多媒体支持基础设施的一部分(通常与一起使用MediaExtractor
, MediaSync
, MediaMuxer
, MediaCrypto
, MediaDrm
, Image
, Surface
,和AudioTrack
)。
广义而言,编解码器处理输入数据以生成输出数据。 它异步处理数据并使用一组输入和输出缓冲区。 在简单的层面上,您请求(或接收)一个空输入缓冲区,填充数据并将其发送到编解码器进行处理。 编解码器使用数据并将其转换为其空的输出缓冲区之一。 最后,您请求(或接收)一个填充的输出缓冲区,消耗其内容并将其释放回编解码器。
编解码器对三种数据进行操作:压缩数据,原始音频数据和原始视频数据。 所有三种数据都可以使用ByteBuffers
进行处理,但您应该使用Surface
作为原始视频数据以提高编解码器的性能。 Surface使用本地视频缓冲区而不映射或将它们复制到ByteBuffers; 因此,它更有效率。 使用Surface时通常无法访问原始视频数据,但可以使用ImageReader
类来访问不安全的已解码(原始)视频帧。 这可能仍然比使用ByteBuffers更高效,因为某些本地缓冲区可能映射到direct ByteBuffers中。 当使用ByteBuffer的模式,您可以使用访问原始视频帧Image
类和getInput
/ OutputImage(int)
。
根据format's type,输入缓冲器(用于解码器)和输出缓冲器(用于编码器)包含压缩数据。 对于视频类型,这是一个单一的压缩视频帧。 对于音频数据,这通常是单个访问单元(编码音频段通常包含由格式类型指示的几毫秒的音频),但是由于缓冲器可能包含多个编码的音频存取单元,所以这个要求稍微宽松。 无论哪种情况,缓冲区都不会以任意字节边界开始或结束,而是在帧/访问单元边界上开始或结束。
原始音频缓冲区包含整个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; }
在ByteBuffer模式下,视频缓冲区按照其color format进行布局 。 您可以从getCodecInfo()
.
getCapabilitiesForType(…)
.
colorFormats
获得支持的颜色格式。 视频编解码器可支持三种颜色格式:
COLOR_FormatSurface
and it can be used with an input or output Surface.COLOR_FormatYUV420Flexible
): These can be used with an input/output Surface, as well as in ByteBuffer mode, by using getInput
/OutputImage(int)
.MediaCodecInfo.CodecCapabilities
. For color formats that are equivalent to a flexible format, you can still use getInput
/OutputImage(int)
.自 LOLLIPOP_MR1
以来,所有视频编解码器都支持灵活的YUV 4:2:0缓冲区。
在支持 LOLLIPOP
和 Image
之前,需要使用 KEY_STRIDE
和 KEY_SLICE_HEIGHT
输出格式值来了解原始输出缓冲区的布局。
请注意,在某些设备上,切片高度被广告为0.这可能意味着切片高度与帧高度相同,或者切片高度是与某个值对齐的帧高度(通常是2)。 不幸的是,在这种情况下无法分辨实际的切片高度。 此外,平面格式的U
平面的垂直跨度也未被指定或定义,尽管通常它是切片高度的一半。
KEY_WIDTH
和KEY_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
的含义在各个设备上并不一致。 在某些设备上,偏移指向裁剪矩形的左上角像素,而在大多数设备上,它指向整个帧的左上角像素。
在其生命周期中,编解码器概念上存在三种状态之一:停止,执行或释放。 停止的集体状态实际上是三种状态的集合:未初始化,已配置和错误,而执行状态在概念上通过三个子状态:刷新,运行和结束流。
当您使用其中一种工厂方法创建编解码器时,编解码器处于未初始化状态。 首先,您需要通过configure(…)
进行配置,使其进入Configured状态,然后调用start()
将其移至Executing状态。 在这种状态下,您可以通过上述的缓冲区队列处理来处理数据。
执行状态有三个子状态:刷新,运行和结束流。 紧接在start()
之后,编解码器处于Flushed子状态,它保存所有缓冲区。 只要第一个输入缓冲区出列,编解码器就会转移到运行子状态,在该状态下它大部分时间都在使用。 当您使用end-of-stream marker对输入缓冲区进行排队时 ,编解码器将转换为流结束子状态。 在这种状态下,编解码器不再接受进一步的输入缓冲器,但仍然产生输出缓冲器,直到输出端达到输出端。 您可以在处于Executing状态时使用flush()
随时移回Flushed子状态。
调用stop()
可将编解码器返回到未初始化状态,然后可再次进行配置。 当您完成使用编解码器时,您必须通过拨打release()
来释放它。
在极少数情况下,编解码器可能会遇到错误并进入错误状态。 这是使用来自排队操作的无效返回值或有时通过异常传递的。 致电reset()
以使编解码器再次可用。 您可以从任何状态调用它以将编解码器移回未初始化状态。 否则,请致电release()
移至终端发布状态。
使用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)
。 但是,这不能用于注入功能,并且可能会创建无法处理特定所需媒体格式的编解码器。
在版本KITKAT_WATCH
和更早的版本上,安全编解码器可能不会在MediaCodecList
列出,但仍可能在系统上可用。 通过将".secure"
附加到常规编解码器的名称(所有安全编解码器的名称必须以".secure"
结尾),可以通过名称仅实例化存在的安全编解码器。如果编解码器不存在于系统上, createByCodecName(String)
将抛出IOException
。
从 LOLLIPOP
开始,您应该使用媒体格式中的 FEATURE_SecurePlayback
功能来创建安全解码器。
创建编解码器后,如果要异步处理数据,可以使用setCallback
设置回调。 然后, configure使用特定的媒体格式的编解码器。 这是您可以为视频制作者指定输出Surface
生成原始视频数据的编解码器(例如视频解码器)。 这也是您可以设置安全编解码器的解密参数时的情况(请参阅MediaCrypto
)。 最后,由于一些编解码器可以在多种模式下运行,因此您必须指定是否要将其用作解码器或编码器。
从LOLLIPOP
,您可以在Configured状态下查询生成的输入和输出格式。 在启动编解码器之前,您可以使用它来验证生成的配置,例如颜色格式。
如果您想要使用视频使用者本地处理原始输入视频缓冲区 - 处理原始视频输入的编解码器(例如视频编码器) - 在配置后使用createInputSurface()
为输入数据创建目标表面。 或者,建立了编解码器使用以前创建persistent input surface致电setInputSurface(Surface)
。
某些格式,特别是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标记的输出缓冲区中的任何有效输出缓冲区之前创建并返回编解码器特定数据。 包含编解码器专用数据的缓冲器没有有意义的时间戳。
每个编解码器都维护一组由API调用中的缓冲区ID引用的输入和输出缓冲区。 在成功调用start()
,客户端“拥有”既没有输入也没有输出缓冲区。 在同步模式中,呼叫dequeueInput
/ OutputBuffer(…)
获得(获得的所有权)从编解码器的输入或输出缓冲区。 在异步模式下,您将自动通过接收可用缓冲区MediaCodec.Callback.onInput
/ OutputBufferAvailable(…)
回调。
在获得输入缓冲区时,填充数据并使用queueInputBuffer
或queueSecureInputBuffer
如果使用解密)将其提交给编解码器。 不要使用相同的时间戳提交多个输入缓冲区(除非它被标记为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 |
由于LOLLIPOP
,首选方法是在调用configure
之前通过设置回调来异步处理数据。 异步模式改变的状态转换咯,因为你必须调用start()
后flush()
过渡编解码器的跑分状态,并开始接收输入缓冲器。 同样,在初始调用start
,编解码器将直接移至Running子状态,并通过回调开始传递可用的输入缓冲区。
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();
由于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();
在版本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();
当你到达输入数据的最后,你必须通过指定其信号编解码器BUFFER_FLAG_END_OF_STREAM
呼叫标志queueInputBuffer
。 您可以在最后一个有效的输入缓冲区上执行此操作,或者通过提交一个额外的空输入缓冲区并设置流结束标志。 如果使用空缓冲区,时间戳将被忽略。
编解码器将继续返回输出缓冲区,直到它最终通过在MediaCodec.BufferInfo
设置的dequeueOutputBuffer
指定的相同流结束标志或通过onOutputBufferAvailable
返回来发onOutputBufferAvailable
输出流的结束。 这可以在最后一个有效的输出缓冲区上设置,或者在最后一个有效的输出缓冲区之后的空缓冲区上设置。 这个空缓冲区的时间戳应该被忽略。
除非编解码器已被刷新,停止或重新启动,否则在发出输入流结束信号后,请勿提交其他输入缓冲区。
在使用输出Surface
时,数据处理与ByteBuffer模式几乎相同; 但是,输出缓冲区将不可访问,并表示为null
值。 例如getOutputBuffer
/ Image(int)
将返回null
和getOutputBuffers()
将返回仅含有一个数组null
-s。
使用输出曲面时,可以选择是否渲染曲面上的每个输出缓冲区。 你有三个选择:
releaseOutputBuffer(bufferId, false)
.releaseOutputBuffer(bufferId, true)
.releaseOutputBuffer(bufferId, timestamp)
.由于M
,默认时间戳是缓冲区的presentation timestamp (转换为纳秒)。 在此之前没有定义。
另外由于 M
,您可以使用 setOutputSurface
动态更改输出曲面。
在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
事件已被弃用,因此每次输出格式更改后都可以这样做。
当使用输入表面时,没有可访问的输入缓冲区,因为缓冲区会自动从输入表面传递到编解码器。 调用dequeueInputBuffer
将抛出一个IllegalStateException
,并且getInputBuffers()
返回一个不能写入的伪造的ByteBuffer[]
数组。
致电signalEndOfInputStream()
以表示流结束。 此通话后,输入表面将立即停止向编解码器提交数据。
视频解码器(以及一般使用压缩视频数据的编解码器)在搜索和格式更改方面表现不同,无论它们是否支持并配置为自适应播放。 您可以检查解码器支持adaptive playback通过CodecCapabilities.isFeatureSupported(String)
。 只有将编解码器配置为解码到Surface
才会激活对视频解码器的自适应播放支持。
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.) |
为了开始解码与先前提交的数据不相邻的数据(即,在寻找之后),您必须清空解码器。 由于所有输出缓冲区在冲洗点立即被撤销,因此您可能需要首先发出信号,然后等待数据流结束,然后再致电flush
。 冲洗后的输入数据始于合适的流边界/关键帧,这一点很重要。
注意:刷新后提交的数据格式不能改变; flush()
不支持格式不连续; 为此,完整的stop()
- configure(…)
- start()
周期是必要的。
另请注意:如果您在start()
之后start()
刷新编解码器 - 通常在收到第一个输出缓冲区或输出格式更改之前 - 您将需要重新提交编解码器特定数据到编解码器。 有关更多信息,请参阅codec-specific-data section 。
为了开始解码与先前提交的数据不相邻的数据(即,在寻找之后), 不需要刷新解码器; 然而,不连续性之后的输入数据必须从合适的流边界/关键帧开始。
对于某些视频格式(即H.264,H.265,VP8和VP9),也可以在中途更改图片大小或配置。 为此,您必须将全部新的编解码器专用配置数据与关键帧一起打包到单个缓冲区(包括任何启动代码)中,并将其作为常规输入缓冲区提交。
您将收到来自 dequeueOutputBuffer
的 INFO_OUTPUT_FORMAT_CHANGED
返回值或 onOutputFormatChanged
在图片大小更改发生后以及任何具有新大小的帧返回之前的回 INFO_OUTPUT_FORMAT_CHANGED
值。
注意:就像编解码器专用数据的情况一样,在更改图片尺寸后不久请致电flush()
时请小心。 如果您还没有收到图片尺寸更改的确认,则需要重新请求新图片尺寸。
该工厂方法createByCodecName
和createDecoder
/ EncoderByType
掷IOException
失败,你必须赶上或申报错过。 当方法从不允许的编解码器状态调用时,MediaCodec方法抛出IllegalStateException
; 这通常是由于不正确的应用程序API使用。 涉及安全缓冲区的方法可能会抛出MediaCodec.CryptoException
,它具有可从getErrorCode()
获得的更多错误信息。
内部编解码器错误导致MediaCodec.CodecException
,这可能是由于媒体内容损坏,硬件故障,资源耗尽等等,即使应用程序正确使用API。 通过拨打isRecoverable()
和isTransient()
可以确定收到CodecException
时的建议操作:
isRecoverable()
returns true, then call stop()
, configure(…)
, and start()
to recover.isTransient()
returns true, then resources are temporarily unavailable and the method may be retried at a later time.isRecoverable()
and isTransient()
return false, then the CodecException
is fatal and the codec must be reset or released.isRecoverable()
和 isTransient()
都不会同时返回true。
本部分总结了每种状态下有效的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 |
● | ● | ● | ● | ● | ● | ● | ● |
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中已弃用。请改为使用 |
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中已弃用。由于 |
int |
INFO_OUTPUT_FORMAT_CHANGED 输出格式已更改,后续数据将采用新格式。 |
int |
INFO_TRY_AGAIN_LATER 如果在 |
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) 返回一个 |
ByteBuffer[] |
getInputBuffers() 此方法在API级别21中已弃用。每次输入缓冲区出列时,请使用新的 |
final MediaFormat |
getInputFormat() 在 |
Image |
getInputImage(int index) 返回出队输入缓冲区索引的可写Image对象,以包含原始输入视频帧。 |
final String |
getName() 获取组件名称。 |
ByteBuffer |
getOutputBuffer(int index) 返回出队输出缓冲区索引的只读ByteBuffer。 |
ByteBuffer[] |
getOutputBuffers() 此方法在API级别21中已弃用。每次输出缓冲区出列时,请使用新的 |
final MediaFormat |
getOutputFormat(int index) 返回特定输出缓冲区的输出格式。 |
final MediaFormat |
getOutputFormat() 在dequeueOutputBuffer通过返回 |
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) 类似于 |
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) 如果先前调用 |
final void |
signalEndOfInputStream() 输入信号结束码。 |
final void |
start() 成功配置组件后,请致电 |
final void |
stop() 完成解码/编码会话,注意,编解码器实例保持活跃,且已可 |
Protected methods |
|
---|---|
void |
finalize() 当垃圾收集确定没有更多对该对象的引用时,由对象上的垃圾回收器调用。 |
Inherited methods |
|
---|---|
From class java.lang.Object
|
int BUFFER_FLAG_CODEC_CONFIG
这表明标记为这样的缓冲区包含编解码器初始化/编解码器特定数据而不是媒体数据。
常量值:2(0x00000002)
int BUFFER_FLAG_END_OF_STREAM
这表示流的结束,即在此之后没有缓冲区可用,除非 flush()
。
常量值:4(0x00000004)
int BUFFER_FLAG_KEY_FRAME
这表示标记为(编码)的缓冲区包含关键帧的数据。
常数值:1(0x00000001)
int BUFFER_FLAG_SYNC_FRAME
此常数在API级别21中已弃用。
改为使用BUFFER_FLAG_KEY_FRAME
。
这表示标记为(编码)的缓冲区包含关键帧的数据。
常数值:1(0x00000001)
int CONFIGURE_FLAG_ENCODE
如果此编解码器要用作编码器,请传递此标志。
常数值:1(0x00000001)
int INFO_OUTPUT_BUFFERS_CHANGED
此常数在API级别21中已弃用。
这个返回值可以被忽略,因为getOutputBuffers()
已被弃用。 每次出队时,客户端都应该使用get-buffer或get-image方法的on命令来请求当前缓冲区。
输出缓冲区已更改,客户端必须参考 getOutputBuffers()
从 getOutputBuffers()
返回的新输出缓冲区集。
此外,此事件表示视频缩放模式可能已重置为默认值。
常量值:-3(0xfffffffd)
int INFO_OUTPUT_FORMAT_CHANGED
输出格式已更改,后续数据将采用新格式。 getOutputFormat()
返回新的格式。 请注意,您也可以使用新的getOutputFormat(int)
方法获取特定输出缓冲区的格式。 这使您无需跟踪输出格式更改。
常量值:-2(0xfffffffe)
int INFO_TRY_AGAIN_LATER
如果在 dequeueOutputBuffer(MediaCodec.BufferInfo, long)
的呼叫中指定了非负超时,则表示呼叫超时。
常量值:-1(0xffffffff)
String PARAMETER_KEY_REQUEST_SYNC_FRAME
请求编码器“很快”产生一个同步帧。 提供值为0的整数。
常量值:“请求同步”
String PARAMETER_KEY_SUSPEND
临时挂起/恢复输入数据的编码。 暂停的输入数据被有效地丢弃,而不是被送入编码器。 该参数对于在“表面输入”模式下使用编码器确实非常有意义,因为在这种情况下客户端代码无法控制编码器的输入端。 该值是一个Integer对象,其中包含暂挂值1或要恢复的值0。
常量值:“drop-input-frames”
String PARAMETER_KEY_VIDEO_BITRATE
即时更改视频编码器的目标比特率。 该值是包含bps新比特率的Integer对象。
常数值:“视频比特率”
int VIDEO_SCALING_MODE_SCALE_TO_FIT
内容缩放到表面尺寸
常数值:1(0x00000001)
int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
内容被缩放,保持其宽高比,整个表面区域被使用,内容可能被裁剪。
此模式仅适用于1:1像素长宽比的内容,因为您无法配置 Surface
的像素宽高比。
从 N
版本开始,如果视频是 rotated 90或270度,则此模式可能不起作用。
常量值:2(0x00000002)
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. |
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. |
MediaCodec createDecoderByType (String type)
实例化支持给定MIME类型的输入数据的首选解码器。 以下是定义的MIME类型及其语义的部分列表:
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. |
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. |
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. |
Surface createPersistentInputSurface ()
创建可与通常具有输入表面的编解码器一起使用的持久输入表面,例如视频编码器。 持续输入可以被后续的MediaCodec
或MediaRecorder
实例重复使用,但最多只能同时使用一个编解码器或记录器实例。
应用程序负责在完成时调用Surface上的release()。
Returns | |
---|---|
Surface |
an input surface that can be used with setInputSurface(Surface) . |
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. |
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. |
void flush ()
冲洗组件的输入和输出端口。
返回后,以前通过调用 dequeueInputBuffer
和 dequeueOutputBuffer
返回的所有索引或通过 onInputBufferAvailable
或 onOutputBufferAvailable
回调获得的 onInputBufferAvailable
变为无效,并且所有缓冲区都归编解码器所有。
如果编解码器配置为异步模式,则返回flush
以恢复编解码器操作后调用start()
。 在这种情况发生之前,编解码器不会请求输入缓冲器。 但请注意,在致电flush
之前,可能仍有未完成的onOutputBufferAvailable
回调。 通过这些回调返回的指数在拨打flush
后也会失效,应该丢弃。
如果编解码器配置为同步模式,则编解码器将在配置输入表面时自动恢复。 否则,将在dequeueInputBuffer
被调用时恢复。
Throws | |
---|---|
IllegalStateException |
if not in the Executing state. |
MediaCodec.CodecException |
upon codec error. |
MediaCodecInfo getCodecInfo ()
获取编解码器信息。 如果编解码器是由createDecoderByType或createEncoderByType创建的,则选择哪个组件并不是事先知道的,因此调用者没有MediaCodecInfo。
Returns | |
---|---|
MediaCodecInfo |
Throws | |
---|---|
IllegalStateException |
if in the Released state. |
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. |
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. |
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. |
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. |
String getName ()
获取组件名称。 如果编解码器是由createDecoderByType或createEncoderByType创建的,则选择的组件是事先不知道的。
Returns | |
---|---|
String |
Throws | |
---|---|
IllegalStateException |
if in the Released state. |
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. |
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. |
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. |
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. |
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. |
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) |
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. |
void release ()
释放编解码器实例使用的资源。 确保在你完成释放任何打开的组件实例时调用它,而不是依赖垃圾回收器在将来的某个时刻为你做这件事。
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. |
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:
|
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. |
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. |
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.) |
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). |
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() . |
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. |
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. |
void setParameters (Bundle params)
将其他参数更改传递给组件实例。 注意:其中一些参数更改可能无法应用。
Parameters | |
---|---|
params |
Bundle : The bundle of parameters to set. |
Throws | |
---|---|
IllegalStateException |
if in the Released state. |
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. |
void signalEndOfInputStream ()
输入信号结束码。 相当于提交一个BUFFER_FLAG_END_OF_STREAM
集的空缓冲区。 这只能用于接收来createInputSurface()
创建的Surface的输入的编码器。
Throws | |
---|---|
IllegalStateException |
if not in the Executing state. |
MediaCodec.CodecException |
upon codec error. |
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. |
void stop ()
完成解码/编码会话,注意,编解码器实例保持活跃,且已可start()
再编。 为了确保它可以被其他客户端调用release()
并且不只是依靠垃圾收集来最终为你做到这一点。
Throws | |
---|---|
IllegalStateException |
if in the Released state. |
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
导致此对象的终止被暂停,但是会被忽略。