macOS 从 .mov 文件创建自定义屏幕保护程序

macOS create custom screen saver from .mov file

我正在尝试使用 .mov 文件创建自定义屏幕保护程序。

Xcode - 新项目 - 屏幕保护程序

下面是使用 Swift 的代码。问题是没有任何反应 - AV 播放器没有做任何事情。

import Foundation
import AVFoundation
import AVKit
import ScreenSaver

class MoonView: ScreenSaverView {
    private var player: AVPlayer!

    override init?(frame: NSRect, isPreview: Bool) {
        super.init(frame: frame, isPreview: isPreview)

        guard let path = Bundle.main.path(forResource: "moon", ofType:"mov") else {
            fatalError("moon.mov not found")
        }
        player = AVPlayer(url: URL(fileURLWithPath: path))
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: NSRect) {

        let playerLayerAV = AVPlayerLayer(player: player)
        playerLayerAV.frame = rect
        player.play()
    }

    override func animateOneFrame() {
        super.animateOneFrame()
        setNeedsDisplay(bounds)
    }

}

几天后就能正常工作了

import Foundation
import ScreenSaver
import AVKit

class MoonView: ScreenSaverView {
    private var player: AVPlayer!
    private var playerLayer: AVPlayerLayer!
            
    override init?(frame: NSRect, isPreview: Bool) {
        super.init(frame: frame, isPreview: isPreview)
        animationTimeInterval = 1.0/30.0
        wantsLayer = true
        player = createAVPlayer()
        playerLayer = createAVPlayerLayer(player: player)
        self.layer = playerLayer
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func startAnimation() {
        super.startAnimation()
        player.play()
    }
    
    override func stopAnimation() {
        super.stopAnimation()
        player.pause()
    }
        
    func createAVPlayer() -> AVPlayer {
        let moonBundle: Bundle = Bundle(for: MoonView.self)
        guard let url = moonBundle.url(forResource: "moon", withExtension: "mov") else {
            fatalError("moon.mov not found in \(moonBundle.bundlePath)")
        }
        let avPlayer = AVPlayer(url: url)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(playerItemDidReachEnd),
                                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
                                               object: nil)
        return avPlayer
    }
    
    func createAVPlayerLayer(player: AVPlayer) -> AVPlayerLayer {
        let avPlayerLayer: AVPlayerLayer = AVPlayerLayer(player: player)
        avPlayerLayer.frame = bounds
        avPlayerLayer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
        avPlayerLayer.needsDisplayOnBoundsChange = true
        avPlayerLayer.contentsGravity = .resizeAspect
        avPlayerLayer.backgroundColor = CGColor(red: 0.00, green: 0.01, blue: 0.00, alpha:1.0)
        return avPlayerLayer
    }
    
    // Notification Handling
    @objc func playerItemDidReachEnd(notification: NSNotification) {
        player.seek(to: CMTime.zero)
        player.play()
    }
    
    // Remove Observer
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}