IOS使用AVFoundation在视频上添加字幕以及控制字幕时间

IOS在视频上添加字幕效果的基本思路是:

  1. 使用自定义的CATextLayer文字图层或者CAShapeLayer文字图层,添加到视频的Layer上创建用户自定义的字幕效果。这两者的区别是:CATextLayer支持设置简单的文字效果,包括文字的内容、字体、字号大小、对其方式、文字颜色、背景颜色等基本的属性;CAShapeLayer功能更强大,提供了CATextLayer没有的边框大小、边框颜色等设置,如果需要更高级的文字内容展示,需要使用CATextLayer配合UIBezierPath来定制自定义的文字内容。

  2. 通过设置Layer图层的动画来控制字幕的时间点和时间长度,这里有一个坑如果单独设置CATextLayer或者CAShapeLayer的动画不能控制开始的时间,需要额外添加一个CALayer图层,把文字图层CATextLayer或者CAShapeLayer添加到父CALayer图层中,在文字图层CATextLayer或者CAShapeLayer上设置开始的动画

    1NSTimeInterval animatedInStartTime = startTime + initAnimationDuration; 2CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 3fadeInAnimation.fromValue = @0.0f; 4fadeInAnimation.toValue = @1.0f; 5fadeInAnimation.additive = NO; 6fadeInAnimation.removedOnCompletion = NO; 7fadeInAnimation.beginTime = animatedInStartTime; 8fadeInAnimation.duration = animationDuration; 9fadeInAnimation.autoreverses = NO; 10fadeInAnimation.fillMode = kCAFillModeBoth; 11[textLayer addAnimation:fadeInAnimation forKey:@"opacity"];

在父CALayer图层上设置结束的动画,这样设置才能实现用户自定义的时间点和时间长度

1NSTimeInterval animatedOutStartTime = startTime + duration - animationDuration; 2 CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 3 fadeOutAnimation.fromValue = @1.0f; 4 fadeOutAnimation.toValue = @0.0f; 5 fadeOutAnimation.additive = NO; 6 fadeOutAnimation.removedOnCompletion = NO; 7 fadeOutAnimation.beginTime = animatedOutStartTime; 8 fadeOutAnimation.duration = animationDuration; 9 fadeOutAnimation.autoreverses = NO; 10 fadeOutAnimation.fillMode = kCAFillModeBoth; 11 [animatedTitleLayer addAnimation:fadeOutAnimation forKey:@"opacity"];

完整的代码

1- (CALayer *)buildLayerbuildTxt:(NSString*)text 2 textSize:(CGFloat)textSize 3 textColor:(UIColor*)textColor 4 strokeColor:(UIColor*)strokeColor 5 opacity:(CGFloat)opacity 6 textRect:(CGRect)textRect 7 fontPath:(NSString*)fontPath 8 viewBounds:(CGSize)viewBounds 9 startTime:(NSTimeInterval)startTime 10 duration:(NSTimeInterval)duration 11{ 12 if (!text || [text isEqualToString:@""]) 13 { 14 return nil; 15 } 16 17 // Create a layer for the overall title animation. 18 CALayer *animatedTitleLayer = [CALayer layer]; 19 20 // 1. Create a layer for the text of the title. 21 CATextLayer *titleLayer = [CATextLayer layer]; 22 titleLayer.string = text; 23 titleLayer.font = (__bridge CFTypeRef)(@"Helvetica"); 24 titleLayer.fontSize = textSize; 25 titleLayer.alignmentMode = kCAAlignmentCenter; 26 titleLayer.bounds = CGRectMake(0, 0, textRect.size.width, textRect.size.height); 27 titleLayer.foregroundColor = textColor.CGColor; 28 titleLayer.backgroundColor = [UIColor clearColor].CGColor; 29 // [animatedTitleLayer addSublayer:titleLayer]; 30 31 // 添加文字以及边框效果 32 UIFont *font = nil; 33 if ((fontPath != nil) && (fontPath.length > 0)) { 34 font = [[FLVideoEditFontManager sharedFLVideoEditFontManager] fontWithPath:fontPath size:textSize]; 35 titleLayer.font = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName); 36 } 37 if (font == nil) { 38 titleLayer.font = (__bridge CFTypeRef)(@"Helvetica"); 39 } 40 41 UIBezierPath *path = nil; 42 if (font) { 43 path = [FLLayerBuilderTool createPathForText:text fontHeight:textSize fontName:(__bridge CFStringRef)(font.fontName)]; 44 } 45 else 46 { 47 path = [FLLayerBuilderTool createPathForText:text fontHeight:textSize fontName:CFSTR("Helvetica")]; 48 } 49 CGRect rectPath = CGPathGetBoundingBox(path.CGPath); 50 CAShapeLayer *textLayer = [CAShapeLayer layer]; 51 textLayer.path = path.CGPath; 52 textLayer.lineWidth = 1; 53 if (strokeColor != nil) { 54 textLayer.strokeColor = strokeColor.CGColor; 55 } 56 if (textColor != nil) { 57 textLayer.fillColor = textColor.CGColor; 58 } 59 textLayer.lineJoin = kCALineJoinRound; 60 textLayer.lineCap = kCALineCapRound; 61 textLayer.geometryFlipped = NO; 62 textLayer.opacity = opacity; 63 textLayer.bounds = CGRectMake(0, 0, rectPath.size.width, textSize+10); 64 [animatedTitleLayer addSublayer:textLayer]; 65 66 // 动画图层位置 67 animatedTitleLayer.position = CGPointMake(textRect.origin.x+textRect.size.width/2, viewBounds.height - textRect.size.height/2 - textRect.origin.y); 68 69 NSTimeInterval initAnimationDuration = 0.1f; 70 NSTimeInterval animationDuration = 0.1f; 71 72 // 3.显示动画 73 NSTimeInterval animatedInStartTime = startTime + initAnimationDuration; 74 CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 75 fadeInAnimation.fromValue = @0.0f; 76 fadeInAnimation.toValue = @1.0f; 77 fadeInAnimation.additive = NO; 78 fadeInAnimation.removedOnCompletion = NO; 79 fadeInAnimation.beginTime = animatedInStartTime; 80 fadeInAnimation.duration = animationDuration; 81 fadeInAnimation.autoreverses = NO; 82 fadeInAnimation.fillMode = kCAFillModeBoth; 83 [textLayer addAnimation:fadeInAnimation forKey:@"opacity"]; 84 85 NSTimeInterval animatedOutStartTime = startTime + duration - animationDuration; 86 CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 87 fadeOutAnimation.fromValue = @1.0f; 88 fadeOutAnimation.toValue = @0.0f; 89 fadeOutAnimation.additive = NO; 90 fadeOutAnimation.removedOnCompletion = NO; 91 fadeOutAnimation.beginTime = animatedOutStartTime; 92 fadeOutAnimation.duration = animationDuration; 93 fadeOutAnimation.autoreverses = NO; 94 fadeOutAnimation.fillMode = kCAFillModeBoth; 95 96 [animatedTitleLayer addAnimation:fadeOutAnimation forKey:@"opacity"]; 97 98 return animatedTitleLayer; 99}

依赖的工具类FLLayerBuilderTool.m文件:

1#import "FLLayerBuilderTool.h" 2#import <CoreText/CoreText.h> 3 4@implementation FLLayerBuilderTool 5 6 7+ (UIBezierPath*) createPathForText:(NSString*)string fontHeight:(CGFloat)height fontName:(CFStringRef)fontName 8{ 9 if ([string length] < 1) 10 return nil; 11 12 UIBezierPath *combinedGlyphsPath = nil; 13 CGMutablePathRef letters = CGPathCreateMutable(); 14 15 CTFontRef font = CTFontCreateWithName(fontName, height, NULL); 16 if (font == nil) { 17 font = (__bridge CFTypeRef)(@"Helvetica"); 18 } 19 NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys: 20 (__bridge id)font, kCTFontAttributeName, 21 nil]; 22 NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string 23 attributes:attrs]; 24 CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString); 25 CFArrayRef runArray = CTLineGetGlyphRuns(line); 26 27 // for each RUN 28 for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++) 29 { 30 // Get FONT for this run 31 CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex); 32 CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName); 33 34 // for each GLYPH in run 35 for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++) 36 { 37 // get Glyph & Glyph-data 38 CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1); 39 CGGlyph glyph; 40 CGPoint position; 41 CTRunGetGlyphs(run, thisGlyphRange, &glyph); 42 CTRunGetPositions(run, thisGlyphRange, &position); 43 44 // Get PATH of outline 45 { 46 CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL); 47 CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y); 48 CGPathAddPath(letters, &t, letter); 49 CGPathRelease(letter); 50 } 51 } 52 } 53 CFRelease(line); 54 55 combinedGlyphsPath = [UIBezierPath bezierPath]; 56 [combinedGlyphsPath moveToPoint:CGPointZero]; 57 [combinedGlyphsPath appendPath:[UIBezierPath bezierPathWithCGPath:letters]]; 58 59 CGPathRelease(letters); 60 CFRelease(font); 61 62 if (attrString) 63 { 64 attrString = nil; 65 } 66 67 return combinedGlyphsPath; 68} 69 70@end

参考资料:
视频特效制作:如何给视频添加边框、水印、动画以及3D效果
视频特效制作2
AVFoundation Tutorial: Adding Overlays and Animations to Videos

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一篇文章带你了解JavaScript日期

日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用

mysql设置时区

mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0

为什么mysql不推荐使用雪花ID作为主键

作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究