Cięcie filmów na podstawie czasu rozpoczęcia i zakończenia za pomocą ffmpeg


510

Próbowałem wyciąć wideo, używając czasu rozpoczęcia i zakończenia wideo, używając następującego polecenia

ffmpeg -ss 00:00:03 -t 00:00:08 -i movie.mp4 -acodec copy -vcodec copy -async 1 cut.mp4

Korzystając z powyższego polecenia, chcę wyciąć wideo z 00:00:03na 00:00:08. Ale to nie jest cięcie wideo między tymi czasami, ale to, że tnie wideo z pierwszymi 11 sekundami. czy ktoś może mi pomóc, jak to rozwiązać?

Edycja 1:

Próbowałem wyciąć za pomocą następującego polecenia, które jest sugerowane przez mark4o

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

Ale pokazano następujący błąd.

koder „aac” jest eksperymentalny, ale eksperymentalne kodeki nie są włączone

więc dodałem -strict -2do polecenia tj.

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -strict -2 cut.mp4

Teraz działa dobrze.


3
Brakuje pełnego, nieciętego wyjścia konsoli ffmpeg. Zawsze pytaj o to, pytając. Dzięki.
slhck

3
Skąd masz -strict 2? Ciekawe, ponieważ nie ma go w dokumentach: ffmpeg.org/ffmpeg.html
StackOverflowed

Jego jakość po zainstalowaniu ffmpeg, W pomocy ffmpeg można znaleźć tę opcję
Kalai


1
Myślę, że problemem tutaj był fakt, że umieściłeś przed i przed ZANI -i movie.mp4. Argumenty za tym strumieniem idą PO, prawda? Dlatego działał w inny sposób. = /
Brent Rittenhouse

Odpowiedzi:


572

Prawdopodobnie nie masz klatki kluczowej na 3 sekundowym znaku. Ponieważ klatki inne niż klatki kluczowe kodują różnice w stosunku do innych klatek, wymagają one wszystkich danych, zaczynając od poprzedniej klatki kluczowej.

W kontenerze mp4 możliwe jest cięcie bez klatki kluczowej bez ponownego kodowania przy użyciu listy edycji. Innymi słowy, jeśli najbliższa klatka kluczowa przed 3s ma wartość 0, skopiuje wideo zaczynając od 0 i użyje listy edycji, aby powiedzieć graczowi, aby zaczął odtwarzać 3 sekundy.

Jeśli używasz najnowszej wersji ffmpeg od git master, zrobi to za pomocą listy edycji po wywołaniu za pomocą podanego polecenia. Jeśli to nie działa, prawdopodobnie używasz starszej wersji ffmpeg lub twój odtwarzacz nie obsługuje list edycji. Niektóre odtwarzacze zignorują listę edycji i zawsze odtwarzają wszystkie multimedia w pliku od początku do końca.

Jeśli chcesz wycinać dokładnie zaczynając od klatki kluczowej i chcesz, aby grała od wybranego miejsca na odtwarzaczu, który nie obsługuje list edycji, lub chcesz upewnić się, że wycięta część nie znajduje się w pliku wyjściowym (na przykład jeśli zawiera poufne informacje), możesz to zrobić, ponownie kodując, aby klatka kluczowa była dokładnie w żądanym czasie rozpoczęcia. Ponowne kodowanie jest domyślne, jeśli nie zostanie określone copy. Na przykład:

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

Podczas ponownego kodowania możesz również chcieć uwzględnić dodatkowe opcje związane z jakością lub określony koder AAC. Aby uzyskać szczegółowe informacje, zobacz Podręcznik kodowania x264 ffmpeg dla wideo i Podręcznik kodowania AAC dla audio.

Ponadto -topcja określa czas trwania, a nie czas zakończenia. Powyższe polecenie zakoduje 8 s wideo zaczynając od 3 s. Aby rozpocząć od 3s i zakończyć od 8s użyj -t 5. Jeśli używasz aktualnej wersji FFmpeg można również wymienić -tze -tow powyższym poleceniu do końca w określonym czasie.


4
Czy istnieje skrót do określenia do końca filmu?
Jikku Jose

20
@JikkuJose: Pomiń argument -t/ -toi jego argument, aby przejść do końca.
mark4o

41
Uwaga: szybsze jest dostarczenie -ssPRZED plikiem wejściowym (wcześniej -i), ponieważ w ten sposób ffmpeg przejdzie bezpośrednio do lokalizacji. Spowoduje to jednak również ustawienie czasu „zero” w tej lokalizacji, co oznacza, że -towskaże niewłaściwy czas. Źródło: trac.ffmpeg.org/wiki/Seeking
Denilson Sá Maia

4
Po użyciu ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4pojawia się problem z synchronizacją dźwięku i obrazu , chociaż w oryginalnym pliku nie ma takiego problemu.
user2002522,

6
@ user2002522: Spróbuj bez -async 1 .
mark4o

429

Spróbuj użyć tego. Jest to najszybszy i najlepszy sposób, w jaki udało mi się to ustalić:

 ffmpeg -ss 00:01:00 -i input.mp4 -to 00:02:00 -c copy output.mp4

To polecenie przycina wideo w kilka sekund!

Wyjaśniłem to na moim blogu tutaj :

-i: określa plik wejściowy. W takim przypadku jest to (input.mp4).
-ss: Używany z -i, szuka pliku wejściowego (input.mp4) do pozycji.
00:01:00: To jest czas, od którego zaczniesz przycięte wideo.
-to: określa czas trwania od początku (00:01:40) do końca (00:02:12).
00:02:00: To jest czas, w którym skończy się przycięte wideo.
-c kopiuj: Jest to opcja przycinania za pomocą kopiowania strumieniowego. (Uwaga: bardzo szybko)

Format czasu to: hh: mm: ss

Należy pamiętać, że obecna bardzo pozytywna odpowiedź jest nieaktualna, a przycinanie byłoby bardzo wolne. Aby uzyskać więcej informacji, spójrz na ten oficjalny ffmpeg artykułem .


9
to przetworzyło mój 45 min plik 720p w 3 sekundy. To powinna być poprawna odpowiedź.
Dheeraj Bhaskar

7
Jednak nadal możesz cierpieć z powodu braku klatek kluczowych. Podjąłem twoje podejście do cięcia, a następnie ponownie zakodowałem zgodnie z przyjętą odpowiedzią, aby upewnić się, że zminimalizowałem czas potrzebny na ponowne kodowanie.
pelson

7
Jak mówi @pelson, spowoduje to odcięcie klatek kluczowych i pozostawienie pierwszych kilku sekund pustych (jeśli czas cięcia jest między klatkami kluczowymi). Co ciekawe, zmieniając kolejność parametrów rozwiązuje problem: ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -ss 00:01:00 -to 00:02:00 -c copy output.mp4. Teraz jednak pomijanie jest zepsute, a czas zakończenia jest nieprawidłowy (w moim przypadku).
Raphael,

6
Powinieneś użyć tej odpowiedzi, jeśli nie musisz przycinać dokładnie w milisekundie, dlatego wybierze najbliższą dostępną klatkę kluczową. Dlatego jest tak szybki, że wybiera najbliższe klatki kluczowe i usuwa fragment kodu bez potrzeby ponownego kodowania. Jeśli jednak potrzebujesz dokładnego czasu, pobranie najbliższej klatki kluczowej nie wystarczy, ponieważ na pewno nie będzie dokładnie pasować. Jedynym dostępnym rozwiązaniem jest ponowne zakodowanie wideo, dlatego jest tak wolne. To jednak jedyne rozwiązanie, jeśli tego potrzebujesz. Dlatego druga odpowiedź powinna być zaakceptowana, ponieważ o to właśnie chodziło w OP.
Yamaneko

4
Nie jestem pewien, dlaczego, ale nie wydaje się to bardziej poprawne niż zaakceptowana odpowiedź, ponieważ prowadzi to do problemów z brakującymi ramkami kluczowymi. W przypadku krótkich klipów wideo efekt jest nie do przyjęcia. Powolne ponowne kodowanie wydaje się jedynym rozwiązaniem w takich przypadkach.
icarus74,

91
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 

Użyj opcji -c copy, aby zrobić natychmiast. W takim przypadku ffmpeg nie ponownie koduje wideo, po prostu przycina do odpowiedniego rozmiaru.


2
z -c kopia działa świetnie, ale tylko jeśli usunę -async 1
dorien

2
To kończy się niepowodzeniem podczas zapisu z powodu nieprawidłowych nagłówków w przypadku różnych kontenerów wejściowych i wyjściowych, np. Danych wejściowych mkv i danych wyjściowych .mp4.
Assil Ksiksi

1
W porządku, aby przekonwertować .mkv na .mp4, musisz użyć innego polecenia: ffmpeg -i movie.mkv -vcodec copy -acodec copy converted_movie.mp4i odwrotnie
Vlad Hudnitsky

Jakie są zalety ponownego kodowania? Czy jest to przydatne, jeśli chcemy tylko mniejsze wideo w tym samym formacie?
Harsha

29
    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

Upuść wszystko oprócz drugiej sekundy do drugiej 8.


4
Dostaję pierwsze 8 sekund, z pierwszymi 3 sekundami zamrożonymi na pierwszej klatce. Naprawiono przez setpts=PTS-STARTPTSfiltr łańcuchowy za filtrem trymowania.
jiggunjer,

Mówi to: „Koder„ aac ”jest eksperymentalny, ale eksperymentalne kodeki nie są włączone, dodaj„ -strict -2 ”, jeśli chcesz go użyć.” Dodanie -strict -2 nie pomaga. Wynikiem jest plik o zerowej długości.
Ivan

4
@Ivan, czy próbowałeś -strict -2wcześniej dodać cut.mp4(w przeciwieństwie do końca wiersza poleceń)?
Jan Gondol

Hej, czy możesz mi powiedzieć, czy chcę tylko wideo bez 3 do 8 sekund?
Parth Solanki

1
To jest bardzo wolne
Tessaracter

21

Aby wyciąć na podstawie czasu rozpoczęcia i zakończenia ze źródłowego wideo i uniknąć konieczności wykonywania obliczeń matematycznych, określ czas zakończenia jako opcję wprowadzania, a czas rozpoczęcia jako opcję wyjścia.

ffmpeg -t 1:00 -i input.mpg -ss 45 output.mpg

Spowoduje to 15-sekundowe cięcie od 0:45 do 1:00.

Dzieje się tak, ponieważ gdy -sspodano jako opcję wyjściową, odrzucony czas jest nadal uwzględniany w całkowitym czasie odczytanym z wejścia, który -twykorzystuje, aby wiedzieć, kiedy zatrzymać. Jeśli -sspodano jako opcję wprowadzania , czas rozpoczęcia jest szukany i nie jest liczony , stąd pochodzi zamieszanie.

Jest wolniejszy niż wyszukiwanie, ponieważ pominięty segment jest przetwarzany przed jego odrzuceniem, ale o ile wiem, jest to jedyny sposób, aby to zrobić. Jeśli przycinasz z głębi dużego pliku, rozsądniej jest po prostu wykonać matematykę i użyć -ssdanych wejściowych.


4
powoli, ale jedyna rzecz, która zadziałała dla mnie (bez utraty ramek z innych odpowiedzi)
techkuz

8

Oto, czego używam:

ffmpeg -i input.mkv -ss 00:01:00 -to 00:02:00 -c:v copy -c:a copy output.mp4

Wygenerowane mp4pliki można również wykorzystać w iMovie.

Odniesienie: https://www.arj.no/2018/05/18/trimvideo


Jeśli chcesz połączyć wiele scen przerywników, możesz użyć następującego skryptu:

#!/usr/bin/env python3

import subprocess

name = "batman.mp4"

times = []
times.append(["01:06:00", "01:07:00"])
times.append(["01:08:00", "01:09:00"])

open('concatenate.txt', 'w').close()
for idx, time in enumerate(times):
    output_filename = f"output{idx}.mp4"
    cmd = ["ffmpeg", "-i", name, "-ss", time[0], "-to", time[1], "-c:v", "copy", "-c:a", "copy", output_filename]
    subprocess.check_output(cmd)
    with open("concatenate.txt", "a") as myfile:
        myfile.write(f"file {output_filename}\n")

cmd = ["ffmpeg", "-f", "concat", "-i", "concatenate.txt", "-c", "copy", "final.mp4"]
output = subprocess.check_output(cmd).decode("utf-8").strip()

Na to jednak już odpowiedziano
Tessaracter,

1
Moje podejście różni się od przyjętych odpowiedzi. Próbowałem tych, które mają więcej czasu na zbudowanie pliku MP4. @Tessaracter
alper

1
To jest JEDYNA odpowiedź tutaj, która zadziałała dla mnie w przypadku wycięcia małego klipu z dużego wideo. To działa i SZYBKO !!! Dziękuję
lacostenycoder

1
Nie ma za co, cieszę się, że mogę pomóc. Znalazłem tę odpowiedź po wypróbowaniu wielu podejść. Większość z nich była dość powolna. @lacostenycoder
alper

Czy nie można po prostu użyć „-c” z „kopiowaniem” zamiast podziału -c: v i -c: a?
nstenz


-3

Chociaż jestem spóźniony 6 lat, ale myślę, że wszystkie powyższe odpowiedzi nie odnoszą się do pytania, które zadaje @kalai . Poniższy skrypt bash przetworzy plik tekstowy w następującym formacie:

URL | start_time | end_time | filename

na przykład

https://www.youtube.com/watch?v=iUDURCrvrMI|00:02:02|00:03:41|1

i pętli pliku, pobiera plik, który youtube-dlpodporach, obliczania czasu trwania pomiędzy start_timea end_timei przepuszczenie go ffmpeg, ponieważ -tjest rzeczywiście czas trwania , a nie prawdziweend_time

Uderz mnie, jeśli masz jakieś pytanie.

    for i in $(<video.txt);
    do
        URL=`echo $i | cut -d "|" -f 1`;
        START=`echo $i | cut -d "|" -f 2`;
        END=`echo $i | cut -d "|" -f 3`;
        FILE=`echo $i | cut -d "|" -f 4`;

        SEC1=`echo $START | sed 's/^/((/; s/:/)*60+/g' | bc`
        SEC2=`echo $END | sed 's/^/((/; s/:/)*60+/g' | bc`

        DIFFSEC=`expr ${SEC2} - ${SEC1}`

        ffmpeg $(youtube-dl -g $URL | sed "s/.*/-ss $START -i &/") -t $DIFFSEC -c copy $FILE".mkv";
        ffmpeg -i $FILE".mkv" -f mp3 -ab 192000 -vn $FILE".mp3";
        rm $FILE".mkv";
    done;

Wyprowadza to tylko plik audio MP3, a NIE wideo.
lacostenycoder

Tak ... po prostu zmień format wyjściowy.
rolodex
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.