Reputation: 2438
I am trying to create a custom screen saver using a .mov file.
Xcode - New Project - ScreenSaver
Below is the code using Swift. The problem is that nothing happens - the AV player is not doing anything.
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)
}
}
Upvotes: 1
Views: 335
Reputation: 2438
Was able to get it working after few days
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)
}
}
Upvotes: 3