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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:41:53