在编辑视频的过程当中,时常有场景须要对视频增添更多个性化的内容,如字幕、水印或者表情等,此时须要对视频增长一个动画叠加层,在实现上来说就须要结合 AVFoundation 和 CoreAnimation 一同使用。ide
在 AVFoundation 中使用 CoreAnimation 和在 iOS 其余地方使用 CoreAnimation 同样,可是最大的差异在于时间模型。正常使用 CoreAnimation 的时候,时间模型取决于系统主机,可是视频动画有其本身的时间线,同时须要支持中止、暂停、回退或快进等效果,因此不能直接用系统主机的时间模型向一个视频中添加基于时间的动画。工具
针对这一特性,AVFoundation 在两个场景下提供了两个工具实现此效果动画
不清楚为何须要两个类实现同一个效果,这样作会致使在实现带有 CoreAnimation 的 layer 时,要保证 layer 的坐标与尺寸保持一致会很是麻烦。ui
首先实现一个简单的 CALayer 来展现一段字符串组成的字幕spa
CGFloat fontSize = 32.0f;
UIFont *font = [UIFont fontWithName:@"GillSans-Bold" size:fontSize];
NSDictionary *attrs = @{NSFontAttributeName : font, NSForegroundColorAttributeName : (id)[UIColor whiteColor].CGColor};
NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"hello yasic" attributes:attrs];
CGSize textSize = [@"hello yasic" sizeWithAttributes:attrs];
CATextLayer *layer = [CATextLayer layer];
layer.opacity = 0.0;
layer.string = string;
layer.frame = CGRectMake((SCREEN_WIDTH - textSize.width)/2.0, (SCREEN_HEIGHT - textSize.height)/2.0, textSize.width, textSize.height);
layer.backgroundColor = [UIColor clearColor].CGColor;
复制代码
而后对这个 layer 加上 CoreAnimationcode
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
animation.values = @[@0.0f, @1.0f, @1.0f, @0.0f];
animation.keyTimes = @[@0.0f, @0.3f, @0.7f, @1.0f];
animation.beginTime = CMTimeGetSeconds(CMTimeMake(1, 1));
animation.duration = 5.0f;
animation.removedOnCompletion = NO;
[layer addAnimation:animation forKey:@"opacity"];
复制代码
这里必定要设置起始时间,若是要表示影片片头,不能用 0.0 来赋值 beginTime,由于 CoreAnimation 会将 0.0 的 beginTime 转为 CACurrentMediaTime(),因此要用 AVCoreAnimationBeginTimeAtZero 来代替。视频
另外,须要注意要将 CoreAnimation 的 removedOnCompletion 属性设置为 NO,不然在播放过程当中动画执行一次后就从图层树上移除了,以后就不会出现动画了。ip
CoreAnimation 提供了 CAAnimationGroup 来组合多个动画,可是书中建议在视频动画中避免使用 CAAnimationGroup。ci
最终将这个 layer 加入到 AVSynchronizedLayer 上rem
AVSynchronizedLayer *syncLayer = [AVSynchronizedLayer synchronizedLayerWithPlayerItem:self.avPlayerItem];
[syncLayer addSublayer:[self makeTextLayer]];
syncLayer.frame = CGRectMake(0, 0, 1280, 720);
[self.layer addSublayer:syncLayer];
复制代码
能够看到 AVSynchronizedLayer 是与 AVPlayerItem 绑定的,这样就能实现时间同步了。
导出时也须要建立 CALayer
CALayer *animationLayer = [CALayer layer];
animationLayer.frame = CGRectMake(0, 0, 1280.f, 720.f);
CALayer *videoLayer = [CALayer layer];
videoLayer.frame = CGRectMake(0, 0, 1280.f, 720.f);
[animationLayer addSublayer:videoLayer];
[animationLayer addSublayer:[self makeTextLayer]];
animationLayer.geometryFlipped = YES; // 避免错位现象
AVVideoCompositionCoreAnimationTool *animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:animationLayer];
复制代码
获得 animationTool 后将其绑定到 AVMutableVideoComposition 上,便可用于导出了。
AVMutableVideoComposition *finalVideocomposition = [videoComposition copy];
finalVideocomposition.animationTool = animationTool;
复制代码