5

ビデオ プレーヤーで奇妙な状況が発生しています。そのコア コードは、以前に作成したアプリで機能していたものとあまり変わっていません。問題は次のとおりです。「_loadingLayer」(ビデオがロード中であることを示す CATextLayer) を挿入し、AVPlayer の currentItem の status プロパティを観察して、「_loadingLayer」をいつ削除し、実際の「_playerLayer」に置き換えるかを判断します。 . そのための私のKVOコードは次のとおりです。

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if ((object == _playerLayer) && (_playerLayer.player.currentItem.status == AVPlayerItemStatusReadyToPlay)) {

    [CATransaction setAnimationDuration:1.8];

    _loadingLayer.opaque = NO;

    if (_playerLayer.readyForDisplay) {

        NSLog(@"Should be ready now.");

    }

    [self addPlayerLayerToLayerTree];

}

}

私の問題は、ビデオが開始されているが、オーディオのみが再生されていることです.レイヤーは黒のままです. 上記の NSLog ステートメントを挿入すると、その理由がわかりました。明らかに、currentItem のステータスは "AVPlayerItemStatusReadyToPlay" ですが、プレーヤー レイヤーは実際には ReadyForDisplay ではありません。これは私には意味がありません。直感に反しているように思えます。誰かが私にこれについてのガイダンスを教えてもらえますか?

背景色を赤に設定することで、_playerLayer がレイヤー ツリーに追加されていることを確認できました。

関連していると思われるもう1つの奇妙なこと....デバッガーコンソールに次のメッセージが表示されています。

PSsetwindowlevel、エラー設定ウィンドウ レベル (1000) CGSSetIgnoresCycle: エラー 1000 ウィンドウ タグの設定またはクリア

前もって感謝します。これは Apple Dev Forums からのクロスポストです。

4

1 に答える 1

5

同様の問題があり、iOS 5.1 (およびおそらくそれ以前のバージョン) のバグであると思われるものにたどり着きました。iOS 6.0 で修正されました。これに対する解決策がどこにも見つからなかったので、この問題を抱えている将来の人々のために長い記事を書いています.

AVPlayerLayer が取得される前に AVPlayerItem が AVPlayerStatusReadyToPlay のステータスを報告する場合、AVPlayer はそれが readyForDisplay であることを決して報告しません。

だからあなたがするとき:

self.player = [AVPlayer playerWithPlayerItem:self.playerItem];

次のようになっていることを確認してください。

self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 

そして、2 つの間にコードがほとんどないことを確認してください。

100% の確率で動作するか、100% の確率で失敗するようにテスト装置を構築しました。実際のアプリで何が起こっているかを確認するのは難しい場合があることに注意してください。ビデオの読み込み時間はさまざまであり、それが playerItem が AVPlayerStatusReadyToPlay を報告する速度に影響するからです。

アプリでテストする場合は、これを単純なビューに入れます。以下は、iOS 5.1 では機能しません (つまり、オーディオは聞こえますが、ビデオは表示されません)。loadPlayerLayer を loadPlayer の最後で呼び出されるように切り替えると、常に機能します。

今後の読者のためのフォローアップ: いくつかのプレイヤー イベントがこの順序を変更し、機能していると思わせる可能性があります。AVStatusReadyToPlay の前に playerLayer が取得されるように、誤ってロード順序を逆にしているため、これらは厄介者です。イベントは次のとおりです。ビデオを探す、ホーム画面に移動してからアプリを再アクティブ化する、プレーヤーが HLS ビデオ内の別のビデオ/オーディオ トラックに切り替える。これらのアクションは AVStatusReadyToPlay を再度トリガーし、AVStatusReadyToPlay の前に playerLayer を発生させます。

Apple のテスト HLS ビデオを使用するテスト ハーネスは次のとおりです。

-(void)loadPlayer
{
  NSLog(@"loadPlayer invoked");

  NSURL *url = [NSURL URLWithString:@"https://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"];
  self.playerItem = [AVPlayerItem playerItemWithURL:url];
  [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerContext];
  self.player = [AVPlayer playerWithPlayerItem:self.playerItem];

}

-(void)loadPlayerLayer
{
  NSLog(@"starting player layer");
  self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 
  [self.playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerLayerContext];
  [self.playerLayer setFrame:[[self view] bounds]];
  [[[self view] layer] addSublayer:self.playerLayer];
}

-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context
{
  if(context == &kPlayerContext){
    if([self.player status] == AVPlayerStatusReadyToPlay){
      NSLog(@"Player is ready to play");
      //Robert: Never works if after AVPlayerItem reports AVPlayerStatusReadyToPlay
      if(!self.startedPlayerLayer){
        self.startedPlayerLayer = YES;
        [self loadPlayerLayer];
      }
    }
  }

  if(context == &kPlayerLayerContext){
    if([self.playerLayer isReadyForDisplay] == YES){
      NSLog(@"PlayerLayer says it's ready to display now");
      [self playTheVideoIfReady];
    }
  }
}
于 2012-10-28T21:39:42.317 に答える