Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVErrorInvalidVideoComposition = -11841

I am merging multiple videos and multiple songs and I am bot getting what is wrong in the code because the same code was running absolutely fine yesterday but today I'm getting the following response AVAssetExportSessionStatus = 4,error = Error Domain=AVFoundationErrorDomain Code=-11841 "The operation couldn’t be completed. (AVFoundationErrorDomain error -11841.)" I did some research and found that exporting is getting failed due to invalid video composition.Please find out what is wrong with the video composition.

- (void)mergeAllselectedVideos
{
    NSArray *pathArray = [DocumentDirectory getUrlFromDocumentDirectoryOfList:self.selectedClipsArray];
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc]init];
    NSMutableArray *layerinstructions = [[NSMutableArray alloc]init];
    CMTime time = kCMTimeZero;
    CMTime previousSongDuration = kCMTimeZero;
    for (int i = 0 ; i < pathArray.count; i++)
    {
        //VIDEO TRACK//
        time = CMTimeAdd(time, previousSongDuration);
        NSURL *url = [NSURL URLWithString:[pathArray objectAtIndex:i]];
        AVAsset *avAsset = [AVAsset assetWithURL:url];
        AVMutableCompositionTrack *track = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
        [track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:[[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:time error:nil];
    previousSongDuration = avAsset.duration;
    }
    CMTime audioTime = kCMTimeZero;
    for (int i = 0; i < self.selectedSongsArray.count; i++)
    {
        MPMediaItem * songItem = [self.selectedSongsArray objectAtIndex:i];
        NSURL *songURL = [songItem valueForProperty: MPMediaItemPropertyAssetURL];
        AVAsset *audioAsset = [AVAsset assetWithURL:songURL];
        AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
        CMTimeRange timeRange = CMTimeRangeMake(audioTime, audioAsset.duration);
        if(CMTimeGetSeconds(CMTimeAdd(audioTime, audioAsset.duration)) > CMTimeGetSeconds(time))
        {
            timeRange = CMTimeRangeMake(audioTime, CMTimeSubtract(time,audioTime));
        }
        [AudioTrack insertTimeRange:timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
        audioTime = CMTimeAdd(audioTime, audioAsset.duration);
    }

    AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, time);
    MainInstruction.layerInstructions = layerinstructions;

    AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];
    MainCompositionInst.instructions = [NSArray arrayWithObject:MainInstruction];
    MainCompositionInst.frameDuration = CMTimeMake(1, 30);
    MainCompositionInst.renderSize = CGSizeMake(320.0, 480.0);

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    movieName = [CoreDataFunctions getNameForMovieForDate:[CalendarFunctions getCurrentDateString]];
    self.moviePlayButton.titleLabel.text = movieName;
    NSString *myPathDocs =  [documentsDirectory stringByAppendingPathComponent:movieName];

    NSURL *url = [NSURL fileURLWithPath:myPathDocs];

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=url;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.videoComposition = MainCompositionInst;
    exporter.shouldOptimizeForNetworkUse = YES;
    [exporter exportAsynchronouslyWithCompletionHandler:^{dispatch_async(dispatch_get_main_queue(), ^{[self exportDidFinish:exporter];});}];
}
- (void)exportDidFinish:(AVAssetExportSession*)session
{
    //Printing error
    NSLog(@"AVAssetExportSessionStatus = %i,error = %@",session.status,session.error);
}
like image 406
Shubham Sharma Avatar asked Oct 12 '12 09:10

Shubham Sharma


1 Answers

I found your question while having the same problem. My theory on this issue is that all the properties for the video composition are not set at export time, so it's crapping out. Here's the stanza that I am now using which is now resulting in an error-free export:

AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1,30);
videoComposition.renderScale = 1.0;
videoComposition.renderSize = CGSizeMake(352.0, 288.0);
instruction.layerInstructions = [NSArray arrayWithObject: layerInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);
videoComposition.instructions = [NSArray arrayWithObject: instruction];

In my case, I was missing the timeRange property on the instruction. Check your own properties to ensure they're getting the correct values. Good luck! This stuff is hard.

like image 114
Aaron Vegh Avatar answered Sep 29 '22 22:09

Aaron Vegh