我正在尝试使用 MediaCodec 将帧(通过相机或解码器)编码为视频。
当通过 dequeueOutputBuffer() 处理编码器输出时,我期望收到返回索引 = MediaCodec.INFO_OUTPUT_FORMAT_CHANGED,因此我可以调用 getOutputFormat() 来获取编码器输出格式作为当前使用的 ffmpeg 复用器的输入。
我测试了一些Android版本4.1~4.3的pad/phone设备。它们都至少有一个硬件视频AVC编码器并用于测试。在版本 4.3 的设备上,编码器在按预期写入编码数据之前会给出 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED,并且从 getOutputFormat() 返回的输出格式可以被复用器正确使用。在 4.2.2 或更低版本的设备上,编码器永远不会给出 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED,同时它仍然可以输出编码的基本流,但复用器无法知道确切的输出格式。
我想问以下问题:
- 编码器的行为(在输出编码数据之前是否给出 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)是否取决于 Android API 级别或各个设备上的芯片?
- 如果编码器在MediaCodec.INFO_OUTPUT_FORMAT_CHANGED出现之前写入数据,有没有办法获取编码数据的输出格式?
- 编码器仍然在编码数据之前在设备上输出编解码器配置数据(带有标志 MediaCodec.BUFFER_FLAG_CODEC_CONFIG)。它主要用于配置解码器,但是我可以通过编解码器配置数据导出输出格式吗?
我尝试过这些解决方案来获取输出格式但失败:
- 在整个编码过程中频繁调用 getOutputFormat()。但是,它们都抛出 IllegalStateException,但没有出现 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED。
-
使用初始 MediaFormat 在开始时配置编码器,如下例所示:
m_init_encode_format = MediaFormat.createVideoFormat(m_encode_video_mime, m_frame_width, m_frame_height);
int encode_bit_rate = 3000000;
int encode_frame_rate = 15;
int encode_iframe_interval = 2;
m_init_encode_format.setInteger(MediaFormat.KEY_COLOR_FORMAT, m_encode_color_format);
m_init_encode_format.setInteger(MediaFormat.KEY_BIT_RATE, encode_bit_rate);
m_init_encode_format.setInteger(MediaFormat.KEY_FRAME_RATE, encode_frame_rate);
m_init_encode_format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, encode_iframe_interval);
m_encoder = MediaCodec.createByCodecName(m_video_encoder_codec_info.getName());
m_encoder.configure(m_init_encode_format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
// Assume m_init_encode_format is the output format of the encoder
然而,它失败了,因为编码器的输出格式仍然比初始格式“改变”。
请帮助我实现编码器的行为,以及如果缺少所需的 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED,是否有任何解决方案来查询输出格式。
通过比较输出格式和编解码器配置数据,缺少的字段为 csd-0、csd-1 和值为 1869968451 的“what”字段。
(我不明白“什么”字段。它似乎是一个常量,不是必需的。有人能告诉我它的含义吗?)
如果我将编解码器配置数据解析为 csd-1 字段(最后 8 个字节)和 csd-0 字段(剩余字节),则复用器似乎可以正常工作并输出可在所有测试设备上播放的视频。
(但我想问:这个8字节的假设是否正确,或者有更可靠的方法来解析数据?)
但是,我遇到了另一个问题,如果我再次使用 Android MediaCodec 解码视频,则 dequeueOutputBuffer() 获得的 BufferInfo.presentationTimeUs 值对于大多数解码帧来说都是 0。只有最后几帧的时间是正确的。 MediaExtractor.getSampleTime() 获取的采样时间是正确的,并且与我为编码器/复用器设置的值完全相同,但解码的帧时间不是。此问题仅发生在 4.2.2 或更低版本的设备上。
奇怪的是,帧时间不正确,但视频可以在设备上以正确的速度播放。 (我测试过的大多数 4.2.2 或更低版本的设备只有 1 个视频 AVC 解码器。)我是否需要设置可能影响演示时间的其他字段?
的行为MediaCodec
编码器在 Android 4.3 中进行了更改,以适应引入MediaMuxer
班级。在 Android 4.3 中,您将始终收到INFO_OUTPUT_FORMAT_CHANGED
来自编码器。在以前的版本中,您不会。 (我已经更新了相关常见问题解答条目 http://bigflake.com/mediacodec/#q9.)
无法查询编码器的MediaFormat
.
我没有使用过基于 ffmpeg 的复用器,所以我不确定它需要什么信息。如果它正在寻找 csd-0 / csd-1 密钥,您可以从CODEC_CONFIG
数据包(我认为你必须解析 SPS / PPS 值并将它们放在单独的键中)。检查内容MediaFormat
在 4.3 设备上将显示您缺少哪些字段。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)