在Apple的AVPlayerDemo示例项目的AVPlayerDemoPlaybackViewController中将mPlayer.usesExternalPlaybackWhileExternalScreenIsActive
设置为YES
之后,如何限制清理,以免在AppleTV上落后?
我的意思是,当您快速前后移动滑块时,AppleTV会执行每次seekToTime
操作,但需要更长时间才能执行此操作,然后用户需要滑动。
该演示的一个问题是它使用“Touch Drag Inside”和“Value Changed”事件,导致它发送两次相同的值。如果删除“Value Changed”,它会有所改善,但仍会滞后。
我已尝试四舍五入到整秒,然后只在第二次更改时发送seekToTime
,但这似乎没有那么多帮助。我真正需要做的是用户移动滑块的速度越快,发送的命令越少,但当用户移动速度越慢时,发送的命令就越多。
关于如何实现这一目标的任何想法?
答案 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