同様の問題があり、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];
}
}
}