这是我的最终目标:我想AVVideoCompositionCoreAnimationTool
用来创建Core Animation的视频.我不会在这个组合中使用现有的AVAsset.
我的问题是,如何AVMutableComposition
在给定的时间内制作具有静态纯色的视频?在我想出来后,我可以添加动画.
这是我的代码:
- (void)exportVideo { AVMutableComposition *mixComposition = [AVMutableComposition composition]; CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(10, 600)); [mixComposition insertEmptyTimeRange:timeRange]; AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [videoTrack insertEmptyTimeRange:timeRange]; AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; mainInstruction.timeRange = timeRange; mainInstruction.backgroundColor = [UIColor blueColor].CGColor; AVMutableVideoComposition *mainComposition = [AVMutableVideoComposition videoComposition]; mainComposition.renderSize = CGSizeMake(500, 500); mainComposition.instructions = [NSArray arrayWithObject:mainInstruction]; mainComposition.frameDuration = CMTimeMake(1, 30); NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"FinalVideo-%d.mov",arc4random() % 1000]]; NSURL *url = [NSURL fileURLWithPath:myPathDocs]; AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality]; exporter.outputURL = url; exporter.outputFileType = AVFileTypeQuickTimeMovie; exporter.shouldOptimizeForNetworkUse = YES; exporter.videoComposition = mainComposition; [exporter exportAsynchronouslyWithCompletionHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ [self exportDidFinish:exporter]; }); }]; }
我知道你必须在mixComposition中添加至少一个轨道,所以我添加了一个视频轨道并插入了一个空的时间范围,但是当我调用时exportAsynchronouslyWithCompletionHandler
,从不调用处理程序.我可以dispatch_after
在调用export后添加一个任意时间,并观察导出器的状态为AVAssetExportSessionStatusExporting
.
我究竟做错了什么?
在几个月前玩这个之后,我发现让它工作的唯一可靠方法是在AVMutableCompositionTrack中使用一个短的空白视频,然后用所需的图层覆盖它.
由于模拟器中的错误,我在一个月前将项目上传到GitHub.如果您愿意,可以在此处下载空白视频.
-(void)exportVideo { CGSize renderingSize = CGSizeMake(640, 360); // The desired size of your video float displayDuration = 2.0f; //The duration of the desired video, in seconds NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"FinalVideo-%d.mov",arc4random() % 1000]]; NSURL *url = [NSURL fileURLWithPath:myPathDocs]; NSError *error; [[NSFileManager defaultManager] removeItemAtURL:url error:&error]; mutableComposition = [AVMutableComposition composition]; mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.renderSize = renderingSize; videoComposition.frameDuration = CMTimeMake(1, 30); CALayer *parentLayer = [CALayer layer]; CALayer *videoLayer = [CALayer layer]; parentLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height); videoLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height); [parentLayer addSublayer:videoLayer]; videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_1080p" ofType:@"mp4"]; NSURL *trackUrl = [NSURL fileURLWithPath:path]; AVAsset *asset = [AVAsset assetWithURL:trackUrl]; AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; [mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,CMTimeMakeWithSeconds(displayDuration, 600)) ofTrack:track atTime:kCMTimeZero error:nil]; CALayer *imageLayer = [CALayer layer]; imageLayer.bounds = parentLayer.frame; imageLayer.anchorPoint = CGPointMake(0.5, 0.5); imageLayer.position = CGPointMake(CGRectGetMidX(imageLayer.bounds), CGRectGetMidY(imageLayer.bounds)); imageLayer.backgroundColor = [UIColor blueColor].CGColor; imageLayer.contentsGravity = kCAGravityResizeAspectFill; [parentLayer addSublayer:imageLayer]; AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(displayDuration, 600)); videoComposition.instructions = @[instruction]; exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality]; exporter.outputURL = url; exporter.videoComposition = videoComposition; exporter.outputFileType= AVFileTypeMPEG4; exporter.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(displayDuration, 600)); exporter.shouldOptimizeForNetworkUse = YES; [exporter exportAsynchronouslyWithCompletionHandler:^(void){ dispatch_async(dispatch_get_main_queue(), ^{ [self exportDidFinish:exporter]; }); }]; }