Swift视频添加水印速度极慢,求优化方案及第三方库推荐
视频添加水印速度慢的优化思路及第三方库推荐
我用Swift实现了本地视频添加图片和文字水印的功能,但目前处理速度极慢,恳请大家提供优化思路,同时推荐靠谱的第三方水印库。
我的实现代码如下:
public func addWatermark( fromVideoAt videoURL: URL, watermark: Watermark, fileName: String, onSuccess: @escaping (URL) -> Void, onFailure: @escaping ((Error?) -> Void) ) { let asset = AVURLAsset(url: videoURL) let composition = AVMutableComposition() guard let compositionTrack = composition.addMutableTrack( withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid ), let assetTrack = asset.tracks(withMediaType: .video).first else { onFailure(nil) return } do { let timeRange = CMTimeRange(start: .zero, duration: assetTrack.timeRange.duration) try compositionTrack.insertTimeRange(timeRange, of: assetTrack, at: .zero) if let audioAssetTrack = asset.tracks(withMediaType: .audio).first, let compositionAudioTrack = composition.addMutableTrack( withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid ) { try compositionAudioTrack.insertTimeRange( timeRange, of: audioAssetTrack, at: .zero ) } } catch { onFailure(error) return } compositionTrack.preferredTransform = assetTrack.preferredTransform let videoInfo = orientation(from: assetTrack.preferredTransform) let videoSize: CGSize if videoInfo.isPortrait { videoSize = CGSize( width: assetTrack.naturalSize.height, height: assetTrack.naturalSize.width ) } else { videoSize = assetTrack.naturalSize } let videoLayer = CALayer() videoLayer.frame = CGRect(origin: .zero, size: videoSize) let overlayLayer = CALayer() overlayLayer.frame = CGRect(origin: .zero, size: videoSize) videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height) let imageFrame = watermark.calculateImageFrame(parentSize: videoSize) addImage(watermark.image, to: overlayLayer, frame: imageFrame) let textOrigin = CGPoint(x: imageFrame.minX + 4, y: imageFrame.minY) if let text = watermark.text { addText( text, to: overlayLayer, origin: textOrigin, textAttributes: Watermark.textAttributes(type: watermark.type) ) } let outputLayer = CALayer() outputLayer.frame = CGRect(origin: .zero, size: videoSize) outputLayer.addSublayer(videoLayer) outputLayer.addSublayer(overlayLayer) let videoComposition = AVMutableVideoComposition() videoComposition.renderSize = videoSize videoComposition.frameDuration = CMTime(value: 1, timescale: 60) videoComposition.animationTool = AVVideoCompositionCoreAnimationTool( postProcessingAsVideoLayer: videoLayer, in: outputLayer ) videoComposition.colorPrimaries = AVVideoColorPrimaries_ITU_R_709_2 videoComposition.colorTransferFunction = "sRGB" videoComposition.colorYCbCrMatrix = nil let instruction = AVMutableVideoCompositionInstruction() instruction.timeRange = CMTimeRange(start: .zero, duration: composition.duration) videoComposition.instructions = [instruction] let layerInstruction = compositionLayerInstruction( for: compositionTrack, assetTrack: assetTrack ) instruction.layerInstructions = [layerInstruction] guard let export = AVAssetExportSession( asset: composition, presetName: AVAssetExportPresetHighestQuality ) else { onFailure(nil) return } let exportURL = URL(fileURLWithPath: NSTemporaryDirectory()) .appendingPathComponent(fileName) .appendingPathExtension("mov") export.videoComposition = videoComposition export.outputFileType = .mov export.outputURL = exportURL export.exportAsynchronously { DispatchQueue.main.async { switch export.status { case .completed: onSuccess(exportURL) default: onFailure(export.error) } } } }
Watermark是自定义结构体,封装了水印的图片/文字内容、文本属性、尺寸位置等信息。
我已经尝试过以下优化方案,但都没有效果:
- 设置
export.shouldOptimizeForNetworkUse = true,无明显提升 - 用
AVAssetExportPresetPassthrough替代AVAssetExportPresetHighestQuality,结果水印直接消失
优化思路
- 替换CoreAnimation渲染方式:当前使用的
AVVideoCompositionCoreAnimationTool依赖CPU渲染,性能瓶颈明显。建议改用自定义AVVideoCompositionInstruction结合AVVideoCompositionRenderContext,或直接用Metal/OpenGL做GPU加速渲染,能大幅提升处理速度。 - 降低导出编码开销:
AVAssetExportPresetHighestQuality会强制全量重新编码,耗时极长。可换成AVAssetExportPresetMediumQuality,或手动设置导出的比特率、分辨率等参数,尽量匹配原视频编码规格,减少编码工作量。 - 复用原视频轨道参数:如果原视频编码格式支持,尝试保留原视频的编码参数,仅对需要添加水印的帧进行处理,避免整个视频重新编码。
- 简化图层结构:把图片和文字水印合并成单个图层再渲染,减少图层层级,降低CoreAnimation的渲染负担(如果暂时不换渲染方式的话)。
- 确保后台处理独立性:虽然代码用了
exportAsynchronously,但要确认导出操作在独立的后台队列执行,避免占用主线程资源影响效率。
第三方库推荐
- GPUImage:基于GPU的多媒体处理库,支持用滤镜快速添加图片/文字水印,GPU加速比CoreAnimation快很多,API友好易上手。
- FFmpegKit:封装FFmpeg的Swift库,底层用FFmpeg处理视频,性能拉满,适合复杂水印需求(如动态水印、多水印叠加),但学习成本稍高。
- VideoEditorSDK:功能全面的视频编辑SDK,内置多种水印类型的添加功能,适合快速集成,部分高级功能需付费。
内容的提问来源于stack exchange,提问作者Levan Karanadze
相关产品推荐
相关产品推荐

