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:
- 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.
- 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:
- Numer pliku (czyli który to -i)
- Typ strumienia: audio albo video
- 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