Pregunta

¿Alguien sabe si AVQueuePlayer inicia el almacenamiento temporal la próxima AVPlayerItem cuando el elemento actual está a punto de juego de meta?

Yo sé que no hay nada en la documentación para sugerir esto, yo estoy pidiendo sobre todo si alguien ha observado este tipo de comportamiento o no.

¿Fue útil?

Solución

Ok, he mirado sobre este problema una y otra escrito algo de código de revisar AVQueuePlayer.

La respuesta de jollyCocoa me señaló en la dirección correcta por lo que sugiere observar la propiedad de estado en AVPlayerItem. Sin embargo, la documentación no parece señalar que esta propiedad (y su valor AVPlayerItemStatusReadyToPlay en particular) podrían estar relacionados con el almacenamiento en búfer.

Sin embargo la propiedad AVPlayerItem's loadedTimeRanges parece más relacionada con el almacenamiento en búfer.

Hacer MVA en esa serie fue un poco más complicado - el objeto de matriz en sí no cambia, sólo que es hacer artículos -. Por lo que recurrí a cabo la impresión de que el contenido de cada segundo

Lo que descubrí es que unos pocos segundos en primera pieza de la cola, el loadedTimeRanges para muestra el segundo elemento hacia arriba con un nuevo CMTimeRange hora de inicio 0 y alguna pequeña duración. La duración puede aumentar hasta 60 o menos segundos, mientras que el punto anterior sigue jugando.

Respuesta corta:. AVQueuePlayer amortiguará la siguiente AVPlayerItem durante la reproducción de la actual

Otros consejos

A partir de iOS 5, parece que AVQueuePlayer ya no-buffers pre. No pasó pre-búfer la siguiente pista en IOS 4.

No estoy seguro de por qué no ha habido un cambio o si es aún deliberar por parte de Apple o simplemente un error. En cualquier caso, se trata de un dolor y me va a enviar un bug con ellos al respecto.

Encontrados alrededor de trabajo !!! Después de muchas horas de búsqueda y pruebas fallidas, he encontrado una solución que funciona en iOS 5 y superiores.

Esto reproducir archivos sin ningún tipo de retraso en el medio. No es tan conveniente si se quiere pasar de un archivo, pero sin duda va a poner todo junto para usted. Todavía es posible hacer un seguimiento de cada archivo donde se inicia, al agregar AVURLAsset, mantienen la variable CMTime, algo como:

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

y luego sólo tiene que ir a través de la matriz, comprobando el valor de la hora actual y compararlo usando CMTimeCompare.

Edit: ¿Se encuentra en esta página visibles desde el archivo web (el enlace apunta actualmente a correo no deseado).

He estado experimentando con el uso de películas AVQueuePlayer proporcionados por un servidor. En esta prueba en particular He creado un queuePlayer con AVPlayerItems inicializados con URL a dos diferentes activos de vídeo de diferentes tipos. Se trata de un archivo .mp4-(descarga progresiva), el otro un archivo .m3u8 http streaming. Se hace actuar un poco cobarde, todo sea dicho.

En función del orden en el que la cola de los archivos me sale un comportamiento bastante diferente. Si comienzo con la .mp4-archivo, el AVPlayerLayer queda en blanco y en silencio cuando el jugador comienza nextItem (el .m3u8-archivo). Si cambio el orden y empezar con la M3U8-archivo, el AVPlayerLayer queda en blanco, pero el audio del segundo archivo se reproduce bien.

Mi impresión, por lo que he visto hasta ahora, es que la AVQueuePlayer hace NO iniciar la descarga de la siguiente AVPlayerItem antes de la actual AVPlayerItem tiene terminado de jugar. Pero puedo estar equivocado.

Para continuar supongo ...

Edit: Ok, por lo que he hecho algunas pruebas más y parece que los siguientes artículos se inicia la descarga antes de que acabe último elemento jugar. Ver post de abajo. Impulsar el "NO" ...

Edit2: Adición de mi explicación aquí en su lugar, ya que el comentario me dejó sin opciones de formato. (La mejor práctica de esto es bienvenido, si esto es una mala manera de manejar las actualizaciones de respuesta)

De todos modos, iterado a través de mi itemsArray adición de observación de la propiedad de estado usando MVA ...

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

También puse mi controlador como el observador de la Notificación AVPlayerItem AVPlayerItemDidPlayToEndTimeNotification

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

Ahora podría registrar el cambio de estado del AVPlayerItem, y resulta que la próxima AVPlayerItem en la cola se registra con un cambio de estado AVPlayerItemStatusReadyToPlay antes de los extremos actuales de artículos reproducción.

Mi conclusión es que para ello el siguiente elemento de la línea inicia la descarga antes de los extremos del artículo actual.

Sin embargo! puedo crear una matriz con AVPlayerItems que utilizo para crear mi reproductor. Lectura de la documentación AVFoundation en AVAssets, tengo la impresión de que se trata de descargar sus activos de forma asíncrona, pero estoy todavía incierto cuando estas descargas se inician por la IAPlayerItem. Todavía tengo un comportamiento cobarde cuando agrego el .m3u8-archivo a la cola, lo que hace que me pregunte si estos activos comienzan a descargar en el momento de la creación (parece un poco extraño para mí, sin embargo).

Hice demostración simple para usted y otras personas que desean reducir el tiempo de cada video desde una URL buffering.

  

Nota: no conoce esta es la forma correcta o no pero es perfecto para mí trabajar sin ningún problema. Si alguien sabe más o quieren mejorar el código para un mejor resultado entonces bienvenido a cambiar mi respuesta.

En el siguiente código, Primer vídeo tomar tiempo de almacenamiento normal. El siguiente vídeo se inicia automáticamente cuando la corriente de vídeo está acabado y se puede deslizar hacia la izquierda y derecha para mover el vídeo siguiente y anterior.

Siga el siguiente pasos.

1) En el videoPlayerVC.h archivo.

#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) En el videoPlayerVC.m archivo

Aquí puede comenzar a reproducir el video haciendo clic en el botón. A continuación se muestra el método de acción del botón.

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

Ahora escribir código del método 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

    }
}

observador de notificación para indicar video es el final.

- (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.
}

Método para el juego siguiente vídeo

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

Método para la reproducción de vídeo anterior.

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

Siga estos pasos. Si alguna duda luego comentar este archivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top