简体   繁体   中英

Now playing indicator out of sync with AVPlayer playback

I have a now playing indicator view I've made for video playback, for the most part it is working, however I've noticed my indicator isn't synced quite right as it gets towards the end of the playback time.

The video finishes and doesn't loop back like it should because the indicator's X origin didn't cross the right scrubber's X origin, meaning the sync is incorrect.

I'd appreciate any help offered. Here's a picture of where the indicator is wrongly positioned at the end of playback.

在此处输入图片说明

- (void)observePlayerTime
{
    CMTime intervalTime = CMTimeMake(33, 1000);

    __weak typeof(self) weakSelf = self;

    self.playbackObserver = [self.playerLayer.player addPeriodicTimeObserverForInterval:
    intervalTime queue:dispatch_get_main_queue() usingBlock:^(CMTime time)
    {
        UICollectionViewFlowLayout *videoFrameLayout =
        (UICollectionViewFlowLayout *)
        weakSelf.videoFramesCollectionView.collectionViewLayout;

        if (weakSelf.playerLayer.player.rate >= 1.0)
        {
            CGRect newFrame = weakSelf.nowPlayingIndicatorView.frame;

            newFrame.origin.x += (videoFrameLayout.itemSize.width / intervalTime.value);

            if (newFrame.origin.x >= weakSelf.rightScrubberView.frame.origin.x)
            {
                // Here we loop the player

                CGRect newIndicatorFrame = weakSelf.nowPlayingIndicatorView.frame;

                newIndicatorFrame.origin.x = (weakSelf.leftScrubberView.frame.origin.x 
                    + weakSelf.leftScrubberView.bounds.size.width) 
                    - newIndicatorFrame.size.width;

                weakSelf.nowPlayingIndicatorView.frame = newIndicatorFrame;

                [weakSelf.playerLayer.player seekToTime:weakSelf.lastPlayerTime 
                    toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
            }
            else
            {
                weakSelf.nowPlayingIndicatorView.frame = newFrame;
            }
        }
    }];
}

I seem to have solved it using a dispatch_source_t instead of the addPeriodicTimeObserverForInterval

Code:

@property (nonatomic, strong) dispatch_source_t playbackTimer;

- (void)observePlaybackTime
{
    self.playbackTimer = CreateTimerDispatchSource(50000000, 0,
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
    {
        dispatch_async(dispatch_get_main_queue(),^
        {
            if (self.playerLayer.player.rate >= 1.0)
            {
                UICollectionViewFlowLayout *videoFrameLayout = 
                (UICollectionViewFlowLayout *)
                self.videoFramesCollectionView.collectionViewLayout;

                CGRect newFrame = self.nowPlayingIndicatorView.frame;

                newFrame.origin.x += videoFrameLayout.itemSize.width / 20.7;

                if (newFrame.origin.x >= self.rightScrubberView.frame.origin.x)
                {
                    if (CMTIME_IS_VALID(self.lastPlayerTime))
                    {
                        // Loop playback

                        CGRect newIndicatorFrame = self.nowPlayingIndicatorView.frame;

                        newIndicatorFrame.origin.x =
                        self.leftScrubberView.frame.origin.x
                        + self.leftScrubberView.bounds.size.width;

                        self.nowPlayingIndicatorView.frame = newIndicatorFrame;

                        [self.playerLayer.player 
                        seekToTime:self.lastPlayerTime 
                        toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
                    }
                }
                else
                {
                    self.nowPlayingIndicatorView.frame = newFrame;
                }
            }
        });
    });
}

dispatch_source_t CreateTimerDispatchSource(uint64_t interval, uint64_t leeway, 
dispatch_queue_t queue, dispatch_block_t block)
{
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
    queue);

    if (timer)
    {
        dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);

        dispatch_source_set_event_handler(timer, block);

        dispatch_resume(timer);
    }

    return timer;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM