Remarque, pour la question ci-dessous: Tous les actifs sont locaux sur l'appareil - aucune diffusion en continu sur le 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 est le suivant 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 quelle est la prochaine série (approximativement) de 10 clips vidéo, mais nous ne savons pas lequel exactement, jusqu’à ce que le moment venu 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
sur le lecteur vidéo, avec un laps de temps d’une milliseconde pour voir à quel moment la vidéo a réellement commencé à être lue, 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'ici, j'ai constaté que l'utilisation de la combinaison de AVAsset
chargement, puis de créer une AVPlayerItem
à partir de cette fois, une fois prêt, puis d'attendre AVPlayerStatusReadyToPlay
avant d'appeler le jeu prend généralement entre 1 et 3 secondes. pour démarrer le clip.
Depuis, je suis passé à ce que je pense est à peu près équivalent: appeler [AVPlayerItem playerItemWithURL:]
et attendre que AVPlayerItemStatusReadyToPlay
soit joué. À peu près la même performance.
Ce que je remarque, c’est que le premier chargement d’AVPlayer est plus lent que le reste. Une des idées semble être d’avoir AVPLayer avec un élément court/vide avant de lire la première vidéo, ce qui pourrait être une bonne pratique générale. [ Démarrage lent d’AVAudioPlayer lors de la première lecture d’un son
J'aimerais beaucoup réduire le plus possible les heures de début de la vidéo et avoir quelques idées de choses à expérimenter, tout en souhaitant des conseils de la part de ceux qui pourraient peut-être nous aider.
Mise à jour: l'idée 7 ci-dessous, telle que mise en œuvre, 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: Utiliser N AVPlayers (ne fonctionnera pas)
En utilisant ~ 10 objets AVPPlayer
et en démarrant et en mettant en pause tous les ~ 10 clips, et une fois que nous connaissons ceux dont nous avons réellement besoin, basculez sur la AVPlayer
correcte, annulez-la et recommencez pour le cycle suivant.
Je ne pense pas que cela fonctionne, car j'ai lu qu'il y avait à peu près une limite de 4 AVPlayer's
actifs dans iOS. Quelqu'un qui a posé des questions à ce sujet sur StackOverflow ici a découvert la limite de 4 AVPlayer: commutation rapide entre vidéos-using-avfoundation
Idée 2: Utiliser AVQueuePlayer (ne fonctionnera pas)
Je ne crois pas que le fait de placer 10 AVPlayerItems
dans une AVQueuePlayer
les pré-chargerait tous pour un démarrage en douceur. AVQueuePlayer
est une file d'attente, et je pense que cela prépare uniquement la vidéo suivante dans la file d'attente pour une lecture immédiate. Je ne sais pas laquelle des ~ 10 vidéos nous voulons lire, jusqu'à ce qu'il soit temps de commencer celle-ci. préchargement ios-avplayer-video
Idée 3: Charger, lire et conserver AVPlayerItems
en arrière-plan (pas encore sûr à 100% - mais ne semble pas bon)
Je cherche à savoir s'il est avantageux de charger et de lire la première seconde de chaque clip vidéo en arrière-plan (supprimer la sortie vidéo et audio), et de garder une référence à chaque AVPlayerItem
, et quand nous savons quel élément doit être lu. pour de vrai, échangez-le et échangez l’AVPlayer en arrière-plan avec celui qui est actif. Rincer et répéter.
La théorie serait que les AVPlayer/AVPlayerItem
récemment joués peuvent encore contenir des ressources préparées qui accéléreraient la lecture ultérieure. Jusqu’à présent, je n’en ai pas vu les avantages, mais je n’ai peut-être pas correctement configuré la variable AVPlayerLayer
pour le fond. Je doute que cela va vraiment améliorer les choses de ce que j'ai vu.
Idée 4: Utilisez un format de fichier différent - peut-être un format plus rapide à charger?
J'utilise actuellement le format H.264 au format .m4v (video-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 constaté que l'utilisation de paramètres plus avancés réduisant la taille du fichier augmentait le temps de recherche, mais je n'ai trouvé aucune option inversée.
Idée 5: Combinaison du format vidéo sans perte + AVQueuePlayer
Si un format vidéo est rapide à charger, mais que la taille du fichier est insalubre, une idée pourrait être de préparer à l'avance les 10 premières secondes de chaque clip vidéo avec une version gonflée mais plus rapide à charger, mais en retour cela avec un actif qui est encodé en H.264. Utilisez un AVQueuePlayer, ajoutez les 10 premières secondes au format de fichier non compressé, puis ajoutez-en un qui est au format H.264 et qui dure jusqu'à 10 secondes du temps de préparation/préchargement. J'obtiendrais donc «le meilleur» des deux mondes: des temps de démarrage rapides, mais aussi un format plus compact.Idée 6: Utiliser un AVPlayer non standard/écrire le mien/utiliser le code de quelqu'un d'autre.
Compte tenu de mes besoins, je ne peux peut-être pas utiliser AVPlayer, mais je dois utiliser AVAssetReader et décoder les premières secondes (éventuellement écrire un fichier brut sur un disque). Lorsqu'il s'agit de la lecture, utilisez le format brut pour le lire. retour rapide. Cela me semble être un projet énorme, et si je le fais avec naïveté, il n’est pas clair/il est peu probable que nous travaillions mieux. Chaque image vidéo décodée et non compressée correspond à 2,25 Mo. Pour parler naïvement - si nous prenons environ 30 images par seconde pour la vidéo, il nous faudrait environ 60 Mo/s de lecture requise à partir du disque, ce qui est probablement impossible. Évidemment, nous devrions 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 y a-t-il une bibliothèque que je peux utiliser?
Idée 7: Combinez le tout en un seul élément de film et seekToTime
Une idée qui pourrait être plus facile que certaines des solutions ci-dessus consiste à tout combiner en un seul film et à utiliser seekToTime. Le fait est que nous sauterions partout. Accès essentiellement aléatoire au film. Je pense que cela pourrait bien marcher: avplayer-movie-playing-lag-in-ios5
Quelle approche pensez-vous serait la meilleure? Jusqu'ici, je n'ai pas fait beaucoup de progrès en termes de réduction du retard.
Which approach do you think would be best? So far, I've not made that much progress in terms of reducing the lag.
Vous devriez d'abord essayer l'option n ° 7, juste pour voir si vous pouvez la faire fonctionner. Je soupçonne que cela ne fonctionnera pas vraiment 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, je vous conseillerais donc de choisir l'option 4/6 et de jeter un œil à ma bibliothèque iOS spécialement conçue à cet effet. Vous n'avez qu'à effectuer une recherche rapide sur AVAnimator pour en savoir plus. Ma bibliothèque permet d'implémenter des boucles transparentes et de passer d'un clip à un autre, c'est très rapide car la vidéo doit être décodée au préalable dans un fichier. Dans votre cas, les 10 clips vidéo seraient tous décodés en fichiers avant de commencer, mais le passage entre eux serait rapide.
L'actif peut ne pas être prêt une fois que vous l'avez créé, il peut effectuer des calculs comme la durée d'un film. Assurez-vous de contenir toutes les métadonnées du film dans le fichier.
Sans avoir rien fait de tel dans le passé, en fonction de vos pensées et de vos expériences, j'essaierais de combiner 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 du moins de données. Pendant que vous jouez le morceau sélectionné, vous avez suffisamment de temps pour préparer 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 le basculement peut être effectué sans heurts pour ne pas perturber la lecture.
(J'aurais ajouté ceci comme commentaire si je pouvais.)
Meilleur, Peter
Pour iOS 10.x et les versions plus récentes, afin de réduire le délai de démarrage d’AVPlayer, j’ai défini: avplayer.automaticallyWaitsToMinimizeStalling = false;
et cela a semblé régler le problème pour moi. Cela pourrait avoir d'autres conséquences, mais je ne les ai pas encore touchées.
J'en ai eu l'idée de: https://stackoverflow.com/a/50598525/9620547
Si j'ai bien compris votre problème, il semblerait que vous ayez une vidéo en continu sur laquelle vous devez charger la piste audio très rapidement.
Si tel est le cas, je suggère de regarder dans BASS . BASS est une bibliothèque audio très semblable à AVPlayer qui vous donne un accès (relativement) facile aux API de bas niveau du framework AudioUnits dans iOS. Qu'est-ce que cela signifie pour vous? Cela signifie qu’avec un peu de manipulation de la mémoire tampon (vous n’en aurez peut-être même pas besoin, cela dépend du temps que vous souhaitez prendre), vous pouvez commencer à jouer de la musique instantanément.
Les limitations s’étendent toutefois à la vidéo. Comme je l’ai dit, il s’agit d’une bibliothèque audio. Toute manipulation vidéo devra donc toujours être effectuée avec AVPlayer. Cependant, en utilisant-seekToTime:toleranfeBefore:toleranceAfter:
, vous devriez pouvoir effectuer une recherche rapide dans la vidéo à condition que vous disposiez de toutes les options nécessaires.
Si vous synchronisez plusieurs appareils (ce que votre application pourrait suggérer), laissez simplement un commentaire et je me ferai un plaisir de modifier ma réponse.
PS: BASS peut sembler décourageant au premier abord à cause de son format C-like, mais il est vraiment très facile à utiliser.