Domanda

Qualcuno sa se AVQueuePlayer inizia tamponando il prossimo AVPlayerItem quando l'elemento corrente sta per finire a giocare?

So che non c'è niente nella documentazione per suggerire questo, sto chiedendo per lo più se qualcuno ha osservato questo tipo di comportamento o meno.

È stato utile?

Soluzione

Ok, ho guardato su questo problema ancora e scritto del codice per controllare AVQueuePlayer.

La risposta di jollyCocoa mi ha segnalato nella giusta direzione, suggerendo di osservare la proprietà di stato sul AVPlayerItem. Tuttavia la documentazione non sembra far notare che questa proprietà (e il suo valore AVPlayerItemStatusReadyToPlay in particolare) potrebbe essere correlato al buffering.

Tuttavia la proprietà AVPlayerItem's loadedTimeRanges sembra più relative al buffer.

In questo KVO su tale array è stato un po 'più complicato - l'oggetto matrice stessa non cambia, solo che è gli articoli -. Così ho fatto ricorso a stampare il suo contenuto ogni secondo

Quello che ho scoperto è che pochi secondi prima voce della coda, il loadedTimeRanges per il secondo mostra Voce su una nuova CMTimeRange con il tempo di inizio 0 e qualche piccola durata. La durata può aumentare fino a 60 o giù di lì secondi mentre la voce precedente continua a suonare.

Risposta breve:. AVQueuePlayer sarà tamponare il prossimo AVPlayerItem durante la riproduzione di quella attuale

Altri suggerimenti

Come di iOS 5, sembra che AVQueuePlayer non è più pre-buffer. Lo ha fatto pre-buffer traccia successiva in iOS 4.

Non sono sicuro che il motivo per cui c'è stato un cambiamento o se è ancora deliberare da parte di Apple o semplicemente un bug. In ogni caso, si tratta di un dolore e ti presenterà un bug a loro su di esso.

Trovato un giro di lavoro !!! Dopo molte ore di ricerca e test falliti, ho trovato una soluzione che funziona su iOS 5 e superiori.

In questo modo la riproduzione di file senza alcun ritardo in mezzo. Non altrettanto comodo se si vuole passare da un file, ma sarà certamente mettere insieme tutto per voi. E 'ancora possibile tenere traccia di dove ogni file inizia, quando si aggiungono AVURLAsset, mantengono la variabile CMTime, qualcosa come:

NSValue *toJumpTo = [NSValue valueWithCMTime:composition.duration];
[array addObject:toJumpTo];

e poi semplicemente passare attraverso la matrice, controllando il valore dell'ora corrente e confrontandola con CMTimeCompare.

Edit: è stato trovato su questa pagina visibili dall'archivio web (link attualmente punti di spam).

Ho avuto modo di sperimentare con l'AVQueuePlayer utilizzando filmati forniti da un server. In questo particolare test ho creato un queuePlayer con AVPlayerItems inizializzati con l'URL di a due diverse risorse video di tipo diverso. Uno è un file .mp4 (download progressivo), l'altro un file .m3u8 http-streaming. Lo fa agire un po 'funky, devo dire.

A seconda dell'ordine in cui ho coda i file ottengo un comportamento molto diverso. Se comincio con il .mp4 file, l'AVPlayerLayer diventa vuoto e silenzioso quando il NextItem inizia giocatore (il .m3u8-file). Se cambio l'ordine e iniziare con la M3U8-file, l'AVPlayerLayer diventa nero, ma l'audio dal secondo file riprodotto correttamente.

La mia impressione, da quello che ho visto finora, è che l'AVQueuePlayer fa NON iniziare a scaricare la prossima AVPlayerItem prima che la corrente AVPlayerItem ha finito di giocare. Ma potrei sbagliarmi.

Per essere continuato immagino ...

Edit: Ok, così ho fatto un po 'di test e sembra che i prossimi articoli si avvia il download di prima del termine ultimo elemento a giocare. Vedere post qui sotto. Corsa il "NOT" ...

Edit2: Aggiunta la mia spiegazione qui invece, in quanto il commento mi ha lasciato senza opzioni di formattazione. (Best practice per questo è il benvenuto, se questo è un brutto modo di gestire gli aggiornamenti di risposta)

In ogni caso, ho iterato attraverso il mio itemsArray aggiungendo l'osservazione della proprietà di stato utilizzando KVO ...

[playerItem addObserver: self forKeyPath:@"status" options: 0 context: NULL];

Inoltre ho impostato il mio controller come osservatore della notifica AVPlayerItem AVPlayerItemDidPlayToEndTimeNotification :

[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(playerItemDidReachEnd:) 
                                             name: AVPlayerItemDidPlayToEndTimeNotification 
                                           object: nil];

Ora ho potuto registrare il cambio di stato del AVPlayerItem, e si scopre il prossimo AVPlayerItem nella coda viene registrato con un cambiamento di stato AVPlayerItemStatusReadyToPlay prima che la corrente finisce voce riproduzione.

La mia conclusione è che Perciò l'elemento successivo in linea inizia a scaricare prima estremità voce corrente.

Tuttavia! Ho creare un array con AVPlayerItems che io uso per creare il mio lettore. Leggendo la documentazione AVFoundation su AVAssets, ho l'impressione che questi scaricare i loro beni in modo asincrono, ma io sono ancora incerto quando questi download vengono attivate dal IAPlayerItem. Ho ancora qualche comportamento funky quando aggiungo il .m3u8-file sulla coda, che mi fa chiedere se tali attività iniziano il download al momento della creazione (sembra un po 'strano per me però).

Ho fatto semplice demo per voi e per gli altri che vogliono ridurre i tempi di ogni video da URL buffering.

  

Nota: non so questo è il modo giusto o no, ma è perfetto per me lavorare senza alcun problema. Se qualcuno sa più o vogliono migliorare il codice per un risultato migliore poi il benvenuto a cambiare la mia risposta.

Nella sottostante Codice, Primo video prendere normale tempo di buffer. Video successivo verrà avviato automaticamente quando la corrente video è finitura e si può scorrere verso sinistra e destra per spostare il video successivo e precedente.

Segui il passaggi qui sotto.

1) videoPlayerVC.h file.

#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>

@interface videoPlayerVC : UIViewController
{
    AVPlayerViewController *avPlyrViewController;
    AVPlayerItem *currentAVPlyrItem;

    int currentVideoNO;  // For current video track.
    NSMutableArray *arrOfAVPItems;
    NSMutableArray *arrOfPlyer;
}

2) videoPlayerVC.m file

Qui è possibile iniziare a riprodurre il video cliccando sul pulsante. Qui di seguito è il metodo di azione del pulsante.

-(void)clickOnPlayVideosImage:(UIButton *)sender
{
   // In my App. all video URLs is up to 15 second.
    currentVideoNO = 0;
    NSMutableArray *arrForVideoURL = [[NSMutableArray alloc]initWithObjects:
                                      [NSURL URLWithString:@"http://videos/url1.mov"],
                                      [NSURL URLWithString:@"http://videos/url2.mov"],
                                      [NSURL URLWithString:@"http://videos/url3.mov"],
                                      [NSURL URLWithString:@"http://videos/url3.mov"],
                                      [NSURL URLWithString:@"http://videos/url4.mov"],
                                      [NSURL URLWithString:@"http://videos/url5.mov"], nil];

    AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:0]];
    AVPlayerItem *thePlayerItemB = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:1]];
    AVPlayerItem *thePlayerItemC = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:2]];
    AVPlayerItem *thePlayerItemD = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:3]];
    AVPlayerItem *thePlayerItemE = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:4]];
    AVPlayerItem *thePlayerItemF = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:5]];

    if(arrOfAVPItems.count > 0)
       [arrOfAVPItems removeAllObjects];
    arrOfAVPItems = nil;

    if(arrOfPlyer.count > 0)
        [arrOfPlyer removeAllObjects];
    arrOfPlyer = nil;
    arrOfPlyer = [[NSMutableArray alloc] init];

    arrOfAVPItems = [NSMutableArray arrayWithObjects:thePlayerItemA, thePlayerItemB, thePlayerItemC, thePlayerItemD, thePlayerItemE, thePlayerItemF, nil]; // Add All items in the Array

    for(AVPlayerItem *myPlyrItem in arrOfAVPItems)
    {
        AVPlayer *videoPlayerNext = [AVPlayer playerWithPlayerItem:myPlyrItem]; /// Add item in the player
        [videoPlayerNext play]; 
        [videoPlayerNext pause];
        [arrOfPlyer addObject:videoPlayerNext]; /// Make Array of  "AVPlayer" just reduce buffering of each video. 
    }

    avPlyrViewController = [AVPlayerViewController new];
    avPlyrViewController.delegate = self;
    avPlyrViewController.player = (AVPlayer *)arrOfPlyer[0]; // Add first player from the Array.
    avPlyrViewController.showsPlaybackControls = YES;
    avPlyrViewController.allowsPictureInPicturePlayback = YES;
    avPlyrViewController.videoGravity = AVLayerVideoGravityResizeAspect;

    [self presentViewController:avPlyrViewController animated:YES completion:^{
        [self performSelector:@selector(playVideos) withObject:nil afterDelay:1];/// call method after one second for play video.

        UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToNextVideo:)];
        swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
        [avPlyrViewController.view addGestureRecognizer:swipeleft]; // Add left swipe for move on next video

        UISwipeGestureRecognizer * swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToPerviousVideo:)];
        swiperight.direction=UISwipeGestureRecognizerDirectionRight;
        [avPlyrViewController.view addGestureRecognizer:swiperight]; // Add right swipe for move on previous video
    }];
}

Ora scrivere il codice metodo playVideos.

#pragma mark - AVPlayer Methods -

-(void)playVideos
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // remove current "AVPlayerItem" from the notification observe.

    if(arrOfAVPItems.count > 0)
    {
        currentAVPlyrItem = (AVPlayerItem *)arrOfAVPItems[currentVideoNO]; // Add "AVPlayerItem" from the array.

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // Add notification observer to indication current "AVPlayerItem" is finish.

        // pause and nil previous player if available.
        [avPlyrViewController.player pause];
        avPlyrViewController.player = nil;

        avPlyrViewController.player = (AVPlayer *)arrOfPlyer[currentVideoNO]; // add new player from the array
        [avPlyrViewController.player.currentItem seekToTime:kCMTimeZero]; // set for start video on initial position.
        [avPlyrViewController.player play]; // Play video

    }
}

Notifica osservatore per indicare il video è finitura.

- (void)playerItemDidReachEnd:(NSNotification *)notification
{
    NSLog(@"IT REACHED THE END");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem];  // remove current "AVPlayerItem" from the notification observe.

    [self swipeleftToNextVideo:nil]; // Call method for next video.
}

Metodo per giocare prossimo video

-(void)swipeleftToNextVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
    currentVideoNO++;
    if(currentVideoNO > (arrOfAVPItems.count -1))
        currentVideoNO = 0;

    NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));

    [self playVideos];
}

Metodo per giocare video precedente.

-(void)swipeleftToPerviousVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
    currentVideoNO--;
    if(currentVideoNO < 0)
        currentVideoNO = (int)(arrOfAVPItems.count -1);

    NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));

    [self playVideos];
}

, procedere come segue. In caso di dubbi poi commentare per favore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top