如何使用AVAsset合并多个视频和音频

时间:2014-10-22 19:14:21

标签: ios avfoundation avcomposition

您好我正在尝试使用AVMutableComposition合并视频。 我遇到的问题是AVAsset tracksWithMediaTypes方法返回一个空数组,应用程序崩溃。

有人可以指出我做错了什么。 感谢

这是我到目前为止所做的:

-(void) mergeVideosAndAudio:(AVAsset *)audioAsset{

    //Load Video Assets

    NSError *error;
    NSArray *dirFiles;
    if ((dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self documentsDirectory] error:&error]) == nil) {
        // handle the error
    };
    // find all the temp files
    NSArray *movFiles = [dirFiles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self BEGINSWITH 'temp'"]];
    NSLog(@"The are %i temp files",movFiles.count);
    NSArray *filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:[self documentsDirectory]  error:nil];

        //Create the composition
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];

    // 1 - Video track
    AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    CMTime videoTrackDuration;

    for (int j = 0; j < filePathsArray.count; j++) {
        NSURL *url = [NSURL fileURLWithPath:filePathsArray[j]];
        AVURLAsset *currentAsset = [[AVURLAsset alloc]initWithURL:url options:nil];
        videoTrackDuration = CMTimeAdd(videoTrackDuration, currentAsset.duration);
        CMTime time;
        if (j == 0) {
            time = kCMTimeZero;

        }else{
            NSURL *previousAssetURL = [NSURL fileURLWithPath:filePathsArray[j-1]];
            AVURLAsset *previousAsset = [[AVURLAsset alloc]initWithURL:previousAssetURL options:nil];
            time = previousAsset.duration;
        }

        [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentAsset.duration) ofTrack:[[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:time error:nil];
    }

    // 2 - Audio track
    if (audioAsset!=nil){
        AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                            preferredTrackID:kCMPersistentTrackID_Invalid];
        [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoTrackDuration)
                            ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
    }

    //3 - Get Path for merge
    NSString *myPathDocs =  [[self documentsDirectory] stringByAppendingPathComponent:
                             [NSString stringWithFormat:@"mergeVideo-%d.mov",arc4random() % 1000]];
    self.fileURL = [NSURL URLWithString: myPathDocs];

    // 5 - Create exporter
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                      presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=self.fileURL;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.shouldOptimizeForNetworkUse = YES;
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [self exportDidFinish:exporter];
        });
    }];

}
-(void)exportDidFinish:(AVAssetExportSession*)session {
    if (session.status == AVAssetExportSessionStatusCompleted) {
        self.fileURL = session.outputURL;
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:self.fileURL]) {
            [library writeVideoAtPathToSavedPhotosAlbum:self.fileURL completionBlock:^(NSURL *assetURL, NSError *error){
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (error) {
                        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Video Saving Failed"
                                                                       delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                        [alert show];
                    } else {
                        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Video Saved" message:@"Saved To Photo Album"
                                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                        [alert show];
                    }
                });
            }];
        }
    }
    [self removeTempFilesFromDocuments];
}

以下是错误的屏幕截图: enter image description here

4 个答案:

答案 0 :(得分:0)

嗯,错误就在那里“索引0超出空数组的界限”。 这意味着您拥有空的视频资产数组。因此,通过NSFileManager获取视频资产存在问题。去检查数组filePathsArray,它有什么问题。

答案 1 :(得分:0)

首先检查视频是否存在于特定路径并正常运行。

就我而言,视频存在于路径中,但无法运行。 这主要是因为视频在该路径上没有正确写入。 希望它有所帮助。

答案 2 :(得分:0)

请检查您的文件持续时间应该为零。

答案 3 :(得分:0)

不确定这是否解决了您的问题。但是在我尝试从URL加载AVAsset但是获得没有轨道的资产之前我遇到过这个问题。为我修复的是在创建NSURL时添加“isDirectory:NO”:

NSURL *url = [NSURL fileURLWithPath:filePathsArray[j] isDirectory:NO];