Przycinanie plików przy pomocy ffmpeg

Lubie sobie pograć w gry. Nie będzie to oczywiście zaskoczenie dla czytelników tego bloga. Gra jako interaktywne medium ma to do siebie że mogą wydarzyć się w niej nieoczekiwane rzeczy: od błędów czy różnego rodzaju glitchy, do strzelenia niemożliwych strzałów. Jak jeszcze – względnie – niedawno wymagało to albo specjalnego przygotowania albo sprzętu, tak teraz większość kart graficznych – czy konsol – posiada funkcje nagrywania. Teraz gdy wydarzy się nieoczekiwana akcja, należy nacisnąć dedykowany przycisk na padzie, lub odpowiednią kombinacje klawiszy i ostatnie parę minut rozgrywki będziemy mieli nagrane na dysku.

Rzadko się jednak zdarza że cały film będzie zawierał akcję którą będziemy chcieli pokazać. Dobrze by było film pociąć tak by nie było trzeba całego wrzucać na YouTube. I oszczędzimy sobie czas i transfer potrzebny na wysłanie. Taką prostą operacje można wykonać w jakimś wielkim kombajnie pokroju Adobe Premier (na którego mam nadzieje macie licencje), ale równie dobrze można skorzystać z darmowego i otwarto źródłowego ffmpeg.

Zazwyczaj będziemy chcieli wyciąć ostatnie sekundy lub minuty filmu, dlatego że to w nich najprawdopodobniej będzie się działo to co chcemy pokazać. By to zrobić należy wykonać następujące polecenie:

ffmpeg -ss CZAS_OD -i PLIK_ŹRÓDŁOWY -c copy PLIK_DOCELOWY

Należy tutaj zwrócić uwagę na dwie rzeczy:

  1. Czas od którego zaczynamy wycinanie, znajduje się przed plikiem źródłowym. Jest to dlatego że ffmpeg różnie interpretuje pozycje startową w zależności od tego czy znajduje się przed czy po pliku wejściowym. Różnica jest następująca:
    • Ustawienie przed: ffmpeg wyestymuje na podstawie metadanych gdzie mniej-więcej znajduje się czas od którego chcemy zacząć wycinanie. Takie rozwiązanie nie będzie idealnie dokładne, ale będzie szybsze. I z mojego doświadczenia jest ono wystarczająco dokładne.
    • Ustawienie po: ffmpeg przeskanuje plik i zacznie wycinanie dokładnie od wskazanego miejsca. To rozwiązanie jest idealnie dokładne, ale też wolniejsze. Przy dużych filmach nawet zdecydowanie.
  2. Tajemnicze -c copy nakazuje by ffmpeg nie kodował ponownie pliku, tylko skopiował zawartość stosownych strumieni. Bez tego ffmpeg zacznie reenkodowanie filmu na podstawie domyślnych ustawień.

Co jednak jeśli chcemy wyciąć z filmu pewnie fragment ze środka, a nie tylko końcówkę? Do tego posłuży nam jeden z dwóch parametrów: -d lub -to

ffmpeg -ss CZAS_OD -d DŁUGOŚĆ -i PLIK_ŹRÓDŁOWY -c copy PLIK_DOCELOWY

lub

ffmpeg -ss CZAS_OD -to CZAS_DO -i PLIK_ŹRÓDŁOWY -c copy PLIK_DOCELOWY

Jak można się domyślić, to opcja -d służy do podania długości klipu, gdzie opcja -to służy do wskazania czasu gdzie ffmpeg ma zakończyć działanie.

Po wykonaniu którejś z powyższych komend, możemy zauważyć że kopiowane są tylko pierwsze strumienie (i te z dźwiękiem i z obrazem). Dla przykładu NVIDIA ShadowPlay (czy jak się dowiedziałem z wikipedii: NVIDIA Share) może być tak skonfigurowana by nagrywała dźwięk z mikrofonu i z systemu jako dwa osobne strumienie. Można je razem zmiksować przy pomocy „zaawansowanych filtrów”:

ffmpeg -ss CZAS_OD -to CZAS_DO -i PLIK_ŹRÓDŁOWY -filter_complex amix -c:v copy PLIK_DOCELOWY

W tym poleceniu korzystamy z specjalnego filtra nazwanego amix. Robi to na co wskazuje jego nazwa: miksuje (miesza?) strumienie audio. Domyślnie tylko dwa pierwsze. A jako że modyfikujemy strumień audio, nie możemy go skopiować, dlatego ograniczamy kopiowanie tylko do strumienia obrazu.

Jeśli mamy więcej strumieni które chcemy zmieszać, należy dodać specjalny argument do filtru:

ffmpeg -ss CZAS_OD -to CZAS_DO -i PLIK_ŹRÓDŁOWY -filter_complex amix=length=ILOŚĆ -c:v copy PLIK_DOCELOWY

A jeśli chcemy zmieszać inne strumienie niż dwa pierwsze:

ffmpeg -ss CZAS_OD -to CZAS_DO -i PLIK_ŹRÓDŁOWY -filter_complex "[0:a:IDX] [0:a:IDX2] amix" -c:v copy PLIK_DOCELOWY

Gdzie format wyboru – znajdujący się między kwadratowymi nawiasami – to:

  1. Numer pliku (czyli który to -i)
  2. Typ strumienia: audio albo video
  3. Numer strumienia

Obie techniki można oczywiście łączyć, a napisanie przykładu zostawiam czytelnikom.

Gdy pracujemy z plikami które mają wiele strumieni, jest bardzo prawdopodobne że nie będziemy chcieli ich modyfikować poza samym wycięciem z nich fragmentu. Domyślnie jednak ffmpeg skopiuje tylko pierwsze strumienie i zignoruje resztę. By skopiował wszystkie należy dodać nowy parametr: -map 0:

ffmpeg -ss CZAS_OD -to CZAS_DO -i PLIK_ŹRÓDŁOWY -c copy -map 0 PLIK_DOCELOWY

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s

Ta witryna wykorzystuje usługę Akismet aby zredukować ilość spamu. Dowiedz się w jaki sposób dane w twoich komentarzach są przetwarzane.