这不足为奇。 AVPlayerLayer 是一个特殊的层类,因为它不存在于 QuartzCore 框架中或具有 CA 类前缀。它还经过高度优化,可将视频帧渲染到显示器。尝试通过 UIKit 间接或直接通过 Core Animation 将动画添加到 AVPlayerLayer,对我来说会导致奇怪的行为。
可能将任何类型的动画应用于AVPlayerLayer 的唯一方法是创建主机视图的快照或将图层内容直接渲染到图形上下文中。但是,如果后者不起作用,我不会感到惊讶,因为 AVPlayerLayer 可能不包含 Core Animation 能够渲染的后备存储。
编辑:这是针对此问题的 Playground 解决方案,尽管它确实依赖于使用 UIKit,而不是单独使用 Core Animation。我尚未在设备或模拟器中进行测试,但这似乎可行:
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 中,可使Core Animation 将AVPlayerLayer 合成到视图层次结构中,这意味着视图的几何变化将影响视频播放器层的呈现。 AVFoundation 仍然很可能以它想要的方式渲染视频帧,但它为 Core Animation 提供了一个纹理来合成它想要的任何东西。
这可能会导致微妙的播放器计时抖动,因为您将以前独立渲染的视频强制进入 UIKit 的渲染循环。一般来说,同步这些特殊层是很棘手的,因为 Core Animation 不可避免地必须等待各种进程全部完成为它们的层提供渲染位图,以便它可以将所有内容合成到一个屏幕刷新中。
但这都是我的猜测。