Mix video with static image in CALayer using AVVideoCompositionCoreAnimationTool

Solution 1:

After playing around I ended up with something like this in a addition to the above code, also changing the used method to videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:

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:videoLayer];
[parentLayer addSublayer:aLayer];
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

Hope it helps somebody.

Solution 2:

i got this to work! heres the code! i didn't write most of it, i just tweaked some, but the only issue is the video itself is rotated for landscape in portrait mode? and then in landscape its portrait video, but the image is right side up!

CALayer *aLayer = [CALayer layer];
    aLayer.frame = CGRectMake(5, 0, 320, 480);
    aLayer.bounds = CGRectMake(5, 0, 320, 480);
    aLayer.contents = (id) [UIImage imageNamed:@"image.png"].CGImage;
    aLayer.opacity = 0.5;
    aLayer.backgroundColor = [UIColor clearColor].CGColor;
    NSURL *url = [NSURL fileURLWithPath:[urlsOfVideos objectAtIndex:self.pageControl.currentPage]];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
    cmp = [AVMutableComposition composition]; 

    AVMutableCompositionTrack *trackA = [cmp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVAssetTrack *sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    [trackA insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:sourceVideoTrack atTime:kCMTimeZero error:nil] ;

    animComp = [AVMutableVideoComposition videoComposition];
    animComp.renderSize = CGSizeMake(320, 480);
    animComp.frameDuration = CMTimeMake(1,30);
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, 320, 480);
    videoLayer.frame = CGRectMake(0, 0, 320, 480);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:aLayer];
    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trackA];
    //[layerInstruction setTrackID:2];
    [layerInstruction setOpacity:1.0 atTime:kCMTimeZero];
    instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction] ;
    animComp.instructions = [NSArray arrayWithObject:instruction];
    [self exportMovie:self];

and here is the exporting code

-(IBAction) exportMovie:(id)sender{
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *tempPath = [docPaths objectAtIndex:0];
NSLog(@"Temp Path: %@",tempPath);

NSString *fileName = [NSString stringWithFormat:@"%@/output-anot.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;
    } 
}];

}