私はswiftが初めてで、アプリが起動したらウィンドウの背景としてAVPlayerを使用して、アプリのリソースからビデオをループするMac OSアプリを作成しようとしています。ユーザーがメニュー項目を選択するかボタンをクリックすると、背景ビデオがアプリのリソースとは別のビデオに即座に変更され、そのビデオがウィンドウの背景としてループし始めます。
このチュートリアルに従ってアプリを起動すると、最初のビデオを再生できました: ( https://youtu.be/QgeQc587w70 )。また、この投稿に従ってビデオループ自体をシームレスに作成することにも成功しました: ( Looping AVPlayer seamlessly )。
私が今直面している問題は、メニュー項目が選択されたりボタンがクリックされたりすると、ビデオを別のビデオに変更することです。私が目指していたアプローチは、URL を変更し、新しい URL を使用して新しい AVPlayer を作成し、この投稿に従って playerView.player に影響を与えることです: ( Swift How to update url of video when a button on a button?)。ただし、メニュー項目が選択されるたびに、「thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)」というエラーでアプリがクラッシュします。これは明らかに、playerView の値が nil であることが原因です。playerView は AVPlayerView オブジェクトであり、xib ファイルを使用して作成し、コントロールを押しながらドラッグして Swift ファイルにリンクしたため、この理由がよくわかりません。する。この理由とそれを修正する方法を知っている場合は、私に助けを提供してください。または、上記のことを行うより良い方法を知っている場合も教えてください. どんな助けでも大歓迎です!
私のコードは次のとおりです。アプリをクラッシュさせる行は一番下にあります。
import Cocoa
import AppKit
import AVKit
import AVFoundation
struct videoVariables {
static var videoName = "Test_Video" //declaring the video name as a global variable
}
var videoIsPlaying = true
var theURL = Bundle.main.url(forResource:videoVariables.videoName, withExtension: "mp4") //creating the video url
var player = AVPlayer.init(url: theURL!)
class BackgroundWindow: NSWindowController {
@IBOutlet weak var playerView: AVPlayerView! // AVPlayerView Linked using control-drag from xib file
@IBOutlet var mainWindow: NSWindow!
@IBOutlet weak var TempBG: NSImageView!
override var windowNibName : String! {
return "BackgroundWindow"
}
//function used for resizing the temporary background image and the playerView to the window’s size
func resizeBG() {
var scrn: NSScreen = NSScreen.main()!
var rect: NSRect = scrn.frame
var height = rect.size.height
var width = rect.size.width
TempBG.setFrameSize(NSSize(width: Int(width), height: Int(height)))
TempBG.frame.origin = CGPoint(x: 0, y: 0)
playerView!.setFrameSize(NSSize(width: Int(width), height: Int(height)))
playerView!.frame.origin = CGPoint(x: 0, y: 0)
}
override func windowDidLoad() {
super.windowDidLoad()
self.window?.titleVisibility = NSWindowTitleVisibility.hidden //hide window’s title
self.window?.styleMask = NSBorderlessWindowMask //hide window’s border
self.window?.hasShadow = false //hide window’s shadow
self.window?.level = Int(CGWindowLevelForKey(CGWindowLevelKey.desktopWindow)) //set window’s layer as desktopWindow layer
self.window?.center()
self.window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
if let screen = NSScreen.main() {
self.window?.setFrame(screen.visibleFrame, display: true, animate: false) //resizing the window to cover the whole screen
}
resizeBG() //resizing the temporary background image and the playerView to the window’s size
startVideo() //start playing and loop the first video as the window’s background
}
//function used for starting the video again once it has been played fully
func playerItemDidReachEnd(notification: NSNotification) {
playerView.player?.seek(to: kCMTimeZero)
playerView.player?.play()
}
//function used for starting and looping the video
func startVideo() {
//set the seeking time to be 2ms ahead to prevent a black screen every time the video loops
let playAhead = CMTimeMake(2, 100);
//loops the video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object:
playerView.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.playerView.player?.seek(to: playAhead)
self.playerView.player?.play()
}
})
var playerLayer: AVPlayerLayer?
playerLayer = AVPlayerLayer(player: player)
playerView?.player = player
print(playerView?.player)
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
player.play()
}
//changing the url to the new url and create a new AVPlayer then affect it to the playerView.player once the menu item is being selected
@IBAction func renderBG(_ sender: NSMenuItem) {
videoVariables.videoName = "Test_Video_2"
var theNewURL = Bundle.main.url(forResource:videoVariables.videoName, withExtension: "mp4")
player = AVPlayer.init(url: theNewURL!)
//!!this line crashes the app with the error "thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)" every time the menu item is being selected!!
playerView.player = player
}
}
さらに、背景ビデオはインタラクティブであるとは想定されていないため (たとえば、ユーザーはビデオを一時停止/早送りできません)、ユーザーのインタラクティブ性によって引き起こされる可能性のある問題は無視できます。アプリの目的は、ユーザーのデスクトップでビデオを再生し、コマンドを実行した場合とまったく同じ効果を生み出すことです。
ターミナルで「/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background」。
どんな助けでも大歓迎です!