Ändern der Größe von Videos mit ffmpeg / avconv, um sie in einen Player mit statischer Größe zu integrieren

65

Ich habe einen HTML 5-Videoplayer, der 700px breit und 400px hoch ist. Ich versuche, avconvffmpeg zu verwenden , um die Größe zu ändern (unter Beibehaltung des Seitenverhältnisses) und sicherzustellen, dass es in meinen Player passt.

Bei der Eingabe kann es sich um eine Datei beliebiger Größe handeln. Daher muss ich die Größe der größeren Datei ändern, die kleineren Dateien jedoch mit schwarzen Balken zentrieren. Bisher habe ich Folgendes versucht: -sund -aspect, ich habe gesehen, paddass der -vfSwitch verwendet wird, verstehe aber nicht, wie er genug funktioniert, um das zu bekommen, was ich brauche.

Bilder

Dies ist eine ungefähre Vorstellung von dem, was ich brauche. Ich bin mir nicht sicher, ob es überhaupt möglich ist. Es ist fast so wie die maximale Breite / maximale Höhe von CSS. Mir ist klar, dass dies nur ein Durcheinander von Wörtern sein kann, aber wenn jemand versteht, wovon ich spreche, wäre ich dankbar für Hilfe, danke.

Befehl avconv:

avconv -y -i control.avi -vcodec libx264 -b 2000k -bufsize 20M -acodec aac -strict experimental -ar 44100 -ab 256k bigbuck_out.mp4

Jamie Taylor
quelle
4
Ich werde später eine Antwort schreiben, aber ich dachte, ich würde Folgendes erwähnen: Ein Video neu zu codieren, um eine feste Säule oder einen Briefkasten hinzuzufügen, ist eine schreckliche Idee. Dadurch wird nicht nur die Qualität beeinträchtigt (oder die Dateigröße unnötig erhöht), sondern es wird auch unmöglich, die Balken später wieder zu entfernen. Im Idealfall sollte sich Ihr Player einfach darum kümmern und die Größe des Videos ändern, während es angezeigt wird. Was ist Ihr Anwendungsfall, wenn ich fragen darf?
Slhck
Wir verstauen die Originaldatei in einem S3-Bucket, das ist also kein Problem, und wir codieren sie trotzdem neu, da wir eine große Anzahl von Videotypen akzeptieren. All diese müssen als H.264-MP4-Dateien enden, die für das Streaming geeignet sind ein Browser. Sie würden also vorschlagen, die Größe des Videos zu ändern und dann HTML / CSS-Säulen / Briefkästen zu erstellen? Vielen Dank
Jamie Taylor
1
Als Besitzer der akzeptierten Antwort würde ich vorschlagen, dass Sie meinen Beitrag ablehnen und stattdessen LordNeckbeards Antwort akzeptieren, da dies die aktuellste und viel einfachere ist.
Slhck
@slhck, ich habe darüber nachgedacht, mit deinem Segen werde ich es so machen.
Jamie Taylor

Antworten:

52

Eine einfache Methode ist die Verwendung der force_original_aspect_ratioOption im Skalenfilter .

Original Bild
Original Bild. Stellt ein Video mit einem Seitenverhältnis von 640 x 480 und 4: 3 dar.

In diesen Beispielen wird das Originalbild so skaliert, dass es in ein Seitenverhältnis von 16: 9 passt, wobei das ursprüngliche Seitenverhältnis beibehalten wird. Dazu können Sie entweder:

Pillarbox oder Briefkasten

pillarboxed Bild
Pillarboxed Bild. Anpassen eines 640 x 480 (4: 3) Eingangs an einen 1280 x 720 (16: 9) Ausgang.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output
  • Dadurch wird das Bild vergrößert. Wenn Sie eine Hochskalierung vermeiden möchten, sehen Sie sich das folgende Beispiel an.

  • Letterboxing würde stattdessen auftreten, wenn das Eingabe-Seitenverhältnis breiter als das Ausgabe-Seitenverhältnis ist. Beispielsweise führt eine Eingabe mit einem Seitenverhältnis von 2,35: 1, die in eine 16: 9-Ausgabe passt, zu Letterboxing.

Wie oben, jedoch ohne Hochskalierung

keine Hochskalierung
640 x 480 (4: 3) Eingaben in 1280 x 720 (16: 9) Ausgaben ohne Hochskalierung.

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

Ernte

Bildbeschreibung hier eingeben
Zugeschnittenes Bild. 4: 3 Eingangs-Seitenverhältnis, 16: 9 Ausgangs-Seitenverhältnis.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output
Logan
quelle
Und damit ich eine leere Füllung hinzufüge?
Tiago Ferezin
@TiagoFerezin Was ist eine "leere Füllung"?
Logan
oh sorry, Füllen Sie mit einer anderen Farbe anstelle von Schwarz als Beispiel
Tiago Ferezin
2
@TiagoFerezin Ah ja. Leicht zu schaffen. In den Beispielen, die den Pad-Filter verwenden, können Sie die colorOption hinzufügen , z. B. pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(oder Sie können das Hexadezimalzeichen verwenden, wenn Sie dies vorziehen). Siehe Liste der Farben .
Logan
61

Hier ist der Befehl, der Säulen- oder Letterboxing für eine feste Ausgabebreite hinzufügt. Es ist ein bisschen lang, aber Sie müssen die Polsterung irgendwie angeben.

Definieren Sie zunächst in Ihrer Shell die Ausgabebreite und -höhe:

width=700
height=400

Führen Sie dann den Befehl aus:

ffmpeg -i in.mp4 -filter:v "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2" out.mp4

Dies ist auf das Nötigste reduziert, um die Größe zu ändern und zu füllen - fügen Sie Ihre anderen Video- und Audiooptionen hinzu, wie Sie es für richtig halten. Beachten Sie, dass die Zahlen für widthund heightdurch 2 teilbar sein müssen, um für die meisten Codecs zu funktionieren.

Hier ist die Erklärung, was los ist:

  • Skalierung:
    • Zuerst müssen wir herausfinden, ob wir nach Breite oder Höhe skalieren sollen.
    • Dazu teilen wir die Ausgabebreite durch die Eingabebreite und die Ausgabehöhe durch die Eingabehöhe. Dies gibt uns die Skalierungsfaktoren für jede Dimension.
    • Wir überprüfen dann, welches niedriger ist (mit min()) und wählen nur diesen Faktor für die Größenänderung.
    • Schließlich multiplizieren wir sowohl die Breite als auch die Höhe der Eingabe mit diesem Faktor ( iw*min(…):ih*min(…)).
  • Polsterung:
    • $width:$height ist die Ausgabebreite und -höhe
    • Um herauszufinden, wo das resultierende Video platziert werden soll, müssen wir die skalierte Breite von der maximalen Ausgabebreite und die skalierte Höhe von der maximalen Ausgabehöhe abziehen.
    • Die skalierten Breiten und Höhen sind die Ausdrücke aus dem scaleFilter.
    • Wir teilen den resultierenden Versatz durch 2, um Ränder auf beiden Seiten hinzuzufügen.
slhck
quelle
3
@JamieTaylor Erwägen Sie -movflags +faststart, das Beispiel von slhck zu ergänzen. Das progressiv heruntergeladene Video kann abgespielt werden, bevor es vollständig heruntergeladen ist. Weitere Codierungsanweisungen und Beispiele finden Sie im FFmpeg- und x264-Codierungshandbuch sowie im FFmpeg- und AAC-Codierungshandbuch .
Logan
Sie könnten den Pad-Filter so kürzen, denke ich:pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
jdi
1
@jdi Dies funktioniert nicht, wenn Sie verkleinern, da dies zu negativen Werten für führt ow-iw.
Slhck
Danke für den Startpunkt! Um jedoch ein korrektes Seitenverhältnis für Videos mit einem Beispielseitenverhältnis zu erhalten! = 1, muss jedes Vorkommen von "iw" mit "sar" multipliziert werden, sodass JEDES Vorkommen von "iw" durch "(sar * iw)" ersetzt wird. im filter funktioniert der ausdruck bei mir.
schieferstapel
@slhck Hey, ich versuche es in Android, aber es scheint nicht zu funktionieren, kannst du mir dabei helfen !!! ffmpeg -i input.mp4 -Filter: v scale = 640 * min (700 / 640,400 / 360): 360 * min (700 / 640,400 / 360), pad = 700: 400: (700-640 * min (700 / 640,400) / 360)) / 2: (400-360 * min (700 / 640,400 / 360)) / 2 Ausgabe.mp4
Nisarg
8

Es scheint mir, dass Sie dies in drei Schritten tun müssen:

  1. Überprüfen Sie das Eingabe-Seitenverhältnis
  2. Skalieren Sie Videos mit einem DAR> 7/4 in der Breite (ändern Sie die Breite auf 700 und skalieren Sie die Höhe, um das Seitenverhältnis beizubehalten) und skalieren Sie die Videos mit einem DAR <7/4 in der Höhe
  3. Platzieren Sie das Video so, dass es in den 700: 400-Bereich passt.

FFmpeg / avconv kann die Skalierung / Auffüllung mit Videofiltern in einem einzigen Schritt durchführen und nur einmal transkodieren. Wenn Sie beispielsweise ein 16: 9-Video aufnehmen möchten, skalieren Sie es in der Breite und schreiben Sie die Ergebnisse in eine Letterbox:

ffmpeg -i input.avi -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
-c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k output.mp4

... aber für den ersten Schritt (Ermitteln des Seitenverhältnisses und Vergleichen mit dem gewünschten 7: 4-Format) müssen Sie ein Skript verwenden.

ffprobe input.avi 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0-9]*\)].*/\1/p'

... zeigt das Seitenverhältnis des Videos an, das wie folgt aussieht: "16: 9" oder "4: 3". In einem Bash-Skript würde ich Folgendes verwenden:

#!/bin/bash

##  Get the aspect ratio in the form x/y
dar=$(ffprobe test0.mp4 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0:9]*\)].*/\1/p' | sed 's|:|/|')
##  use bc to do x/y*100 (bash can't handle floats)
DAR=$(bc <<< 'scale=2; $dar*100')

##  ${DAR%.00} will remove the trailing .00 left by bc
if [ ${DAR%.00} -ge 175 ]; then
    ffmpeg -i "$1" -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
else
    ffmpeg -i "$1" -filter:v 'scale=-1:400,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
fi

exit 0

Natürlich müssen Sie es an Ihre Bedürfnisse anpassen.

Übelsuppe
quelle
1
Es ist jedoch möglich, dies in einem einzigen Schritt zu tun, siehe meine Antwort.
Slhck
@slhck Jetzt ist es einfacher. Siehe Antwort mit Gitarrenbarbe.
Logan
@LordNeckbeard Danke! Ich habe diese Option kürzlich gesehen, was sie in der Tat viel einfacher macht.
Slhck