AVPlayer seekToTime ne joue pas à la bonne position
j'ai un AVPlayer qui joue un flux vidéo HLS. Mon interface utilisateur fournit une rangée de boutons, un pour chaque "chapitre" dans la vidéo (les boutons sont marqués "1", "2", "3"). L'application télécharge des méta-données d'un serveur qui contient la liste des points de coupure de chapitre indiqués en secondes. Par exemple, une vidéo a une durée de 12 minutes. 0, 58, 71, 230, 530, etc., etc.
quand l'utilisateur tape un des "boutons de chapitre" le gestionnaire de bouton code fait ceci:
[self.avPlayer pause];
[self.avPlayer seekToTime: CMTimeMakeWithSeconds(seekTime, 600)
toleranceBefore: kCMTimeZero
toleranceAfter: kCMTimeZero
completionHandler: ^(BOOL finished)
{
[self.avPlayer play];
}];
où "seekTime" est un var local qui contient le point de coupure (tel que décrit ci-dessus).
le problème est que la vidéo ne démarre pas toujours au bon endroit. Parfois, il n'. Mais parfois, il se situe entre un dixième de seconde et 2 secondes avant le seekTime demandé. Il ne commence jamais après le seekTime demandé.
Voici quelques statistiques sur l'encodage de la vidéo:
Codeur: handbrakeCLI Codec: h.264 Fréquence d'images: 24 (en fait, 23.976 - même que la façon dont il a été tourné) Bitrate vidéo: bitrate multiple (64/150/300/500/800/1200) Débit Audio: 128k Images clés: 23.976 (1 par seconde)
j'utilise L'outil Apple mediafilesegmenter, bien sûr, et le variantplaylistcreator pour générer la playlist.
les fichiers sont servis à partir d'un seau Amazon Cloud/S3.
une zone sur laquelle je ne suis pas clair est Cmtimemakewithsecondes-j'ai j'ai essayé plusieurs variantes basées sur différents articles/docs que j'ai lus. Par exemple, dans l'extrait ci-dessus, j'utilise:
Cmtimemakewithsecondes (seekTime, 600)
j'ai aussi essayé:
Cmtimemakewithsecondes (seekTime, 1)
Je ne peux pas dire ce qui est correct, bien que les deux semblent produire les mêmes résultats incohérents!
j'ai aussi essayé:
Cmtimemakewithsecondes (seekTime, 23.967)
quelques articles revendication cela fonctionne comme un numérateur / dénominateur, donc n / 1 doit être correct où " n " est le nombre de secondes (comme dans Cmtimemakewithsecondes(n, 1)). Mais, le code a été créé à l'origine par un programmeur différent (qui est parti maintenant) et il a utilisé le numéro 600 pour le preferredtimale (ie. Cmtimemakewithsecondes (n, 600)).
est-ce que quelqu'un peut donner des indices sur ce que je fais mal, ou même si le genre de précision que j'essaie d'atteindre est même possible?
et dans le cas où quelqu'un est tenté d'offrir des solutions "alternatives", nous envisageons déjà de scinder la vidéo en flux séparés, un par chapitre, mais nous ne pensons pas que cela nous donnera la même performance dans le sens où changer de chapitre prendra plus de temps qu'un AVPlayerItem nouveau devra être créé et chargé, etc, etc., etc. Donc, si vous pensez que c'est la seule solution qui fonctionne (et nous ne nous attendons cela permettra d'atteindre le résultat que nous voulons - ie. chaque chapitre va commencer exactement où nous voulons qu'il) se sentent gratuit de le dire.
Merci d'avance!
4 réponses
int32_t timeScale = self.player.currentItem.asset.duration.timescale;
CMTime time = CMTimeMakeWithSeconds(77.000000, timeScale);
[self.player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
j'ai eu un problème avec "seekToTime". J'ai résolu mon problème avec ce code. 'calendrier' est l'astuce pour ce problème.
ma suggestion: 1) N'utilisez pas [avplayer seekToTime: toleranceBefore: toleranceAfter:], cela retardera votre temps de recherche de 4-5 secondes.
2) HLS vidéo coupée à 10 secondes par segment. Votre position de départ de chapitre doit correspondre à la valeur qui est des multiples de 10. Comme le segment commence avec I frame, de cette façon, vous pouvez obtenir le temps de recherche rapide et le temps précis.
s'il vous plaît utiliser la fonction comme [player seekToTime:CMTimeMakeWithSeconds(seekTime,1)]
.
Parce que votre valeur de tolérance kCMTimeZero
va prendre plus de temps à chercher.Au lieu d'utiliser la valeur de tolérance de kCMTimeZero, vous pouvez utiliser kCMTimeIndefinite qui est l'équivalent de la fonction que j'ai indiqué plus haut.
mettez ce code il pourrait être résoudre votre problème.
let targetTime = CMTimeMakeWithSeconds(videoLastDuration, 1) // videoLastDuration hold the previous video state.
self.playerController.player?.currentItem?.seekToTime(targetTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)