Konwertuj wideo na stały rozmiar ekranu, przycinając i zmieniając rozmiar


22

Sam próbowałem to rozgryźć, ale niezliczona ilość opcji mnie zaskakuje.

Chcę używać idealnie albo ffmpegczy mencoder(lub coś innego, ale te dwa Wiem, że pracuje) przekonwertować dowolny film przychodzące do ustalonej wielkości ekranu.

Jeśli wideo jest na niego szersze lub za krótkie, należy je przyciąć do środka. Jeśli nie jest to odpowiedni rozmiar, zmień rozmiar w górę lub w dół, aby uzyskać dokładnie stały rozmiar ekranu.

Dokładnie ostatnia rzecz, której potrzebuję, to 720x480 w XVid AVI ze ścieżką audio MP3.

Znalazłem wiele stron pokazujących, jak zmienić rozmiar do maksymalnej rozdzielczości, ale muszę mieć dokładnie taką rozdzielczość wideo (z przyciętymi dodatkowymi częściami, bez czarnych pasków).

Czy ktoś może mi powiedzieć, że powinienem uruchomić wiersz poleceń - a przynajmniej doprowadzić mnie tam / w większości? Jeśli musi to być wiele wierszy poleceń (uruchom X, aby uzyskać rozdzielczość, wykonaj te obliczenia, a następnie uruchom Y z wynikiem tych obliczeń), mogę to skrypty.


Najwyraźniej urządzenie wideo współpracuje z Mpeg4 oraz XVid AVI, jeśli jest to łatwiejsze / lepsze.
Andy Jeffries

Odpowiedzi:


19

Nie jestem guru ffmpeg, ale to powinno wystarczyć.

Przede wszystkim możesz uzyskać rozmiar wejściowego wideo w następujący sposób:

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

Dzięki stosunkowo nowej wersji ffmpeg możesz zmienić rozmiar swojego filmu za pomocą następujących opcji:

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

Możesz ustawić szerokość lub wysokość na -1, aby umożliwić ffmpegzmianę rozmiaru wideo z zachowaniem proporcji. W rzeczywistości -2jest lepszym wyborem, ponieważ obliczona wartość powinna być parzysta. Więc możesz wpisać:

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

Po uzyskaniu wideo może być większe niż oczekiwano, 720x480ponieważ pozwalasz ffmpegobliczyć wysokość, więc musisz go przyciąć. Można to zrobić w następujący sposób:

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

Na koniec możesz napisać taki skrypt (można go łatwo zoptymalizować, ale zapewniłem czytelność):

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

Miałem dziwne wrażenie, że przegapiłbym scenariusz, ale wypróbowałem go z dużą ilością plików wideo i wydaje się, że poprawnie przycina i zmienia rozmiar filmów do absolutnie poprawnego rozmiaru - dobra robota!
Andy Jeffries

wygląda na to, że coś jest nie tak z decyzją CROP_SIDE.
Sutra,

`# Uzyskaj współczynnik między faktycznym a pożądanym rozmiarem 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}' # Weźmy krótszy bok, więc film będzie co najmniej tak duży # jak pożądany rozmiar, i przyciąć dłuższy bok: crop_side = 'n' jeśli [$ {w_rate} -gt $ {h_rate}]; następnie 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

Zamień „input.file” na nazwę pliku wejściowego.


To powinna być najwyższa odpowiedź, ponieważ nie wymaga połączenia z ffprobe. Zwróć uwagę na sekwencje przecinków odwrotnych ukośników w poleceniu. Musisz wstawić ukośniki odwrotne, jeśli umieścisz polecenie w ciągu C / JavaScript / PHP.
cleong

Fajnie, Brian. Filtr wideo jest dokładnie tym, czego potrzebowałem. (tj. do konwersji starych filmów 4: 3 na 16: 9)!
Dave

1
geniusz! wszystko zrobione w jednym.
Soli,

2
Znacznie czystsze niż powyższy skrypt. Uwaga: jeśli nie chcesz XVID / MP3, możesz po prostu zmienić tagi po drugim cudzysłowie na coś w stylu-c:a copy scaled_result.mp4
Nick

7

Jeśli chcesz przycinać i skalować za jednym razem, możesz utworzyć łańcuch filtrów przycinania i skalowania w następujący sposób:

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

Powyższe pierwsze przycina wideo do portretu 16: 9, a następnie skaluje do wysokości 400 pikseli x odpowiedniej (parzystej liczby) szerokości.


1

Jestem nowy w ffmpeg, ale teraz mam ładny, mały konwerter w VB.NET, który tworzy surowe filmy o różnych formatach wyjściowych do użytku w małych urządzeniach, które mają dostęp do karty SD, ale nie mają wystarczającej mocy, aby dekodować złożone wideo.

Ze względu na sposób, w jaki działa podczas zmiany rozmiaru i przycinania, musiałem go kodować ręcznie i budować parametry. Zasadniczo muszę znać wynikową szerokość i wysokość.

Mam 2 pola wyboru dla opcji: -

Zachowaj proporcje obrazu (X) Wypełnij wszystkie piksele (X)

Potrzebne są tylko 4 zmienne jako dane wejściowe (1) Oryginalna szerokość wideo, (2) Oryginalna wysokość wideo, (3) Szerokość urządzenia, (4) Wysokość urządzenia.

Chociaż dla VB.NET można dostosować dość łatwo dla dowolnego języka.

    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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.