2014-08-28 97 views
0

我的代碼基於學習Core Audio第6章中的代碼。是否可以使用AudioFileWritePackets寫入文件而不替換該文件上的現有數據?

該功能用於獲取輸入文件並將該文件的數據包複製到輸出文件。我正在使用它將許多輸入文件的數據寫入一個輸出文件,並且工作得很好。

我遇到的唯一問題是當我添加一個新的輸入文件並將startPacketPosition設置爲輸出文件上已經有數據包寫入的區域時。它用新數據替換舊數據。

有沒有辦法在不替換現有數據的情況下將新數據包寫入文件。這就像在歌曲文件中添加音效而不替換任何歌曲數據。

如果這不可能使用AudioFileWritePackets,那麼最好的選擇是什麼?

static void writeInputFileToOutputFile(AudioStreamBasicDescription *format, ExtAudioFileRef *inputFile, AudioFileID *outputFile, UInt32 *startPacketPosition) { 
    //determine the size of the output buffer 
    UInt32 outputBufferSize = 32 * 1024; //32kb 
    UInt32 sizePerPacket = format->mBytesPerPacket; 
    UInt32 packetsPerBuffer = outputBufferSize/sizePerPacket; 

    //allocate a buffer for recieving the data 
    UInt8 *outputBuffer = (UInt8 *)malloc(sizeof(UInt8) * outputBufferSize); 

    //read-convert-write 
    while (1) { 
     AudioBufferList convertedData; //create an audio buffer list 
     convertedData.mNumberBuffers = 1; //with only one buffer 
     //set the properties on the single buffer 
     convertedData.mBuffers[0].mNumberChannels = format->mChannelsPerFrame; 
     convertedData.mBuffers[0].mDataByteSize = outputBufferSize; 
     convertedData.mBuffers[0].mData = outputBuffer; 

     //get the number of frames and buffer data from the input file 
     UInt32 framesPerBuffer = packetsPerBuffer; 
     CheckError(ExtAudioFileRead(*inputFile, &framesPerBuffer, &convertedData), "ExtAudioFileRead"); 

     //if framecount is 0, were finished 
     if (framesPerBuffer == 0) { 
      return; 
     } 

     UInt32 bytes = format->mBytesPerPacket; 
     CheckError(AudioFileWritePackets(*outputFile, false, framesPerBuffer*bytes, NULL, *startPacketPosition, &framesPerBuffer, convertedData.mBuffers[0].mData), "AudioFileWritePackets"); 

     //increase the ouput file packet position 
     *startPacketPosition += framesPerBuffer; 
    } 
    free(outputBuffer); 

}

回答

0

我找到了一種方法來完成這項使用AVMutableComposition

-(void)addInputAsset:(AVURLAsset *)input toOutputComposition:(AVMutableComposition *)composition atTime:(float)seconds { 
    //add the input to the composition 
    AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
    AVAssetTrack *clipAudioTrack = [[input tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 

    //set the start time 
    int sampleRate = 44100; 
    CMTime nextClipStartTime = CMTimeMakeWithSeconds(seconds, sampleRate); 
    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, input.duration) ofTrack:clipAudioTrack atTime:nextClipStartTime error:nil]; 
} 

要使用此方法將兩種音頻文件,你會這樣稱呼它:

-(void)mixAudio { 
    //create a mutable compsition 
    AVMutableComposition* composition = [AVMutableComposition composition]; 

    //audio file 1 
    NSURL *url1 = [NSURL URLWithString:@"path/to/file1.mp3"]; 
    AVURLAsset* asset1 = [[AVURLAsset alloc]initWithURL:url1 options:nil]; 
    [self addInputAsset:asset1 toOutputComposition:composition atTime:0.0]; 

    //audio file 2 
    NSURL *url2 = [NSURL URLWithString:@"path/to/file2.aif"]; 
    AVURLAsset* asset2 = [[AVURLAsset alloc]initWithURL:url2 options:nil]; 
    [self addInputAsset:asset2 toOutputComposition:composition atTime:0.2]; 

    //create the export session 
    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A]; 
    if (exportSession == nil) { 
     //ERROR: abort 
    } 

    // configure export session output with all our parameters 
    exportSession.outputURL = [NSURL fileURLWithPath:@"path/to/output_file.m4a"]; // output path 
    exportSession.outputFileType = AVFileTypeAppleM4A; // output file type 

    //export the file 
    [exportSession exportAsynchronouslyWithCompletionHandler:^{ 
     if (AVAssetExportSessionStatusCompleted == exportSession.status) { 
      NSLog(@"AVAssetExportSessionStatusCompleted"); 
     } else if (AVAssetExportSessionStatusFailed == exportSession.status) { 
      NSLog(@"AVAssetExportSessionStatusFailed"); 
     } else { 
      NSLog(@"Export Session Status: %ld", (long)exportSession.status); 
     } 
    }]; 
} 
相關問題