Skip to content

Instantly share code, notes, and snippets.

@ukudala
Created March 3, 2016 21:49
Show Gist options
  • Save ukudala/ac529a1b183e4873ed6f to your computer and use it in GitHub Desktop.
Save ukudala/ac529a1b183e4873ed6f to your computer and use it in GitHub Desktop.
Smooth AVPlayer scrolling performance fix
> DESCRIPTION OF PROBLEM
> In Photos.app, Videos.app, and iMovie.app, local videos can be rewound using the video scrubber. Scrubbing backwards in a video is extremely smooth and satisfying.
>
> Using AVPlayer in our app, ScoreBreak, we cannot achieve the same smoothness when scrubbing a video backwards. There are reports on stack overflow which indicate that this is due to the codec used by AVPlayer.
>
> We would like to deliver the same beautiful user interaction with videos as offered by your system apps. Can you instruct us on how to achieve this while using AVFoundation?
>
> STEPS TO REPRODUCE
> • Create test application which utilizes AVPlayer for local video file playback
> • Scrub backwards using AVPlayer controller
> • Compare against Photos.app (or iMovie) scrubbing performance
> • Note that the scrolling is "jumpy", or choppy; not smooth
I assume you are using the AVPlayer seekToTime method to perform seeks when scrubbing?
And are you calling AVPlayer seekToTime in rapid succession when the user drags the scrubber?
If you are calling AVPlayer seekToTime in rapid succession, this can have the effect of cancelling any seeks already in progress, resulting in a lot of seeking and not a lot of displaying of the target frames. Instead, you can use the completionHandler variety of that method (
seekToTime:completionHandler:) and wait for a seek in progress to complete first before issuing another.
Here's an example:
```
- (void)_actuallySeekToTime
{
_isSeekInProgress = YES;
CMTime seekTimeInProgress = _chaseTime;
[_player seekToTime:seekTimeInProgress toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:
^(BOOL isFinished)
{
if (CMTIME_COMPARE_INLINE(seekTimeInProgress, ==, _chaseTime))
_isSeekInProgress = NO;
else
[self _trySeekToChaseTime];
}];
}
- (void)_trySeekToChaseTime
{
if (_playerCurrentItemStatus == AVPlayerItemStatusUnknown)
{
// do it when item becomes ready (KVO _player.currentItem.status)
}
else if (_playerCurrentItemStatus == AVPlayerItemStatusReadyToPlay)
{
[self _actuallySeekToTime];
}
}
- (void)stopPlayingAndSeekSmoothlyToTime:(CMTime)newChaseTime
{
[_player setRate:0.0];
if (CMTIME_COMPARE_INLINE(newChaseTime, !=, _chaseTime))
{
_chaseTime = newChaseTime;
if (!_isSeekInProgress)
[self _trySeekToChaseTime];
}
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment