Remarque, pour la question ci-dessous: Tous les actifs sont locaux sur l'appareil - aucune diffusion réseau n'a lieu. Les vidéos contiennent des pistes audio.
Je travaille sur une application iOS qui nécessite la lecture de fichiers vidéo avec un délai minimum pour démarrer le clip vidéo en question. Malheureusement, nous ne savons pas quel clip vidéo spécifique est le prochain jusqu'à ce que nous ayons réellement besoin de le démarrer. Plus précisément: lorsqu'un clip vidéo est en cours de lecture, nous saurons ce que sera le prochain ensemble de (environ) 10 clips vidéo, mais nous ne savons pas lequel exactement, jusqu'à ce qu'il soit temps de lire «immédiatement» le clip suivant.
Ce que j'ai fait pour examiner les retards de démarrage réels est d'appeler addBoundaryTimeObserverForTimes
le lecteur vidéo, avec une période d'une milliseconde pour voir quand la vidéo a réellement commencé à jouer, et je prends la différence de cet horodatage avec la première place dans le code qui indique quel actif commencer à jouer.
D'après ce que j'ai vu jusqu'à présent, j'ai trouvé que l'utilisation de la combinaison de AVAsset
chargement, puis la création d'un à AVPlayerItem
partir de celui-ci une fois qu'il est prêt, puis attendre AVPlayerStatusReadyToPlay
avant d'appeler play, a tendance à prendre entre 1 et 3 secondes pour démarrer le agrafe.
Depuis, je suis passé à ce que je pense être à peu près équivalent: appeler [AVPlayerItem playerItemWithURL:]
et attendre pour AVPlayerItemStatusReadyToPlay
jouer. À peu près les mêmes performances.
Une chose que j'observe est que le premier chargement d'élément AVPlayer est plus lent que le reste. Il semble qu'une idée soit de pré-piloter l'AVPlayer avec un élément court / vide avant d'essayer de lire la première vidéo pourrait être une bonne pratique générale. [ Démarrage lent pour AVAudioPlayer la première fois qu'un son est lu
J'adorerais réduire autant que possible les heures de début de la vidéo et avoir des idées de choses à expérimenter, mais j'aimerais recevoir des conseils de toute personne qui pourrait être en mesure de vous aider.
Mise à jour: l'idée 7, ci-dessous, telle qu'implémentée, donne des temps de commutation d'environ 500 ms. C'est une amélioration, mais ce serait bien de l'obtenir encore plus rapidement.
Idée 1: Utilisez N AVPlayers (ne fonctionnera pas)
En utilisant ~ 10 AVPPlayer
objets et en démarrant et en mettant en pause les ~ 10 clips, et une fois que nous savons lequel nous avons vraiment besoin, basculez vers et réactivez la pause AVPlayer
, et recommencez pour le cycle suivant.
Je ne pense pas que cela fonctionne, car j'ai lu qu'il y a environ une limite de 4 actifs AVPlayer's
dans iOS. Quelqu'un a posé une question à ce sujet sur StackOverflow ici, et a découvert la limite de 4 AVPlayer: commutation rapide entre les vidéos en utilisant avfoundation
Idée 2: utilisez AVQueuePlayer (ne fonctionnera pas)
Je ne crois pas que pousser 10 AVPlayerItems
dans un AVQueuePlayer
les pré-chargerait tous pour un démarrage transparent. AVQueuePlayer
est une file d'attente, et je pense que cela ne fait que préparer la prochaine vidéo de la file d'attente pour une lecture immédiate. Je ne sais pas laquelle des ~ 10 vidéos que nous voulons lire, jusqu'à ce qu'il soit temps de commencer celle-là. ios-avplayer-vidéo-préchargement
Idée 3: charger, lire et conserver AVPlayerItems
en arrière-plan (pas encore sûr à 100% - mais pas beau)
Je regarde s'il y a un avantage à charger et à lire la première seconde de chaque clip vidéo en arrière-plan (supprimer la sortie vidéo et audio), et garder une référence à chacun AVPlayerItem
, et quand nous savons pour quel élément doit être lu réel, échangez celui-là et échangez l'AVPlayer d'arrière-plan avec celui actif. Rincez et répétez.
La théorie serait que les jeux récemment joués AVPlayer/AVPlayerItem
peuvent encore contenir des ressources préparées qui rendraient la lecture ultérieure plus rapide. Jusqu'à présent, je n'en ai pas vu les avantages, mais je n'ai peut-être pas la AVPlayerLayer
configuration correctement pour l'arrière-plan. Je doute que cela améliorera vraiment les choses par rapport à ce que j'ai vu.
Idée 4: Utilisez un format de fichier différent - peut-être un format de fichier plus rapide à charger?
J'utilise actuellement le format H.264 .m4v (vidéo-MPEG4). H.264 a beaucoup d'options de codec différentes, il est donc possible que certaines options soient plus rapides à rechercher que d'autres. J'ai trouvé que l'utilisation de paramètres plus avancés qui réduisent la taille du fichier augmente le temps de recherche, mais je n'ai trouvé aucune option qui va dans l'autre sens.
Idée 5: combinaison de format vidéo sans perte + AVQueuePlayer
S'il existe un format vidéo rapide à charger, mais peut-être où la taille du fichier est insensée, une idée pourrait être de pré-préparer les 10 premières secondes de chaque clip vidéo avec une version gonflée mais plus rapide à charger, mais en arrière cela avec un actif encodé en H.264. Utilisez un AVQueuePlayer et ajoutez les 10 premières secondes au format de fichier non compressé, puis faites-en un qui est en H.264 qui obtient jusqu'à 10 secondes de temps de préparation / préchargement. J'obtiendrais donc «le meilleur» des deux mondes: des temps de démarrage rapides, mais aussi des avantages d'un format plus compact.
Idée 6: utiliser un AVPlayer non standard / écrire le mien / utiliser celui de quelqu'un d'autre
Compte tenu de mes besoins, je ne peux peut-être pas utiliser AVPlayer, mais je dois recourir à AVAssetReader et décoder les premières secondes (éventuellement écrire un fichier brut sur le disque), et quand il s'agit de la lecture, utilisez le format brut pour le lire retour rapide. Cela me semble être un énorme projet, et si je le fais de manière naïve, il n'est pas clair / il est peu probable qu'il fonctionne mieux. Chaque image vidéo décodée et non compressée est de 2,25 Mo. Naïvement - si nous optons pour ~ 30 fps pour la vidéo, je me retrouverais avec ~ 60 Mo / s de lecture à partir du disque, ce qui est probablement impossible / pousser. Évidemment, nous devrons faire un certain niveau de compression d'image (peut-être des formats de compression openGL / es natifs via PVRTC) ... mais c'est un peu fou. Peut-être qu'il existe une bibliothèque que je peux utiliser?
Idée 7: combinez tout dans un seul élément de film et seekToTime
Une idée qui pourrait être plus facile que certaines des solutions ci-dessus est de tout combiner en un seul film et d'utiliser seekToTime. Le truc, c'est que nous sauterions partout. Accès essentiellement aléatoire au film. Je pense que cela peut fonctionner correctement: avplayer-movie-playing-lag-in-ios5
Quelle approche pensez-vous être la meilleure? Jusqu'à présent, je n'ai pas fait autant de progrès en termes de réduction du décalage.
Réponses:
Pour iOS 10.x et supérieur pour réduire le délai de démarrage d'AVPlayer que j'ai défini:
avplayer.automaticallyWaitsToMinimizeStalling = false;
et cela a semblé résoudre le problème pour moi. Cela pourrait avoir d'autres conséquences, mais je ne les ai pas encore atteintes.J'ai eu l'idée de: https://stackoverflow.com/a/50598525/9620547
la source
L'élément peut ne pas être prêt une fois que vous l'avez créé, il peut effectuer des calculs tels que la durée du film, assurez-vous de contenir toutes les métadonnées du film dans le fichier.
la source
Vous devriez d'abord essayer l'option 7, juste pour voir si vous pouvez faire fonctionner cela. Je soupçonne que cela ne fonctionnera pas réellement pour vos besoins car le temps de recherche ne sera probablement pas assez rapide pour vous permettre de basculer de manière transparente entre les clips. Si vous essayez cela et que cela échoue, alors je vous conseillerais de faire l'option 4/6 et de jeter un œil à ma bibliothèque iOS conçue spécifiquement à cet effet, faites simplement une recherche rapide sur Google sur AVAnimator pour en savoir plus. Ma bibliothèque permet de mettre en place des boucles fluides et de passer d'un clip à un autre, c'est très rapide car la vidéo doit être décodée dans un fichier au préalable. Dans votre cas, les 10 clips vidéo seraient décodés en fichiers avant de commencer, mais basculer entre eux serait rapide.
la source
Sans avoir rien fait de tel dans le passé, en fonction de vos pensées et de vos expériences, j'essaierais une combinaison de 7 et 1: préchargez un AVPlayer avec les premières secondes des 10 vidéos de suivi. Ensuite, le saut sera très probablement plus rapide et plus fiable en raison de moins de données. Pendant que vous jouez le morceau sélectionné, vous avez suffisamment de temps pour préparer l'AVPlayer pour le reste de la vidéo de suivi sélectionnée en arrière-plan. Lorsque le début est terminé, vous passez à l'AVPlayer préparé. Donc, au total, vous avez à tout moment un maximum de 2 AVPlayers chargés.
Bien sûr, je ne sais pas si la commutation peut être effectuée si facilement qu'elle ne perturbe pas la lecture.
(J'aurais ajouté ceci comme commentaire si je pouvais.)
Meilleur, Peter
la source
Si j'ai bien compris votre problème, il semble que vous ayez une vidéo continue sur laquelle vous devez charger la piste audio à tout moment.
Si tel est le cas, je suggère de regarder dans BASS . BASS est une bibliothèque audio similaire à AVPlayer qui vous donne un accès (relativement) facile aux API de bas niveau du framework AudioUnits sous iOS. Qu'est-ce que cela signifie pour vous? Cela signifie qu'avec un tout petit peu de manipulation du tampon (vous n'en aurez peut-être même pas besoin, cela dépend de la taille du délai souhaité), vous pouvez commencer à jouer de la musique instantanément.
Les limitations s'étendent cependant à la vidéo, comme je l'ai dit, il s'agit d'une bibliothèque audio , donc toute manipulation vidéo devra toujours être effectuée avec AVPlayer. Cependant, en utilisant,
-seekToTime:toleranfeBefore:toleranceAfter:
vous devriez être en mesure d'obtenir une recherche rapide dans la vidéo tant que vous pré-enroulez avec toutes les options nécessaires.Si vous synchronisez sur plusieurs appareils (ce que votre application pourrait suggérer), laissez simplement un commentaire et je serais heureux de modifier ma réponse.
PS: BASS peut sembler intimidant au début à cause de son format de type C, mais il est vraiment très facile à utiliser pour ce qu'il est.
la source
Voici plusieurs propriétés et méthodes fournies par la classe AVAsset qui peuvent aider:
la source