Mezcle video con imagen estática en CALayer usando AVVideoCompositionCoreAnimationTool

Intento mezclar video, que proviene de la cámara con una imagen estática (marca de agua).

He revisado las preguntas y respuestas aquí y algunos ejemplos, incluido WWDC AVEditDemo de Apple, y finalizó con el siguiente código. Lamentablemente, el video exportado no contiene la capa con la imagen. ¿Algunas ideas?

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { /// incoming video NSURL *videoURL = [info valueForKey:UIImagePickerControllerMediaURL]; /// UIImage into CALayer UIImage *myImage = [UIImage imageNamed:@"m1h.png"]; CALayer *aLayer = [CALayer layer]; aLayer.contents = (id)myImage.CGImage; AVURLAsset* url = [AVURLAsset URLAssetWithURL:videoURL options:nil]; AVMutableComposition *videoComposition = [AVMutableComposition composition]; NSError *error; NSFileManager *fileManager = [NSFileManager defaultManager]; AVMutableCompositionTrack *compositionVideoTrack = [videoComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; AVAssetTrack *clipVideoTrack = [[url tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [url duration]) ofTrack:clipVideoTrack atTime:kCMTimeZero error:&error]; AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain]; videoComp.renderSize = CGSizeMake(640, 480); videoComp.frameDuration = CMTimeMake(1, 30); videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:aLayer asTrackID:2]; /// instruction AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) ); AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack]; instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction]; videoComp.instructions = [NSArray arrayWithObject: instruction]; /// outputs NSString *filePath = nil; filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; filePath = [filePath stringByAppendingPathComponent:@"temp.mov"]; NSLog(@"exporting to: %@", filePath); if ([fileManager fileExistsAtPath:filePath]) { BOOL success = [fileManager removeItemAtPath:filePath error:&error]; if (!success) NSLog(@"FM error: %@", [error localizedDescription]); } /// exporting AVAssetExportSession *exporter; exporter = [[AVAssetExportSession alloc] initWithAsset:videoComposition presetName:AVAssetExportPresetHighestQuality] ; exporter.videoComposition = videoComp; exporter.outputURL=[NSURL fileURLWithPath:filePath]; exporter.outputFileType=AVFileTypeQuickTimeMovie; [statusLabel setText:@"processing..."]; [exporter exportAsynchronouslyWithCompletionHandler:^(void){ switch (exporter.status) { case AVAssetExportSessionStatusFailed: NSLog(@"exporting failed"); break; case AVAssetExportSessionStatusCompleted: NSLog(@"exporting completed"); UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, @selector(video:didFinishSavingWithError:contextInfo:), NULL); break; case AVAssetExportSessionStatusCancelled: NSLog(@"export cancelled"); break; } }]; 

}

Después de jugar, terminé con algo así en una adición al código anterior, y también cambié el método usado a 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]; 

Espero que ayude a alguien.

tengo esto para trabajar! aquí está el código! No escribí la mayor parte, acabo de ajustar un poco, ¿pero el único problema es que el video en sí se gira para el paisaje en modo vertical? y luego en el paisaje su video de retrato, ¡pero la imagen está boca arriba!

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

y aquí está el código de exportación

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

}