IOS addPeriodicTimeObserverForInterval 触发太多次

标签 ios ios5 avplayer

我注意到我的应用发生了一件奇怪的事情。 这是一个视频应用程序,使用 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 中的一个项目创建了一个播放器,然后我在我的 View 中创建了一个布局

/* 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 是电影的帧率)。 在我的 block 中,我现在只写日志。

/* 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 次。我尝试了不同的电影和编解码器。 如果我提高速率(es: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) 对其进行测试,因为它不精确。

这是一个错误?我想念什么?你听说过类似的事情吗?

感谢您的帮助。 丹妮尔

更新: 这似乎是一个开始和结束的问题。

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 尝试了不同的和更高的时间尺度......但没有效果

最佳答案

我知道这个问题有点老了,但无论如何......

要事第一:

如果您检查 documentation你可能会看到下面的语句。

The block is invoked periodically at the interval specified, interpreted according to the timeline of the current item. The block is also invoked whenever time jumps and whenever playback starts or stops. If the interval corresponds to a very short interval in real time, the player may invoke the block less frequently than requested. Even so, the player will invoke the block sufficiently often for the client to update indications of the current time appropriately in its end-user interface.

这表明为什么在开始和结束播放时调用它。

关于被多次调用的函数,我猜它的发生是因为玩家正在遭受内部状态变化。我检查了播放器的“速率”、“状态”和“playerItem”属性,但似乎没有说明发生了什么。

解决此问题的一件事是只考虑玩家真正玩游戏后的事件。

在调用播放方法之前添加以下代码。

__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 上,您只需检查我们刚刚分配的变量。

__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
                                      }
                                  }];

Well 不是更清洁的解决方案,但对我来说效果很好。如果我找到更好的东西,我会来编辑。

关于IOS addPeriodicTimeObserverForInterval 触发太多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13401206/

相关文章:

iphone - 从不同线程访问 UIView 的简单快捷方式

ios - 启动在后台运行的 iOS 应用程序

php - mysql_fetch_array() 带有奇怪的输出

ios - 在 iOS5 中打开原生 map 应用

ios - AVPlayer ReadyToPlay 枚举是一个未解析的标识符

ios - m3u8 音频流在 MPMoviePlayerController 中播放但不在 AVPlayer 中播放?

iphone - 获取 NULL 值解析 JSON 字符串

objective-c - 当uialertview进入其委托(delegate)方法时如何隐藏它?

iphone - 由于一般错误 (1095),此时无法处理应用程序 info.plist 验证

ios - 如何检测 AVPlayer 实际上开始快速播放