如何附加到录制的 MPEG4 AAC 文件?
Posted
技术标签:
【中文标题】如何附加到录制的 MPEG4 AAC 文件?【英文标题】:How can I append to a recorded MPEG4 AAC file? 【发布时间】:2011-03-01 11:50:52 【问题描述】:我正在 iPhone 上录制音频,使用 AVAudioRecorder
并进行以下设置:
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
执行此操作的选项,因此我正在录制到一个新文件并将它们连接起来。
目前我正在使用AVMutableComposition
和AVMutableCompositionTrack
作为here 附加文件,但是对于较长时间的录制来说真的很慢,所以这并不可行。
我想如果我可以从第二个文件中剥离标题,将音频数据附加到第一个文件,然后更改组合文件的标题以反映新的持续时间,那会更快。我知道这两个文件都是使用完全相同的设置创建的,我认为标题中的其他细节应该是相同的。
很遗憾,我找不到任何有关标题格式的信息,或者是否可以以这种方式组合文件。
所以我的问题是:
在 iPhone 上创建的 MPEG-4 AAC 文件头的格式是什么? 我可以通过像这样弄乱标题来合并两个音频文件吗? 有没有更好的方法可以几乎瞬间附加两个 MPEG-4 AAC 音频文件?【问题讨论】:
您绝对需要使用 MPEG4 吗? WAV呢?还是在两者之间转换? 我不知道 teedyay,但我使用 MPEG4 是因为文件压缩。 WAV 太大,两者之间的转换与导出 AVMutableComposition 一样会占用过多的时间。 是的,尺寸肯定是其中的一部分。我们还需要通过网络将生成的音频文件发送到我们无法控制的服务:他们需要接收 AAC。 【参考方案1】:虽然我们要求AVAudioRecorder
以 MPEG4-AAC 格式录制,但它始终会生成一个 .caf(核心音频格式)文件。然而,这只是一种包装格式,它包含的实际音频数据是 AAC 格式。
最后,附加文件归结为逐字节操作 .caf 文件。核心音频格式文件的规范是here。消化这份文档并相应地处理文件一开始有点令人反感,但事实证明规范非常清晰和完整,因此并不太繁重。
正如规范所解释的,.caf 文件由开头有四字节名称的块组成。对于 AAC 文件,总是有一个 desc
块和一个 kuki
块。我们知道我们的两个原始文件格式相同,我们可以将这些块原封不动地复制到输出文件中。
还有一个pakt
块和一个data
块。我们无法保证它们在输入文件中的顺序。可能有也可能没有free
块 - 但这仅包含填充 0x00,因此我们无需将其复制到输出文件。
要合并pakt
块,我们需要检查块头并生成一个新的pakt
块,其mNumberPackets
和mNumberValidFrames
字段是输入文件中的总和。 mPrimingFrames
和 mRemainderFrames
始终为零 - 这些仅与流媒体相关。大部分pakt
块(即实际的数据包表数据)可以连接起来。
data
块也是如此:mChunkSize
字段需要求和,然后可以连接大部分数据。
从这些文件中的所有二进制数字字段读取数据时要小心:这些文件是大端的,但 iPhone 是小端的。
为了获得额外的功劳,您可能还想考虑从文件中删除音频片段,或者将一个音频文件插入另一个文件的中间。这有点棘手,因为您必须解析 pakt
块的内容。再次是遵循规范的情况:有一个很好的描述数据包大小如何存储在可变长度整数中,因此您必须解析这些以找出每个数据包在 data
块中占用的字节数,并据此计算他们的位置。
总而言之,这比我希望的要麻烦得多。也许有一个开源库可以为您完成所有这些工作,但我找不到。
但是,与在原始问题中使用 AVMutableComposition
和 AVMutableCompositionTrack
相比,处理这样的原始文件速度快得令人眼花缭乱 - 将长达一小时的录音插入另一个相同长度的录音大约需要两秒钟。
祝你好运!
【讨论】:
听起来你实现了这个?我现在正在自己处理它,但是如果您在我完成之前有任何可共享的代码,我将不胜感激。 如果可以的话。我的雇主同意我分享代码 sn-ps,但不太热衷于我赠送他们付钱让我花几天时间编写的东西。 :-(【参考方案2】:我找到了一种实现起来更快的方法:
使用 AVAudioRecorder 并使用扩展名“m4a”作为临时文件,但是如果需要,您也可以使用“caf”,但这不是必需的。
修改代码 here 以使用 AVAssetExportPresetPassthrough 和 exportSession.outputFileType = AVFileTypeQuickTimeMovie 和文件名“audioJoined.mov”。使用您新录制的临时 m4a 和现有的 m4a 文件。这为您提供了即时加入(无需重新压缩)并产生“mov”。
注意。不幸的是,AVAudioPlayer 无法播放“mov”,因此下一步是将其转换为可播放的内容。但是,如果您只是要在某处共享文件,则可能会跳过下一步,因为 mov 在 Mac 上的 Quicktime 中可以完美播放。它也可以在 iTunes 中播放并同步回 iPhone 并在 iPod 应用程序中播放。
-
使用 [[AVAssetExportSession alloc] initWithAsset:movFileAsset presetName:AVAssetExportPresetAppleM4A], @"audioJoined.m4a" 作为文件名和 exportSession.outputFileType = AVFileTypeAppleM4A 将 mov 转换回 m4a。同样,这是即时的。我猜在这种情况下,当导出器从 mov 资产而不是 AVMutableComposition 资产开始时,它会更聪明。
我在一个应用程序中使用了这种技术,它能够在停止录制并播放文件后恢复录制,或者即使应用程序重新启动,也很酷。
【讨论】:
感谢您提供此信息。我尝试使用它,它的工作原理与您所说的完全一样。一个缺点是您似乎没有办法控制输出采样率/文件大小。对于我的应用程序,文件大小是原始文件或生成 .mov 文件中的 m4a 的 6 倍。如果您对如何解决此问题有任何想法,我将不胜感激。以上是关于如何附加到录制的 MPEG4 AAC 文件?的主要内容,如果未能解决你的问题,请参考以下文章
使用 AVAssetWriter 和 AVAssetReader 进行音频录制和播放