1

Hi I am trying to merge videos together using AVMutableComposition . The problem I am having is that the AVAsset tracksWithMediaTypes method returns an empty array and the app crashed.

Can someone point out what I am doing wrong. Thanks

Here is what I have so far:

-(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];
}

Here is a screenshot of the error: enter image description here

Kaitis
  • 628
  • 9
  • 21

4 Answers4

0

Well, the error is right there "index 0 beyond bounds for empty array". That means that you have empty array of video assets. Thus, there is something wrong with getting your videoassets via NSFileManager. Go check the array filePathsArray, there is something wrong with it.

eoLithic
  • 863
  • 3
  • 10
  • 18
  • thanks but the empty array error is called at [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentAsset.duration) ofTrack:[[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:time error:nil]; – Kaitis Oct 24 '14 at 10:43
  • Oh, then your asset simply doesn't have any video tracks. Maybe it's an audio file, but perhaps it's not even an audiovisual file. You're still getting the wrong files from NSFileManager. Check the files in your temp folder! – eoLithic Oct 24 '14 at 21:56
0

First Check video is present at particular path and run proper .

In my case,video is present at path ,but not able to run . This mostly happen because video not write properly at that path. Hope it helps.

pallavi_dev
  • 85
  • 1
  • 9
0

Please check your files duration that should't be zero.

user3306145
  • 76
  • 2
  • 12
0

Not sure if this solves your problem. But I've ran into this issue before when I was trying to load an AVAsset from a url but was getting an asset with no tracks. What fixed it for me was adding "isDirectory:NO" when creating the NSURL:

NSURL *url = [NSURL fileURLWithPath:filePathsArray[j] isDirectory:NO];
l-l
  • 3,804
  • 6
  • 36
  • 42