Android MediaCodec如何准确地修剪音频

时间:2016-06-16 23:01:25

标签: android audio mediacodec mediamuxer mediaextractor

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

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

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

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的音频帧。输出视频最后会在剪辑结束时丢失几毫秒的音频,或者如果我写了太多数据,音频帧会从剪辑的末尾完全丢弃。

如何正确修剪音频帧?

1 个答案:

答案 0 :(得分:1)

这里有一些事情可以发挥作用:

  • 正如Dave指出的那样,你应该将0而不是info.offset传递给audioEncoder.queueInputBuffer - 当你用{{设置缓冲区位置时,你已经考虑了解码器输出缓冲区的偏移量了1}}。但也许你已经以某种方式更新了它。

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

  • 请记住,音频也是基于帧的(对于AAC,它是1024个采样帧,除非您使用低延迟变体或HE-AAC),因此对于44 kHz,您可以拥有音频持续时间只有23毫秒的粒度。如果您希望音频在适当数量的样本之后精确结束,则需要使用容器信号来指示此情况。我不确定MediaCodec音频编码器是否会刷新你最后的半帧,或者如果你手动需要在末尾传递额外的零以获得最后几个样本,如果你不是这样的话。 t与框架尺寸对齐。但可能不需要它。

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

相关问题