Convertir une vidéo en une taille d'écran fixe en recadrant et en redimensionnant

22

J'ai essayé de comprendre cela moi-même, mais la myriade d'options me déconcerte.

Je veux utiliser idéalement soit ffmpegou mencoder(ou autre chose, mais ces deux que je sais que je travaille) pour convertir toute vidéo entrante en une taille d'écran fixe.

Si la vidéo est plus large ou trop courte, recadrez la vidéo au centre. Si ce n'est pas la bonne taille, redimensionnez-la vers le haut ou vers le bas pour en faire exactement la taille d'écran fixe.

La dernière chose dont j'ai besoin est de 720x480 dans un XVid AVI avec une piste audio MP3.

J'ai trouvé beaucoup de pages montrant comment redimensionner à une résolution maximale, mais j'ai besoin que la vidéo soit exactement cette résolution (avec des parties supplémentaires coupées, pas de barres noires).

Quelqu'un peut-il me dire la ligne de commande à exécuter - ou au moins me faire une partie de la plupart du chemin? S'il doit s'agir de plusieurs lignes de commande (exécutez X pour obtenir la résolution, faites ce calcul, puis exécutez Y avec la sortie de ce calcul), je peux l'écrire.

Andy Jeffries
la source
Apparemment, le périphérique vidéo fonctionne avec Mpeg4 ainsi qu'avec XVid AVI, si c'est plus facile / meilleur.
Andy Jeffries

Réponses:

19

Je ne suis pas un gourou ffmpeg, mais cela devrait faire l'affaire.

Tout d'abord, vous pouvez obtenir la taille de la vidéo d'entrée comme ceci:

ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width in.mp4

Avec un ffmpeg raisonnablement récent, vous pouvez redimensionner votre vidéo avec ces options:

ffmpeg -i in.mp4 -vf scale=720:480 out.mp4

Vous pouvez définir la largeur ou la hauteur -1afin de laisser ffmpegredimensionner la vidéo en conservant le rapport hauteur / largeur. En fait, -2c'est un meilleur choix car la valeur calculée devrait être égale. Vous pouvez donc taper:

ffmpeg -i in.mp4 -vf scale=720:-2 out.mp4

Une fois que vous obtenez la vidéo, elle peut être plus grande que prévu 720x480car vous laissez ffmpegcalculer la hauteur, vous devrez donc la recadrer. Cela peut être fait comme ceci:

ffmpeg -i in.mp4 -filter:v "crop=in_w:480" out.mp4

Enfin, vous pouvez écrire un script comme celui-ci (peut facilement être optimisé, mais je l'ai gardé simple pour la lisibilité):

#!/bin/bash

FILE="/tmp/test.mp4"
TMP="/tmp/tmp.mp4"
OUT="/tmp/out.mp4"

OUT_WIDTH=720
OUT_HEIGHT=480

# Get the size of input video:
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${FILE})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Get the difference between actual and desired size
W_DIFF=$[ ${OUT_WIDTH} - ${IN_WIDTH} ]
H_DIFF=$[ ${OUT_HEIGHT} - ${IN_HEIGHT} ]

# Let's take the shorter side, so the video will be at least as big
# as the desired size:
CROP_SIDE="n"
if [ ${W_DIFF} -lt ${H_DIFF} ] ; then
  SCALE="-2:${OUT_HEIGHT}"
  CROP_SIDE="w"
else
  SCALE="${OUT_WIDTH}:-2"
  CROP_SIDE="h"
fi

# Then perform a first resizing
ffmpeg -i ${FILE} -vf scale=${SCALE} ${TMP}

# Now get the temporary video size
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${TMP})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Calculate how much we should crop
if [ "z${CROP_SIDE}" = "zh" ] ; then
  DIFF=$[ ${IN_HEIGHT} - ${OUT_HEIGHT} ]
  CROP="in_w:in_h-${DIFF}"
elif [ "z${CROP_SIDE}" = "zw" ] ; then
  DIFF=$[ ${IN_WIDTH} - ${OUT_WIDTH} ]
  CROP="in_w-${DIFF}:in_h"
fi

# Then crop...
ffmpeg -i ${TMP} -filter:v "crop=${CROP}" ${OUT}
apaul
la source
J'ai eu cette drôle de sensation qu'il manquerait un scénario, mais je l'ai essayé avec beaucoup de fichiers vidéo et il semble recadrer et redimensionner correctement les vidéos à la taille correcte absolue - bravo!
Andy Jeffries
il semble qu'il y ait un problème avec la décision CROP_SIDE.
Sutra
`# Obtenez le taux entre la taille réelle et la taille souhaitée w_rate = echo "scale=3; ${in_width}/${out_width}*1000"| bc | awk '{printf "%d", $0}' h_rate = echo "scale=3; ${in_height}/${out_height}*1000"| bc | awk '{printf "%d", $0}' # Prenons le côté le plus court, pour que la vidéo soit au moins aussi grande # que la taille souhaitée, et recadrez le côté le plus long: crop_side = 'n' if [$ {w_rate} -gt $ {h_rate}]; alors scale = "- 2: $ {out_height}" crop_side = 'w' else scale = "$ {out_width}: - 2" crop_side = 'h' fi '
Sutra
23
ffmpeg -i input.file -vf "scale=(iw*sar)*max(720/(iw*sar)\,480/ih):ih*max(720/(iw*sar)\,480/ih), crop=720:480" -c:v mpeg4 -vtag XVID -q:v 4 -c:a libmp3lame -q:a 4 output.avi

Remplacez "input.file" par le nom de votre fichier d'entrée.

Brian
la source
Cela devrait être la première réponse car elle ne nécessite pas d'appel à ffprobe. Notez les séquences de virgules antislash dans la commande. Vous devrez échapper aux barres obliques inverses si vous placez la commande dans une chaîne C / JavaScript / PHP.
cleong
Bien, Brian. La portion de filtre vidéo est exactement ce dont j'avais besoin aussi. (c'est-à-dire pour convertir d'anciennes vidéos 4: 3 en 16: 9)!
Dave
1
génie! tout est fait en un.
Soli
2
Beaucoup plus propre que le script ci-dessus. Notez que si vous ne voulez pas XVID / MP3, vous pouvez simplement changer les balises après la deuxième citation en quelque chose comme-c:a copy scaled_result.mp4
Nick
7

Si vous souhaitez recadrer et redimensionner en une seule fois, vous pouvez créer une chaîne de filtres recadrer puis redimensionner comme suit:

ffmpeg -i SomeInput.mp4 -vf "crop=in_h*9/16:in_h,scale=-2:400" -t 4 SomeOutput.mp4

Ce qui précède recadre d'abord une vidéo au format 16: 9, puis redimensionne à 400 pixels de haut x la largeur appropriée (nombre pair).

Chris
la source
1

Je suis nouveau sur ffmpeg mais j'ai maintenant un joli petit convertisseur en VB.NET qui crée des films bruts de différents formats de sortie pour une utilisation dans de petits appareils qui ont accès à la carte SD mais pas assez de puissance pour décoder des vidéos complexes.

En raison de la façon dont cela fonctionne lors du redimensionnement et du recadrage, j'ai dû le coder manuellement et créer les paramètres. Fondamentalement, j'ai besoin de connaître la largeur et la hauteur résultantes.

J'ai 2 cases à cocher pour les options: -

Conserver le rapport hauteur / largeur (X) Remplir tous les pixels (X)

Seules 4 variables sont nécessaires en entrée (1) Largeur de la vidéo d'origine, (2) Hauteur de la vidéo d'origine, (3) Largeur de l'appareil, (4) Hauteur de l'appareil.

Bien que VB.NET puisse être adapté assez facilement pour n'importe quelle langue.

    Dim crop As String = "" ' will build this in ffmpeg format for -s or scale and crop

    If cbAspectRatio.Checked = False Then
        m_dest_output_w = sz._w
        m_dest_output_h = sz._h

        ' scale to w * h - simple
        crop = " -s " & m_dest_output_w & ":" & m_dest_output_h
    Else
        Dim ratio As Double = CDbl(m_video_width) / CDbl(m_video_height) ' this is aspect ratio of original unsized video

        If cbFillPixels.Checked = False Then ' shrink to fit
            If sz._w * ratio <= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w / ratio
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h / ratio
            End If

            ' no cropping just resizing to a non-filled area that fits

            crop = " -s " & m_dest_output_w & ":" & m_dest_output_h ' no cropping needed as letterboxed

        Else ' expand / fill --- cropping needed
            If sz._w * ratio >= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":0:" & Math.Abs((m_dest_output_h - sz._h)) \ 2
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":" & Math.Abs((m_dest_output_w - sz._w)) \ 2 & ":0"
            End If

            crop = " -vf scale=" & m_dest_output_w & ":" & m_dest_output_h & crop

            m_dest_output_w = sz._w
            m_dest_output_h = sz._h
        End If
    End If
TheWhitde
la source