监控AVPlayerItem播放速率时,时基通知每秒触发4-8次的问题咨询
解决AVPlayerItem时基速率变化通知频繁触发的问题
我之前也碰到过一模一样的情况——kCMTimebaseNotification_EffectiveRateChanged确实会因为AVPlayer底层的微小速率调整频繁触发,哪怕播放看起来完全是匀速的。这是因为AVPlayer在播放过程中(尤其是流媒体场景),会通过微调速率来同步音视频、适配缓冲状态,这些底层的小调整都会触发通知,但大多时候对业务逻辑来说是无关的。
这里有两个实用的解决方案来过滤掉不必要的触发:
1. 设置速率变化阈值
只有当速率变化超过你设定的阈值(比如0.01)时,才处理通知事件,忽略微小的波动。
首先在你的类里添加一个属性保存上一次的有效速率:
@property (nonatomic, assign) Float64 lastEffectiveRate;
然后修改通知处理方法:
- (void)timeBaseEffectiveRateChanged:(NSNotification *)notification { CMTimebaseRef timebase = (__bridge CMTimebaseRef)notification.object; Float64 currentRate = CMTimebaseGetEffectiveRate(timebase); // 只有速率变化超过0.01时才执行逻辑 if (fabs(currentRate - self.lastEffectiveRate) > 0.01) { // 这里写你的速率变化处理逻辑 NSLog(@"有效播放速率已变更:%.2f", currentRate); self.lastEffectiveRate = currentRate; } }
2. 防抖处理
通过延迟执行的方式,确保只在速率稳定后才处理事件——如果短时间内多次触发通知,就重置延迟任务,只处理最后一次的速率值。
同样先添加必要的属性:
@property (nonatomic, strong) dispatch_block_t pendingRateChangeHandler; @property (nonatomic, assign) Float64 lastEffectiveRate;
然后实现防抖逻辑:
- (void)timeBaseEffectiveRateChanged:(NSNotification *)notification { CMTimebaseRef timebase = (__bridge CMTimebaseRef)notification.object; Float64 currentRate = CMTimebaseGetEffectiveRate(timebase); // 取消之前待执行的任务 if (self.pendingRateChangeHandler) { dispatch_block_cancel(self.pendingRateChangeHandler); } // 创建新的延迟任务(这里设置100ms延迟,可根据需求调整) self.pendingRateChangeHandler = dispatch_block_create(0, ^{ // 执行你的业务逻辑 NSLog(@"稳定后的有效播放速率:%.2f", currentRate); self.lastEffectiveRate = currentRate; self.pendingRateChangeHandler = nil; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), self.pendingRateChangeHandler); }
补充说明
如果你只关心用户主动设置的播放速率(比如播放/暂停/快进),也可以考虑直接观察AVPlayer的rate属性(用KVO),但要注意:AVPlayer的rate是你设置的目标速率,而时基的effectiveRate是实际的播放速率——比如缓冲不足时,实际速率可能会降到0,这时候rate还是你设置的1.0,但effectiveRate已经变了。所以如果需要监控实际的播放状态,还是得用时基通知+过滤的方案。
内容的提问来源于stack exchange,提问作者Dries Cleymans
相关产品推荐
相关产品推荐

