SeekToTime working smoothly just for forwards, freezy on backwards

717 Views Asked by At

I know there is a bunch of posts, but none of them helped. I have videos with different FPS(if it matter somehow) over my device. I'm calculating the exact CMTime (if we translate them to seconds they'll be 10.33333,10.4444 etc'). I'm seeking using this code :

  self.player.seekToTime( time, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

It only runs smoothly forward, but backwards it doesn't. Any ideas why?

3

There are 3 best solutions below

0
On BEST ANSWER

This is due to the fact that compressed video works with 'key-frames'. A key frame is an entirely rendered video frame but not every frame is a key frame. Frames that follow a key frame are only stored as the incremental differences from that key frame. This means that when you are moving forward through video the player displays a key frame, moves to the next frame and draws the changes, moves to the next frame, etc, etc. When moving backwards through video the only thing the player can actually display are the key frames. Usually it will use the encoded data to display the key frame plus a few frames AFTER the key frame so you get to see what's happening at that point in the video. The only way around this is to uncompress the video into a buffer and scan backwards through that - for obvious reasons this is too slow for most purposes.

http://www.dacast.com/blog/what-is-a-key-frame-for-video/

1
On

Try this Hope

     let timeScale: Int32 = (self.playerController1.player?.currentItem!.asset.duration.timescale)!

    let time: CMTime = CMTimeMakeWithSeconds(77.000000, timeScale)

    self.playerController1.player?.seekToTime(time,toleranceBefore:kCMTimeZero ,toleranceAfter:kCMTimeZero)
0
On

When you call seekToTime, the player item will cancel previous seeks in progress, resulting in lot of seeking and not much frame display. Let use a bool var isSeekInProgress to indicate when the player item is seeking or not.

Let try like this:

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()
        }
    })
}

For more info: https://developer.apple.com/library/content/qa/qa1820/_index.html