Jaki jest skuteczny sposób na płynne przejście wideo za pomocą FFmpeg?

11

Przejście między dwoma fragmentami treści wideo jest w FFmpeg dość skomplikowane. Nie ma takiego filtru, jak w przypadku dźwięku.

Jak skutecznie to zrobić?

Mark Gerolimatos
źródło
Ładne pytanie, na które odpowiedziałeś sam!
JakeGould,
Ta odpowiedź musi uzyskać DUŻO więcej głosów pozytywnych ... Mark, bardzo bym cię kochał na zawsze, gdybyś dodał również cross-fading dla dźwięku ...
Merc
Jak tylko wymyślę, dodam to. Myślę, że płynne przenikanie dźwięku jest szybkie, ale wierzcie, że jest do tego prosty filtr.
Mark Gerolimatos,
Po prostu dodałem [0:a][1:a] acrossfade=d=1 [audio]do filtra, a następnie -map "[audio]" do polecenia i zadziałało. Jeśli chcesz, przetestuj i zaktualizuj odpowiedź!
Merc,
Możliwy duplikat przenikania między 2 filmami za pomocą ffmpeg
r_alex_hall

Odpowiedzi:

17

Wersja TL; DR:

W tym przykładzie wykonuje się tylko wideo, zakładając, że oba klipy wideo mają tę samą rozdzielczość, szybkość klatek itp. Spowoduje to 1-sekundowe przenikanie pomiędzy fadeoutclip i fadeinclip. Załóżmy, że wyciszenie trwa 10 sekund. Zauważ, że jest to sformatowane dla jasności: tak naprawdę jest to jeden wiersz kodu.

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an \
-filter_complex "\
    [0:v]trim=start=0:end=9,setpts=PTS-STARTPTS[firstclip]; \
    [1:v]trim=start=1,setpts=PTS-STARTPTS[secondclip]; \
    [0:v]trim=start=9:end=10,setpts=PTS-STARTPTS[fadeoutsrc]; \
    [1:v]trim=start=0:end=1,setpts=PTS-STARTPTS[fadeinsrc]; \
    [fadeinsrc]format=pix_fmts=yuva420p, \
                fade=t=in:st=0:d=1:alpha=1[fadein]; \
    [fadeoutsrc]format=pix_fmts=yuva420p, \
                fade=t=out:st=0:d=1:alpha=1[fadeout]; \
    [fadein]fifo[fadeinfifo]; \
    [fadeout]fifo[fadeoutfifo]; \
    [fadeoutfifo][fadeinfifo]overlay[crossfade]; \
    [firstclip][crossfade][secondclip]concat=n=3[output] \
    " \
-map "[output]" <add in encoding part here>

Pełna wersja:

Oto wyjaśnienie, o co w tym wszystkim chodziło:

Specyfikacja wejściowa ... oczywista

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an

Tworzenie filter_complex: zakładając, że już rozumiesz kompleksy filtrów:

-filter_complex

Najpierw rozbieramy dwa strumienie na dwa kawałki, używając filtru przycinania : zawartość i sekcja przenikania. Wyciszenie jest podzielone na zawartość i sekcję przenikania, podczas gdy wyciszanie jest dzielone na sekcję przenikania i zawartość. Łącznie cztery sekcje.

Zauważ, że ściśle mówiąc, nie musimy rozdzielać przekrojów: MUSIMY po prostu określić czasy zanikania i zanikania dla dwóch klipów wideo. Jednak w ten sposób:

  • Postępuj zgodnie z metodologią używaną zwykle przez edytory wideo GUI
  • Unikaj frustrującej złożoności overlayużytkowania filtra
  • Upewnij się, że rozwiązanie jest tak ogólne, jak to możliwe (tj. Kod wielokrotnego użytku)
  • Pozwól nam wstępnie przetworzyć i przetworzyć sekcję crossfade w razie potrzeby (nie zrobiono tutaj)

Każda z tych czterech sekcji określa: czas rozpoczęcia (sekundy), czas zakończenia (sekundy) oraz tajemniczy setpts=PTS-STARTPTSfiltr , który zasadniczo powoduje, że każdy klip wideo rozpoczyna się od 0 sekund. Będzie to miało zasadnicze znaczenie podczas ich ponownego łączenia.

Zauważ, że s=0specyfikatory są redundantne, a setptsfiltr dla s=0nich jest również redundantny. Oba są jednak nadmiarowe, aby umożliwić zmianę czasu rozpoczęcia od 0, bez naruszania kompleksu filtrów. Ponadto drugi klip zawartości biegnie do końca, więc e=część (end =) nie jest określona.

    [0:v]trim=s=0:e=9,setpts=PTS-STARTPTS[firstclip];
    [1:v]trim=s=1,setpts=PTS-STARTPTS[secondclip];
    [0:v]trim=s=9:e=10,setpts=PTS-STARTPTS[fadeoutsrc];
    [1:v]trim=s=0:e=1,setpts=PTS-STARTPTS[fadeinsrc];

Następnie określamy przenikanie i zanikanie: Najpierw dodajemy kanał alfa (przezroczystość) do obu sekcji przenikania, określając format pikseliyuva420p . Możesz użyć dowolnego formatu, który zapewnia kanał alfa.

Następna w tym filtrze subcomplex określamy jedną zgaśnie, a jeden zanikać w. The alpha=1oznacza, że sam film nie zostanie wygaszony, tylko ilość przejrzystość „Fade”. stoznacza początek, doznacza czas trwania.

    [fadeinsrc]format=pix_fmts=yuva420p,      
                fade=t=in:st=0:d=1:alpha=1[fadein];
    [fadeoutsrc]format=pix_fmts=yuva420p,
                fade=t=out:st=0:d=1:alpha=1[fadeout];

Co to jest ?: Do fifofiltrów zapewnia, że nie jest bufor przestrzeń dostępną w filtrze złożonym. O dziwo, NIE jest to ustawienie domyślne. Jeśli tego nie zrobisz, crossfade może się nie udać, jeśli wynik powyższego etapu przekroczy filtr nakładki poniżej. Tak, wiem o czym teraz myślisz. To rzeczywiście błąd FFMPEG .

    [fadein]fifo[fadeinfifo];
    [fadeout]fifo[fadeoutfifo];

Teraz nałóż dwie sekcje przenikania : upewniając się, że dwie sekcje przenikania mają ten sam rozmiar, nie musimy się martwić o dość paskudne opcje, jakie ma filtr nakładki (dlatego je tutaj ignorujemy):

    [fadeoutfifo][fadeinfifo]overlay[crossfade];

Na koniec, wyrównujemy nasze trzy segmenty za pomocą filtra konkat .

    [firstclip][crossfade][secondclip]concat=n=3[output]

A teraz zamapuj pad wyjściowy jako źródło wideo.

NIE ZAPOMNIJ ustawić formatu piksela NA CO NORMALNIE UŻYWAĆ (zwykle yuv420p), ponieważ sekcja przejścia pojawi się yuv420na kanale wyjściowym! (ponieważ nie określiliśmy tego, możesz użyć argumentów nakładki) Oczywiście, jeśli CHCESZ yuv420, to nic ci nie jest :-)

-map "[output]" <add your normal encoding part here>

Następnie można ponownie połączyć audio później (poza zakresem niniejszego pytania i odpowiedzi)

Mark Gerolimatos
źródło
1
W najnowszym ffmpeg musi tak być trim=start=0:end=9(zamiast trim=st=0:e=9,...
Merc
Ale tak na poważnie, to będzie najlepsza odpowiedź na temat FFMPEG, jaką kiedykolwiek widziałem, i najczystsze wyjaśnienie ffmpeg w historii.
Merc
Człowieku, to pójdzie mi do głowy :-) Dzięki za rekwizyty !!!!
Mark Gerolimatos,
Bez obaw. Zaktualizuj odpowiedź, szczególnie za pomocą = trim = start = 0, ponieważ teraz nie działa z najnowszym ffmpeg
Merc
Najnowsza wersja ffmpeg daje mi ten błąd: Filter setpts has an unconnected outputdla skryptu. Zmieniłem już parametry przycinania, aby rozpocząć i zakończyć.