Lors du conditionnement d'un flux pour la lecture DASH, les points d'accès aléatoires doivent être exactement à la même heure de flux source dans tous les flux. La façon habituelle de le faire est de forcer une fréquence d'images fixe et une longueur GOP fixe (c'est-à-dire une image clé toutes les N images).
Dans FFmpeg, la fréquence d'images fixe est facile (-r NUMBER).
Mais pour les emplacements d'images clés fixes (longueur du GOP), il existe trois méthodes ... laquelle est "correcte"? La documentation FFmpeg est frustrante et vague à ce sujet.
Méthode 1: jouer avec les arguments de libx264
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Il semble y avoir un débat quant à savoir si la mise en scène doit être désactivée ou non, car il n'est pas clair si le "compteur" d'images clés est redémarré lorsqu'une scène est coupée.
Méthode 2: définition d'une taille GOP fixe:
-g GOP_LEN_IN_FRAMES
Ceci n'est malheureusement documenté qu'en passant dans la documentation FFMPEG, et donc l'effet de cet argument n'est pas très clair.
Méthode 3: insérez une image clé toutes les N secondes ( peut-être? ):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Ceci est explicitement documenté. Mais il n'est pas encore clair immédiatement si le "compteur de temps" redémarre après chaque image clé. Par exemple, dans un GOP attendu de 5 secondes, s'il y a une scenecut
image clé injectée 3 secondes par libx264, l'image clé suivante serait-elle 5 secondes plus tard ou 2 secondes plus tard?
En fait, la documentation FFmpeg fait la différence entre cela et l' -g
option, mais elle ne dit pas vraiment comment ces deux options ci-dessus sont les moins différentes (évidemment, cela -g
va nécessiter une fréquence d'images fixe).
Quelle est la bonne?
Il semblerait que le -force_key_frames
serait supérieur , car il ne nécessiterait pas une fréquence d'images fixe. Cependant, cela nécessite que
- il est conforme aux spécifications GOP en H.264 (le cas échéant )
- il GARANTIT qu'il y aurait une image clé en cadence fixe, indépendamment des images
scenecut
clés libx264 .
Il semblerait également que -g
cela ne pourrait pas fonctionner sans forcer une fréquence d'images fixe ( -r
) , car il n'y a aucune garantie que plusieurs exécutions de ffmpeg
avec différents arguments de codec fourniraient la même fréquence d'images instantanée dans chaque résolution. Des fréquences d'images fixes peuvent réduire les performances de compression (IMPORTANT dans un scénario DASH!).
Enfin, la keyint
méthode semble être un hack . J'espère contre espoir que ce n'est pas la bonne réponse.
Les références:
Un exemple utilisant la -force_key_frames
méthode
la source
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, puis en coloriant les cellules. Je crains qu'il n'y ait pas de discussions publiques, mais je vais voir si je peux trouver certains des liens que j'ai trouvés à l'époque.-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
formulaire? Je viens de l'essayer et j'ai constaté que, même s'il y avait des images I supplémentaires dans le flux, cela semblait respecter ma règle. Un programme PERL suivra comme une "réponse", car vous ne pouvez apparemment pas utiliser de balisage dans les commentaires.-force_key_frames
n'a pas fonctionné pour moi, et je ne l'ai donc jamais réessayé. C'était il y a plus d'un an. C'était peut-être un bug. Je réessayerai bientôt.Voici mes cinquante cents pour l'affaire.
Générez des iframes uniquement aux intervalles souhaités.
Exemple 1:
Générez des iframes comme prévu comme ceci:
La méthode 2 est dépréciée. Ommit.
Exemple 2
Générez un iframes d'une manière légèrement différente:
Comme vous pouvez le voir, il place des iframes toutes les 2 secondes ET sur des scènes (secondes avec partie flottante), ce qui est important pour la complexité du flux vidéo à mon avis.
Les tailles de fichier générées sont à peu près les mêmes. Très étrange que même avec plus d'images clés dans la méthode 3, il génère parfois moins de fichiers que l'algorithme de bibliothèque x264 standard.
Pour générer plusieurs fichiers de débit binaire pour le flux HLS, nous choisissons la méthode trois. Il est parfaitement aligné avec 2 secondes entre les morceaux, ils ont un iframe au début de chaque morceau et ils ont des iframes supplémentaires sur des scènes complexes qui offrent une meilleure expérience pour les utilisateurs qui ont des appareils obsolètes et ne peuvent pas lire les profils élevés x264.
J'espère que cela aide quelqu'un.
la source
La réponse semble donc être:
libx264
spécifique et se fait au prix de l'élimination de l'scenecut
option très utile danslibx264
.-g
semble obsolète. Il ne semble ni fonctionner, ni défini explicitement dans la documentation, ni trouvé dans l'aide, ni être utilisé dans le code. L'inspection du code montre que l'-g
option est probablement destinée aux flux MPEG-2 (il existe même des strophes de code faisant référence à PAL et NTSC!).Également:
Script pour l'
-force_key_frames
optionVoici un court programme PERL que j'ai utilisé pour vérifier la cadence de l'image I en fonction de la sortie de la suggestion ffprobe de slhck. Il semble vérifier que la
-force_key_frames
méthode fonctionnera également et présente l'avantage supplémentaire de permettre lesscenecut
trames. Je n'ai absolument aucune idée de la façon dont FFMPEG fait fonctionner cela, ou si j'ai juste eu de la chance parce que mes streams sont bien conditionnés.Dans mon cas, j'ai encodé à 30 images par seconde avec une taille GOP attendue de 6 secondes, ou 180 images. J'ai utilisé 180 comme argument Gopsize de ce programme qui a vérifié une trame I à chaque multiple de 180, mais le définir sur 181 (ou tout autre nombre différent de 180) l'a fait se plaindre.
la source
force_key_frames
, cela gâche en quelque sorte l'algorithme d'allocation x264 bits, de sorte qu'il peut vous donner une qualité pire que de simplement définir un intervalle d'images clés fixe.-g
, vous dites: "Cela ne semble pas fonctionner, ... ni ne semble être utilisé dans le code.". J'ai vérifié et l'entréeg
est stockée dansavctx->gop_size
et qui fait de libx264 utilise de celui - ci:x4->params.i_keyint_max = avctx->gop_size;
. Lorsque je sonde ce fichier de test généréffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
:, j'obtiens des images clés exactement0,37,74,111,148,185,222,259,296,333,370
. Un GOP pourrait être écourté si un changement de scène est déclenché, et pour cela, il-sc_threshold
pourrait être défini, qui est également capté par x264.Je voulais ajouter des informations ici, car ma recherche sur Google a entraîné cette discussion un peu dans ma quête pour trouver des informations sur la façon de trouver un moyen de segmenter mon encodage DASH comme je le souhaitais, et aucune des informations que j'ai trouvées n'était totalement correcte.
Plusieurs idées fausses dont il faut se débarrasser:
Tous les cadres I ne sont pas identiques. Il y a de grands cadres en "I" et de petits cadres en "i". Ou pour utiliser la terminologie correcte, les cadres I IDR et les cadres I non IDR. Les images I IDR (parfois appelées "images clés") créeront un nouveau GOP. Les trames non IDR ne le seront pas. Ils sont pratiques pour avoir à l'intérieur d'un GOP où il y a un changement de scène.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← Cela ne fait pas ce que vous pensez. Cela m'a pris un peu de temps pour comprendre. Il s'avère que lemin-keyint
est limité dans le code. Il ne doit pas être supérieur à(keyint / 2) + 1
. Ainsi, l'attribution de la même valeur à ces deux variables entraîne unemin-keyint
réduction de moitié de la valeur lors de l'encodage.Voici le truc: la coupe de scène est vraiment géniale, surtout dans les vidéos qui ont des coupes rapides et dures. Il le garde agréable et net, donc je ne veux pas le désactiver, mais en même temps, je ne pouvais pas obtenir une taille GOP fixe tant qu'il était activé. Je voulais activer le découpage de scène, mais le faire uniquement utiliser des images I non IDR. Mais cela ne fonctionnait pas. Jusqu'à ce que je comprenne (à partir de nombreuses lectures) une idée fausse n ° 2.
Il s'avère que je devais régler
keyint
le double de la taille GOP souhaitée. Cela signifie que vousmin-keyint
pouvez définir la taille GOP souhaitée (sans que le code interne ne le coupe en deux), ce qui empêche la détection de coupure de scène d'utiliser des images I IDR à l'intérieur de la taille GOP car le nombre d'images depuis la dernière image I IDR est toujours moins quemin-keyinit
.Enfin, la définition de l'
force_key_frame
option remplace la double taillekeyint
. Voici donc ce qui fonctionne:Je préfère les segments en morceaux de 2 secondes, donc ma GOPSIZE = Framerate * 2
Vous pouvez vérifier en utilisant ffprobe:
Dans le fichier CSV généré, chaque ligne vous indiquera:
frame, [is_an_IDR_?], [frame_type], [frame_number]
:Le résultat est que vous ne devriez voir les images I IDR qu'à
GOPSIZE
intervalles fixes , tandis que toutes les autres images I sont des images I non IDR insérées selon les besoins par la détection de coupure de scène.la source
Il semble que cette syntaxe ne fonctionne pas toujours .. J'ai testé beaucoup sur notre contenu VOD ainsi que le contenu en direct (vidage de fichiers) et parfois Scenecut ne fonctionne pas et déclenche un iframe intermédiaire:
Syntaxe pour une conversion ascendante i50-> p50, gop / segment de 2 secondes, IDR au début, iframes intermédiaires si nécessaire
la source
Twitch a un post à ce sujet. Ils expliquent qu'ils ont décidé d'utiliser leur propre programme pour plusieurs raisons; L'un d'eux était que ffmpeg ne vous permet pas d'exécuter différentes instances x264 dans différents threads, mais consacre plutôt tous les threads spécifiés à une image dans une sortie avant de passer à la sortie suivante.
Si vous ne faites pas de streaming en temps réel, vous avez plus de luxe. La méthode «correcte» consiste probablement à coder à une résolution avec uniquement la taille GOP spécifiée avec -g, puis à coder les autres résolutions en forçant les images clés aux mêmes endroits.
Si vous le souhaitez, vous pouvez utiliser ffprobe pour obtenir les heures des images clés, puis utiliser un script shell ou un véritable langage de programmation pour le convertir en une commande ffmpeg.
Mais pour la plupart des contenus, il y a très peu de différence entre avoir une image clé toutes les 5 secondes et deux images clés toutes les 5 secondes (une forcée et une de scenecut). Il s'agit de la taille moyenne des images I par rapport à la taille des images P et des images B. Si vous utilisez x264 avec des paramètres typiques (la seule raison pour laquelle je pense que vous devriez faire quoi que ce soit pour les modifier est si vous définissez -qmin, comme un moyen médiocre d'empêcher x264 d'utiliser le débit binaire sur un contenu facile; cela limite tous les types de trames à la même valeur , Je pense) et obtenez un résultat comme une taille moyenne de trame I de 46 Ko, une trame P de 24 Ko, une trame B de 17 Ko (moitié moins fréquente que des trames P), puis une trame I supplémentaire chaque seconde à 30 ips est seulement une augmentation de 3% de la taille du fichier. La différence entre h264 et h263 pourrait être constituée d'un tas de diminutions de 3%, mais une seule n'est pas très importante.
Sur d'autres types de contenu, les tailles de trame seront différentes. Pour être honnête, il s'agit de complexité temporelle et non de complexité spatiale, donc ce n'est pas seulement un contenu facile vs un contenu dur. Mais en général, les sites de streaming vidéo ont une limite de débit binaire, et le contenu avec des images I relativement grandes est un contenu facile qui sera encodé à haute qualité quel que soit le nombre d'images clés supplémentaires ajoutées. C'est du gaspillage, mais ces déchets ne seront généralement pas remarqués. Le cas le plus inutile est probablement une vidéo qui n'est qu'une image statique accompagnant une chanson, où chaque image clé est exactement la même.
Une chose dont je ne suis pas sûr est de savoir comment les images clés forcées interagissent avec le limiteur de débit défini avec -maxrate et -bufsize. Je pense que même YouTube a récemment rencontré des problèmes de configuration correcte des paramètres de tampon pour donner une qualité constante. Si vous utilisez simplement des paramètres de débit binaire moyens comme certains sites peuvent le voir (puisque vous pouvez inspecter les options de x264 dans l'atome header / mov? Avec un éditeur hexadécimal), le modèle de tampon n'est pas un problème, mais si vous êtes diffusant du contenu généré par l'utilisateur, le débit binaire moyen encourage les utilisateurs à ajouter un écran noir à la fin de leur vidéo.
L'option -g de Ffmpeg, ou toute autre option d'encodeur que vous utilisez, est mappée à l'option spécifique à l'encodeur. Donc '-x264-params keyint = GOPSIZE' est équivalent à '-g GOPSIZE'.
Un problème avec l'utilisation de la détection de scène est que vous préférez des images clés à proximité de nombres spécifiques pour une raison quelconque. Si vous spécifiez des images clés toutes les 5 secondes et utilisez la détection de scène, et qu'il y a un changement de scène à 4,5, il doit être détecté, mais l'image clé suivante sera à 9,5. Si le temps continue à augmenter comme ça, vous pourriez vous retrouver avec des images clés à 42,5, 47,5, 52,5, etc., au lieu de 40, 45, 50, 55. Inversement, s'il y a un changement de scène à 5,5, alors il y aura une image clé à 5 et 5,5 sera trop tôt pour une autre. Ffmpeg ne vous permet pas de spécifier "créer une image clé ici s'il n'y a pas de changement de scène dans les 30 images suivantes". Cependant, quelqu'un qui comprend C pourrait ajouter cette option.
Pour la vidéo à fréquence d'images variable, lorsque vous ne diffusez pas en direct comme Twitch, vous devriez pouvoir utiliser les changements de scène sans convertir de manière permanente en fréquence d'images constante. Si vous utilisez le filtre 'select' dans ffmpeg et utilisez la constante 'scene' dans l'expression, la sortie de débogage (-v debug ou appuyez plusieurs fois sur '+' lors de l'encodage) affiche le numéro de changement de scène. Ceci est probablement différent et pas aussi utile que le nombre utilisé par x264, mais il pourrait quand même être utile.
La procédure serait alors probablement de faire une vidéo de test uniquement pour les changements d'images clés, mais pourrait peut-être être utilisée pour les données de contrôle de débit si vous utilisez 2 passes. (Je ne sais pas si les données générées sont utiles pour différentes résolutions et paramètres; les données de l'arborescence des macroblocs ne le seront pas.) Convertissez-les en vidéo à fréquence d'images constante, mais voyez ce bogue sur la sortie du bégaiement lors de la réduction de moitié du framerate si jamais vous décidez pour utiliser le filtre fps à d'autres fins. Exécutez-le via x264 avec les images clés et les paramètres GOP souhaités.
Utilisez ensuite ces temps d'images clés avec la vidéo à fréquence d'images variable d'origine.
Si vous autorisez un contenu généré par l'utilisateur complètement fou avec un intervalle de 20 secondes entre les images, alors pour l'encodage à fréquence d'images variable, vous pouvez diviser la sortie, utiliser le filtre fps, utiliser en quelque sorte le filtre de sélection (peut-être créer une expression très longue qui a chaque image clé) ... ou vous pouvez peut-être utiliser la vidéo de test comme entrée et décoder uniquement les images clés, si cette option ffmpeg fonctionne, ou utiliser le filtre de sélection pour sélectionner les images clés. Ensuite, redimensionnez-le à la bonne taille (il y a même un filtre scale2ref pour cela) et superposez la vidéo originale dessus. Utilisez ensuite le filtre d'entrelacement pour combiner ces images clés forcées destinées à être utilisées avec la vidéo d'origine. Si cela se traduit par deux images distantes de 0,001 seconde que le filtre d'entrelacement n'empêche pas, résolvez vous-même ce problème avec un autre filtre de sélection. Le traitement des limites de tampon de trame pour le filtre d'entrelacement pourrait être le problème principal ici. Ceux-ci pourraient tous fonctionner: utiliser une sorte de filtre pour tamponner le flux plus dense (filtre fifo?); se référer au fichier d'entrée plusieurs fois pour qu'il soit décodé plus d'une fois et les images n'ont pas besoin d'être stockées; utiliser le filtre 'streamselect', ce que je n'ai jamais fait, exactement au moment des images clés; améliorer le filtre d'entrelacement en modifiant son comportement par défaut ou en ajoutant une option pour sortir la plus ancienne trame dans un tampon au lieu de supprimer une trame. ce que je n'ai jamais fait, exactement au moment des images clés; améliorer le filtre d'entrelacement en modifiant son comportement par défaut ou en ajoutant une option pour sortir la plus ancienne trame dans un tampon au lieu de supprimer une trame. ce que je n'ai jamais fait, exactement au moment des images clés; améliorer le filtre d'entrelacement en modifiant son comportement par défaut ou en ajoutant une option pour sortir la plus ancienne trame dans un tampon au lieu de supprimer une trame.
la source