4

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

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

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

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. 输出视频要么在剪辑末尾丢失几毫秒的音频,要么如果我写入太多数据,音频帧会从剪辑末尾完全丢弃。

如何正确修剪音频帧?

4

1 回答 1

4

这里有几件事在起作用:

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

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

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

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

于 2016-06-17T13:01:39.820 回答