如何附加到录制的MPEG4 AAC文件?

时间:2011-03-01 11:50:53

标签: iphone objective-c audio avaudiorecorder aac

我正在使用AVAudioRecorder使用以下设置在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执行此操作,因此我正在录制到一个新文件并连接它们。

目前,我使用AVMutableCompositionAVMutableCompositionTrack作为here附加文件,但是对于较长的录制内容来说真的很慢,所以这不太可行。

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

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

所以我的问题是:

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

2 个答案:

答案 0 :(得分:3)

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

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

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

还有一个pakt块和一个data块。我们无法保证输入文件中的这些顺序。可能有也可能没有free块 - 但这只包含填充0x00,所以我们不需要将它复制到输出文件。

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

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

从这些文件中的所有二进制数字字段读取数据时要小心:文件是big-endian但iPhone是little-endian。

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

总而言之,这比我希望的更麻烦。也许有一个开源库可以为你做这一切,但我找不到一个。

然而,与原始问题中使用AVMutableCompositionAVMutableCompositionTrack相比,处理这样的原始文件的速度非常快 - 将长达一小时的记录插入另一个相同长度的记录大约需要两秒钟。

祝你好运!

答案 1 :(得分:1)

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

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

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

  3. 请注意。不幸的是,AVAudioPlayer无法播放“mov”,因此下一步是将其转换为可播放的内容。但是,如果你只是想在某个地方共享文件,那么你可能会跳过下一步,因为在Quicktime中可以在Mac上完全播放mov。它也可以在iTunes中播放并同步回iPhone并在iPod应用程序中播放。

    1. 使用[[AVAssetExportSession alloc] initWithAsset:movFileAsset presetName:AVAssetExportPresetAppleM4A],@“audioJoined.m4a”将文件名和exportSession.outputFileType = AVFileTypeAppleM4A转换回m4a。再次,这是即时的。我猜这个出口商在这种情况下更聪明,因为它以mov资产而不是AVMutableComposition资产开始。
    2. 我在一个应用程序中使用此技术,该应用程序能够在录制停止并且文件已播放后恢复录制,或者即使应用程序重新启动,也非常酷。