You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS视频应用开发:如何在指定时段为视频添加文字?

实现视频添加文字水印(基于CATextLayer + AVFoundation)

你要做的本地视频选片加文字水印功能,用CATextLayer结合AVFoundation就能搞定,我把你的代码补全并整理了完整实现,顺便给你拆解关键步骤:

完整代码实现

- (void)createWatermark:(UIImage*)image video:(NSURL*)videoURL {
    if (videoURL == nil) return;
    
    // 加载原视频资源
    AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
    CMTime videoDuration = videoAsset.duration;
    
    // 创建视频合成容器
    AVMutableComposition* mixComposition = [AVMutableComposition composition];
    
    // 添加原视频轨道到合成容器
    AVMutableCompositionTrack* compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVAssetTrack* videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
    NSError* error = nil;
    [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoDuration)
                                   ofTrack:videoTrack
                                    atTime:kCMTimeZero
                                     error:&error];
    if (error) {
        NSLog(@"插入视频轨道失败: %@", error.localizedDescription);
        return;
    }
    
    // 初始化视频合成配置
    AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:videoAsset];
    videoComposition.renderSize = videoTrack.naturalSize;
    videoComposition.frameDuration = CMTimeMake(1, 30); // 按30帧每秒渲染
    
    // 创建图层容器:用于承载原视频层和水印层
    CALayer* parentLayer = [CALayer layer];
    CALayer* videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
    videoLayer.frame = parentLayer.frame;
    [parentLayer addSublayer:videoLayer];
    
    // 配置文字水印的CATextLayer
    CATextLayer* textLayer = [CATextLayer layer];
    textLayer.string = @"我的专属水印"; // 替换成你需要的水印文字
    textLayer.font = (__bridge CFTypeRef)(@"PingFang SC"); // 设置字体
    textLayer.fontSize = 32.0;
    textLayer.foregroundColor = [UIColor whiteColor].CGColor;
    textLayer.backgroundColor = [UIColor blackColor].CGColor;
    textLayer.opacity = 0.8; // 调整水印透明度
    textLayer.alignmentMode = kCAAlignmentCenter;
    
    // 计算文字尺寸,设置水印位置(示例为右下角,可自行调整)
    CGSize textSize = [textLayer.string sizeWithAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"PingFang SC" size:32.0]}];
    CGFloat margin = 20.0;
    textLayer.frame = CGRectMake(
        videoComposition.renderSize.width - textSize.width - margin,
        videoComposition.renderSize.height - textSize.height - margin,
        textSize.width,
        textSize.height
    );
    [parentLayer addSublayer:textLayer];
    
    // 将图层容器关联到视频合成配置
    videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
    
    // 创建导出会话,生成带水印的视频
    AVAssetExportSession* exportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
    exportSession.outputURL = [self outputVideoURL];
    exportSession.outputFileType = AVFileTypeMP4;
    exportSession.videoComposition = videoComposition;
    exportSession.shouldOptimizeForNetworkUse = YES;
    
    // 执行导出,完成后回调
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            switch (exportSession.status) {
                case AVAssetExportSessionStatusCompleted:
                    NSLog(@"水印添加完成!视频路径:%@", exportSession.outputURL.path);
                    // 这里可以添加后续操作,比如保存到相册、预览视频等
                    break;
                case AVAssetExportSessionStatusFailed:
                    NSLog(@"导出失败:%@", exportSession.error.localizedDescription);
                    break;
                case AVAssetExportSessionStatusCancelled:
                    NSLog(@"导出已取消");
                    break;
                default:
                    break;
            }
        });
    }];
}

// 生成视频输出路径的辅助方法
- (NSURL*)outputVideoURL {
    NSString* docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString* fileName = [NSString stringWithFormat:@"watermarked_%lld.mp4", (long long)[[NSDate date] timeIntervalSince1970]];
    return [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:fileName]];
}

关键细节说明

  • 轨道处理:必须把原视频的轨道插入到AVMutableComposition中,这是后续添加水印的基础,确保原视频内容能被纳入合成流程。
  • CATextLayer配置:你可以根据需求自由修改文字内容、字体、颜色、位置——比如想把水印放左上角,就调整textLayer.frame的x和y值为margin即可;字体要确保设备上存在,避免显示异常。
  • 图层关联:通过AVVideoCompositionCoreAnimationTool把视频层和水印层绑定,这一步是让水印能被渲染到最终视频里的核心操作。
  • 导出注意:导出操作是异步的,完成后一定要切回主线程处理UI提示;另外要记得在Info.plist中添加相册访问权限(NSPhotoLibraryUsageDescription),不然选视频会被系统拦截。

内容的提问来源于stack exchange,提问作者Anand Gautam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:45:52