Объединение нескольких CAAnimation в AVAssetExportSession - PullRequest
0 голосов
/ 29 апреля 2019

Я пытаюсь экспортировать видеофайл с наложением CALayer и несколькими вложенными CAAnimation, связанными со временем. Для этого я использую AVVideoCompositionCoreAnimationTool.

Мои CABasicAnimation объединены в цепочку путем смещения их beginTime. Внутри animationDidStop(_:finished:) я обновляю анимированное свойство соответствующего CALayer.

Я удалил большую часть шаблона из примера кода ниже ...


/* AnimationChainer is A simple class whose instance will
 * update a CALayer's model to reflect the final state of
 * the animation. a translation on the y-axis in this case. */

class AnimationChainer: NSObject, CAAnimationDelegate {

  func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    let val = anim.value(forKey: "yTranslation") as! CGFloat
    let layer = anim.value(forKey: "layer") as! CALayer
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.transform = CATransform3DMakeTranslation(0.0, val, 0.0)
    CATransaction.commit()
  }

}

/* animation setup - a layer going up by 200pt then back to original pos. */

let chainer: AnimationChainer!
let interval = 2
let movingLayer = CALayer()

let translateOnceAnimation = CABasicAnimation(keyPath: "transform.translation.y")
translateOnceAnimation.duration = 0.4
translateOnceAnimation.fromValue = 0
translateOnceAnimation.byValue = -200
translateOnceAnimation.isRemovedOnCompletion = false
translateOnceAnimation.fillMode = .forwards
translateOnceAnimation.setValue(-200, forKey: "yTranslation")
translateOnceAnimation.setValue(movingLayer, forKey: "layer")
translateOnceAnimation.delegate = chainer
translateOnceAnimation.beginTime = AVCoreAnimationBeginTimeAtZero

let translateTwiceAnimation = CABasicAnimation(keyPath: "transform.translation.y")
translateTwiceAnimation.duration = 0.4
translateTwiceAnimation.fromValue = -200
translateTwiceAnimation.byValue = 200
translateTwiceAnimation.isRemovedOnCompletion = false
translateTwiceAnimation.fillMode = .forwards
translateTwiceAnimation.setValue(0.0, forKey: "yTranslation")
translateTwiceAnimation.setValue(movingLayer, forKey: "layer")
translateTwiceAnimation.delegate = chainer
translateTwiceAnimation.beginTime = AVCoreAnimationBeginTimeAtZero + interval

movingLayer.add(translateOnceAnimation, forKey: nil)
movingLayer.add(translateTwiceAnimation, forKey: nil)

let parentLayer = CALayer()
parentLayer.addSublayer(movingLayer)

/* end of animation setup */

let compo: AVMutableComposition!
let videoCompo: AVMutableVideoComposition!
let videoLayer: CALayer!

videoCompo.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

let exporter = AVAssetExportSession(asset: compo, presetName: AVAssetExportPresetHighestQuality)
exporter?.videoComposition = videoCompo
exporter?.exportAsynchronously {
  self.exportDidFinish(exporter!)
}

Это хорошо работает, когда я связываю анимированный слой в корневом представлении контроллера представления. Но всякий раз, когда я использую его с AVVideoCompositionCoreAnimationTool, вызывается animationDidStop(_:finished:), но в случайном порядке. В результате неверное конечное состояние для анимированного свойства.

Самое странное, что если я поставлю точку останова внутри animationDidStop(_:finished:), это сработает!

Еще один тревожный результат: если я удаляю делегатов, он все еще работает ... вероятно, из-за fillMode. но я не могу объяснить это полностью.

1 Ответ

1 голос
/ 29 апреля 2019

В реальной жизни анимация запускается внутри транзакции CAT, напротив настенных часов. У них есть начало, середина и конец, как это было. Сервер анимации проверяет ситуацию в режиме реального времени при каждом повороте цикла запуска и при необходимости перемещает кадры.

Но при использовании AVSynchronizedLayer или AVVideoCompositionCoreAnimationTool настенные часы не используются; нет сервера анимации. Анимация заморожена, и ее кадры сопоставляются посредством расчета с временными кодами видео. Таким образом, методы, основанные на транзакциях, не работают; все, что у вас есть, это отдельные кадры.

Как вы правильно сказали, режим заполнения очень помогает в этой ситуации.

...