Swift 4中使用AVMutableComposition实现视频图片定时消失的正确方法
解决AVMutableComposition中CALayer动画不生效的问题
我之前也踩过这个坑——直接给CALayer加CABasicAnimation在AVFoundation的视频合成流程里根本不会按预期工作,因为AVFoundation是离线逐帧渲染视频,不是实时处理UI图层动画那套逻辑。你遇到的动画不消失、代理方法触发异常的问题,核心原因是没把Core Animation和AVVideoComposition的渲染体系绑定起来,也没对齐动画时间和视频时间轴。
关键解决思路
要让图层动画被正确合成到视频里,需要做到这几点:
- 用
AVVideoCompositionCoreAnimationTool把你的自定义图层和视频图层关联起来,这是让Core Animation动画能被AVFoundation识别的核心桥梁。 - 动画的时间参数(时长、开始时间)必须和视频的
CMTime对齐,而不是用普通的秒数(虽然可以转换,但要对应视频时间轴)。 - 正确设置动画的
removedOnCompletion和fillMode,确保动画结束后保持最终状态。
修改后的完整代码示例
let mixComposition = AVMutableComposition() // 注意:这里需要你先完成视频轨道的添加和配置(比如把视频片段插入到mixComposition中) let outputSize = CGSize(width: 414, height: 414) let videoLayer = CALayer() videoLayer.frame = CGRect(origin: .zero, size: outputSize) let parentLayer = CALayer() parentLayer.frame = CGRect(origin: .zero, size: outputSize) parentLayer.addSublayer(videoLayer) // 初始化图片图层 let imageLayer = CALayer() imageLayer.backgroundColor = UIColor.green.cgColor imageLayer.frame = CGRect(x: 100, y: 100, width: 50, height: 50) imageLayer.contents = UIImage(named: "music")?.cgImage parentLayer.addSublayer(imageLayer) // 🔑 关键步骤:创建CoreAnimationTool,绑定父图层和视频图层 let animationTool = AVVideoCompositionCoreAnimationTool( postProcessingAsVideoLayer: videoLayer, in: parentLayer ) // 配置淡隐动画,对齐视频时间轴 let fadeOut = CABasicAnimation(keyPath: "opacity") fadeOut.fromValue = 1.0 fadeOut.toValue = 0.0 // 动画持续2秒,转换为视频时间对应的秒数 fadeOut.duration = CMTimeGetSeconds(CMTimeMake(value: 2, timescale: 1)) // 动画从视频第0秒开始 fadeOut.beginTime = AVCoreAnimationBeginTimeAtZero // 动画结束后保持最终状态 fadeOut.fillMode = CAMediaTimingFillMode.forwards fadeOut.removedOnCompletion = false // 必须设置为false,否则动画结束后图层会恢复初始状态 imageLayer.add(fadeOut, forKey: "fadeOut") // 视频合成指令 let mainInstruction = AVMutableVideoCompositionInstruction() // 假设insertTime是你的视频总时长 mainInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: insertTime) mainInstruction.layerInstructions = arrayLayerInstructions // 这里是你创建的视频轨道图层指令 mainInstruction.backgroundColor = UIColor.systemPink.cgColor // 主视频合成配置 let mainComposition = AVMutableVideoComposition() mainComposition.instructions = [mainInstruction] mainComposition.frameDuration = CMTimeMake(value: 1, timescale: 30) mainComposition.renderSize = outputSize // 🔑 把animationTool赋值给视频合成,让动画被纳入渲染流程 mainComposition.animationTool = animationTool
额外注意事项
- 不要依赖
CAAnimationDelegate的animationDidStop方法:因为视频是离线渲染的,这些代理方法会在渲染阶段触发,而不是视频播放到对应时间点时触发,所以没法用来控制视频内的动画状态。 - 如果需要更复杂的时间控制(比如动画在视频第3秒开始,持续2秒),可以用
convertTime(_:from:)把视频的CMTime转换为图层的时间,赋值给动画的beginTime:let startTime = CMTimeMake(value: 3, timescale: 1) fadeOut.beginTime = parentLayer.convertTime(startTime, from: nil)
内容的提问来源于stack exchange,提问作者Victor Altadonna
相关产品推荐
相关产品推荐

