Achieve smooth video scrubbing with AVPlayer

前端 未结 4 1629
你的背包
你的背包 2021-01-02 02:30

I am trying to achieve smooth video scrubbing with AVPlayer through UISlider I have searched and it seems Apple has a Technical Q&A and explain

相关标签:
4条回答
  • 2021-01-02 02:57

    try to add selectors to your slider like this at the begining:

    playerView.timeSlider.addTarget(self, action: #selector(PlayerViewController.timeSliderBeganTracking(_:)), for:.touchDown) // moved
            playerView.timeSlider.addTarget(self, action: #selector(PlayerViewController.timeSliderEndedTracking(_:)), for: .touchUpInside)
            playerView.timeSlider.addTarget(self, action: #selector(PlayerViewController.timeSliderEndedTracking(_:)), for: .touchUpOutside )
    

    then in timeSliderBeganTracking set isSeekInProgress to true and pause your player and invalidate timers and remove observers if you have any

    then in timeSliderEndedTracking seek to current time like this :

    let currentSeconds = Float64(self.playerView.timeSlider.value) container.player.seek(to: CMTimeMakeWithSeconds(currentSeconds, 100)) then add the observers and timers back and at the end set isSeekInProgress to false

    HERE you can find a complete sample of creating a custom videoPlayer

    0 讨论(0)
  • 2021-01-02 03:12

    I know this is an old problem, I encountered it too. The solution can help someone now. Apple sample make slider super smooth and pretty. To make the sample work:

    private static var context = 1
    func playVideo() {
      ...
      player.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem.status), options: [.new, .initial], context: &VideoViewController.context)
      ...
     }
    
    override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath else { return }
        guard context == &VideoViewController.context else { return }
        switch keyPath {
        case #keyPath(AVPlayer.currentItem.status):
            if let newStatus = change.map({ $0[.newKey] as? NSNumber }), 
               let parsedNewStatus = newStatus.map({ AVPlayerItem.Status(rawValue: $0.intValue) ?? .unknown})  {
                playerCurrentItemStatus = parsedNewStatus
            } else {
                playerCurrentItemStatus = .unknown
            }
        default: break
        }
    }
    

    Observe and update playerCurrentItemStatus

    0 讨论(0)
  • 2021-01-02 03:13

    On slider value change event, just call the

    stopPlayingAndSeekSmoothlyToTime(CMTime.init(seconds: (player.currentItem?.asset.duration.seconds)!* slider.value, preferredTimescale: 1000))

    The Apples sample code will change the player current time. You can also adjust toleranceBefore and toleranceAfter if you scrub the slider really fast.

    0 讨论(0)
  • 2021-01-02 03:13

    Although I'm not using the same method as you do which is stopPlayingAndSeekSmoothlyToTime, I thought I should help you with the seeking action of the player.

    func sliderValueChanged() {
        var timeToSeek = player.currentItem?.asset.duration.seconds
        timeToSeek = timeToSeek * Double(slider.value)
        player.seek(to: CMTimeMake(Int64(timeToSeek), 1))
    }
    

    Also you should set the slider.maximumValue to 1. Hope this helps.

    Note: Please don't forget to handle currentItem optional value. If it is nil you should set the value 0 for timeToSeek variable.

    0 讨论(0)
提交回复
热议问题