1

我能够加入多个 CAF 文件,其中包含编码的 PCM 音频。首先,我从一个 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);

这些步骤是循环完成的。它工作得很好。但是我有一个大问题,现在我尝试对包含 ALAC 格式数据的 CAF 文件执行相同的步骤。它不起作用。不支持 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

有人知道如何加入多个 CAF 文件,里面有 Apple Lossless 数据吗?

4

2 回答 2

1

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

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

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

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

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

有人知道如何加入多个 CAF 文件,里面有 Apple Lossless 数据吗?

What this all means: There will be a high failure rate using the approach you have chosen in the case of ALAC. As well, there's a lot that goes into keeping these files and their chunks correctly synchronized with all the Packet detail that is involved.

So, let's approach this from another angle:

  • use ExtAudioFileCreateWithURL to create a new ALAC file
  • use ExtAudioFileOpenURL to open your input files
  • determine a common sample format from your input files
  • use ExtAudioFileSetProperty + kExtAudioFileProperty_ClientDataFormat to specify the common PCM format
  • Configure the destination/ALAC file's convertor to expect the common PCM format you have chosen.
  • read an input file's sample data, writing to the destination
  • repeat for remaining files
  • close all files

That should be it (but it will probably require a few hundred lines of code, if you are dealing with the raw AudioFile APIs).

于 2012-08-27T07:31:53.157 回答
0

I am wondering why you haven't tried using AVAssetExportSession ,AVMutableComposition, AVAsset,AVMutableCompositionTrack . I can suggest you to follow below steps to combine/merge different audio files.

  1. Load each audio file using its URL into AVAsset.
  2. Initialize AVMutableComposition object using below code.

    AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];
    
  3. Add mutable audio track to mutable composition like below.

    AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    
  4. Add asset time range to AudioTrack as below.

    [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration)) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
    
  5. Create AVAssetExportSession and merge all audio files below code.

    // 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. Also implement method to check the status of export process.

    - (void)exportDidFinishMerging:(AVAssetExportSession*)session {
    if(session.status == AVAssetExportSessionStatusCompleted){
    // notify the calling class that merging is finished
    [self.delegate handler:self didFinishMergingAtPath:[session.outputURL path]];
       }
    }
    

NOTE: Please take a note that this is not sample code which you can directly use into your code but this is just for understanding purpose. Hope this may help you.

于 2012-08-31T11:02:00.153 回答