如何在Swift中检测AVPlayer实际开始播放

30

你好,我已将我的UISlider最小值设置为0.00。然后我以这种方式设置它的最大值。

self.viewPlayer.layer.addSublayer(playerLayer)
    let duration : CMTime = avPlayer.avPlayer.currentItem!.asset.duration
    let seconds : Float64 = CMTimeGetSeconds(duration)

    sliderBar.maximumValue=Float(seconds)
    sliderBar!.isContinuous = false
    sliderBar!.tintColor = UIColor.green

但我得到了这个异常

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempting to set a slider's minimumValue (0.000000) to be larger than the maximumValue (nan)'
enter code here

我知道在调用prepareForPlay()方法后,实际播放视频需要一些时间。那么我该如何检测播放器何时真正开始播放视频? 请帮忙,谢谢。


1
希望这有所帮助: https://dev59.com/-m035IYBdhLWcg3weP3f - nynohu
Player.play() 是一个方法,用于播放您的文件,以便您可以跟踪它。 - Himanshu Moradiya
@HimanshuMoradiya 是的。我想要检测玩家实际开始播放的时候。因为加载完视频后需要一些时间才能开始播放。 - user1960169
@Jose的这个答案可能会对你有所帮助,https://dev59.com/-m035IYBdhLWcg3weP3f - Arpit B Parekh
8个回答

41

自从iOS 10以来,您可以观察AVPlayer的timeControlStatus属性。它可以是.playing

检查代码:

private func setupAVPlayer() {
    avPlayer.addObserver(self, forKeyPath: "status", options: [.old, .new], context: nil)
    if #available(iOS 10.0, *) {
        avPlayer.addObserver(self, forKeyPath: "timeControlStatus", options: [.old, .new], context: nil)
    } else {
        avPlayer.addObserver(self, forKeyPath: "rate", options: [.old, .new], context: nil)
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if object as AnyObject? === avPlayer {
        if keyPath == "status" {
            if avPlayer.status == .readyToPlay {
                avPlayer.play()
            }
        } else if keyPath == "timeControlStatus" {
            if #available(iOS 10.0, *) {
                if avPlayer.timeControlStatus == .playing {
                    videoCell?.muteButton.isHidden = false
                } else {
                    videoCell?.muteButton.isHidden = true
                }
            }
        } else if keyPath == "rate" {
            if avPlayer.rate > 0 {
                videoCell?.muteButton.isHidden = false
            } else {
                videoCell?.muteButton.isHidden = true
            }
        }
    }
}

非常感谢您! - idris yıldız

19

这是我所做的事情,以实际了解视频何时开始(而不仅仅是准备开始)。

Swift 4

player = AVPlayer(url: URL(fileURLWithPath: path))
player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil)

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "rate" {
        if player.rate > 0 {
            print("video started")
        }
    }
}

@AmritTiwari 嗯,这是Swift 4。 - Skoua
你有检查过 observeValue() 是否在执行某些操作吗? - Skoua
是的,我已经使用TimeObserver方法完成了,并感谢您的回复。 - Amrit Tiwari
1
这个非常好用,当玩家开始和停止时,非常感谢。 - Hugo Fortis

12
您可以像这样在AVPlayer对象上添加观察者
player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)

您可以像这样使用AVPlayer检查状态更改:

 func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutableRawPointer) {
    if keyPath == "status" {
        print(player.status)
    }
}

player.status == AVPlayerStatusReadyToPlay 这是表示视频已经开始播放了吗? - user1960169
现在AVPlayer将开始播放。 - Rajat
这只是打印为AVPlayerStatus - user1960169
1
你尝试过在状态为readyToPlay时获取持续时间吗? - Rajat
1
@Rajat 这并没有说明视频是否已经开始播放。它只是表示视频已准备好播放。readyToPlay - Mohammad Zaid Pathan
1
这并没有回答问题。"rate"或"timeControlStatus"是正确的答案。 - thefaj

4
您可以创建一个Combine发布者并观察rate属性:
let isPlayingPublisher: AnyPublisher<Bool, Never> = NotificationCenter.default
        .publisher(for: AVPlayer.rateDidChangeNotification, object: player)
        .compactMap({ $0.object as? AVPlayer })
        .map(\.rate)
        .map({ $0 != 0 })
        .eraseToAnyPublisher()

在SwiftUI中,您可以接收到该值:
.onReceive(isPlayingPublisher) { isPlaying in
    
}

AVPlayer.rateDidChangeNotification 在 iOS 15+ 可用。非常感谢。 - Gargo

3
从苹果公司的文档中: 您可以观察AVPlayerLayer对象的readyForDisplay属性,以便在图层具有用户可见内容时得到通知。特别是,您可能只在有东西供用户观看时将播放器图层插入图层树中,然后执行过渡。

-3

声明全局 AVPlayer

var streamPlayer = AVPlayer()

func playStreamAudio( for audioUrl:String)
    {
        guard streamPlayer.timeControlStatus != .playing else {
            streamPlayer.pause()
            return
        }
        let url = audioUrl //"http://192.168.71.11:7891/rec.wav"
        let playerItem = AVPlayerItem(url: URL(string:url)!)
        streamPlayer = AVPlayer(playerItem:playerItem)
        streamPlayer.rate = 1.0;
        streamPlayer.volume = 1.0
        streamPlayer.play()
    }

-4

超级简单的解决方案 Swift 4-5:

只需检查 timeControlStatus!(也适用于 PlayerQueue)

    if avPlayer?.timeControlStatus.rawValue == 2 {
       
    //video is playing (playing)

    } else if avPlayer?.timeControlStatus.rawValue == 0 { 
    
    //video is not playing (paused)
    
    }

原始值将给您其当前状态 :)


-6

另一种更简单的方法是类似于:

if videoPlayer.rate != 0 && videoPlayer.error == nil {
            print("video player is playing.................")
        } else {
            print("video player is NOT playing.")
        } 

其中videoPlayer的类型显然是AVPlayer。


1
但它不是响应式的。 - Mike Glukhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接