Jak wyciszyć / zejść klip wideo / audio o nieznanym czasie trwania?

19

Pracuję nad projektem, w którym używam ffmpeg do grupowej konwersji niektórych plików wideo i dodawania efektów pojawiania się / zanikania na początku i na końcu każdego klipu.

Użyłem tego fragmentu kodu, aby dodać efekt zanikania / zanikania klipów o znanym czasie trwania:

ffmpeg -i clip.mp4 -filter:v 'fade=in:0:30,fade=out:9650:30' -c:v libx264 -crf 22 -preset veryfast -c:a copy fadeInOut.mp4

Moje dwa pytania to:

  1. Jak mogę jednocześnie wyciszyć wejście / wyjście audio?
  2. Czy ffmpeg może automatycznie określić czas trwania klipu i zostać poinformowanym, że po prostu wyciszy ostatnie 30 klatek?

Dzięki!

d13
źródło

Odpowiedzi:

15

# 1 Aby jednocześnie zanikać wejście / wyjście audio:

ffmpeg -i clip.mp4 -vf 'fade=in:0:30,fade=out:960:30'
                   -af 'afade=in:st=0:d=1,afade=out:st=32:d=1'
       -c:v libx264 -crf 22 -preset veryfast fadeInOut.mp4

Czasy Afade są w sekundach .

# 2 automatycznie? Nie. Ale zobacz obejście poniżej

Możesz najpierw uruchomić ffprobe, aby uzyskać czas trwania.

ffprobe -i clip.mp4 -show_entries stream=codec_type,duration -of compact=p=0:nk=1

Otrzymasz coś takiego:

video|13.556000
audio|13.816000

Następnie możesz użyć powyższego, aby umieścić swoje przejścia. Te czasy są w sekundach.

Obejście

ffmpeg -i clip.mp4 -sseof -1 -copyts -i clip.mp4 -filter_complex
       "[1]fade=out:0:30[t];[0][t]overlay,fade=in:0:30[v];
        anullsrc,atrim=0:2[at];[0][at]acrossfade=d=1,afade=d=1[a]"
       -map "[v]" -map "[a]" -c:v libx264 -crf 22 -preset veryfast -shortest fadeInOut.mp4

FFmpeg ma sseofopcję, która pozwala szukać danych od końca. Możemy to wykorzystać do osiągnięcia naszego celu. Tak więc podajemy dane wejściowe dwa razy, a drugi raz pochłaniamy tylko ostatnią sekundę. Mówimy FFmpeg, aby zachował znaczniki czasu, aby ffmpeg zachował pozycję czasową tej części ogona.

Stosujemy wyciszenie do tego ogona, a następnie nakładamy wynik na pełne wejście. Ponieważ są one tym samym plikiem multimedialnym, pierwszy plan całkowicie pokrywa tło, a ponieważ copytszostał zastosowany, nakładka zachodzi na odpowiednią identyczną ramkę na wejściu tła.

W przypadku dźwięku tworzymy pusty dźwięk fikcyjny o czasie trwania 2 sekundy, a następnie zastosujemy płynne przejście dźwięku z dźwięku głównego do tego dźwięku fikcyjnego. Ponieważ drugi dźwięk jest pusty, jest to w rzeczywistości wyciszenie głównego wejścia. -shortestDodaje opuścić części manekina i dźwięku po nastąpiło Przenikanie.

Gyan
źródło
Daje to błąd „brak takiego filtra!” dla filtra audio.
felwithe
1
Zastosowano 4 filtry audio. Który? Uruchom polecenie z -reportdodanym i udostępnij raport.
Gyan
7

To straszny hack, ale może to zadziałać, jeśli wszystko, co chcesz zrobić, to wyciszanie / zanikanie dźwięku, ale nie wiem dokładnie, jak długo trwa klip:

ffmpeg -i input.mp4 -filter_complex "afade=d=0.5, areverse, afade=d=0.5, areverse" output.mp4

[edytuj 2019-07-24: Pamiętaj, że to rozwiązanie nie jest dobre dla rozwiązań przesyłania strumieniowego, ponieważ wymaga przetworzenia pełnej ścieżki przed przesłaniem pierwszego bajtu]

inną opcją jest użycie acrossfadecichej ścieżki:

ffmpeg -i input.mp4 -filter_complex "aevalsrc=0:d=0.6 [a_silence]; [0:a:0] [a_silence] acrossfade=d=0.6" output.mp4
marekventur
źródło
3
To jest naprawdę dość eleganckie :-)
bk138
to działa świetnie. czy możesz wyjaśnić, jak to działa. próbuje zrozumieć dokumentację.
oberhamsi,
1
@oberhamsi: Opcja 1: Pierwszy filtr dodaje zanikanie na początku ścieżki. Następnie odwraca dźwięk i dodaje kolejne wyciszenie na początku (co w rzeczywistości jest końcem). W końcu ścieżka jest ponownie odwracana. Opcja 2 tworzy cichą ścieżkę o długości 0,6 sekundy i przenika ją przez ten sam czas z oryginalną ścieżką. Wszystkie filtry i ich użycie są udokumentowane tutaj: ffmpeg.org/ffmpeg-filters.html (chociaż muszę zgodzić się, że to trochę tajemnicze)
marekventur
3

Odpowiedź na pytanie 2 brzmi: TAK! Szukałem tej samej funkcjonalności i ostatecznie napisałem skrypt bash, który prosi o czas trwania zanikania w kilka sekund i oblicza początkową ramkę dla wyciszenia:

#!/bin/bash

f="$*" # all args
p="${f##*/}" # file
fn="${p%.*}" # name only
e="${p##*.}" # extension

echo
echo $f
echo $p
echo $fn
echo $e
echo

read -e -p "Number of seconds of fade-out: " -i 1 sec # prompt for fade duration in seconds

r=$(ffprobe -show_streams "$f" 2> /dev/null | grep r_frame_rate | head -1 | cut -d \= -f 2) # frame rate
let "frames = $r * $sec" # duration of fade as number of frames
echo $r
echo $sec
echo $frames
lf=$(ffprobe -show_streams "$f" 2> /dev/null | grep nb_frames | head -1 | cut -d \= -f 2) # total number of frames
let "lf = $lf - $frames" # initial frame to start fade at

ffmpeg -loglevel quiet -i "$f" -vf fade=out:$lf:$frames -r $r -vcodec libx264 -preset slow -crf 12 -bf 2 -flags +cgop -pix_fmt yuv420p -acodec copy "$fn $sec sec fade-out.$e"
open "$fn $sec sec fade-out.$e"

Zanikanie wymaga ponownego kodowania, więc użycie niskiej crfwartości dla libx264daje wysokiej jakości ponowne kodowanie. Komentarze powinny wyjaśniać wszystko inne.

hmj6jmh
źródło
Odpowiedź na pytanie 2 brzmi: TAK! -> wciąż nie. Pytanie brzmi: Czy ffmpeg automatycznie oblicza czas trwania ... ale napisałeś skrypt, który uruchamia wiele poleceń ff *, aby to zrobić. Przydatne jednak w systemach * nix.
Gyan
Rozumiem, więc nalegasz, aby Twoja odpowiedź NADAL była poprawna? Jeśli podążasz za moim skryptem, zobaczysz, że rzeczywiście automatically figure out the durationużywa ffprobe, który jest zainstalowany z ffmpeg. Kto powiedział coś o ograniczeniu liczby poleceń lub *nix? Wygląda na to, że OP używa wersji UNIX. Nie .exew ffmpegpoleceniu. Ja sam używam, OS Xktóry jest zbudowany, UNIXale nie jest UNIX.
hmj6jmh
1
* Jeśli podążysz za moim skryptem, zobaczysz, że rzeczywiście automatycznie to rozgrywa * -> twój skrypt działa, ffmpeg nie.
Gyan
Ale ffprobejest integralną częścią ffmpegdystrybucji. Wybieracie gnidy, aby uratować twarz IMO.
hmj6jmh
Muszę się zgodzić, że coś zrobione przez skrypt bash nie jest czymś automatycznie wykonywanym przez ffmpeg. Ale jeśli to zadziała, jest to sposób na obejście tego problemu. Stąd termin „obejście”. Nie mogę powiedzieć, czy to działa, ponieważ podobnie jak większość ludzi nie mam systemu bash ani systemu unix. W każdym razie +1 za wysiłek.
ashleedawg