Zmiana rozmiaru filmów za pomocą ffmpeg / avconv w celu dopasowania do odtwarzacza o wielkości statycznej

65

Mam odtwarzacz wideo HTML 5 o szerokości 700 pikseli i wysokości 400 pikseli. Próbuję avconvużyć ffmpeg do zmiany rozmiaru (przy zachowaniu współczynnika proporcji) i upewnienia się, że pasuje do mojego odtwarzacza.

Dane wejściowe mogą być plikiem o dowolnym rozmiarze, więc muszę zmienić rozmiar większych, ale wycentrować mniejsze za pomocą czarnych pasków. Do tej pory próbowałem: -si -aspectwidziałem, że jestem padużywany z -vfprzełącznikiem, ale nie rozumiem, jak działa wystarczająco, aby uzyskać to, czego potrzebuję.

Zdjęcia

To jest przybliżony obraz tego, czego potrzebuję. Nie jestem pewien, czy to w ogóle możliwe. To prawie jak maksymalna szerokość / maksymalna wysokość CSS. Zdaję sobie sprawę, że to może być zbieranina słów, ale jeśli ktoś zrozumie, o czym mówię, byłbym wdzięczny za pomoc, dzięki.

polecenie 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
źródło
4
Później napiszę odpowiedź, ale pomyślałem, że wspomnę o następujących rzeczach: Ponowne kodowanie wideo tylko po to, aby dodać stałe wyświetlanie słupków lub liter, to straszny pomysł. Nie tylko stracisz jakość w tym procesie (lub niepotrzebnie zwiększysz rozmiar pliku), ale także uniemożliwi późniejsze usunięcie pasków. Idealnie, twój odtwarzacz powinien po prostu się tym zająć i zmienić rozmiar wideo podczas jego wyświetlania. Jaki jest twój przypadek użycia, jeśli mogę zapytać?
slhck
Przechowujemy oryginalny plik w segmencie S3, więc nie ma problemu, i tak i tak kodujemy ponownie, ponieważ akceptujemy duży zakres typów wideo, wszystkie muszą być skończone jako pliki h.264 mp4 odpowiednie do przesyłania strumieniowego przez przeglądarka. Sugerowałbyś więc zmianę rozmiaru filmu, a następnie utworzenie html / css pillar / letterboxes? Dzięki
Jamie Taylor,
1
Jako właściciel zaakceptowanej odpowiedzi sugeruję, abyś odrzucił mój post i zamiast tego zaakceptował odpowiedź Lorda Neckbearda, ponieważ jest to najnowsza i znacznie prostsza.
slhck
@slhck, rozważałem to, z twoim błogosławieństwem, zrobię to.
Jamie Taylor,

Odpowiedzi:

52

Prostą metodą jest użycie force_original_aspect_ratioopcji w filtrze skali .

oryginalny obraz
Oryginalny obraz. Reprezentuje wideo o proporcjach 640 x 480, 4: 3.

W tych przykładach oryginalny obraz zostanie przeskalowany, aby zmieścił się na wyjściu o współczynniku kształtu 16: 9, zachowując oryginalny współczynnik kształtu. Aby to zrobić, możesz:

Skrzynka na listy lub skrzynka na listy

obraz w ramce
Obraz w ramkach. Dopasowanie wejścia 640x480 (4: 3) do wyjścia 1280x720 (16: 9).

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output
  • Spowoduje to przeskalowanie obrazu. Jeśli chcesz uniknąć skalowania, zobacz poniższy przykład.

  • Zamiast tego pojawiłoby się Letterboxing, jeśli wejściowy współczynnik kształtu jest szerszy niż wyjściowy współczynnik kształtu. Na przykład dane wejściowe o współczynniku kształtu 2,35: 1 pasujące do wyjścia 16: 9 spowodują wstawianie liter.

To samo co powyżej, ale bez skalowania

brak skalowania
Wejście 640x480 (4: 3) do wyjścia 1280x720 (16: 9) bez skalowania.

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

Przyciąć

wprowadź opis zdjęcia tutaj
Przycięty obraz. Współczynnik proporcji 4: 3, współczynnik wyjściowy 16: 9.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output
Llogan
źródło
A dla mnie, aby dodać puste wypełnienie?
Tiago Ferezin
@TiagoFerezin Co to jest „puste wypełnienie”?
llogan
o przepraszam, Wypełnij inny kolor zamiast czarnego, na przykład
Tiago Ferezin
2
@TiagoFerezin Ah, tak. Proste do zrobienia. W przykładach korzystających z filtra pada można dodać coloropcję, np. pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(Lub można użyć wartości szesnastkowej, jeśli wolisz). Zobacz listę kolorów .
llogan
61

Oto polecenie, które dodałoby słupki lub litery do stałej szerokości wyjściowej. Jest trochę długi, ale musisz w jakiś sposób określić wypełnienie.

Najpierw w swojej powłoce określ szerokość i wysokość wyjściową:

width=700
height=400

Następnie uruchom polecenie:

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

Zostało to zredukowane do niezbędnych elementów potrzebnych do zmiany rozmiaru i wypełnienia - dodaj inne opcje wideo i audio według własnego uznania. Zauważ, że liczby dla widthi heightmuszą być podzielne przez 2, aby działać dla większości kodeków.

Oto wyjaśnienie tego, co się dzieje:

  • Skalowanie:
    • Najpierw musimy dowiedzieć się, czy skalować według szerokości czy wysokości.
    • Aby to zrobić, dzielimy szerokość wyjściową przez szerokość wejściową, a wysokość wyjściową przez wysokość wejściową. To da nam współczynniki skali dla każdego wymiaru.
    • Następnie sprawdzamy, który z nich jest niższy (z min()) i wybieramy tylko ten współczynnik do zmiany rozmiaru.
    • Na koniec mnożymy zarówno szerokość wejściową, jak i wysokość przez ten współczynnik ( iw*min(…):ih*min(…)).
  • Wyściółka:
    • $width:$height to szerokość i wysokość wyjściowa
    • Aby dowiedzieć się, gdzie umieścić powstałe wideo, musimy odjąć skalowaną szerokość od maksymalnej szerokości wyjściowej, a skalowaną wysokość od maksymalnej wysokości wyjściowej.
    • Skalowane szerokości i wysokości są wyrażeniami z scalefiltra.
    • Wynikowe przesunięcie dzielimy przez 2, aby dodać ramki po obu stronach.
slhck
źródło
3
@JamieTaylor Zastanów się nad dodaniem -movflags +faststartdo przykładu slhck. Umożliwi to odtwarzanie stopniowo pobieranego wideo przed jego całkowitym pobraniem, a także zapoznaj się z Przewodnikiem kodowania FFmpeg i x264 oraz Przewodnikiem kodowania FFmpeg i AAC, aby uzyskać więcej instrukcji i przykładów kodowania.
llogan
Myślę, że można skrócić do tego filtr pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
padowy
1
@jdi To nie zadziała, jeśli skalujesz w dół, ponieważ spowoduje to ujemne wartości dla ow-iw.
slhck
Dzięki za punkt wyjścia! Jednak, aby uzyskać odpowiedni współczynnik proporcji dla filmów o przykładowym współczynniku proporcji! = 1, każde wystąpienie „iw” należy pomnożyć przez „sar”, więc zastępując KAŻDE wystąpienie „iw” przez „(sar * iw)” w filtrze wyrażenie działa dla mnie.
schieferstapel
@slhck Hej, próbuję w Androidzie, ale wydaje się, że nie działa, czy możesz mi pomóc z tym !!! ffmpeg -i input.mp4 - filtr: v skala = 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 wyjście. Mp4
Nisarg
8

Wydaje mi się, że musisz to zrobić w trzech krokach:

  1. Sprawdź wejściowy współczynnik kształtu
  2. Skaluj filmy z DAR> 7/4 pod względem szerokości (zmień szerokość na 700 i wyskaluj wysokość, aby zachować proporcje) i skaluj te z DAR <7/4 pod względem wysokości
  3. Wypełnij wideo, aby zmieściło się w przestrzeni 700: 400.

FFmpeg / avconv może wykonać skalowanie / wypełnianie za pomocą filtrów wideo w jednym kroku, transkodując tylko raz. Na przykład, aby zrobić wideo 16: 9, przeskaluj je pod kątem szerokości, a następnie przesuń litery do wyników:

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

... ale dla pierwszego kroku (wykrycie współczynnika kształtu i porównanie go z wymaganym 7: 4) będziesz musiał użyć jakiegoś skryptu.

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

... uzyska proporcje filmu, które będą wyglądały jak „16: 9” lub „4: 3”. W skrypcie bash użyłbym czegoś takiego:

#!/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

Oczywiście będziesz musiał dostosować go do swoich potrzeb.

zła
źródło
1
Można to zrobić w jednym kroku, zobacz moją odpowiedź.
slhck
@slhck Teraz jest łatwiej. Zobacz odpowiedź z gitarową barwą.
llogan
@LordNeckbeard Thanks! Niedawno widziałem tę opcję, dzięki której jest ona znacznie łatwiejsza.
slhck