Question

Quelqu'un sait si commence AVQueuePlayer tamponnement suivant AVPlayerItem lorsque l'élément en cours est sur le point fini de jouer?

Je sais qu'il n'y a rien dans les documents à suggérer que, la plupart du temps je demande si quelqu'un a observé ce genre de comportement ou non.

Était-ce utile?

La solution

Ok, je l'ai regardé à nouveau sur ce problème et écrit un code pour vérifier AVQueuePlayer.

La réponse de jollyCocoa m'a orienté dans la bonne direction en suggérant d'observer la propriété d'état sur AVPlayerItem. Cependant, la documentation ne semble pas indiquer que cette propriété (et sa valeur de AVPlayerItemStatusReadyToPlay en particulier) pourraient être liés à mémoire tampon.

Cependant la propriété AVPlayerItem's de loadedTimeRanges semble plus liée à mémoire tampon.

Faire KVO sur ce tableau était un peu plus compliqué - l'objet de tableau lui-même ne change pas, seuls les éléments de le faire il -. Donc je eu recours à l'impression de son contenu chaque seconde

Ce que j'ai découvert que quelques secondes premier élément de la file d'attente, le loadedTimeRanges pour le deuxième élément apparaît une nouvelle CMTimeRange avec le temps de démarrage 0 et une petite durée. La durée peut augmenter jusqu'à 60 ou de secondes alors que l'élément précédent continue à jouer.

Réponse courte:. AVQueuePlayer va tamponner le prochain AVPlayerItem tout en jouant l'actuel

Autres conseils

d'iOS 5, il semble que AVQueuePlayer pas pré-tampons plus. Il ne pré-tampon de la piste suivante dans iOS 4.

Je ne sais pas pourquoi il y a eu un changement ou si elle est délibérer même de la part d'Apple ou tout simplement un bug. Dans tous les cas, il est une douleur et je vais soumettre un bug pour eux à ce sujet.

trouvé un travail autour !!! Après de nombreuses heures de recherche, et des tests ont échoué, j'ai trouvé une solution qui fonctionne sur iOS 5 et au-dessus.

Cela lire des fichiers sans aucun délai entre les deux. Pas aussi pratique si vous voulez basculer entre les fichiers, mais certainement tout mis en place pour vous. Il est toujours possible de garder une trace de l'endroit où chaque fichier commence, lors de l'ajout AVURLAsset, garder la variable CMTime, quelque chose comme:

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

et puis juste passer par le tableau, vérifier la valeur de l'heure actuelle et en le comparant à l'aide CMTimeCompare.

Edit: a été trouvé sur cette page visible de l'archive web (le lien actuellement des points de spam).

Je l'ai expérimenté avec le AVQueuePlayer en utilisant des films fournis par un serveur. Dans ce test particulier, je mis en place un queuePlayer avec AVPlayerItems initialisées avec l'URL de deux actifs vidéo différents de types différents. L'un est un .mp4-fichier (téléchargement progressif), l'autre d'un fichier streaming http .m3u8. Il fait agir un peu funky, je dois dire.

En fonction de l'ordre dans lequel je la file d'attente les fichiers que j'obtenir un comportement tout à fait différent. Si je commence avec le .mp4-fichier, le AVPlayerLayer se vide et silencieux lorsque le joueur commence nextItem (le .m3u8 fichier). Si je change l'ordre et commencer par le m3u8 fichier, le AVPlayerLayer se vide, mais l'audio à partir du deuxième fichier est lu correctement.

Mon impression, de ce que j'ai vu jusqu'à présent, est que le fait AVQueuePlayer PAS commencer à télécharger la prochaine AVPlayerItem avant le AVPlayerItem actuel a fini de jouer. Mais je peux me tromper.

A suivre je suppose ...

Edit: Ok, donc je l'ai fait un peu plus de tests et il semble que les prochains articles commence à télécharger avant la dernière se termine point jouer. Voir ci-dessous après. Actionner la "NOT" ...

Edit2: Ajout mon explication ici à la place, puisque le commentaire m'a laissé sans options de formatage. (Les meilleures pratiques pour c'est la bienvenue, si cela est une mauvaise façon de gérer les mises à jour de réponse)

Quoi qu'il en soit, j'itérés mon observation tabEléments ajoutant de la propriété d'état à l'aide KVO ...

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

Je mets aussi mon contrôleur comme l'observateur de la notification AVPlayerItem AVPlayerItemDidPlayToEndTimeNotification :

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

Maintenant, je pourrais enregistrer le changement d'état de la AVPlayerItem, et il se trouve la prochaine AVPlayerItem dans la file d'attente est enregistrée avec un changement d'état AVPlayerItemStatusReadyToPlay avant la fin actuelle de l'objet de la lecture.

Ma conclusion est que celui-ci l'élément suivant la ligne commence à télécharger avant la fin de l'article courant.

Cependant! Je crée un tableau avec AVPlayerItems que j'utilise pour créer mon lecteur. La lecture des AVFoundation docs sur AVAssets, j'ai l'impression que ces télécharger leurs actifs de manière asynchrone, mais je suis encore incertain lorsque ces téléchargements sont initiés par le IAPlayerItem. J'ai encore un comportement de génial quand j'ajoute le .m3u8 fichier à la file d'attente, ce qui me fait me demander si ces actifs commencent le téléchargement au moment de la création (semble un peu étrange pour moi bien).

J'ai fait simple démo pour vous et d'autres qui veulent réduire le temps de mise en mémoire tampon chaque vidéo à partir de l'URL.

  

NOTE: Je ne sais pas c'est bonne ou pas, mais il travaille parfait pour moi sans aucun problème. Si quelqu'un sait plus ou si vous voulez améliorer le code pour un meilleur résultat alors bienvenue changer ma réponse.

Dans le ci-dessous le code, Première vidéo prendre le temps de mise en mémoire tampon normal. Vidéo suivante sera automatiquement lorsque la vidéo démarre en cours est fini et vous pouvez glisser à gauche et à droite pour déplacer la vidéo suivante et précédente.

Suivez les étapes ci-dessous.

1) Dans le videoPlayerVC.h fichier.

#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) Dans videoPlayerVC.m fichier

Ici, vous pouvez commencer à lire la vidéo en cliquant sur le bouton. Ci-dessous la méthode d'action de bouton.

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

écrire du code de la méthode de 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

    }
}

L'Observateur de notification pour indiquer la vidéo est arrivée.

- (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éthode pour la vidéo suivante

-(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éthode pour la lecture vidéo précédente.

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

Suivez ces étapes. En cas de doute alors des commentaires s'il vous plaît.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top