简体   繁体   中英

AVPlayer when user is seeking the video should pause

I am using AVPlayer to play videos, I want to play the video only if the user does not seeks through the video. If the user wants to go further in the video, (ie he seeks), the video will pause and when the user is done seeking, the player should continue playing from where the seek ended.

Is there a way to do this?
This is what I have for now in my player.

final class PlayerViewController {
    private var playPosition: Int = 0
    private var didInitialSetup = false
    var mainPlayerItem: AVPlayerItem?
    var player: AVPlayer?
    var playerController: AVPlayerViewController!

    private var avPlayerItems: [AVPlayerItem] = []

    weak var delegate: PlayerViewControllerDelegate?

    override var mainPlayerItem: AVPlayerItem? {
        willSet {
            observers.forEach { observer in
                observer.invalidate()
            }
            observers.removeAll()

            let statusObserver = newValue?.observe(\.status, options: [.old, .new], changeHandler: { [weak self] item, _ in
                guard let strongSelf = self else { return }
                switch item.status {
                case .readyToPlay:
                    if strongSelf.didInitialSetup == false {
                        strongSelf.initialSetup()
                    }
                case .failed:
                    if let playError = item.error {
                        strongSelf.displayError(error: playError)
                    }
                case .unknown:
                    break
                }
            })

            if let observer = statusObserver {
                self.observers.append(observer)
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.loadAVPlayerItems()
    }

    // MARK: - Private methods

    private func loadAVPlayerItems() {
        self.player = AVQueuePlayer(items: self.avPlayerItems)
        self.playerController.player = self.player
        self.player?.play()

        let rateObserver = self.player?.observe(\.rate, options: [.new], changeHandler: { [weak self] player, _ in
            guard let strongSelf = self else { return }
            if player.rate == 0 {
                strongSelf.cancelNext()
            }
        })

        if let observer = rateObserver {
            self.observers.append(observer)
        }

        if let lastItem = avPlayerItems.last {
            NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd), name: .AVPlayerItemDidPlayToEndTime, object: lastItem)
        }
    }

    @objc func playerItemDidReachEnd() {
        if let time = self.player?.currentItem?.currentTime() {
            self.eventsLogger?.playerDidComplete(playHeadCMTime: time)
        }

        self.playheadTimer?.invalidate()
        self.playheadTimer = nil

        self.mainPlayerItem = nil
        self.player?.pause()
        self.playPosition = 0

        self.dismiss(animated: true, completion: nil)
    }

    private func initialSetup() {
        guard self.isViewLoaded && (self.view.window != nil) else {
            self.player?.pause()
            return
        }

        self.didInitialSetup = true

        let timePosition = CMTime(seconds: Double(self.playPosition), preferredTimescale: CMTimeScale(NSEC_PER_SEC))
        if self.playPosition > 1 {
            self.player?.seek(to: timePosition)
        }

        self.eventsLogger?.playerDidStart(playHeadCMTime: timePosition)
        self.playheadTimer?.invalidate()
        self.playheadTimer = nil
        self.startPlayheadTimer()
    }
}
class CustomAVPlayer: AVPlayer {
    override func seek(to time: CMTime, toleranceBefore: CMTime, toleranceAfter: CMTime, completionHandler: @escaping (Bool) -> Void) {
        super.seek(to: time, toleranceBefore: toleranceBefore, toleranceAfter: toleranceAfter, completionHandler: completionHandler)
        print(">> user scrubbing")
    }
}

I'll try to answer based on what I understand, and referring to a general case.

Also, I'm assuming that you're building your own video player.


Have a look at player variables you can use observe. AVFoundation has a lot of observable properties, you should use that to your advantage. Here are some properties to look into:

  • AVPlayerItem's playbackBufferEmpty : You will get a notification when you seek forward. Unless your video has finished playing. Generally, you should pause when the buffer is empty, and resume when it's not.

  • AVPlayer's rate : Generally speaking, if it's not 1.0 and the player is not paused, you should pause. That's if you're expecting a normal playback rate. However, if you support different playback speeds (eg using something like canPlaySlowForward ) then you might have to play a bit with it.

    Apple says :

    A value of 0.0 pauses the video, while a value of 1.0 plays the current item at its natural rate.

  • AVPlayer's status

  • AVPlayerItem's status


When I say observe, I mean using something like observeValueForKeyPath:ofObject:change:context: in the class that holds your player.

You can check the keyPath against the value(s) you're trying to observe.

If you are using UISlider, it is easily achieved:

slider.addTarget(self, action: #selector(onSliderValChanged(slider:event:)), for: .valueChanged)

Thenk

@objc func onSliderValChanged(slider: UISlider, event: UIEvent) {
    if let touchEvent = event.allTouches?.first {
        switch touchEvent.phase {
        case .began:
            // handle drag began
            player.pause()
        case .moved:
            // handle drag moved
            player.seek(to: whatever)
        case .ended:
            // handle drag ended
            player.play()
        default:
            break
        }
    }
}

Note in Interface Builder when adding an action you also have the option to add both sender and event parameters to the action.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM