这不足为奇。AVPlayerLayer
是一个特殊的层类,因为它不存在于QuartzCore
框架中,也没有CA
类前缀。它还经过高度优化,可将视频帧渲染到显示器。尝试AVPlayerLayer
通过 UIKit 间接或直接通过 Core Animation 向我添加动画会导致奇怪的行为。
可能应用任何类型动画的唯一方法AVPlayerLayer
是创建主机视图的快照或将图层内容直接渲染到图形上下文中。但是,如果后者不起作用,我不会感到惊讶,因为AVPlayerLayer
可能不包含 Core Animation 能够渲染的后备存储。
编辑:这是针对此问题的 Playground 解决方案,尽管它确实依赖于使用 UIKit,而不是单独的核心动画。我没有在设备上或模拟器中测试过,但这似乎可行:
import UIKit
import AVFoundation
import PlaygroundSupport
let rootView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 600.0, height: 400.0))
rootView.backgroundColor = .white
let playerLayerView = UIView()
playerLayerView.frame.size = CGSize(width: 480.0, height: 270.0)
playerLayerView.center = CGPoint(x: rootView.bounds.midX, y: rootView.bounds.midY)
guard let videoUrl = Bundle.main.url(
forResource: "HEVC_3_iPhone",
withExtension: "m4v")
else { fatalError() }
let player = AVPlayer(url: videoUrl)
player.play()
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = playerLayerView.bounds
playerLayerView.layer.addSublayer(playerLayer)
rootView.addSubview(playerLayerView)
UIView.animate(
withDuration: 1.0,
delay: 0.0,
options: [.autoreverse, .repeat],
animations: {
playerLayerView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
},
completion: nil
)
PlaygroundPage.current.liveView = rootView
这是它的样子:
如果我理解正确的话,“问题”——尽管这不像管道必要性那样严重——AVPlayerLayer
是它位于标准 UIKit 渲染和合成管道之外。与其他特殊层类(如)一起CAMetalLayer
,AVPlayerLayer
在不同的进程中渲染,因为 AVFoundation 需要直接绘制访问不受 UIKit 渲染循环限制的屏幕。所以试图将动画直接附加到图层是行不通的。
UIView
然而,将该层放在AVPlayerLayer
. AVFoundation 仍然很可能以它想要的方式渲染视频帧,但为 Core Animation 提供了一个纹理来合成它想要的任何东西。
这可能会导致微妙的播放器计时抖动,因为您将以前独立渲染的视频强制到 UIKit 的渲染循环中。一般来说,同步这些特殊层是很棘手的,因为 Core Animation 必须不可避免地等待各种进程都完成为它们的层提供渲染位图,以便它可以将所有内容组合在一起成为一个屏幕刷新。
但这都是我的猜测。