连接iPhone(m4a)上的声音文件失败

时间:2013-02-14 14:18:25

标签: iphone avassetexportsession

我试图通过连接几个较小的声音文件制作一个长声音文件 - 所有声音都是m4a格式,结果也应该是m4a格式。

这是代码(audFiles数组包含要加入的声音文件的名称)。 注意我只打印文件大小,让您高枕无忧......

CMTime nextClipStartTime = kCMTimeZero;
AVMutableComposition *combinedSounds = [AVMutableComposition composition];
NSString *tempDir = NSTemporaryDirectory();
NSArray *audFiles;

for (int i = 0; i < [audFiles count]; i++)
{
    NSString *addSound = [tempDir stringByAppendingString:audFiles[i]];
    if ([[NSFileManager defaultManager] fileExistsAtPath:addSound] == YES)
    {
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:addSound error:nil];
        if (fileAttributes != nil)
        {
            NSString *fileSize = [fileAttributes objectForKey:NSFileSize];
            NSLog(@"file %@ %@", addSound, fileSize);
            NSURL *assetURL = [[NSURL alloc] initFileURLWithPath:addSound];

            AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:assetURL options:nil];
            if (asset != nil)
            {
                CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
                NSLog(@"asset %d length %lld", i, asset.duration.value);
                if (asset.duration.value > 0)
                {
                    AVAssetTrack *audTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0];
                    AVMutableCompositionTrack *audioTrack = [combinedSounds addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
                    if ([audioTrack insertTimeRange:timeRange ofTrack:audTrack atTime:nextClipStartTime error:nil] == NO)
                    {
                        NSLog(@"insertTimeRange %d FAILED", i);
                    }
                    nextClipStartTime = CMTimeAdd(nextClipStartTime, asset.duration);
                    nextClipStartTime = CMTimeAdd(nextClipStartTime, CMTimeMake(0.1, 1));
                    NSLog(@"nextClipStartTime %lld", nextClipStartTime.value);
                }
            }
        }
    }
}

NSString *finalSound = [tempDir stringByAppendingString:@"result.m4a"];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:combinedSounds presetName:AVAssetExportPresetPassthrough];

 NSString *exported = [tempDir stringByAppendingString:finalSound];
[[NSFileManager defaultManager] removeItemAtPath:exported error:nil];
NSURL *exportedURL = [[NSURL alloc] initFileURLWithPath:exported];
exportSession.outputURL = exportedURL;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeAppleM4A;

[exportSession exportAsynchronouslyWithCompletionHandler:^{
    switch (exportSession.status)
    {
        case AVAssetExportSessionStatusFailed:
        {
            NSLog(@"exportSession FAIL");
            break;
        }
        case AVAssetExportSessionStatusCompleted:
        {
            NSLog(@"exportSession SUCCESS");
        }
    }
}];
报告

“exportSession SUCCESS”,导出的文件存在且可以播放,但它只包含第一个组成文件。

任何想法我做错了什么?

感谢。

1 个答案:

答案 0 :(得分:1)

Step 1 :在您的项目中添加AVFoundation.FrameworkCoreMedia.Framework

您的Step 2 :文件中的

#import <AVFoundation/AVFoundation.h> .h

Step 3 : Write following method in your .m file

Step 4 : Call this function from ViewDidAppear to create Merged Audio file.

// Get Asset Detail
- (AVAsset *)getAvAssetForFile:(NSString *)fileName andType:(NSString *)fileType
{
    NSString *URLPath = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType];
    NSURL *assetURL = [NSURL fileURLWithPath:URLPath];
    AVAsset *asset = [AVAsset assetWithURL:assetURL];
    return asset;
}

- (void)mergeAudioFiles
{
    // `An Array with List of Audio Clips to be Merged, they could be of different type also`
    NSMutableArray *listOfAudio = [[NSMutableArray alloc] initWithCapacity:0];

    // `Create AVAsset Object from your audio files and add to array`

    [listOfAudio addObject:[self getAvAssetForFile:@"audioFile1" andType:@"caf"]];
    [listOfAudio addObject:[self getAvAssetForFile:@"audioFile2" andType:@"caf"]];
    [listOfAudio addObject:[self getAvAssetForFile:@"audioFile3" andType:@"aiff"]];

    AVMutableComposition *composition = [AVMutableComposition composition];
    CMTime current = kCMTimeZero;
    NSError *compositionError = nil;
    for(AVAsset *asset in listOfAudio) {
        BOOL result = [composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration])
                                           ofAsset:asset
                                            atTime:current
                                             error:&compositionError];
        if(!result) {
            if(compositionError) {
                // manage the composition error case                
                NSLog(@"Error in Merging : %@",[compositionError debugDescription]);
            }
        } else {
            current = CMTimeAdd(current, [asset duration]);
        }
    }

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc]
                                      initWithAsset: composition
                                      presetName: AVAssetExportPresetAppleM4A];

    exporter.outputFileType = @"com.apple.m4a-audio";

    // Set Output FileName
    NSString *fileName = @"myAudioTrack";
    NSString *exportFile = [DOC_DIR_PATH stringByAppendingFormat: @"/%@.m4a", fileName];

    // set up export
    NSURL *exportURL = [NSURL fileURLWithPath:exportFile];
    exporter.outputURL = exportURL;

    // do the export
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        int exportStatus = exporter.status;
        switch (exportStatus) {
            case AVAssetExportSessionStatusFailed: NSLog (@"AVAssetExportSessionStatusFailed: %@", exporter.debugDescription); break;
            case AVAssetExportSessionStatusCompleted: NSLog (@"AVAssetExportSessionStatusCompleted"); break;
            case AVAssetExportSessionStatusUnknown: NSLog (@"AVAssetExportSessionStatusUnknown"); break;
            case AVAssetExportSessionStatusExporting: NSLog (@"AVAssetExportSessionStatusExporting"); break;
            case AVAssetExportSessionStatusCancelled: NSLog (@"AVAssetExportSessionStatusCancelled"); break;
            case AVAssetExportSessionStatusWaiting: NSLog (@"AVAssetExportSessionStatusWaiting"); break;
            default:  NSLog (@"didn't get export status"); break;
        }
    }];    
}