AVPlayer开始播放后立即寻找

AVPlayer seek right after it starts to play

我需要在音频文件开始播放后立即跳转到特定时间。所以我将 seekToTime 方法与完成处理程序一起使用

avPlayer.play()

...

avPlayer?.seekToTime(jumpTime, completionHandler: { isComplete in
    if isComplete {
        MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo![MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds((self.avPlayer!.currentItem?.currentTime())!)
    }
})

问题是开始播放来自互联网的文件需要时间。由于某种原因,带有完成处理程序的 seekToTime 版本使应用程序崩溃,因为它是在 avPlayer 开始播放之前调用的。没有完成处理程序的版本工作正常。

错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'AVPlayerItem cannot service a seek request with a completion handler until its status is AVPlayerItemStatusReadyToPlay.'

有没有办法通过 avPlayer.play() 使用回调?

是的,有办法。

您需要观察播放器的变化:

avPlayer?.addPeriodicTimeObserverForInterval(CMTime(value: 1, timescale: 3), queue: dispatch_get_main_queue()) { [weak self] time in
    self?.handleCallback(time)
}

然后你处理回调中的状态:

func handleCallback(time: CMTime) {    
   if avPlayer?.status == .ReadyToPlay {
       // place your seek logic here
   }
}

请看苹果的回答: https://developer.apple.com/library/content/qa/qa1820/_index.html

    class MyClass {

    var isSeekInProgress = false
    let player = <#A valid player object #>
    var chaseTime = kCMTimeZero
    // your player.currentItem.status
    var playerCurrentItemStatus:AVPlayerItemStatus = .Unknown

    ...

    func stopPlayingAndSeekSmoothlyToTime(newChaseTime:CMTime)
    {
        player.pause()

        if CMTimeCompare(newChaseTime, chaseTime) != 0
        {
            chaseTime = newChaseTime;

            if !isSeekInProgress
            {
                trySeekToChaseTime()
            }
        }
    }

    func trySeekToChaseTime()
    {
        if playerCurrentItemStatus == .Unknown
        {
            // wait until item becomes ready (KVO player.currentItem.status)
        }
        else if playerCurrentItemStatus == .ReadyToPlay
        {
            actuallySeekToTime()
        }
    }

    func actuallySeekToTime()
    {
        isSeekInProgress = true
        let seekTimeInProgress = chaseTime
        player.seekToTime(seekTimeInProgress, toleranceBefore: kCMTimeZero,
                toleranceAfter: kCMTimeZero, completionHandler:
        { (isFinished:Bool) -> Void in

            if CMTimeCompare(seekTimeInProgress, chaseTime) == 0
            {
                isSeekInProgress = false
            }
            else
            {
                trySeekToChaseTime()
            }
        })
    }

}