AVPlayer ускоренная перемотка вперед / назад с помощью жеста панорамирования

Последние два дня я бился головой о досадном сбое и надеялся, что кто-нибудь прольет свет.

Базовая настройка: у меня есть AVPlayerLayer с проигрывателем, распознаватель жестов панорамирования в представлении, и я хочу, чтобы пользователь мог проводить пальцами вперед и назад, и видео будет искать соответственно.

Уловка: я бы хотел, чтобы пользователь поднял палец и снова поместил его в любом месте экрана, чтобы ускоренная перемотка вперед или назад возобновилась на том же кадре, в котором он остановились и продолжаем прогрессировать оттуда.

Я видел эти два вопроса: Pan Gesture с AVPlayer и Панель для поиска AVPlayer

Я попробовал предложение Apple здесь: https://developer.apple.com/library/content/qa/qa1820/_index.html, но проблема в том, что всякий раз, когда я начинаю новый жест панорамирования, проигрыватель перескакивает на несколько кадров и затем возобновляет работу.

Мой последний подход заключался в том, чтобы установить текущее время после завершения блока завершения поиска, а затем я пытаюсь добавить к нему новое время поиска.

Вот моя установка:

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];

И моя обработка распознавателя жестов:

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

Метод нормализации таков:

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

Любая помощь будет очень признательна!


person John Lane    schedule 25.01.2017    source источник
comment
Слегка сбивающая с толку формулировка, вы говорите, если вы начнете панорамирование на 3,00 секунды и скажете панорамирование на 2 пикселя, а затем поднимите, он должен воспроизвести 5,00 или 3,00 снова?   -  person Sean Lintern    schedule 25.01.2017
comment
@ SeanLintern88 Он должен снова играть на 3.0, извините, прояснил   -  person John Lane    schedule 25.01.2017
comment
Хорошо, просто чтобы уточнить, вы бы были на 3.0, панорамируя и прокручивая назад / вперед, а затем на .end вернитесь обратно к 3.0? Но во время скраба видео будет плавно переходить вперед / назад в зависимости от панорамирования? Если да, то в чем именно заключается эта проблема?   -  person Sean Lintern    schedule 25.01.2017


Ответы (1)


При UIGestureRecognizerStateBegan сохраните CMTime до AVPlayer, затем выполните панорамирование изменения дельты, а затем на UIGestureRecognizerStateEnded просто вернетесь к исходному сохраненному времени?

Просто примечание для более плавного поиска не ставьте видео на паузу, установите скорость на 0.

person Sean Lintern    schedule 25.01.2017
comment
Вы действительно правы, я заметил проблему после прочтения вашего комментария, если вы посмотрите мой пример кода, я устанавливал начальное время поиска в UIGestureRecognizerStateChanged, а не в UIGestureRecognizerStateBegan, поэтому я увидел первоначальный рывок, когда пользователь начал проведите пальцем по экрану. - person John Lane; 26.01.2017
comment
Также используйте скорость, чтобы делать паузы, а не делать паузы, это делает поиск гораздо более плавным. - person Sean Lintern; 26.01.2017
comment
Re. разница в паузе / скорости, просто чтобы упомянуть, что на сегодняшний день официальные документы говорят, что это одно и то же: Вызов этого метода аналогичен установке скорости на 0,0. - person superjos; 28.02.2019