Swift Mac OS-버튼 클릭시 AVPlayer로 다른 비디오를 재생하거나 비디오의 URL을 변경하는 방법은 무엇입니까?

아마추어 프로그래머

저는 swift를 처음 사용하고 앱이 시작되면 AVPlayer를 창 배경으로 사용하여 앱 리소스에서 비디오를 반복하는 Mac OS 앱을 만들려고합니다. 사용자가 메뉴 항목을 선택하거나 버튼을 클릭하면 배경 비디오가 즉시 앱의 리소스에서 다른 비디오로 변경되고 해당 비디오를 창의 배경으로 반복하기 시작합니다.

이 튜토리얼 ( https://youtu.be/QgeQc587w70 )에 따라 앱이 시작되면 첫 번째 비디오를 재생할 수 있었고이 게시물에 따라 비디오 루프 자체를 성공적으로 만들었습니다. ( Looping AVPlayer seamlessly ).

지금 당면한 문제는 메뉴 항목을 선택하거나 버튼을 클릭하면 비디오를 다른 비디오로 변경하는 것입니다. 내가하려고했던 접근 방식은 URL을 변경하고 새 URL을 사용하여 새 AVPlayer를 만들고이 게시물에 따라 playerView.player에 영향을주는 것입니다. ( Swift 버튼을 클릭 할 때 AVPlayer에서 비디오의 URL을 업데이트하는 방법은 무엇입니까?). 그러나 메뉴 항목이 선택 될 때마다 앱이 "thread 1 exc_bad_instruction (code = exc_i386_invop subcode = 0x0)"오류와 함께 충돌합니다. 이것은 분명히 playerView의 값이 nil이기 때문입니다. playerView가 xib 파일을 사용하여 생성하고 컨트롤 드래그로 신속한 파일에 연결 한 AVPlayerView 개체이므로 그 이유를 실제로 이해하지 못하며 원하는 작업을 수행하는 다른 적절한 방법을 찾을 수없는 것 같습니다. 할 것. 그 이유와 해결 방법을 알고 있다면 저에게 도움을 주시거나 위에서 언급 한 작업을 수행하는 더 나은 방법을 알고 있다면 저에게도 알려주십시오. 어떤 도움이라도 대단히 감사하겠습니다!

내 코드는 다음과 같으며 앱이 충돌하는 줄은 하단에 있습니다.

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"가 있습니다.

어떤 도움이라도 대단히 감사하겠습니다!

Ihar Katkavets

URL에서 AVPlayer를 만들 필요가 없습니다. AVPlayerItem플레이어 재생 대기열을 조작하는 클래스 가 있습니다 .

let firstAsset = AVURLAsset(url: firstVideoUrl)
let firstPlayerItem = AVPlayerItem(asset: firstAsset)

let player = AVPlayer(playerItem: firstPlayerItem)

let secondAsset = AVURLAsset(url: secondVideoUrl)    
let secondPlayerItem = AVPlayerItem(asset: secondAsset)

player.replaceCurrentItem(with: secondPlayerItem)

AVPlayerItem 에 대한 문서

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관