Comment puis-je adapter une vidéo à une certaine taille, mais ne pas la mettre à l'échelle avec FFmpeg?

13

Je dois adapter des vidéos à 640x360 (le maximum que le lecteur de mon téléphone peut gérer), tout en préservant également le rapport d'aspect , mais je veux également que la vidéo reste inchangée si elle est inférieure à 640x360 (inutile de la mettre à l'échelle après tout).

Existe-t-il un moyen d'obtenir ce comportement en utilisant la ligne de commande de ffmpeg?

sashoalm
la source
Je ne pense pas que cela puisse être fait uniquement dans ffmpeg, mais si vous êtes prêt à l'écrire, cela peut certainement être fait.
evilsoup
Je l'ai déjà écrit, mais je voulais nettoyer mon code au cas où il ne serait pas nécessaire.
sashoalm
C'est probablement possible avec un filtre d'échelle qui utilise des fonctions telles que min(…)mais certainement plus facile avec un script simple qui analyse les dimensions. Voir ma commande ici pour un exemple de ce qui peut être fait: superuser.com/questions/547296/…
slhck

Réponses:

9

Avec les nouvelles versions de ffmpeg, vous pouvez utiliser l' option scaledu filtre force_original_aspect_ratio. Par exemple, pour adapter une vidéo en 1280 × 720, sans mise à l'échelle (voir cet article pour plus d'informations):

ffmpeg -i input.mp4 -filter:v "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

Ici, le scalefiltre est mis à l'échelle à 1280 × 720 si la vidéo d'entrée est plus grande que cela. S'il est plus petit, il ne sera pas mis à l'échelle. Le padfiltre est nécessaire pour amener la vidéo de sortie à 1280 × 720, au cas où son rapport d'aspect ou sa taille diffère de la taille cible.


Avec les anciennes versions de ffmpeg, il existe une solution de contournement quelque peu hacky. Tout d'abord, définissez la largeur, la hauteur et le rapport hauteur / largeur de votre sortie. Cela nous évitera de taper.

width=640; height=360
aspect=$( bc <<< "scale=3; $width / $height") # <= floating point division

Maintenant, appliquons la commande de filtre super complexe que Jim Worrall a écrit :

ffmpeg -i input.mp4 -vf "scale = min(1\,gt(iw\,$width)+gt(ih\,$height)) * (gte(a\,$aspect)*$width + \
lt(a\,$aspect)*(($height*iw)/ih)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*iw : \
min(1\,gt(iw\,$width)+gt(ih\,$height)) * (lte(a\,$aspect)*$height + \
gt(a\,$aspect)*(($width*ih)/iw)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*ih" \
output.mp4

Je ne vais pas vraiment expliquer ce que tout cela fait, mais fondamentalement, vous pouvez le nourrir n'importe quelle vidéo, et cela ne fera que réduire l'échelle, pas la montée en gamme. Si vous en avez envie, vous pouvez disséquer le filtre dans ses expressions individuelles. Il pourrait être possible de raccourcir cela, mais cela fonctionne aussi comme ça.

slhck
la source
1
+1 mais c'est une commande vraiment horrible: P
evilsoup
N'est-ce pas? J'ai passé dix minutes à essayer de le diviser en parties logiques, puis à insérer des valeurs, mais j'ai abandonné. C'est un peu vieux et il serait peut-être possible de l'écrire de manière beaucoup plus concise que cela.
slhck
13

Une version plus lisible peut ressembler à ceci:

-filter_complex "scale=iw*min(1\,min(640/iw\,360/ih)):-1"

640 / iw est le facteur d'échelle horizontal et 360 / ih est le facteur d'échelle vertical

Vous souhaitez adapter l'image mise à l'échelle dans la zone de sortie et conserver le rapport d'aspect (stockage). Pour ce faire, sélectionnez le plus petit facteur d'échelle avec la fonction minimale: min (640 / iw, 360 / ih)

Vous voulez empêcher toute mise à l'échelle (c'est-à-dire un facteur de mise à l'échelle> 1.0), vous ajoutez donc une autre fonction minimale: min (1, min (640 / iw, 360 / ih))

L'étape suivante consiste à calculer la résolution de sortie en multipliant le facteur d'échelle par la largeur d'entrée et la hauteur d'entrée:
largeur de sortie = iw * min (1, min (640 / iw, 360 / ih))
hauteur de sortie = ih * min (1, min (640 / iw, 360 / ih))

La dernière étape consiste à construire la commande de filtre. Il n'est pas nécessaire de spécifier la hauteur de sortie, vous pouvez spécifier -1 et ffmpeg conservera le rapport hauteur / largeur en appliquant le même facteur de mise à l'échelle que pour la largeur.

immerzl
la source
A + Fonctionne hors de la boîte. La solution de la réponse sélectionnée n'a pas conservé le rapport d'aspect. Il a serré les cadres.
287352
5

J'ai eu le même problème aussi, mais résolu en ajustant la vidéo dans un carré 640x640 (à cause des vidéos verticales faites avec les smartphones).

Donc, en utilisant la logique immerzi et quelques recherches, je me retrouve avec ceci:

-vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2"

la dernière partie est destinée à avoir une hauteur divisible par 2 dont ont besoin de nombreux encodeurs.

Shebuka
la source