Question

I've been working on a project of video processing. Until now I succeeded in filtering live camera feeds, capturing still images, recording video from frames, recording audio, and lately succeeded in adding audio to the video capture.

But it seems like the video has lost its orientation - it should be rotated by 90 degrees clockwise. I tried to use the AVmutablevideocomposition, but whatever I do, I keep getting the following error:

[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array';

It seems like the exportUrl is being released or something ..I tried replacing exportUrl by outputURL just to test it was fine..

// adding audio to video
AVMutableComposition *composition = [[AVMutableComposition alloc]init];
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:recordedTmpFile options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:outputURL options:nil];
//

AVMutableCompositionTrack *compositionCommentaryTrack =
    [composition addMutableTrackWithMediaType:AVMediaTypeAudio 
                 preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
    ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] 
    atTime:kCMTimeZero error:nil];

AVMutableCompositionTrack *compositionVideoTrack =
    [composition addMutableTrackWithMediaType:AVMediaTypeVideo 
                 preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
    ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] 
    atTime:kCMTimeZero error:nil];

AVAssetExportSession* _assetExport =
    [[AVAssetExportSession alloc] initWithAsset:composition 
                                  presetName:AVAssetExportPresetPassthrough];

NSString* videoName = @"export.mov";
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
self.exportUrl = [[NSURL fileURLWithPath:exportPath]retain];

if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
    [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}

_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = self.exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
    ^(void ) {
        switch (_assetExport.status) 
        {
        case AVAssetExportSessionStatusCompleted:
            //                export complete 
            NSLog(@"Export Complete");
            break;
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export Failed");
            NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
            //                export error (see exportSession.error)  
            break;
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"Export Failed");
            NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
            //                export cancelled  
            break;
        }
    }]; ;
//

// trying to rotate the video
// if I replace exportUrl by outputURL no error 

AVURLAsset* asset = [[AVURLAsset alloc]initWithURL:self.exportUrl options:nil];
AVMutableVideoComposition* videoComposition = [[AVMutableVideoComposition videoComposition]retain];
videoComposition.renderSize = CGSizeMake(320, 240);
videoComposition.frameDuration = CMTimeMake(1, 30);
AVMutableVideoCompositionInstruction *instruction =
    [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) );
AVMutableVideoCompositionLayerInstruction* rotator =
    [AVMutableVideoCompositionLayerInstruction
       videoCompositionLayerInstructionWithAssetTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]];

CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation( 0,-320);    
CGAffineTransform rotateBy90Degrees = CGAffineTransformMakeRotation( M_PI/2);
CGAffineTransform shrinkWidth = CGAffineTransformMakeScale(0.66, 1); 
CGAffineTransform finalTransform = CGAffineTransformConcat( shrinkWidth, CGAffineTransformConcat(translateToCenter, rotateBy90Degrees) );
[rotator setTransform:finalTransform atTime:kCMTimeZero];
instruction.layerInstructions = [NSArray arrayWithObject: rotator];
videoComposition.instructions = [NSArray arrayWithObject: instruction];

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:self.exportUrl]) {
    [library writeVideoAtPathToSavedPhotosAlbum:self.exportUrl completionBlock:nil];
    [outputURL release];
} 

Any thoughts?

Was it helpful?

Solution

I figured out the problem.

Here's the code now:

         AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:recordedTmpFile options:nil];
         AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:outputURL options:nil];

         AVMutableComposition* composition = [AVMutableComposition composition];
        //
         AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
         videoComposition.frameDuration = CMTimeMake(1,30);
         videoComposition.renderScale = 1.0;
        //

         AVMutableCompositionTrack *compositionCommentaryTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio 
         preferredTrackID:kCMPersistentTrackID_Invalid];
         [compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration) 
         ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] 
         atTime:kCMTimeZero error:nil];

         AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo 
         preferredTrackID:kCMPersistentTrackID_Invalid];
         [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) 
         ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] 
         atTime:kCMTimeZero error:nil];

        //
        AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

        AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];

         AVAssetTrack *sourceVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];


        CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(M_PI/2);
        CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotationTransform,320,0);

         [compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform];
         [layerInstruction setTransform:rotateTranslate atTime:kCMTimeZero];

        instruction.layerInstructions = [NSArray arrayWithObject: layerInstruction];
        videoComposition.instructions = [NSArray arrayWithObject: instruction];

        //


         AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:composition 
         presetName:AVAssetExportPresetPassthrough];   

         NSString* videoName = @"export.mov";

         NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
         self.exportUrl = [NSURL fileURLWithPath:exportPath]; //url of your video created from image

         if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) 
         {
         [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
         }

         _assetExport.outputFileType = @"com.apple.quicktime-movie";
         NSLog(@"file type %@",_assetExport.outputFileType);
         _assetExport.outputURL = self.exportUrl;
         _assetExport.shouldOptimizeForNetworkUse = YES;

        [_assetExport exportAsynchronouslyWithCompletionHandler:
         ^(void ) {
             switch (_assetExport.status) 
             {
                 case AVAssetExportSessionStatusCompleted:
                     //                export complete 
                     NSLog(@"Export Complete");
                     break;
                 case AVAssetExportSessionStatusFailed:
                     NSLog(@"Export Failed");
                     NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                     //                export error (see exportSession.error)  
                     break;
                 case AVAssetExportSessionStatusCancelled:
                     NSLog(@"Export Failed");
                     NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                     //                export cancelled  
                     break;
             }
         }]; 



        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:self.exportUrl]) {
            [library writeVideoAtPathToSavedPhotosAlbum:self.exportUrl completionBlock:nil];
            [outputURL release];
        } 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top