macososx-lionavfoundationavplayer

Seeking accurately, as opposed to two seconds short, in AVPlayer


I'm using AVPlayer in a Cocoa app, and I've implemented a command that jumps to the end of the video.

The problem is, AVPlayer doesn't seek to where I told it to.

For example, one of the videos I have is 4 minutes and 14 seconds long. When I seek to the end, AVPlayer seeks to 4 minutes and 12 seconds—two seconds short. If I then hit play, the player will play for two seconds, then reach the end.

My first attempt was this:

[self.player seekToTime:self.player.currentItem.duration];

I've switched it to this:

[self.player seekToTime:self.player.currentItem.duration
        toleranceBefore:kCMTimePositiveInfinity
         toleranceAfter:kCMTimeZero];

Neither one works any better than the other.

I also tried seeking to kCMTimePositiveInfinity. It just ignored me then.

It doesn't seem to matter whether the player has loaded that part of the video yet. I can even seek to the not-quite-end, play through to the true end, then try again to seek to the end, and it will jump back to the not-quite-end.

The shortfall is not always two seconds. On some of my videos, it works more or less exactly correctly, jumping very close to the true end if not exactly to it. On at least one, it goes to three seconds short. Length does not seem to be a factor; all of these are about the same length, except for one, which is over an hour long and seeks to two seconds short.

So, why is AVPlayer jumping as many as three seconds short of where I told it to, and how do I convince it to jump to the moment I asked for?


Solution

  • I misunderstood the tolerances and had them backwards.

    Each tolerance is how far in that direction AVPlayer is allowed to move away from the requested time. So, passing positive infinity for toleranceBefore is saying “you can be as early as you want”, and passing zero for toleranceAfter is saying “just don't be late” (which would be a neat trick when seeking to the end).

    Thus, the solution is to switch the values:

    [self.player seekToTime:self.player.currentItem.duration
            toleranceBefore:kCMTimeZero
             toleranceAfter:kCMTimePositiveInfinity];
    

    Or, in English: “Don't be early, but you can be as late as you want.”