使用AirPlay时,在AVPlayerDemo中限制UISlider擦除

时间:2013-02-18 03:01:14

标签: ios uislider avplayer airplay apple-tv

在Apple的AVPlayerDemo示例项目的AVPlayerDemoPlaybackViewController中将mPlayer.usesExternalPlaybackWhileExternalScreenIsActive设置为YES之后,如何限制清理,以免在AppleTV上落后?

我的意思是,当您快速前后移动滑块时,AppleTV会执行每次seekToTime操作,但需要更长时间才能执行此操作,然后用户需要滑动。

该演示的一个问题是它使用“Touch Drag Inside”和“Value Changed”事件,导致它发送两次相同的值。如果删除“Value Changed”,它会有所改善,但仍会滞后。

我已尝试四舍五入到整秒,然后只在第二次更改时发送seekToTime,但这似乎没有那么多帮助。我真正需要做的是用户移动滑块的速度越快,发送的命令越少,但当用户移动速度越慢时,发送的命令就越多。

关于如何实现这一目标的任何想法?

2 个答案:

答案 0 :(得分:4)

UISlider已经有点节流了。移动速度越快,从A点到B点的值越少。这不足以阻止搜索操作通过AirPlay进行堆叠。

但是,您可以使用seekToTime:completionHandler:来阻止堆叠:

if(seeking) {
    return;
}

seeking = YES;
[player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) completionHandler:^(BOOL finished) {
    seeking = NO;
}];

这会删除任何新的搜索,直到正在进行的搜索结束。这似乎运作良好。您只需确保在用户停止擦洗后发送最后一次搜索操作。

虽然NSTimer可以做同样的事情,但它不太准确,结果会根据连接的延迟而有所不同。以这种方式使用的completionHandler确保搜索不会叠加,无论延迟时间如何。

我还发现UISlider的“Value Changed”动作可以在任何触摸开始动作之前发生。所以最好使用内部/外部动作的触摸拖动,这可以保证在触摸开始后发生。

答案 1 :(得分:0)

使用其他一些代码改进了Luke答案:

static NSTimeInterval ToleranceForAsset(AVAsset *asset) {
    NSTimeInterval tolerance = 0.0;
    for (AVAssetTrack *track in asset.tracks) {
        NSTimeInterval trackTolerance = CMTimeGetSeconds(track.minFrameDuration);
        tolerance = MAX(tolerance, trackTolerance);
    }
    return tolerance;
}

@interface MyPlayerWrapper ()

@property (strong, nonatomic) AVPlayer *player;
@property (assign, nonatomic) NSTimeInterval playerTime;
@property (assign, nonatomic, getter=isSeeking) BOOL seeking;
@property (assign, nonatomic) CGFloat latestSetTime;

@end

@implementation MyPlayerWrapper

- (NSTimeInterval)playerTime {
    return CMTimeGetSeconds(self.player.currentItem.currentTime);
}

- (void)setPlayerTime:(NSTimeInterval)playerTime {
    NSTimeInterval tolerance = ToleranceForAsset(self.player.currentItem.asset);
    if (tolerance) {
        // round to nearest seek tolerance (for example 1/30 sec)
        playerTime = floor(playerTime / tolerance) * tolerance;
    }

    self.latestSetTime = playerTime;
    if (self.isSeeking) {
        return;
    }

    self.seeking = YES;
    [self.player seekToTime:CMTimeMakeWithSeconds(playerTime, self.player.currentItem.duration.timescale) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
        self.seeking = NO;
        if (ABS(self.player.currentItem.currentTime - latestSetTime) > MAX(tolerance, DBL_EPSILON)) {
            self.playerTime = latestSetTime;
        }
    }];
}

@end