Konvertieren Sie ein Video durch Zuschneiden und Ändern der Größe auf eine feste Bildschirmgröße

21

Ich habe versucht, das selbst herauszufinden, aber die Vielzahl der Möglichkeiten verwirrt mich einfach.

Ich möchte idealerweise entweder ffmpegoder mencoder(oder etwas anderes, aber die beiden, von denen ich weiß, dass sie funktionieren) verwenden, um eingehende Videos in eine feste Bildschirmgröße zu konvertieren.

Wenn das Video breiter oder zu kurz ist, können Sie es in der Mitte zuschneiden. Wenn es dann nicht die richtige Größe ist, ändern Sie die Größe nach oben oder unten, um genau die festgelegte Bildschirmgröße zu erhalten.

Das Letzte, was ich brauche, ist 720x480 in einem XVid-AVI mit einem MP3-Audiotrack.

Ich habe viele Seiten gefunden, auf denen gezeigt wird, wie die Größe auf eine maximale Auflösung geändert werden kann, aber ich benötige ein Video mit genau dieser Auflösung (mit abgeschnittenen zusätzlichen Teilen, ohne schwarze Balken).

Kann mir jemand sagen, dass die Kommandozeile ausgeführt werden soll - oder bringt mich zumindest ein Stück weit dorthin? Wenn es mehrere Befehlszeilen sein müssen (führen Sie X aus, um die Auflösung zu erhalten, führen Sie diese Berechnung aus und führen Sie dann Y mit der Ausgabe dieser Berechnung aus), kann ich das skripten.

Andy Jeffries
quelle
Anscheinend funktioniert das Videogerät sowohl mit Mpeg4 als auch mit XVid AVI, wenn das einfacher / besser ist.
Andy Jeffries

Antworten:

18

Ich bin kein ffmpeg-Guru, aber das sollte den Trick machen.

Zunächst können Sie die Größe des Eingangsvideos wie folgt ermitteln:

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

Mit einem einigermaßen aktuellen ffmpeg können Sie die Größe Ihres Videos mit den folgenden Optionen ändern:

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

Sie können die Breite oder Höhe auf einstellen -1, um die ffmpegGröße des Videos unter Beibehaltung des Seitenverhältnisses zu ändern. Eigentlich -2ist das eine bessere Wahl, da der berechnete Wert gerade sein sollte. Sie könnten also Folgendes eingeben:

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

Sobald Sie das Video erhalten haben, ist es möglicherweise größer als erwartet, 720x480da Sie ffmpegdie Höhe berechnen lassen , sodass Sie es zuschneiden müssen. Das kann so gemacht werden:

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

Schließlich könnten Sie ein Skript wie dieses schreiben (kann leicht optimiert werden, aber ich habe es aus Gründen der Lesbarkeit einfach gehalten):

#!/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
quelle
Ich hatte das komische Gefühl, dass es ein Szenario verpassen würde, aber ich habe es mit vielen Videodateien ausprobiert und es scheint, als würde es die Videos richtig zuschneiden und auf die absolut richtige Größe skalieren - gut gemacht!
Andy Jeffries
Es sieht so aus, als ob ein Fehler bei der CROP_SIDE-Entscheidung vorliegt.
Sutra
`# Ermitteln Sie die Rate zwischen tatsächlicher und gewünschter Größ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}' # Nehmen wir die kürzere Seite, sodass das Video mindestens # so groß ist wie die gewünschte Größe, und schneiden Sie die längere Seite zu: crop_side = 'n' if [$ {w_rate} -gt $ {h_rate}]; dann scale = "- 2: $ {out_height}" crop_side = 'w' sonst 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

Ersetzen Sie "input.file" durch den Namen Ihrer Eingabedatei.

Brian
quelle
Dies sollte die beste Antwort sein, da ffprobe nicht aufgerufen werden muss. Beachten Sie die Backslash-Kommas im Befehl. Sie müssen die umgekehrten Schrägstriche umgehen, wenn Sie den Befehl in eine C / JavaScript / PHP-Zeichenfolge einfügen.
Cleong
Schön, Brian. Der Video-Filter-Teil ist genau das, was ich brauchte. (zB um alte 4: 3 Videos in 16: 9 umzuwandeln)!
Dave
1
Genius! alles in einem erledigt.
Soli
2
Viel sauberer als das obige Drehbuch. Hinweis: Wenn Sie kein XVID / MP3 möchten, können Sie die Tags nach dem zweiten Anführungszeichen in so etwas wie-c:a copy scaled_result.mp4
Nick
7

Wenn Sie in einem Durchgang zuschneiden und skalieren möchten, können Sie eine Filterkette mit anschließender Skalierung wie folgt erstellen:

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

Mit dem obigen Befehl wird ein Video zuerst auf ein 16: 9-Porträt zugeschnitten und dann auf 400px hoch x die entsprechende Breite (gerade Zahl) skaliert.

Chris
quelle
1

Ich bin neu in ffmpeg, habe aber jetzt einen netten kleinen Konverter in VB.NET, der RAW-Filme in verschiedenen Ausgabeformaten für die Verwendung in kleinen Geräten erstellt, die über SD-Kartenzugriff verfügen, aber nicht genug Leistung zum Dekodieren komplexer Videos bieten.

Aufgrund der Art und Weise, wie es beim Ändern der Größe und beim Zuschneiden funktioniert, musste ich es manuell codieren und die Parameter erstellen. Grundsätzlich muss ich die resultierende Breite und Höhe kennen.

Ich habe 2 Kontrollkästchen für die Optionen: -

Seitenverhältnis beibehalten (X) Alle Pixel ausfüllen (X)

Es werden nur 4 Variablen als Eingabe benötigt. (1) Originalvideobreite, (2) Originalvideohöhe, (3) Gerätebreite, (4) Gerätehöhe.

Obwohl für VB.NET könnte für jede Sprache ganz einfach angepasst werden.

    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
quelle