直接上效果图:
Untitled.gif
为本地视频添加烟花、雪花效果。实际就是使用GIF、序列帧背景透明图片组,再用AVVideoCompositionCoreAnimationTool:
AVVideoCompositionCoreAnimationTool* animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
创建parentLayer:
geometryFlipped:可以基于父层颠倒y轴坐标,因为CALayer是以左下角为原点的。
CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
parentLayer.geometryFlipped = true;
加载gif的原理,是提取gif资源中的所有图片、图片时间节点,使用动画加到CALayer上
//从gif提取帧图片信息
-(void)getImagesWithGif:(NSURL *)gifPath resultBlock:(void(^)(NSArray<UIImage*>* images,CGFloat totalTime,NSArray* delayTimes))resultBlock{
CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)gifPath, NULL);
size_t gifCount = CGImageSourceGetCount(gifSource);
NSMutableArray *times = [NSMutableArray array];
NSMutableArray *images = [NSMutableArray array];
NSMutableArray *delayTimes = [NSMutableArray array];
CGFloat totalTime = 0.0;
CGFloat currentTime = 0.0;
for (size_t i = 0; i< gifCount; i++) {
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
[images addObject:(__bridge id _Nonnull)(imageRef)];
//获取到的gif中帧信息
NSDictionary *dict = (NSDictionary*)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL));
NSDictionary *gifDict = [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary];
//持续时间
CGFloat time = [[gifDict valueForKey:(NSString*)kCGImagePropertyGIFUnclampedDelayTime] floatValue];
[delayTimes addObject:[NSNumber numberWithFloat:time]];
//总时间
totalTime = totalTime + time;
}
//图片占据时间点
[delayTimes enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSNumber* number = [NSNumber numberWithFloat:[obj floatValue] + currentTime];
[times addObject:number];
}];
resultBlock(images,totalTime,times);
}
创建动画:
//获取动画
- (void)addGifAnimationFromGifPath:(NSURL*)gifPath resultBlock:(void(^)(CAKeyframeAnimation* animation))resultBlock{
[self getImagesWithGif:gifPath resultBlock:^(NSArray<UIImage *> *images, CGFloat totalTime, NSArray* delayTimes) {
NSMutableArray *times = [NSMutableArray arrayWithCapacity:3];
CGFloat currentTime = 0;
NSInteger count = delayTimes.count;
for (int i = 0; i < count; ++i) {
[times addObject:[NSNumber numberWithFloat:(currentTime / totalTime)]];
currentTime += [[delayTimes objectAtIndex:i] floatValue];
}
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
animation.keyTimes = times;//帧时间
animation.values = images;//总图片
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.duration = totalTime;
animation.repeatCount = HUGE_VALF;
animation.beginTime = AVCoreAnimationBeginTimeAtZero;
animation.removedOnCompletion = NO;
resultBlock(animation);
}];
}
创建animationTool:
//获取animationTool
- (void)addAnimationLayerFromGif:(NSArray<NSURL*>*)gifPaths videoSize:(CGSize)videoSize resultBlock:(void(^)(AVVideoCompositionCoreAnimationTool* animationTool))resultBlock{
CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
parentLayer.geometryFlipped = true;
CALayer *videoLayer = [CALayer layer];
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
[gifPaths enumerateObjectsUsingBlock:^(NSURL * _Nonnull gifPath, NSUInteger idx, BOOL * _Nonnull stop) {
[self addGifAnimationFromGifPath:gifPath resultBlock:^(CAKeyframeAnimation *animation) {
CALayer* gifLayer = [CALayer layer];
gifLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[gifLayer addAnimation:animation forKey:@"gif"];
[parentLayer addSublayer:gifLayer];
if (idx == gifPaths.count - 1) {
//最后
AVVideoCompositionCoreAnimationTool* animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:
];
resultBlock(animationTool);
}
}];
}];
}
GitHub:
https://github.com/qw9685/addGif
网友评论