3

アプリで奇妙なことが起こっていることに気付きました。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倍以上のイベントを発生させます。さまざまな映画とコーデックを試しました。レートを上げると (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のために、別のより高いタイムスケールも試しました...しかし、効果はありません

4

2 に答える 2

4

この質問は少し古いことは知っていますが、とにかく......

まず最初に:

ドキュメントを確認すると、次のステートメントが表示される場合があります。

ブロックは指定された間隔で定期的に呼び出され、現在のアイテムのタイムラインに従って解釈されます。このブロックは、時間がジャンプしたり、再生が開始または停止したりするたびにも呼び出されます。間隔がリアルタイムで非常に短い間隔に対応する場合、プレーヤーは要求されたよりも少ない頻度でブロックを呼び出す可能性があります。それでも、プレーヤーは、クライアントがエンドユーザー インターフェイスで現在の時刻の表示を適切に更新するのに十分な頻度でブロックを呼び出します。

これは、再生の開始時と終了時に呼び出される理由を示しています。

関数が何度も呼び出されていることについては、プレイヤーが苦しんでいる内部状態の変化が原因で発生していると思われます。プレーヤーの「rate」、「status」、および「playerItem」プロパティを確認しましたが、何が起こっているのかわかりません。

これを回避するためにできることの 1 つは、プレイヤーが実際にプレイした後のイベントのみを考慮することです。

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

きれいな解決策ではありませんが、私にとってはうまくいきました。もっと良いものを見つけたら、編集に来ます。

于 2014-12-15T18:57:03.457 に答える
0

おそらく、CMTime 呼び出しで、より高い精度を設定する必要があります。現時点では 25 秒に設定していますが、浮動小数点値を丸める余裕はありません。タイムスケールとして 25,000 を使用してみて、それが機能するかどうかを確認してください。

于 2012-11-16T21:11:10.870 に答える