1
votes

I'm a relative newbie on the whole AVFoundation video editing circuit.

My current test app is a two screen application, the first screen does an AVFoundation Video recording (1.mov), and the second screen lets you view the video and put some title credits on it with a CAAnimation.

The 1.mov video file is recorded in portrait saved to the disk and is then run though this routine which should give me a title on top of the video. However all that I get is a black video of the right dimensions, time length with the CATextLayer on it.

I'm pretty sure I'm missing something basic. I do have code in place that should handle the whole landscape portrait rotation.

-(IBAction)ComposeMovie:(id)sender {
    NSLog (@"ComposeMovie");

    CALayer *aLayer = [CALayer layer];
    aLayer.Frame = CGRectMake(0, 0, videoSize.height, videoSize.width); 
    CALayer *bLayer = [CALayer layer]; 

    NSLog(@"Create the title"); 
    CATextLayer *titleLayer = [CATextLayer layer]; 
    titleLayer.string = @"SUDO make me a sandwich"; 
    titleLayer.font = [UIFont boldSystemFontOfSize:18].fontName; 
    titleLayer.backgroundColor = [UIColor whiteColor].CGColor; 
    titleLayer.foregroundColor = [UIColor blackColor].CGColor; 
    titleLayer.fontSize = 24; 
    titleLayer.alignmentMode = kCAAlignmentRight; 
    titleLayer.bounds = CGRectMake(videoSize.width, videoSize.height /6, 300, 32); 
    [aLayer addSublayer:titleLayer]; 

    NSURL *url = [NSURL fileURLWithPath:getCaptureMoviePath()]; //Hard coded path to the 1.mov file in the documents directory
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];

    AVMutableComposition *cmp = [[AVMutableComposition alloc] init] ;  
    AVMutableCompositionTrack *trackA = [cmp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    NSError *error = nil ;
    AVAssetTrack *sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    [trackA insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:sourceVideoTrack atTime:kCMTimeZero error:&error] ;
    AVMutableVideoComposition *animComp = [[AVMutableVideoComposition videoComposition] retain];
    animComp.renderSize = CGSizeMake(videoSize.height, videoSize.width); 
    animComp.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); // needed because Apple does a "stretch" by default - really, we should find and undo apple's stretch - I suspect it'll be a CALayer defaultTransform, or UIView property causing this
    CGAffineTransform finalTransform = CGAffineTransformConcat( shrinkWidth, CGAffineTransformConcat(translateToCenter, rotateBy90Degrees) );
    [rotator setTransform:finalTransform atTime:kCMTimeZero];

    instruction.layerInstructions = [NSArray arrayWithObject: rotator];
    animComp.instructions = [NSArray arrayWithObject: instruction];


    NSLog(@"Creating Animation"); 
    //animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer: asTrackID:1];
    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:aLayer asTrackID:2];
    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:bLayer asTrackID:3]; 
    //AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trackA];
    //[layerInstruction setTrackID:1]; 

    /*CMTime startTime = CMTimeMake(3,1); 
    CMTime stopTime = CMTimeMake(5,1); 
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime); 
    */ 

    //AVMutableVideoCompositionLayerInstruction *passThroughLayer = AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
    CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
    CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotationTransform,320,0);
    [layerInstruction setTransform:rotateTranslate atTime:kCMTimeZero];

    [layerInstruction setOpacity:1.0 atTime:kCMTimeZero ];
    instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
    animComp.instructions = [NSArray arrayWithObject:instruction];

    CALayer *parentLayer = [CALayer layer]; 
    CALayer *videoLayer = [CALayer layer]; 
    parentLayer.frame = CGRectMake(0,0, videoSize.width, videoSize.height); 
    videoLayer.frame = CGRectMake(0,0, videoSize.width, videoSize.height); 
    [parentLayer addSublayer:aLayer]; 
    [parentLayer addSublayer:bLayer];
    [parentLayer addSublayer:videoLayer]; 

    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

    NSLog(@"Creating File"); 
        NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *tempPath = [docPaths objectAtIndex:0];
        NSLog(@"Temp Path: %@",tempPath);

        NSString *fileName = [NSString stringWithFormat:@"%@/render.MOV",tempPath];
        NSFileManager *fileManager = [NSFileManager defaultManager] ;
        if([fileManager fileExistsAtPath:fileName ]){
            NSError *ferror = nil ;
            BOOL success = [fileManager removeItemAtPath:fileName error:&ferror];
        }

        NSURL *exportURL = [NSURL fileURLWithPath:fileName];

        AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:cmp presetName:AVAssetExportPresetHighestQuality]  ;
        exporter.outputURL = exportURL;
        exporter.videoComposition = animComp ;
        exporter.outputFileType= AVFileTypeQuickTimeMovie ;
        [exporter exportAsynchronouslyWithCompletionHandler:^(void){
            switch (exporter.status) {
                case AVAssetExportSessionStatusFailed:{
                    NSLog(@"Fail");
                    break;
                }
                case AVAssetExportSessionStatusCompleted:{
                    NSLog(@"Success");
                    break;
                }

                default:
                    break;
            }
        }];



    NSLog(@"End ComposeMovie"); 


}
2

2 Answers

1
votes

The problem was with the following lines.

parentLayer.frame = CGRectMake(0,0, videoSize.width, videoSize.height); 
videoLayer.frame = CGRectMake(0,0, videoSize.width, videoSize.height); 

Changing videoSize.width to 320, and videoSize.height = 480 fixed the issue.

1
votes

But if the size of the video wont be 320X480, it will mess up. Try to use this one to get the video size.

        CGSize videoSize = [[[self.videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize];