5

我正在使用AVAudioRecorder具有以下设置的 iPhone 在 iPhone 上录制音频:

NSMutableDictionary *recordSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
       [NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
       [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
       [NSNumber numberWithInt:1], AVNumberOfChannelsKey,
       [NSNumber numberWithInt:12800], AVEncoderBitRateKey,
       [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
       [NSNumber numberWithInt: AVAudioQualityHigh],  AVEncoderAudioQualityKey,
       nil];

(我可以灵活使用这些设置中的大多数,但我必须使用 MPEG4 AAC。)

我将音频保存到文件中。

用户需要能够在以后返回并继续录制到同一文件。似乎没有直接使用的选项AVAudioRecorder,所以我正在录制到一个新文件并将它们连接起来。

目前我正在使用 anAVMutableComposition和 an AVMutableCompositionTrackas here附加文件,但对于较长的录音来说真的很慢,所以这不是真的可行。

我想如果我可以从第二个文件中剥离标题,将音频数据附加到第一个文件,然后更改组合文件的标题以反映新的持续时间,那会快得多。我知道这两个文件都是用完全相同的设置创建的,我认为标题中的其他细节应该是相同的。

不幸的是,我找不到任何有关标题格式的信息,或者是否可以以这种方式组合文件。

所以我的问题是:

  • 在 iPhone 上创建时,MPEG-4 AAC 文件头的格式是什么?
  • 我可以通过弄乱这样的标题来组合两个音频文件吗?
  • 有没有更好的方法可以几乎瞬间附加两个 MPEG-4 AAC 音频文件?
4

2 回答 2

3

虽然我们要求AVAudioRecorder以 MPEG4-AAC 格式录制,但它总是会生成一个 .caf(核心音频格式)文件。然而,这只是一种包装格式,它包含的实际音频数据是 AAC 格式。

最后,附加文件归结为逐字节操作 .caf 文件。核心音频格式文件的规范在这里。消化这个文档并相应地处理文件起初有点令人反感,但事实证明规范非常清晰和完整,因此并不太繁重。

正如规范所解释的,.caf 文件由开头有四字节名称的块组成。对于 AAC 文件,总是有一个desc块和一个kuki块。我们知道我们的两个原始文件格式相同,我们可以将这些块原封不动地复制到输出文件中。

还有一pakt大块和一data大块。我们无法保证它们在输入文件中的顺序。可能有也可能没有free块 - 但这仅包含填充 0x00,因此我们无需将其复制到输出文件。

为了组合pakt块,我们需要检查块头并生成一个新pakt块,其mNumberPacketsmNumberValidFrames字段是输入文件中的总和。和始终为零 - 这些仅与流媒体相关mPrimingFramesmRemainderFrames大部分pakt块(即实际的数据包表数据)可以连接起来。

对于data块也是如此:mChunkSize需要对字段求和,然后可以连接大部分数据。

从这些文件中的所有二进制数字字段读取数据时要小心:文件是大端的,但 iPhone 是小端的。

为了获得额外的功劳,您可能还想考虑从文件中删除音频片段,或者将一个音频文件插入另一个文件的中间。这有点棘手,因为您必须解析pakt块的内容。同样是遵循规范的情况:有一个很好的描述数据包大小如何存储在可变长度整数中,因此您必须解析这些以找出每个数据包在data块中占用的字节数,并计算它们的相应的位置。

总而言之,这比我希望的要麻烦得多。也许有一个开源库可以为您完成所有这些工作,但我找不到。

AVMutableComposition但是,与使用和原始问题相比,像这样处理原始文件的速度快得令人眼花缭乱AVMutableCompositionTrack- 将长达一小时的录音插入另一个相同长度的录音大约需要两秒钟。

祝你好运!

于 2011-03-21T09:58:09.340 回答
1

我找到了一种实施起来更快的方法:

  1. 使用 AVAudioRecorder 并使用扩展名“m4a”作为临时文件,但是如果需要,您也可以使用“caf”,但这不是必需的。

  2. 修改此处的代码以使用 AVAssetExportPresetPassthrough 和 exportSession.outputFileType = AVFileTypeQuickTimeMovie 和文件名“audioJoined.mov”。使用您新录制的临时 m4a 和现有的 m4a 文件。这为您提供了即时加入(无需重新压缩)并产生“mov”。

笔记。不幸的是,AVAudioPlayer 无法播放“mov”,因此下一步是将其转换为可播放的内容。但是,如果您只是要在某处共享文件,则可能会跳过下一步,因为 mov 在 Mac 上的 Quicktime 中可以完美播放。它也可以在 iTunes 中播放并同步回 iPhone 并在 iPod 应用程序中播放。

  1. 使用 [[AVAssetExportSession alloc] initWithAsset:movFileAsset presetName:AVAssetExportPresetAppleM4A], @"audioJoined.m4a" 作为文件名和 exportSession.outputFileType = AVFileTypeAppleM4A 将 mov 转换回 m4a。同样,这是即时的。我猜在这种情况下,当导出器以 mov 资产而不是 AVMutableComposition 资产开始时,它会更聪明。

我在一个应用程序中使用了这种技术,该应用程序能够在停止录制并播放文件后恢复录制,或者即使应用程序重新启动,也很酷。

于 2011-06-09T01:32:21.293 回答