【问题标题】:Android MediaCodec How to Frame Accurately Trim AudioAndroid MediaCodec 如何准确分帧修剪音频
【发布时间】:2016-10-18 15:39:16
【问题描述】:

我正在构建在 Android 上精确修剪视频文件的功能。使用MediaExtractorMediaCodecMediaMuxer 实现转码。我需要帮助截断任意音频帧以匹配对应的视频帧。

我认为必须在解码器输出缓冲区中修剪音频帧,这是可用于编辑未压缩音频数据的逻辑位置。

对于输入/输出修剪,我正在计算对原始音频缓冲区的必要偏移和大小调整,以将其塞入可用的端盖帧中,并且我正在使用以下代码提交数据:

MediaCodec.BufferInfo info = pendingAudioDecoderOutputBufferInfos.poll();
...
ByteBuffer decoderOutputBuffer = audioDecoder.getOutputBuffer(decoderIndex).duplicate();
decoderOutputBuffer.position(info.offset);
decoderOutputBuffer.limit(info.offset + info.size);
encoderInputBuffer.position(0);
encoderInputBuffer.put(decoderOutputBuffer);
info.flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
audioEncoder.queueInputBuffer(encoderIndex, info.offset, info.size, presentationTime, info.flags);
audioDecoder.releaseOutputBuffer(decoderIndex, false);

我的问题是数据调整似乎只影响复制到输出音频缓冲区的数据,而不是缩短写入MediaMuxer 的音频帧。输出视频要么在剪辑末尾丢失几毫秒的音频,要么如果我写入太多数据,音频帧会从剪辑末尾完全丢弃。

如何正确修剪音频帧?

【问题讨论】:

  • 如果我理解正确,当您调用queueInputBuffer 时,使用info.offset 似乎存在差异。编码器输入缓冲区不是从 0 运行到 info.size 而不是 info.offset 到 (info.offset + info.size) 吗?也许您所经历的时间差异正是 0 和 offset 之间的数据量?
  • @Dave 我相信你是对的。不能保证decoderOutputBufferencoderInputBufferaudioEncoder.queueInputBuffer 都将使用相同的sizeoffset 值。我确实尝试了几种组合。我也相信我只是在减少数据的大小,而不是容器。我开始考虑该解决方案可能涉及类似于MediaCodec.BUFFER_FLAG_CODEC_CONFIG 的配置更改。

标签: android audio android-mediacodec mediamuxer mediaextractor


【解决方案1】:

这里有几件事在起作用:

  • 正如 Dave 指出的,您应该将 0 而不是 info.offset 传递给 audioEncoder.queueInputBuffer - 当您使用 decoderOutputBuffer.position(info.offset); 设置缓冲区位置时,您已经考虑了解码器输出缓冲区的偏移量。但也许您已经以某种方式对其进行了更新。

  • 我不确定 MediaCodec 音频编码器是否允许您以任意大小的块传递音频数据,或者您需要一次发送完全完整的音频帧。我认为它可能会接受它 - 那么你很好。如果没有,您需要自己缓冲音频,并在获得完整帧后将其传递给编码器(以防您在开始时修剪掉一些)

  • 请记住,音频也是基于帧的(对于 AAC,它是 1024 个样本帧,除非您使用低延迟变体或 HE-AAC),因此对于 44 kHz,您只能使用 23毫秒粒度。如果您希望音频在正确数量的样本后准确结束,您需要使用容器信号来指示这一点。我不确定 MediaCodec 音频编码器是否会刷新您最后拥有的任何半帧,或者如果您未与帧大小。不过可能不需要。

  • 编码 AAC 音频确实会在音频流中引入一些延迟;解码后,您将在解码流的开头有许多启动样本(这些样本的确切数量取决于编码器 - 对于 Android 中用于 AAC-LC 的软件编码器,它可能是 2048 个样本,但也可能各不相同)。对于 2048 个样本的情况,它正好与 2 帧音频对齐,但它也可能不是整数帧。我也不认为 MediaCodec 表示确切的延迟量。如果您从编码器丢弃 2 个第一个输出数据包(如果延迟为 2048 个样本),您将避免额外的延迟,但前几帧的实际解码音频不会完全正确。 (启动数据包对于能够正确表示您的流开始的任何样本都是必要的,否则它将或多或少地收敛到 2048 个样本内的预期音频。)

【讨论】:

  • 谢谢。今年早些时候,您还回答了我的一个问题,并在这里为我提供了很大的帮助:stackoverflow.com/a/35885471/376829。我同意@Dave 和你关于偏移量的看法。
  • @mstorsjo @David Manpearl 嗨,我使用 MediaCodec 将原始 PCM 数据编码为 AAC 原始数据并将其解码回来。我正在尝试修复错误audio does not get processed right away until you input enough data。例如,用户记录“你好,我的名字是 Kidfrom”,只有“你好,我的名字”会被处理,3 分钟后用户记录的“你来自哪里?”,再次只有“你在哪里”会被正确处理离开。其他用户听到的第一句话是“你好,我的名字是”,3 分钟后是“kidfrom,你在哪里”。这很奇怪。你愿意帮助我吗?
  • 无论如何,我读了你的第二点,我试图设置android.media.AudioRecord bufferSizeInBytes to 2048, it's the MediaCodec.BufferInfo.size value,我认为这是帧大小。但它并没有修复错误。
猜你喜欢
  • 2022-07-26
  • 2015-11-09
  • 2016-10-04
  • 2023-03-27
  • 1970-01-01
  • 2020-08-04
  • 2016-03-12
  • 2022-01-11
  • 1970-01-01
相关资源
最近更新 更多