2012-09-29 4 views
5

Ich stoße in eine seltsame Situation mit meinem Videoplayer, dessen Kerncode nicht viel verändert hat von dem, was in einer früheren App funktioniert hat. Hier ist das Problem: Ich füge einen "_loadingLayer" ein (ein CATextLayer, der besagt, dass das Video geladen wird), und beobachte dann die Statuseigenschaft des AVPlayers currentItem, um herauszufinden, wann "_loadingLayer" entfernt und durch meinen tatsächlichen "_playerLayer" ersetzt werden muss. . Hier ist meine KVO-Code für das:AV Foundation: Unterschied zwischen currentItem ist bereit zu spielen und - [AVPlayer readyForDisplay] -Eigenschaft?

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

} 

} 

Mein Problem ist, dass das Video gestartet wird, sondern nur die Audio-Wiedergabe - die Schicht bleibt schwarz. Als ich oben die NSLog-Anweisung eingefügt habe, habe ich herausgefunden warum: Obwohl der currentItem-Status "AVPlayerItemStatusReadyToPlay" ist, ist die Player-Ebene nicht wirklich readyForDisplay. Das macht für mich keinen Sinn - es scheint nicht intuitiv zu sein. Kann mir bitte jemand eine Anleitung geben?

Ich konnte überprüfen, dass _playerLayer dem Ebenenbaum hinzugefügt wird, indem Sie seine Hintergrundfarbe auf rot festlegen.

Eine andere seltsame Sache, die ich denke, könnten verwandt sein .... Ich habe diese Meldungen im Debugger-Konsole zu sehen:

PSsetwindowlevel, Fehler Einstellungsfenster Ebene (1000) CGSSetIgnoresCycle: Fehler 1000 oder Einstellung Fenster-Tags löschen

Vielen Dank im Voraus. Dies ist ein Crosspost von den Apple Dev Foren.

Antwort

3

Wir hatten ein ähnliches Problem und verfolgten es, was ich glaube, ist ein Fehler in iOS 5.1 (und vielleicht früheren Versionen). Es ist in iOS 6.0 behoben. Da ich nirgendwo eine Lösung finden konnte, schreibe ich eine lange Beschreibung für zukünftige Leute, die dieses Problem haben.

Wenn das AVPlayerItem einen Status von AVPlayerStatusReadyToPlay meldet, bevor der AVPlayerLayer abgerufen wurde, meldet der AVPlayer niemals, dass es readyForDisplay ist. So

wenn Sie das tun:

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

stellen Sie sicher, dass es folgt mit:

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

und dass Sie nicht viel haben, wenn jeder Code in zwischen den beiden.

Ich habe einen Prüfstand gebaut, damit er 100% der Zeit funktioniert oder zu 100% versagt. Beachten Sie, dass es schwierig sein kann zu sehen, was in Ihrer aktuellen App passiert, da Sie unterschiedliche Ladezeiten für das Video haben und sich darauf auswirken, wie schnell playerItem AVPlayerStatusReadyToPlay meldet.

Wenn Sie in Ihrer App testen möchten, bringen Sie dies in eine einfache Ansicht. Das Folgende funktioniert nicht (d. H. Sie hören Audio, aber kein Video) unter iOS 5.1. Wenn Sie loadPlayerLayer so konfigurieren, dass sie am Ende von loadPlayer aufgerufen wird, funktioniert sie immer.

Ein Nachfolger für zukünftige Leser: Ein paar Spielerereignisse können diese Reihenfolge umschalten und Sie glauben lassen, dass sie funktioniert. Sie sind jedoch Red Herings, da sie versehentlich die Ladereihenfolge umkehren, so dass PlayerLayer vor AVStatusReadyToPlay gegriffen wird. Die Ereignisse sind: das Video suchen, zum Home-Bildschirm gehen und dann die App reaktivieren, wobei der Player in einem HLS-Video auf eine andere Video-/Audiospur umschaltet. Diese Aktionen lösen AVStatusReadyToPlay erneut aus und bewirken, dass playerLayer vor AVStatusReadyToPlay ausgelöst wird.

Hier ist die Testumgebung, den Test HLS Video von Apple verwendet:

-(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]; 
    } 
    } 
} 
Verwandte Themen