
[英]In iOS AVPlayer, addPeriodicTimeObserverForInterval seems to be missing
[英]IOS addPeriodicTimeObserverForInterval fire too many times
我注意到我的应用程序发生了一件奇怪的事情。 这是一个视频应用程序,使用AVFoundation类。
我需要在给定的时间触发一些事件。 我放了一些代码,然后我发表了评论:
/* I prepare the movie clip */
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
NSBundle *bundle = [NSBundle mainBundle];
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
NSString *path = [bundle pathForResource:@"13.VIDEO_A (BAULE)" ofType:@"mp4"];
NSURL *videoUrl = [NSURL fileURLWithPath:path];
AVURLAsset* sourceAsset = [AVURLAsset URLAssetWithURL:videoUrl options:optionsDictionary];
[composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, [sourceAsset duration]) ofAsset:sourceAsset atTime:currentTime error:NULL];
在我的viewDidLoad中,我准备剪辑。 我使用AVUrlAsset可以将选项字典与AVURLAssetPreferPreciseDurationAndTimingKey一起使用,以进行更精确的使用。
/* I create the player */
AVPlayer *mPlayer = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithAsset:composition]];
AVPlayerLayer *mPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:mPlayer];
mPlayerLayer.frame = CGRectMake(0.00, 96.00, 1024.00, 576.00);
[self.view.layer addSublayer: mPlayerLayer];
我用AVUrlasset创建一个带有物品的播放器,然后在视图中创建一个布局
/* I set the observer */
[mPlayer addPeriodicTimeObserverForInterval:CMTimeMake(5,25) queue:NULL usingBlock:^(CMTime time) {
NSLog(@"Event : value: %lld, timescale %d, seconds: %f",
time.value, time.timescale,(float) time.value / time.timescale); }];
我每隔5/25秒,0.2秒(25是电影的帧速率)设置观察者。 在我的方块中,我现在只写日志。
/* Play the movie */
[mPlayer play];
最后我玩。
似乎一切正常,除了我的日志错误:
2012-11-15 16:43:05.382 PerfectCircle Beta[6680:707] Evento : value: 0, timescale 1, seconds: 0.000000
2012-11-15 16:43:05.410 PerfectCircle Beta[6680:707] Evento : value: 0, timescale 1, seconds: 0.000000
2012-11-15 16:43:05.563 PerfectCircle Beta[6680:707] Evento : value: 0, timescale 1, seconds: 0.000000
2012-11-15 16:43:05.580 PerfectCircle Beta[6680:707] Evento : value: 0, timescale 1, seconds: 0.000000
2012-11-15 16:43:05.747 PerfectCircle Beta[6680:707] Evento : value: 5489807, timescale 1000000000, seconds: 0.005490
2012-11-15 16:43:05.751 PerfectCircle Beta[6680:707] Evento : value: 8949705, timescale 1000000000, seconds: 0.008950
2012-11-15 16:43:05.753 PerfectCircle Beta[6680:707] Evento : value: 10679967, timescale 1000000000, seconds: 0.010680
2012-11-15 16:43:05.990 PerfectCircle Beta[6680:707] Evento : value: 248121672, timescale 1000000000, seconds: 0.248122
2012-11-15 16:43:06.169 PerfectCircle Beta[6680:707] Evento : value: 426865945, timescale 1000000000, seconds: 0.426866
随机发生多次火灾后,开始计数就很好了。 但开始时会触发事件5/6次。 我尝试了其他电影和编解码器。 如果我提高利率(例如:CMTimeMake(25,25)),则没有任何改变。
我以这种方式从addBoundaryTimeObserverForTimes
开始工作:
NSArray *starts = [NSArray arrayWithObjects:[NSValue valueWithCMTime:CMTimeMakeWithSeconds(0.2,25)],nil];
[_player addBoundaryTimeObserverForTimes:starts queue:NULL usingBlock:^{ log_function }];
但是我有同样的问题。 但是在这里,如果我提高利率,我不会再看到问题了(但这对我的目标不利)。 我的问题是,我必须精确计算电影播放准确时刻的时间。 而且我不能用if (currenttime==0.3)
测试它,因为它if (currenttime==0.3)
。
是个错误吗? 我想念什么吗? 您听说过类似的东西吗?
感谢您的帮助。 丹尼尔
更新:这似乎是一个开始和结束的问题。
2012-11-15 16:43:05.747 PerfectCircle Beta[6680:707] Evento : value: 0, timescale 1, seconds: 0.000000
2012-11-15 16:43:05.747 PerfectCircle Beta[6680:707] Evento : value: 5489807, timescale 1000000000, seconds: 0.005490
错误的日志对正确的日志具有不同的时间范围。 播放结束时也会发生同样的情况。 似乎在开始和结束时它会执行计时器,但影片尚未加载或已经关闭。 我尝试将观察者放在比赛后,但没有任何改变。
我也为我的CMTimeMake尝试了一个不同且更高的时间表...但是没有效果
我知道这个问题有点老了,但是无论如何……。
第一件事:
如果您查看文档 ,则可能会看到以下声明。
该块以指定的时间间隔定期调用,并根据当前项目的时间线进行解释。 每当时间跳跃以及播放开始或停止时,也会调用该块 。 如果该间隔实时对应一个非常短的间隔,则播放器调用该块的频率可能低于请求的频率。 即使这样,播放器仍将足够频繁地调用该块,以使客户端在其最终用户界面中适当地更新当前时间的指示。
指示为什么在开始和结束播放时调用它。
关于函数被多次调用,我猜它是由于玩家遭受的内部状态变化而发生的。 我已经检查了播放器的'rate','status'和'playerItem'属性,但似乎什么也没说。
解决此问题的一件事就是仅考虑玩家真正玩后的事件。
在调用play方法之前,添加以下代码。
__block AVPlayer* blockPlayer = self.player;
__block typeof(self) blockSelf = self;
// Setup boundary time observer to trigger when audio really begins,
// specifically after 1/3 of a second playback
self.startObserver = [self.player addBoundaryTimeObserverForTimes:
@[[NSValue valueWithCMTime:CMTimeAdd(self.player.currentTime, CMTimeMake(1, 3))]]
queue:NULL
usingBlock:^{
blockSelf.isPlaying = YES;
// Remove the boundary time observer
[blockPlayer removeTimeObserver:blockSelf.startObserver];
}];
现在,在addPeriodicTimeObserverForInterval块上,您只需要检查我们刚刚分配的变量即可。
__block typeof(self) blockSelf = self;
[self addPeriodicTimeObserverForInterval:CMTimeMake(60, 1)
queue:dispatch_get_main_queue()
usingBlock:^(CMTime time)
{
if (blockSelf.isPlaying) {
... do some stuff here
}
}];
好吧,不是更干净的解决方案,但对我来说效果很好。 如果我发现更好的东西,我会来编辑。
也许在您的CMTime通话中,您需要设置更高的精度。 目前,您将其设置为25分之一秒,但不允许舍入浮点值。 尝试使用25,000作为时间表,看看是否可行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.