使用 AirPlay 时在 AVPlayerDemo 中限制 UISlider 擦洗
Posted
技术标签:
【中文标题】使用 AirPlay 时在 AVPlayerDemo 中限制 UISlider 擦洗【英文标题】:Throttling UISlider scrubbing in AVPlayerDemo when using AirPlay 【发布时间】:2013-02-18 03:01:14 【问题描述】:在 Apple 的 AVPlayerDemo 示例项目的 AVPlayerDemoPlaybackViewController 中将 mPlayer.usesExternalPlaybackWhileExternalScreenIsActive
设置为 YES
后,如何限制擦洗,使其不会在 AppleTV 上滞后?
我的意思是,当您来回快速移动滑块时,AppleTV 会执行每个seekToTime
操作,但执行此操作所需的时间比用户滑动的时间要长。
演示的一个问题是它同时使用了“Touch Drag Inside”和“Value Changed”事件,这会导致它两次发送相同的值。如果您删除“Value Changed”,它会有所改善,但仍然滞后。
我试过四舍五入到整秒,然后只在第二个更改时发送seekToTime
,但这似乎没有多大帮助。我真正需要做的是,用户移动滑块的速度越快,发送的命令就越少,而当用户移动的速度越慢时,发送的命令就越多。
关于如何实现这一点的任何想法?
【问题讨论】:
【参考方案1】: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”动作可以在任何触摸启动动作之前发生。所以最好改用触摸拖动内部/外部动作,这保证在触摸开始后发生。
【讨论】:
【参考方案2】:用一些额外的代码改进了 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
【讨论】:
以上是关于使用 AirPlay 时在 AVPlayerDemo 中限制 UISlider 擦洗的主要内容,如果未能解决你的问题,请参考以下文章
使用 AVPlayer 的 Airplay 并不总是有效。 “iPhone”选项在 Airplay 菜单中列出两次
使用 MPMoviePlayerController 禁用 AirPlay