2013-05-14 19 views
10

Scrivo lettore personalizzato da AVPlayer per la riproduzione video. Secondo documenti di Apple impostare il livello video:Ripristina riproduzione video AVPlayer dopo l'attivazione dell'app

self.player = [IPLPlayer new]; 
    self.player.playerLayer = (AVPlayerLayer *)self.playerView.layer; 

Dove self.playerView è di classe al solito da quei documenti:

@implementation PlayerView 

+ (Class) layerClass { 
    return [AVPlayerLayer class]; 
} 

- (AVPlayer *)player { 
    return [(AVPlayerLayer *)[self layer] player]; 
} 

- (void)setPlayer:(AVPlayer *) player { 
    [(AVPlayerLayer *) [self layer] setPlayer:player]; 
} 

Il problema è: Quando stretta app (tasto Home), o lo schermo di blocco , la riproduzione del video viene interrotta e quando si riprende SOLO la riproduzione audio riprende, l'immagine sullo schermo è ancora quella precedente allo schermo del blocco: è completamente statica e nota i fotogrammi.

Come riprendere la riproduzione VIDEO dopo lo schermo è bloccato?

Sembra devo registrare le notifiche, e dopo circa diventare attivo strato di riprendere il video:

-(void)registerNotification 
{ 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(willEnterBackground) 
               name:UIApplicationWillResignActiveNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(didEnterForeground) 
               name:UIApplicationDidBecomeActiveNotification object:nil]; 
} 

-(void)unregisterNotification 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 


-(void)willEnterBackground 
{ 
    NSLog(@"willEnterBackground"); 
    [self.playerView willEnterBackground]; 
} 

-(void)didEnterForeground 
{ 
    NSLog(@"didEnterForeground"); 
    [self.playerView didEnterForeground]; 
} 

risposta

15

E una soluzione che unisce tutte queste informazioni insieme.

Forse lo stato del giocatore dovrebbe essere gestito in modo diverso, ma mi piace il modo ricorsivo.

Nota: se non è necessario il tempo di ricerca esatto, è possibile utilizzare [_player seekToTime:<#(CMTime)#> completionHandler:<#^(BOOL finished)completionHandler#>] È più veloce ma cerca il fotogramma chiave più vicino.

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

.... 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; 
} 

-(void)viewWillDisappear:(BOOL)animated 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]; 
} 

.... 

-(void) appEnteredForeground { 
    AVPlayerLayer *player = (AVPlayerLayer *)[playerView layer]; 
    [player setPlayer:NULL]; 
    [player setPlayer:_player]; 
    [self playAt:currentTime]; 
} 

-(void) appEnteredBackground { 
    [_player pause]; 
    currentTime = [_player currentTime]; 
} 

-(void)playAt: (CMTime)time { 
    if(_player.status == AVPlayerStatusReadyToPlay && _player.currentItem.status == AVPlayerItemStatusReadyToPlay) { 
     [_player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) { 
      [_player play]; 
     }]; 
    } else { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      [self playAt:time]; 
     }); 
    } 
} 
3

Utilizzare la UIApplicationWillEnterForegroundNotification pure. In questo modo si conosce la vostra applicazione sarà attivo e visibile per l'utente:

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; 
+2

Mi dispiace, ma la mia domanda non era su di esso. – HotJard

1

Dopo alcune ricerche ho trovato, che la stessa borsa è in lettore iOS (browser web, MPMoviePlayerController). Può essere perché il tipo di distribuzione del contenuto è Download progressivo.

Quindi la soluzione è:

  • Usa sotto le notifiche e risparmiare tempo corrente.
  • Dopo aver ripreso l'app, ricreare AVPlayer e avviare la riproduzione dal tempo salvato .

In tutti gli altri casi l'immagine è bloccata o la vista diventa nera.

+0

Questa dovrebbe essere la risposta accettata. Anche se si implementa il comportamento sulle notifiche, sii consapevole che NON è possibile passare l'oggetto giocatore alle notifiche di UIApplicazione, se la tua notifica non viene mai chiamata questo è il colpevole –

1

Il trucco è quello di staccare tutti i livelli video dai loro giocatori quando l'applicazione ha fatto immettere sfondo e riattaccare quando l'applicazione fatto diventare di nuovo attivo.

Quindi nel tuo -applicationDidEnterBackground: hai da innescare un meccanismo che si traduce in

avPlayerLayer.player = nil; 

e nel vostro -applicationDidBecomeActive: si ricollega il giocatore come

avPlayerLayer.player = self.avPlayer; 

anche dare un'occhiata a questa nota tecnica (QA1668) da Apple.

+0

Non è stato necessario farlo, forse è stato risolto? –

4

questo funziona per me su Swift 3

Aggiungi un posto durante l'impostazione della vista:

NotificationCenter.default.addObserver(self, 
    selector: #selector(appWillEnterForegroundNotification), 
    name: .UIApplicationWillEnterForeground, object: nil) 

Prendi il tuo lettore e costringerlo a giocare:

func appWillEnterForegroundNotification() { 
    myPlayer.play() 
} 

Non dimenticare di rimuovere gli osservatori quando non ne hai bisogno:

override func viewWillDisappear(_ animated: Bool) { 
    super.viewWillDisappear(animated) 
    NotificationCenter.default.removeObserver(self) 
} 
+1

Hmm .. Sono abbastanza sicuro che ciò causerà un mantenimento +1 alla classe che lo contiene. Quindi 'deinit' non sarà mai chiamato. Dovresti rimuovere l'osservatore da qualche altra parte in modo che l'oggetto venga rilasciato:] –

+1

Sì 'viewDidDisappear' sarebbe un buon posto per rimuovere l'osservatore. – Harish

+0

Ho aggiornato la risposta. Grazie @AndresCanella e Harish <3 – budidino

Problemi correlati