video轨道背后的AVFoundation UIImage

我目前正在渲染一个小于输出尺寸的video轨道。 我想在背景中绘制UIImage,以便video位于顶部,图像显示在video不在的区域。 我尝试过使用CoreAnimation图层和videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:inLayer:但是video图层下面的图层似乎没有显示(上面显示的图片很好) – 只是黑色或我在AVMutableVideoCompositionInstruction对象上设置的任何背景颜色。 我也尝试将背景颜色设置为[UIColor clearColor] .CGColor,但它只是以黑色forms出现。

有人做过类似的事并有建议吗?

CALayer *parentLayer = [CALayer layer]; CALayer *videoLayer = [CALayer layer]; CALayer *backgroundLayer = [CALayer layer]; backgroundLayer.frame = rect; parentLayer.frame = rect; videoLayer.frame = rect; videoLayer.backgroundColor = [UIColor clearColor].CGColor; backgroundLayer.backgroundColor = [UIColor purpleColor].CGColor; [parentLayer addSublayer:backgroundLayer]; [parentLayer addSublayer:videoLayer]; mainCompositionInst.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; 

在尝试了几件事之后我终于找到了一种方法。 要使其工作,需要使用空白video/音频轨道。 然后将背景图像添加到此空白video图层。 然后将其导出并合并原始资产(video)和导出的资产(资产)并导出最终资产(video)。希望它能为您提供帮助。

添加叠加层

 - (void)addOverlayImage:(UIImage *)overlayImage ToVideo:(AVMutableVideoComposition *)composition inSize:(CGSize)size { // 1 - set up the overlay CALayer *overlayLayer = [CALayer layer]; [overlayLayer setContents:(id)[overlayImage CGImage]]; overlayLayer.frame = CGRectMake(0, 0, size.width, size.height); [overlayLayer setMasksToBounds:YES]; // 2 - set up the parent layer CALayer *parentLayer = [CALayer layer]; CALayer *videoLayer = [CALayer layer]; parentLayer.frame = CGRectMake(0, 0, size.width, size.height); videoLayer.frame = CGRectMake(0, 0, size.width, size.height); [parentLayer addSublayer:videoLayer]; [parentLayer addSublayer:overlayLayer]; // 3 - apply magic composition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; } - (void)getBackgroundVideoAssetWithcompletion:(void (^)(AVAsset *bgAsset))completionBlock { NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_video" ofType:@"mp4"]; NSURL *trackUrl = [NSURL fileURLWithPath:path]; AVAsset *asset = [AVAsset assetWithURL:trackUrl]; AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; CMTimeRange range = CMTimeRangeMake(kCMTimeZero, [asset duration]); AVMutableComposition* mixComposition = [AVMutableComposition composition]; AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionVideoTrack insertTimeRange:range ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil]; CGAffineTransform videoTransform = track.preferredTransform; CGSize naturalSize = CGSizeApplyAffineTransform(track.naturalSize, videoTransform); naturalSize = CGSizeMake(fabs(naturalSize.width), fabs(naturalSize.height)); AVMutableVideoComposition *composition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:asset]; UIImage *img = [self imageWithImage:[UIImage imageNamed:@"white_image"] convertToSize:naturalSize]; [self addOverlayImage:img ToVideo:composition inSize:naturalSize]; AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = range; composition.instructions = @[instruction]; AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality]; _assetExport.videoComposition = composition; NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"exported-%d.mov", arc4random() % 100000]]; unlink([exportPath UTF8String]); NSURL *exportUrl = [NSURL fileURLWithPath:exportPath]; _assetExport.outputFileType = AVFileTypeQuickTimeMovie; _assetExport.outputURL = exportUrl; _assetExport.shouldOptimizeForNetworkUse = YES; [_assetExport exportAsynchronouslyWithCompletionHandler:^{ switch (_assetExport.status) { case AVAssetExportSessionStatusFailed: break; case AVAssetExportSessionStatusExporting: break; case AVAssetExportSessionStatusCompleted:{ dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Successful!!!"); AVAsset *finalAsset = [AVAsset assetWithURL:_assetExport.outputURL]; completionBlock(finalAsset); }); } break; default: break; } }]; } 

现在有一个带叠加图像的video资源。 只保留原始video和导出的video资产的组合。 导出的资产应该是底层,原始应该是顶层。