加入多个ALAC文件。

时间:2012-08-23 14:21:25

标签: iphone objective-c ios macos audiotoolbox

我能够将多个带有编码PCM音频的CAF文件加入其中。首先,我从一个CAF文件中读取数据格式。

UInt32 size = sizeof(srcFormatDescription);
        status = AudioFileGetProperty(srcAudioFile, kAudioFilePropertyDataFormat, &size, &srcFormatDescription);
PCM数据格式的

如下所示

[Line 7697] mSampleRate: 44100.000000
[Line 7698] mFormatID: 1819304813d
[Line 7699] mFormatFlags: 12d
[Line 7700] mBytesPerPacket: 2d
[Line 7701] mFramesPerPacket: 1d
[Line 7702] mBytesPerFrame: 2d
[Line 7703] mChannelsPerFrame: 1d
[Line 7704] mBitsPerChannel: 16d
[Line 7705] mReserved: 0d

然后我为目标文件设置数据格式,其中包含所有CAF。

destFormatDescription = srcFormatDescription;
status = AudioFileCreateWithURL(dest, kAudioFileCAFType, &destFormatDescription, kAudioFileFlags_EraseFile, &destAudioFile);

下一步我从CAF读取数据

status = AudioFileReadBytes(srcAudioFile,
                                    FALSE,
                                    currentStartForReading,
                                    &bytesNumberToRead,
                                    buffer);

并将其写入destAudioFile

status = AudioFileWriteBytes(destAudioFile,
                                     FALSE,
                                     writePosition,
                                     &bytesNumberToWrite,
                                     buffer);

这个步骤是在一个循环中完成的。它很棒。 但是我有很大的问题,现在我尝试对CAF文件执行相同的步骤,其中包含ALAC格式的数据。它不起作用。 AudioFileWriteBytes不支持返回错误操作。

ALAC数据格式的

如下所示

[Line 7697] mSampleRate: 44100.000000
[Line 7698] mFormatID: 1634492771d
[Line 7699] mFormatFlags: 1d
[Line 7700] mBytesPerPacket: 0d
[Line 7701] mFramesPerPacket: 4096d
[Line 7702] mBytesPerFrame: 0d
[Line 7703] mChannelsPerFrame: 1d
[Line 7704] mBitsPerChannel: 0d
[Line 7705] mReserved: 0d

有人知道如何在Apple Lossless数据中加入多个CAF文件吗?

2 个答案:

答案 0 :(得分:1)

  

我能够将多个带有编码PCM音频的CAF文件加入其中。首先,我从一个CAF文件中读取数据格式。

如果ASBD匹配,那么您的音频文件将是正确的。但是,如果输入文件的样本格式不匹配,那么您的数据将会损坏。这是因为每个CAF文件只定义一个样本数据块和一个音频描述块。

因此,尝试将多种格式的样本数据附加到一个音频数据块中将是错误的。 (未指定是否是您正在尝试的内容)

此外,压缩格式还有一个必须设置的附加字段 - 即魔术cookie。所有的cookie必须是相同的(这是一个不透明的数据表示,顺便说一下。)

最后,编写压缩数据的正确方法是使用Packet Table Chunks。 VBR / VFR格式必须只指定一个数据包表块。

  

有人知道如何在Apple Lossless数据中加入多个CAF文件吗?

这一切意味着什么:使用您在ALAC的情况下选择的方法将会出现高故障率。同样,还有很多东西可以保持这些文件及其块与所涉及的所有Packet详细信息正确同步。

所以,让我们从另一个角度来看待这个问题:

  • 使用ExtAudioFileCreateWithURL创建新的ALAC文件
  • 使用ExtAudioFileOpenURL打开输入文件
  • 从输入文件中确定常见的样本格式
  • 使用ExtAudioFileSetProperty + kExtAudioFileProperty_ClientDataFormat指定常用PCM格式
  • 将目标/ ALAC文件的转换器配置为您选择的常用PCM格式。
  • 读取输入文件的示例数据,写入目标
  • 重复剩余文件
  • 关闭所有文件

应该是它(但如果你正在处理原始的AudioFile API,它可能需要几百行代码。)

答案 1 :(得分:0)

我想知道你为什么没有尝试使用AVAssetExportSessionAVMutableCompositionAVAssetAVMutableCompositionTrack。我建议您按照以下步骤合并/合并不同的音频文件。

  1. 使用其网址将每个音频文件加载到AVAsset
  2. 使用以下代码初始化AVMutableComposition对象。

    AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];
    
  3. 将可变音轨添加到可变组合中,如下所示。

    AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    
  4. 将资产时间范围添加到AudioTrack,如下所示。

    [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration)) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
    
  5. 创建AVAssetExportSession并合并代码下的所有音频文件。

    // Prepare final exporter for merging
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition AVAssetExportPresetAppleM4A];
    exporter.outputURL = outputURL;
    exporter.outputFileType = AVFileTypeAppleM4A;
    exporter.videoComposition = mainCompositionInst;
    exporter.shouldOptimizeForNetworkUse = YES;
    
    // Notify caller that merging process is about tro start
    [self.delegate handler:self didStartMergingAtPath:[outputURL path]];
    
    [exporter exportAsynchronouslyWithCompletionHandler:^ {
         dispatch_async(dispatch_get_main_queue(), ^{
             [self exportDidFinishMerging:exporter];
         });
     }];
    
  6. 还实现检查导出过程状态的方法。

    - (void)exportDidFinishMerging:(AVAssetExportSession*)session {
    if(session.status == AVAssetExportSessionStatusCompleted){
    // notify the calling class that merging is finished
    [self.delegate handler:self didFinishMergingAtPath:[session.outputURL path]];
       }
    }
    
  7. 注意:请注意,这不是您可以直接用于代码的示例代码,但这仅用于理解目的。希望这可以帮到你。