web-dev-qa-db-fra.com

FFMPEG (libx264) "hauteur non divisible par 2"

J'essaie de coder une vidéo au format .mp4 à partir d'un ensemble de trames à l'aide de FFMPEG à l'aide du codec libx264.

C'est la commande que je lance:

/usr/local/bin/ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4

Je reçois parfois l'erreur suivante:

[libx264 @ 0xa3b85a0] height not divisible by 2 (520x369)

Après quelques recherches, il semble que le problème a quelque chose à voir avec l'algorithme de dimensionnement et qu'il puisse être résolu en ajoutant un argument -vf.

Cependant, dans mon cas, je ne veux pas faire de mise à l'échelle. Idéalement, je veux que les dimensions soient identiques à celles des cadres. Aucun conseil? Existe-t-il une sorte de format d'image que h264 applique?

151
Andy Hin

La réponse à la question originale qui ne ne veut pas vouloir redimensionner la vidéo est:

-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Commander:

ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Fondamentalement, .h264 a besoin de dimensions égales pour que ce filtre puisse:

  1. Diviser la hauteur et la largeur d'origine par 2
  2. Arrondis au pixel le plus proche
  3. Multipliez-le par 2 encore, ce qui en fait un nombre pair
  4. Ajouter des pixels de remplissage noirs jusqu'à ce nombre

Vous pouvez changer la couleur du remplissage en ajoutant le paramètre de filtre :color=white. Voir la documentation de pad .

226
Andy Hin

Il suffit d'utiliser -2

De la documentation du filtre de la balance :

Si l'une des valeurs est -n avec n > 1, le filtre d'échelle utilisera également une valeur qui conserve le rapport de format de l'image d'entrée, calculé à partir de l'autre dimension spécifiée. Ensuite, assurez-vous que la dimension calculée est divisible par n et ajustez la valeur si nécessaire.

Exemples

Définissez la largeur sur 1280 et la hauteur sera automatiquement calculée pour conserver le rapport hauteur/largeur, et la hauteur sera divisible par 2:

-vf scale=1280:-2

Comme ci-dessus, mais avec une hauteur déclarée. la largeur laissée à traiter par le filtre:

-vf scale=-2:720

"divisible par 2"

Comme requis par x264, le "divisible par 2 pour la largeur et la hauteur" est nécessaire pour les sorties sous-échantillonnées en chrominance YUV 4: 2: 0. 4: 2: 2 aurait besoin de "divisible par 2 pour la largeur", et 4: 4: 4 n'a pas ces restrictions. Cependant, la plupart des lecteurs non basés sur FFmpeg ne peuvent décoder correctement 4: 2: 0, c'est pourquoi vous voyez souvent les commandes ffmpeg avec l'option -pix_fmt yuv420p lors de la sortie vidéo H.264.

Caveat

Malheureusement, vous ne pouvez pas utiliser -2 pour la largeur et la hauteur , mais si vous avez déjà spécifié une dimension, utilisez -2 une solution simple.

207
llogan

Si vous souhaitez définir une largeur de sortie et obtenir une sortie avec le même rapport que l'original

scale=720:-1 

et ne pas tomber avec ce problème, alors vous pouvez utiliser

scale="720:trunc(ow/a/2)*2"

(Juste pour les personnes cherchant comment faire cela avec la mise à l'échelle)

62
Zbyszek

Cela est probablement dû au fait que la vidéo H264 est généralement convertie de l'espace RVB en espace YUV au format 4: 2: 0 avant l'application de la compression (bien que la conversion de format elle-même soit un algorithme de compression avec perte entraînant une économie d'espace de 50%).

YUV-420 commence par une image RVB (rouge vert bleu) et la convertit en YUV (un canal d'intensité et deux canaux de "teinte"). Les canaux de teinte sont ensuite sous-échantillonnés en créant un échantillon de teinte pour chaque carré de 2X2 de cette teinte.

Si vous avez un nombre impair de pixels RVB horizontalement ou verticalement, vous aurez des données incomplètes pour la dernière colonne ou rangée de pixels dans l'espace de teinte sous-échantillonné de la trame YUV.

18
Adisak

Le problème avec les solutions scale est qu’elles déforment l’image/vidéo source, ce qui n’est presque jamais ce que vous voulez.

Au lieu de cela, j'ai trouvé la meilleure solution consiste à ajouter un tampon de 1 pixel à la dimension impaire. (Par défaut, le rembourrage est noir et difficile à remarquer.)

Le problème avec les autres solutions pad est qu’elles ne se généralisent pas sur des dimensions arbitraires car elles remplissent toujours.

Cette solution ajoute uniquement un pavé de 1 pixel à la hauteur et/ou à la largeur s'ils sont impairs:

-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"

C'est idéal car il fait toujours ce qu'il faut, même si aucun rembourrage n'est nécessaire.

13
danneu

LordNeckbeard a la bonne réponse, très vite

-vf scale=1280:-2

Pour Android, n'oubliez pas d'ajouter

"-preset ultrafast" and|or "-threads n"
2
fallouter

Vous pouvez également utiliser la fonction bitand au lieu de trunc:

bitand (x, 65534)

fera la même chose que trunc(x/2)*2 et il est plus transparent à mon avis.
(Considérons 65534 un nombre magique ici;))


Ma tâche consistait à redimensionner automatiquement beaucoup de fichiers vidéo à demi-résolution.

scale=-2,ih/2 conduit à légèrement images floues

raison:

  • les vidéos d'entrée avaient leur format d'affichage (DAR)
  • scale met à l'échelle les dimensions réelles du cadre
  • lors de la prévisualisation, les tailles des nouvelles vidéos doivent être corrigées avec DAR qui, dans le cas d'une vidéo de faible résolution (360x288, DAR 16: 9) peut entraîner un flou

solution:

-vf "scale='bitand(oh*dar, 65534)':'bitand(ih/2, 65534)', setsar=1"

explication:

  • output_height = input_height/2
  • output_width = output_height * original_display_aspect_ratio
  • output_width et output_height sont maintenant arrondis au nombre le plus proche divisible par 2
  • setsar=1 signifie que les dimensions de la sortie sont finales, aucune correction de rapport de format ne doit être appliquée

Quelqu'un pourrait trouver cela utile.

1
endigo