Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVPlayer doesn't play

In my project, I am using a Kolada view (here) to present a stack of cards, each with a video on them. Sometimes when I am loading the next video, My AVPlayer fails to play a video, it will just show the first frame and be frozen. I am using several observers to track when the video will actually play, if it is likely to keep up with playback. Could observers cause playback to freeze if they are not properly deallocated? If not, What else causes playback for AVPlayer to freeze?

UPDATE: I've noticed that playbackLikelyToKeepUp is never called sometimes, and when this happens, the AVPlayer then never calls it again even if I change the player item. Thus video playing never resumes.

 init(frame: CGRect, mediaURL: NSURL, thumbURL: NSURL?, isLoop: Bool) {
    self.mediaURL = mediaURL
    self.isLoop = isLoop

    let asset = AVAsset(URL: mediaURL)
    let item = AVPlayerItem(asset: asset)
    player = AVPlayer(playerItem: item)
    player!.actionAtItemEnd = .None

    super.init(frame: frame)

    asset.loadValuesAsynchronouslyForKeys(["duration"], completionHandler: { () -> Void in
        var error: NSError?
        let keyStatus: AVKeyValueStatus = asset.statusOfValueForKey("duration", error: &error)
        switch (keyStatus) {

        case .Loaded:
            let duration: CMTime = asset.duration
            self.currentDuration = duration
            self.delegate?.updateDuration()
        default:
            break
        }

    })

    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: #selector(MediaPlayerView.playerItemDidReachEnd(_:)),
        name: AVPlayerItemDidPlayToEndTimeNotification,
        object: player!.currentItem)

    self.timeObserver = self.player!.addPeriodicTimeObserverForInterval(CMTimeMakeWithSeconds(1.0 / 30.0, Int32(NSEC_PER_SEC)), queue: nil, usingBlock: {
        [weak self] (time) -> Void in

        if time.value > 0 {
            self?.spinnerView?.stopAnimating()
            if(self?.player != nil){
                if(self?.player!.rate > 0){
                    self?.placeholderImageView?.hidden = true
                }
            }

            let timeInSeconds = CMTimeGetSeconds(time)
            self?.delegate?.playbackReachedTime(timeInSeconds)

        }
    })

    player!.currentItem?.addObserver(self, forKeyPath: playbackLikelyToKeepUp, options: .New, context: &observationContext)
    player!.addObserver(self, forKeyPath: "rate", options: .New, context: &observationContext)

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MediaPlayerView.playerIsTapped(_:)))
    addGestureRecognizer(tapGesture)
}
like image 620
Josh O'Connor Avatar asked May 30 '26 07:05

Josh O'Connor


1 Answers

Use the replaceCurrentItemWithPlayerItem on an existing instance of an AVPlayer object, setting the value to nil to destroy it.

like image 113
James Bush Avatar answered Jun 01 '26 04:06

James Bush



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!