Skip to content

Instantly share code, notes, and snippets.

@Cellane
Created March 17, 2017 12:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cellane/be6ba000eb8937235c6d1c2cf5376f42 to your computer and use it in GitHub Desktop.
Save Cellane/be6ba000eb8937235c6d1c2cf5376f42 to your computer and use it in GitHub Desktop.
//
// ELSeekableVideoPlayerView.m
// CKSiS
//
// Created by Milan Vít on 13.03.17.
// Copyright (c) 2017 EYELEVEL. All rights reserved.
//
#import <Masonry/Masonry.h>
#import "ELSeekableVideoPlayerView.h"
@interface ELSeekableVideoPlayerView ()
@property (strong, nonatomic) UIPanGestureRecognizer *panGestureRecognizer;
@property (assign, nonatomic) CMTime currentTime;
@property (assign, nonatomic) CMTime chaseTime;
@property (assign, nonatomic) BOOL seekInProgress;
@end
@implementation ELSeekableVideoPlayerView
#pragma mark - NSObject
- (void)awakeFromNib {
[super awakeFromNib];
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panVideo:)];
[self addGestureRecognizer:self.panGestureRecognizer];
}
#pragma mark - IBAction
- (IBAction)panVideo:(UIPanGestureRecognizer *)sender {
switch (sender.state) {
case UIGestureRecognizerStateBegan:
self.player.rate = 0;
self.currentTime = self.player.currentTime;
break;
case UIGestureRecognizerStateChanged: {
CGPoint translation = [sender translationInView:self];
float horizontalTranslation = translation.x;
float durationInSeconds = (float) CMTimeGetSeconds(self.player.currentItem.asset.duration);
float translationLimit = self.bounds.size.width;
if (horizontalTranslation > translationLimit) {
horizontalTranslation = translationLimit;
}
if (horizontalTranslation < -translationLimit) {
horizontalTranslation = -translationLimit;
}
float timeToSeekTo = [self normalize:horizontalTranslation minDelta:-translationLimit maxDelta:translationLimit minDuration:-durationInSeconds maxDuration:durationInSeconds];
if (CMTIME_IS_VALID(self.currentTime)) {
float seconds = self.currentTime.value / self.currentTime.timescale;
float finalTime = MAX(0, seconds + timeToSeekTo);
[self seekSmoothlyToTime:CMTimeMakeWithSeconds(finalTime, self.player.currentTime.timescale)];
} else {
[self seekSmoothlyToTime:CMTimeMakeWithSeconds(timeToSeekTo, self.player.currentTime.timescale)];
}
break;
}
default:
break;
}
}
- (void)seekSmoothlyToTime:(CMTime)newTime {
if (CMTIME_COMPARE_INLINE(newTime, !=, self.chaseTime)) {
self.chaseTime = newTime;
if (!self.seekInProgress) {
[self trySeekToChaseTime];
}
}
}
- (void)trySeekToChaseTime {
if (self.player.currentItem.status == AVPlayerStatusReadyToPlay) {
[self actuallySeekToChaseTime];
}
}
- (void)actuallySeekToChaseTime {
self.seekInProgress = YES;
CMTime seekTimeInProgress = self.chaseTime;
[self.player seekToTime:seekTimeInProgress toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
if (CMTIME_COMPARE_INLINE(seekTimeInProgress, ==, self.chaseTime)) {
self.seekInProgress = NO;
} else {
[self trySeekToChaseTime];
}
}];
}
- (float)normalize:(float)delta minDelta:(float)minDelta maxDelta:(float)maxDelta minDuration:(float)minDuration maxDuration:(float)maxDuration {
return ((delta - minDelta) * (maxDuration - minDuration) / (maxDelta - minDelta) + minDuration);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment