2012-09-29 11 views
5

Mi trovo in una strana situazione con il mio lettore video, il cui codice base non è cambiato molto da quello che ha funzionato in una app precedente. Ecco il problema: sto inserendo un "_loadingLayer" (un CATextLayer che dice che il video sta caricando), e poi osservando la proprietà di stato di currentItem di AVPlayer per capire quando rimuovere "_loadingLayer" e sostituirlo con il mio attuale "_playerLayer" . Ecco il mio codice di KVO per questo:Base AV: differenza tra la versione corrente pronta per la riproduzione e la proprietà [AVPlayer readyForDisplay]?

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

} 

} 

Il mio problema è che il video sta iniziando, ma solo l'audio è in riproduzione - lo strato rimane nero. Quando ho inserito l'istruzione NSLog sopra, ho scoperto perché: Apparentemente sebbene lo stato di currentItem sia "AVPlayerItemStatusReadyToPlay", il layer player non è in realtà readyForDisplay. Questo non ha senso per me - sembra controintuitivo. Qualcuno può darmi qualche consiglio su questo?

Sono stato in grado di verificare che _playerLayer venga aggiunto all'albero dei livelli impostando il colore dello sfondo sul rosso.

Un'altra cosa strana che credo potrebbe essere correlato .... Ho visto questi messaggi nella console debugger:

PSsetwindowlevel, errore di impostazione livello di finestra (1000) CGSSetIgnoresCycle: errore di impostazione 1000 o clearing window tag

Grazie in anticipo. Questo è un crosspost dei Forum Apple Dev.

risposta

3

Abbiamo avuto un problema simile e lo abbiamo rintracciato in quello che ritengo sia un bug in iOS 5.1 (e forse nelle versioni precedenti). È stato risolto in iOS 6.0. Dal momento che non sono riuscito a trovare una soluzione a questo ovunque, sto scrivendo una lunga scrittura per le persone future che hanno questo problema.

Se AVPlayerItem riporta uno stato di AVPlayerStatusReadyToPlay prima che AVPlayerLayer sia stato ottenuto, AVPlayer non segnalerà mai che è ReadyForDisplay.

Quindi, quando si fare:

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

assicurarsi che sia seguito con:

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

e che non hanno molto se qualsiasi codice tra i due.

Ho costruito un banco di prova per farlo funzionare al 100% delle volte o fallire il 100% delle volte. Tieni presente che può essere complicato vedere cosa succede nella tua app effettiva dato che avrai diversi tempi di caricamento sul video e questo influenzerà la velocità con cui playerItem riporta AVPlayerStatusReadyToPlay.

Se si desidera eseguire il test nella propria app, inserirla in una vista semplice. Il sotto non funzionerà (ad esempio sentirai l'audio ma non vedrai il video) su iOS 5.1. Se si passa loadPlayerLayer a essere invocato alla fine di loadPlayer, funzionerà sempre.

Un seguito per i futuri lettori: un paio di eventi giocatore possono attivare questo ordine e farti pensare che funzioni. Si tratta però di falsi dati poiché invertono inavvertitamente l'ordine di caricamento in modo tale che venga catturato playerLayer prima di AVStatusReadyToPlay. Gli eventi sono: cercare il video, andare alla schermata iniziale e quindi riattivare l'app, il giocatore passa a una traccia video/audio diversa all'interno di un video HLS. Queste azioni innescano nuovamente AVStatusReadyToPlay e quindi fanno accadere il playerLayer prima di AVStatusReadyToPlay.

Ecco il coordinatore di prova che utilizza video di prova HLS di Apple:

-(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]; 
    } 
    } 
} 
Problemi correlati