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

    xiaoxiao2021-03-26  41

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

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

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

    NSTimeInterval animatedInStartTime = startTime + initAnimationDuration; CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeInAnimation.fromValue = @0.0f; fadeInAnimation.toValue = @1.0f; fadeInAnimation.additive = NO; fadeInAnimation.removedOnCompletion = NO; fadeInAnimation.beginTime = animatedInStartTime; fadeInAnimation.duration = animationDuration; fadeInAnimation.autoreverses = NO; fadeInAnimation.fillMode = kCAFillModeBoth; [textLayer addAnimation:fadeInAnimation forKey:@"opacity"];

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

    NSTimeInterval animatedOutStartTime = startTime + duration - animationDuration; CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeOutAnimation.fromValue = @1.0f; fadeOutAnimation.toValue = @0.0f; fadeOutAnimation.additive = NO; fadeOutAnimation.removedOnCompletion = NO; fadeOutAnimation.beginTime = animatedOutStartTime; fadeOutAnimation.duration = animationDuration; fadeOutAnimation.autoreverses = NO; fadeOutAnimation.fillMode = kCAFillModeBoth; [animatedTitleLayer addAnimation:fadeOutAnimation forKey:@"opacity"];

    完整的代码

    - (CALayer *)buildLayerbuildTxt:(NSString*)text textSize:(CGFloat)textSize textColor:(UIColor*)textColor strokeColor:(UIColor*)strokeColor opacity:(CGFloat)opacity textRect:(CGRect)textRect fontPath:(NSString*)fontPath viewBounds:(CGSize)viewBounds startTime:(NSTimeInterval)startTime duration:(NSTimeInterval)duration { if (!text || [text isEqualToString:@""]) { return nil; } // Create a layer for the overall title animation. CALayer *animatedTitleLayer = [CALayer layer]; // 1. Create a layer for the text of the title. CATextLayer *titleLayer = [CATextLayer layer]; titleLayer.string = text; titleLayer.font = (__bridge CFTypeRef)(@"Helvetica"); titleLayer.fontSize = textSize; titleLayer.alignmentMode = kCAAlignmentCenter; titleLayer.bounds = CGRectMake(0, 0, textRect.size.width, textRect.size.height); titleLayer.foregroundColor = textColor.CGColor; titleLayer.backgroundColor = [UIColor clearColor].CGColor; // [animatedTitleLayer addSublayer:titleLayer]; // 添加文字以及边框效果 UIFont *font = nil; if ((fontPath != nil) && (fontPath.length > 0)) { font = [[FLVideoEditFontManager sharedFLVideoEditFontManager] fontWithPath:fontPath size:textSize]; titleLayer.font = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName); } if (font == nil) { titleLayer.font = (__bridge CFTypeRef)(@"Helvetica"); } UIBezierPath *path = nil; if (font) { path = [FLLayerBuilderTool createPathForText:text fontHeight:textSize fontName:(__bridge CFStringRef)(font.fontName)]; } else { path = [FLLayerBuilderTool createPathForText:text fontHeight:textSize fontName:CFSTR("Helvetica")]; } CGRect rectPath = CGPathGetBoundingBox(path.CGPath); CAShapeLayer *textLayer = [CAShapeLayer layer]; textLayer.path = path.CGPath; textLayer.lineWidth = 1; if (strokeColor != nil) { textLayer.strokeColor = strokeColor.CGColor; } if (textColor != nil) { textLayer.fillColor = textColor.CGColor; } textLayer.lineJoin = kCALineJoinRound; textLayer.lineCap = kCALineCapRound; textLayer.geometryFlipped = NO; textLayer.opacity = opacity; textLayer.bounds = CGRectMake(0, 0, rectPath.size.width, textSize+10); [animatedTitleLayer addSublayer:textLayer]; // 动画图层位置 animatedTitleLayer.position = CGPointMake(textRect.origin.x+textRect.size.width/2, viewBounds.height - textRect.size.height/2 - textRect.origin.y); NSTimeInterval initAnimationDuration = 0.1f; NSTimeInterval animationDuration = 0.1f; // 3.显示动画 NSTimeInterval animatedInStartTime = startTime + initAnimationDuration; CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeInAnimation.fromValue = @0.0f; fadeInAnimation.toValue = @1.0f; fadeInAnimation.additive = NO; fadeInAnimation.removedOnCompletion = NO; fadeInAnimation.beginTime = animatedInStartTime; fadeInAnimation.duration = animationDuration; fadeInAnimation.autoreverses = NO; fadeInAnimation.fillMode = kCAFillModeBoth; [textLayer addAnimation:fadeInAnimation forKey:@"opacity"]; NSTimeInterval animatedOutStartTime = startTime + duration - animationDuration; CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeOutAnimation.fromValue = @1.0f; fadeOutAnimation.toValue = @0.0f; fadeOutAnimation.additive = NO; fadeOutAnimation.removedOnCompletion = NO; fadeOutAnimation.beginTime = animatedOutStartTime; fadeOutAnimation.duration = animationDuration; fadeOutAnimation.autoreverses = NO; fadeOutAnimation.fillMode = kCAFillModeBoth; [animatedTitleLayer addAnimation:fadeOutAnimation forKey:@"opacity"]; return animatedTitleLayer; }

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

    #import "FLLayerBuilderTool.h" #import <CoreText/CoreText.h> @implementation FLLayerBuilderTool + (UIBezierPath*) createPathForText:(NSString*)string fontHeight:(CGFloat)height fontName:(CFStringRef)fontName { if ([string length] < 1) return nil; UIBezierPath *combinedGlyphsPath = nil; CGMutablePathRef letters = CGPathCreateMutable(); CTFontRef font = CTFontCreateWithName(fontName, height, NULL); if (font == nil) { font = (__bridge CFTypeRef)(@"Helvetica"); } NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys: (__bridge id)font, kCTFontAttributeName, nil]; NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string attributes:attrs]; CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString); CFArrayRef runArray = CTLineGetGlyphRuns(line); // for each RUN for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++) { // Get FONT for this run CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex); CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName); // for each GLYPH in run for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++) { // get Glyph & Glyph-data CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1); CGGlyph glyph; CGPoint position; CTRunGetGlyphs(run, thisGlyphRange, &glyph); CTRunGetPositions(run, thisGlyphRange, &position); // Get PATH of outline { CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL); CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y); CGPathAddPath(letters, &t, letter); CGPathRelease(letter); } } } CFRelease(line); combinedGlyphsPath = [UIBezierPath bezierPath]; [combinedGlyphsPath moveToPoint:CGPointZero]; [combinedGlyphsPath appendPath:[UIBezierPath bezierPathWithCGPath:letters]]; CGPathRelease(letters); CFRelease(font); if (attrString) { attrString = nil; } return combinedGlyphsPath; } @end

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

    转载请注明原文地址: https://ju.6miu.com/read-661772.html

    最新回复(0)