使用AVComposition为视频添加水印的性能优化求助
Hey there, let’s fix this slow watermarking issue—15 seconds for a 20-second video is totally unacceptable for end users, especially with network transfer waiting on top. I’ve worked through plenty of AVFoundation performance bottlenecks, so here are targeted fixes based on your workflow areas:
1. Optimize Export Settings to Avoid Unnecessary Re-encoding
This is usually the biggest performance hit:
- Use Passthrough Preset When Possible: If your source video’s codec, resolution, and frame rate match your export target, use
AVAssetExportSessionPresetPassthrough. This skips re-encoding the entire video and only composites the watermark layer—cutting processing time drastically. - Match Preset to Source Quality: Ditch overkill presets like
AVAssetExportSessionPresetHighestQualityunless you absolutely need it. Use a preset that matches your source video’s resolution (e.g.,AVAssetExportSessionPreset1080pfor 1080p source) to reduce encoding overhead. - Enable Hardware Acceleration: Ensure your export session uses hardware-accelerated encoding. Check
AVAssetExportSession.supportsHardwareAcceleratedVideoEncodingand prioritize codecs like H.264/H.265 (which most iOS/macOS devices accelerate natively). Also setshouldOptimizeForNetworkUse = trueto let the export session optimize for faster transfer later.
2. Streamline Watermark Addition
How you add the watermark can make a huge difference:
- Use Static CALayers for Fixed Watermarks: Avoid per-frame drawing or CIFilter overhead by using a static
CALayerfor your watermark. Here’s a quick example:// Preload your watermark image once let watermarkImage = UIImage(named: "watermark")! let watermarkLayer = CALayer() watermarkLayer.contents = watermarkImage.cgImage watermarkLayer.frame = CGRect(x: 20, y: 20, width: 100, height: 50) // Adjust position/size watermarkLayer.opacity = 0.7 // Set transparency once // Set up composition layers let videoSize = asset.tracks(withMediaType: .video).first?.naturalSize ?? .zero let parentLayer = CALayer() let videoLayer = CALayer() parentLayer.frame = CGRect(origin: .zero, size: videoSize) videoLayer.frame = parentLayer.frame parentLayer.addSublayer(videoLayer) parentLayer.addSublayer(watermarkLayer) // Attach to video composition let animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer) let videoComposition = AVVideoComposition(asset: asset) { request in request.finish(with: request.sourceImage) } videoComposition.animationTool = animationTool - Avoid Real-Time CIFilters: If you’re using CIFilters to modify the watermark (e.g., tint), pre-process the watermark image before adding it to the layer—don’t apply the filter during video composition.
- Resize Watermarks to Fit: Use a watermark image that’s already sized appropriately for your video. Scaling large images during composition adds unnecessary GPU/CPU load.
3. Optimize Video Conversion Workflow
Tweak how you handle the asset and processing queue:
- Preload Asset Metadata: Use
AVAsset.loadValuesAsynchronously(forKeys:)to preload critical keys liketracksanddurationbefore starting composition. This avoids blocking the export process while the asset loads:let asset = AVURLAsset(url: videoURL) let keysToLoad = ["tracks", "duration"] asset.loadValuesAsynchronously(forKeys: keysToLoad) { // Check for load errors, then start composition/export on a background queue DispatchQueue.global(qos: .userInitiated).async { self.startWatermarkingAndExport(asset: asset) } } - Use High-Priority Background Queues: Run export/composition tasks on a queue with
.userInitiatedQoS—this tells the system to prioritize the task since the user is waiting for the result. - Trim Unused Tracks: Remove any unused audio/video tracks from your
AVComposition(e.g., if you don’t need to modify audio, just add the original audio track without processing).
4. Advanced: Switch to AVAssetWriter for Finer Control
If AVAssetExportSession is still too slow, use AVAssetWriter directly. It’s more code, but lets you skip unnecessary processing steps:
- Write the original video samples directly to the output file, overlaying the watermark on each frame using
CVPixelBufferoperations (hardware-accelerated if possible). - Avoid intermediate buffers by processing frames as they’re read from the source asset.
Start with the passthrough preset and static CALayer fixes—those usually give the biggest performance gains with minimal code changes. If you still need more speed, dive into AVAssetWriter for full control.
内容的提问来源于stack exchange,提问作者thelearner

