I've been bashing my head with an annoying glitch for the past two days and was hoping somebody could shed some light.
Basic setup: I have an AVPlayerLayer with a player, a pan gesture recognizer in the view and I want the user to be able to swipe their fingers back and forth and the video would seek accordingly.
The catch: I would like if the user lifts their finger and places it again,anywhere on the screen for the fast forward or backward to resume at the exact same frame where it left off and continue progressing from there.
I've seen these two questions: Pan Gesture with AVPlayer and Pan to seek AVPlayer
I've tried Apple's suggestion here: https://developer.apple.com/library/content/qa/qa1820/_index.html as well, but the problem is that whenever I start a new pan gesture, the player jumps a few frames and then resumes.
My latest approach was to set the current time once the seek completion block finishes and then I try and append the new seek time to that.
Here is my setup:
self.item = [AVPlayerItem playerItemWithURL:resource];
self.player = [AVPlayer playerWithPlayerItem:self.item];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.view.layer addSublayer:self.playerLayer];
self.playerLayer.frame = self.view.bounds;
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
[self.view addGestureRecognizer:recognizer];
And my gesture recognizer handling:
- (void)swipe:(UIPanGestureRecognizer *)paramRecognizer
{
switch(paramRecognizer.state) {
// case UIGestureRecognizerStateBegan:
case UIGestureRecognizerStateChanged:
{
[self.player pause];
CGPoint translation = [paramRecognizer translationInView:self.view];
float horizontalTranslation = translation.x;
float durationInSeconds = CMTimeGetSeconds(self.player.currentItem.asset.duration);
//I'd like to be able to swipe across the whole view.
float translationLimit = self.view.bounds.size.width;
float minTranslation = 0;
float maxTranslation = translationLimit;
if (horizontalTranslation > maxTranslation) {
horizontalTranslation = maxTranslation;
}
if (horizontalTranslation < minTranslation) {
horizontalTranslation = minTranslation;
}
float timeToSeekTo = [self normalize:horizontalTranslation
andMinDelta:minTranslation
andMaxDelta:maxTranslation
andMinDuration:0
andMaxDuration:durationInSeconds];
if(CMTIME_IS_VALID(self.currentTime)){
float seconds = self.currentTime.value/self.currentTime.timescale;
[self.player seekToTime:CMTimeMakeWithSeconds(seconds+timeToSeekTo, self.player.currentTime.timescale)
toleranceBefore:kCMTimeZero
toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished)
{
if(finished)
self.currentTime = self.player.currentItem.currentTime;
}];
}
else
{
[self.player seekToTime:CMTimeMakeWithSeconds(timeToSeekTo,
self.player.currentTime.timescale) toleranceBefore:kCMTimeZero
toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
if(finished)
self.currentTime = self.player.currentItem.currentTime;
}];
}
}
break;
}
}
The normalize method is this:
- (float)normalize:(float)delta
andMinDelta:(float)minDelta
andMaxDelta:(float)maxDelta
andMinDuration:(float)minDuration
andMaxDuration:(float)maxDuration
{
float result = ((delta - minDelta) * (maxDuration - minDuration) / (maxDelta - minDelta) + minDuration);
return result;
}
Any help would be extremely appreciated!