Jak połączyć dwa pliki MP4 za pomocą FFmpeg?


443

Próbuję połączyć dwa pliki mp4 za pomocą ffmpeg. Potrzebuję, aby był to proces automatyczny, dlatego wybrałem ffmpeg. Konwertuję dwa pliki na pliki .ts, a następnie łączę je, a następnie próbuję zakodować ten skonsolidowany plik .ts. Pliki są zakodowane w formacie h264 i aac i mam nadzieję, że jakość pozostanie taka sama lub jak najbardziej zbliżona do oryginału.

ffmpeg -i part1.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part1.ts
ffmpeg -i part2.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part2.ts
cat part1.ts part2.ts > parts.ts
ffmpeg -y -i parts.ts -acodec copy -ar 44100 -ab 96k -coder ac -vbsf h264_mp4toannexb parts.mp4

Niestety otrzymuję następujący komunikat o błędzie wracający z ffmpeg podczas kodowania:

[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[NULL @ 0x101d600]error, non monotone timestamps 13779431 >= 13779431kbits/s    
av_interleaved_write_frame(): Error while opening file

Dzieje się tak mniej więcej w połowie kodowania, co sprawia, że ​​myślę, że nie można połączyć dwóch plików .ts i sprawić, by działało.

Odpowiedzi:


786

FFmpeg ma trzy metody konkatenacji:

1. konkat filtr wideo

Tej metody należy użyć, jeśli dane wejściowe nie mają tych samych parametrów (szerokość, wysokość itp.) Lub nie są tymi samymi formatami / kodekami lub jeśli chcesz przeprowadzić filtrowanie. (Możesz ponownie zakodować tylko te wejścia, które nie pasują, aby miały ten sam kodek i inne parametry, a następnie użyj demuxera konkat, aby uniknąć ponownego kodowania innych wejść).

ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv \
       -filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] 
                        concat=n=3:v=1:a=1 [v] [a]" \
       -map "[v]" -map "[a]" output.mkv

Zauważ, że ta metoda wykonuje ponowne kodowanie.

2. demultiplekser konkat

Użyj tej metody, jeśli chcesz uniknąć ponownego kodowania, a Twój format nie obsługuje konkatenacji na poziomie plików (większość plików używanych przez zwykłych użytkowników nie obsługuje konkatenacji na poziomie plików).

$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

W systemie Windows :

(echo file 'first file.mp4' & echo file 'second file.mp4' )>list.txt
ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4

3. protokół konkat

Tej metody należy używać w przypadku formatów obsługujących konkatenację na poziomie plików (MPEG-1, MPEG-2 PS, DV). Czy nie korzystać z MP4.

ffmpeg -i "concat:input1|input2" -codec copy output.mkv

Ta metoda nie działa dla wielu formatów, w tym MP4, ze względu na naturę tych formatów i uproszczoną konkatenację wykonywaną tą metodą.


Jeśli masz wątpliwości, której metody użyć, wypróbuj demuxer konkat.

Zobacz także


3
Znakiem zmiany znaczenia w wierszu polecenia systemu Windows jest ^; Miałem też problemy ze znakami cudzysłowu, więc stało się to: ffmpeg -i concat: input1 ^ | input2 - kodowanie kopii wyjścia
user423430

1
Pomocna odpowiedź I miało to dla mnie jeszcze większy sens, gdy czytam tę odmianę: superuser.com/a/607384/74576
Ryan

3
demultiplekser konkat działa dla wideo, ale tracę dźwięk
Loïc

24
W przypadku programu oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv akceptuje więcej kodeków niż mp4, ale możesz także wypróbować go z mp4). -safe 0Jest dla nowszych wersji ffmpeg narzekających nazwy plików uznanych za niebezpieczne , i -type fto tylko dla wymieniając pliki. Dodałem, | sortaby posortować pliki alfabetycznie; ponieważ findodczytuje je w kolejności zapisanej w systemie plików. Działa również w przypadku plików z białymi spacjami.
erik

1
Dla mnie w systemie Windows, cudzysłów pracował (a nie pojedyncza w swoim przykładzie) ffmpeg -i "concat:input1|input2" -codec copy output. Nie ma potrzeby ucieczki od znaku potoku.
Shovalt,

83

DLA PLIKÓW MP4

W przypadku plików .mp4 (które otrzymałem z DailyMotion.com: 50-minutowy odcinek telewizyjny, do pobrania tylko w trzech częściach, jako trzy pliki wideo .mp4) poniższe rozwiązanie było skutecznym rozwiązaniem dla systemu Windows 7 i NIE wymaga ponownego kodowania akta.

Zmieniłem nazwy plików (na file1.mp4 , file2.mp4 , file3.mp4 ), tak aby części były w odpowiedniej kolejności do oglądania całego odcinka telewizji.

Następnie utworzyłem prosty plik wsadowy (concat.bat) o następującej treści:

:: Create File List
echo file file1.mp4 >  mylist.txt 
echo file file2.mp4 >> mylist.txt
echo file file3.mp4 >> mylist.txt

:: Concatenate Files
ffmpeg -f concat -i mylist.txt -c copy output.mp4

Plik wsadowy i ffmpeg.exe , musi być zarówno umieścić w tym samym folderze co pliki .mp4 mają być połączone. Następnie uruchom plik wsadowy. Uruchomienie zajmuje zwykle mniej niż dziesięć sekund.
.

Dodatek (2018/10/21) -

Jeśli to, czego szukałeś, to metoda określania wszystkich plików mp4 w bieżącym folderze bez konieczności ponownego wpisywania, spróbuj tego w pliku wsadowym systemu Windows ( MUSI zawierać opcję -safe 0 ):

:: Create File List
for %%i in (*.mp4) do echo file '%%i'>> mylist.txt

:: Concatenate Files
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

Działa to w systemie Windows 7 w pliku wsadowym. Nie próbuj używać go w wierszu poleceń, ponieważ działa tylko w pliku wsadowym!


5
Jak dotąd najprostsze rozwiązanie.
1934286

To powinna być najlepsza i najłatwiejsza odpowiedź. Dobra robota, mój bracie. Uratowałeś mi dzień.
DysaniazzZ

To dobre rozwiązanie, ale rozmowa o pliku wsadowym sprawia, że ​​ten dźwięk jest prymitywny (tak jak zostało to zrobione wsadowo) i bardziej złożony niż jest (ponieważ plik wsadowy jest całkowicie niepotrzebny). Jest to o wiele wyraźniejsze, jeśli po prostu pokażesz C:\blah>type mylist.txt<ENTER>(aby zobaczyli zawartość tego pliku). Następnie ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> powinieneś również dołączyć referencję trac.ffmpeg.org/wiki/Concatenate (ta referencja używa nawet tej samej nazwy pliku, mylist.txt)
barlop

Jest to bardzo dobre rozwiązanie, ponieważ pozwala uniknąć wpisywania długich list plików -iparametrów. W Linuksie zrobiłem to: ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtco jest jeszcze fajniejsze niż kodowanie skryptu wsadowego. W każdym razie -c copydziała bardzo szybko (czego nie byłem świadomy) i to jest prawdziwa magia tej odpowiedzi.
Würgspaß,

1
W przypadku moich plików mp4 po uruchomieniu kodu konkat na komputerze Mac za pomocą ffmpeg v2.2.2 nie ma dźwięku w pliku wyjściowym.
kakyo

60

Oto szybki (zajmuje mniej niż 1 minuta) i bezstratny sposób na zrobienie tego bez potrzeby używania plików pośrednich:

ls Movie_Part_1.mp4 Movie_Part_2.mp4 | \
perl -ne 'print "file $_"' | \
ffmpeg -f concat -i - -c copy Movie_Joined.mp4

„Ls” zawiera pliki do przyłączenia „perl” tworzy plik konkatenacji w locie do potoku Część „-i -” informuje ffmpeg, aby czytał z potoku

(uwaga - w moich plikach nie było spacji ani dziwnych rzeczy - będziesz potrzebował odpowiedniego ucieczki od powłoki, jeśli chcesz zrobić ten pomysł z „twardymi” plikami).


2
Zrobiłem to na OSX i działało świetnie! Niesamowite, szybkie bezstratne rozwiązanie o małych wymaganiach.
GM Lucid

1
Z odpowiednim ucieczką dla plików zawierających spacje:ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne '$_ =~ s/\n$//; print "file '"'"'$_'"'"'\n"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
Thomas Bachem

4
Możesz także zrobić, ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4jeśli twoje pliki są dobrze nazwane i uporządkowane. Działa świetnie dla mnie na OS X, dokładnie to, czego chciałem.
natebeaty

3
W systemie Linux użyłem tego narzędzia oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv akceptuje więcej kodeków niż mp4, ale możesz także wypróbować go z mp4). -safe 0Jest dla nowszych wersji ffmpeg narzekających nazwy plików uznanych za niebezpieczne , i -type fto tylko dla wymieniając pliki. Dodałem, | sortaby posortować pliki alfabetycznie; ponieważ findodczytuje je w kolejności zapisanej w systemie plików. Działa również w przypadku plików z białymi spacjami.
erik

13
Musiałem dodać ten parametr, ffmpegaby działał:-protocol_whitelist file,tcp,http,pipe
Bensge,

44

dla plików MP4:

Jeśli nie są one dokładnie takie same (100% taki sam kodek, ta sama rozdzielczość, ten sam typ) plików MP4, najpierw musisz je przekodować do strumieni pośrednich:

ffmpeg -i myfile1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1.ts
ffmpeg -i myfile2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2.ts
// now join
ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

UWAGA! : Dane wyjściowe będą jak pierwszy plik (a nie drugi)


2
Jak pokazano w mojej odpowiedzi poniżej, transkodowanie plików nie jest konieczne. FFmpeg może łączyć wiele plików mp4 w jeden plik mp4 - bez żadnych pośrednich kroków i bez ponownego kodowania. Jedynym przypadkiem, w którym konieczne byłoby ponowne kodowanie, jest to, że oryginalne pliki nie są plikami MP4, ale intencją jest utworzenie pliku MP4 jako pliku wyjściowego.
Ed999,

@T. Todua: Chciałbym dowiedzieć się, jakie dokładnie są różnice między Twoimi dwoma plikami źródłowymi MP4. Czy używają różnych częstotliwości próbkowania (np. 44 100 Hz i 48 000 Hz)? A może używają różnych przepływności (np. 128 kb / s i 64 kb / s)? W obu przypadkach nie do końca rozumiem, w jaki sposób polecenie -c copy (instrukcja stream-copy) zmodyfikuje pliki źródłowe, aby uczynić je kompatybilnymi.
Ed999

4
@ T.Todua Cześć, polecenie działa dobrze, gdy filmy nie zawierają ścieżki dźwiękowej. Jednak gdy plik myfile1.mp4 jest bez dźwięku, a plik myfile2.mp4 jest z dźwiękiem, wynik wyjściowy.mp4 jest bez dźwięku. Oczekiwany wynik. Mp4 powinien zawierać dźwięk. Jak mogę to rozwiązać?
Odpowiedź Zhao

2
@ T.Todua er .... To szkoda. Plik1 | plik2 generuje różne wideo za pomocą pliku2 | plik1. kolejność jest ważna.
OdpowiedźZhao,

1
Próbowałem twojej komendy na plikach concat 2 mp4. To działa. Jednak dźwięk drugiego pliku staje się niepewny jak głosy Ah-oh-Ee w nowej konkatenacji. masz to naprawić?
superlinux

35

Próbowałem połączyć trzy .mp3pliki audio w jeden.m4a plik i to polecenie ffmpeg działa.

Komenda wejściowa:

ffmpeg -i input1.mp3 -i input2.mp3 -i input3.mp3 -filter_complex concat=n=3:v=0:a=1 -f MOV -vn -y input.m4a

Znaczenie: "-filter_complex concat = n = 3: v = 0: a = 1" :

concat oznacza użycie medialnej funkcji konkatenacji (łączenia).
n oznacza całkowitą liczbę plików wejściowych.
v oznacza, że ma wideo ? użyj 0 = brak wideo, 1 = zawiera wideo.
a środek ma dźwięku ? użyj 0 = brak dźwięku, 1 = zawiera dźwięk.
-f oznacza wymuszenie ustawienia formatu pliku (aby zobaczyć wszystkie obsługiwane formaty, użyj ffmpeg -formats)
-vn oznacza wyłączenie wideo (a także -anwyłączyłby dźwięk, jeśli nie był potrzebny)
-y oznacza zastąpienie plików wyjściowych (jeśli plik wyjściowy już istnieje).

Aby uzyskać więcej informacji: użyj ffmpeg -h full opcji drukowania wszystkich opcji (w tym wszystkich opcji specyficznych dla formatu i kodeka, bardzo długo)


1
fi skorzystam z tego, -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"to się konkatuje, ale kiedy niektóre filmy są z dźwiękiem, a niektóre bez dźwięku, nie działa, jak mogę to rozwiązać. Dzięki -
Ahmad

1
To działa. Dziękuję za szczegółowe wyjaśnienie w odpowiedzi. To bardzo pomocne.
Joe T. Boka,

31

Skończyło się na tym, że używałem mpg jako formatu pośredniego i zadziałało (UWAGA to niebezpieczny przykład, -qscale 0 ponownie zakoduje wideo ...)

ffmpeg -i 1.mp4 -qscale 0 1.mpg
ffmpeg -i 2.mp4 -qscale 0 2.mpg
cat 1.mpg 2.mpg | ffmpeg -f mpeg -i - -qscale 0 -vcodec mpeg4 output.mp4

8
Z tego powodu -sameqzostał usunięty. Użyj -qscale 0zamiast tego.
Xavier Ho

6
-sameqnie oznacza „tej samej jakości” i został usunięty z ffmpeg, jak wspomniano w @XavierHo.
llogan

3
Szkoda, że ​​trzeba transkodować wideo w formacie pośrednim, aby połączyć dwa pliki. Dostaniesz stratę pokolenia. Lepiej nie wchodzić głębiej niż format kontenera i użyć concatpolecenia w ffmpeg, jak to robi @rogerdpack powyżej.
Randall Cook

8
Dlaczego to jest akceptowana odpowiedź? To bardzo zła metoda.
Nazwa wyświetlana

4
@SargeBorsch Ponieważ to działa. Próbowałem już wszystkiego na stronie - żadne z nich nie działa.

14

Szczegółową dokumentację na temat różnych sposobów łączenia w ffmpeg można znaleźć tutaj .

Możesz użyć „filtru Concat” do szybkiego połączenia.

Wykonuje ponowne kodowanie. Ta opcja jest najlepsza, gdy wejścia mają różne formaty wideo / audio.

W przypadku łączenia 2 plików:

ffmpeg -i input1.mp4 -i input2.webm \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

W przypadku łączenia 3 plików:

ffmpeg -i input1.mp4 -i input2.webm -i input3.mp4 \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] concat=n=3:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

Działa to tak samo, jak dla wielu typów plików wejściowych.


czy możesz podać więcej szczegółów na temat opcji, które masz w tym przykładzie?
Deweloper

@Developer: Aby uzyskać wyjaśnienie opcji -> Concat filter wiki
SJ00

4
Podczas łączenia 3 plików należy użyć concat = n = 3: v = 1: a = 1 nie n = 2
Cynapsis

1
nie dostaję bezstratnej konkatenacji ouput.mp4szybkość transmisji mojego wideo jest znacznie niższa niż szybkość transmisji wideo na wejściu
jasan

Dzięki Cynapsis za wskazanie go i georgiecasey za zaktualizowanie polecenia
SJ00

10

Odkryłem, że operator potoku nie działał dla mnie, gdy użyłem opcji 3 do konkatowania kilku MP4 na komputerze Mac w przyjętej odpowiedzi.

Następujący jednowierszowy działa na komputerze Mac (High Sierra) w celu połączenia plików MP4, bez konieczności tworzenia plików pośrednich.

ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4


2
Ta prosta odpowiedź jest jedyną, która faktycznie dla mnie zadziałała. Strony po stronach dokumentacji tutaj i gdzie indziej, podczas gdy ten prosty linijka jest wszystkim, co jest wymagane - i faktycznie działa. Dziękuję Ci.
blujay,

10

Tutaj 2 rozwiązania czysto bash używają tylko ffmpegi nie używają

  • plik pośredni
  • perl, python ani javascript

Jednowarstwowe rozwiązanie przy użyciu ls

ls video1.mp4 video2.mp4 | while read line; do echo file \'$line\'; done | ffmpeg -protocol_whitelist file,pipe -f concat -i - -c copy output.mp4

Funkcja, która przyjmuje argumenty 0 lub 2+

#######################################
# Merge mp4 files into one output mp4 file
# usage:
#   mergemp4 #merges all mp4 in current directory
#   mergemp4 video1.mp4 video2.mp4
#   mergemp4 video1.mp4 video2.mp4 [ video3.mp4 ...] output.mp4 
#######################################
function mergemp4() {
  if [ $# = 1 ]; then return; fi

  outputfile="output.mp4"

  #if no arguments we take all mp4 in current directory as array
  if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
  if [ $# = 2 ]; then inputfiles=($1 $2); fi  
  if [ $# -ge 3 ]; then
    outputfile=${@: -1} # Get the last argument
    inputfiles=(${@:1:$# - 1}) # Get all arguments besides last one as array
  fi

  # -y: automatically overwrite output file if exists
  # -loglevel quiet: disable ffmpeg logs
  ffmpeg -y \
  -loglevel quiet \
  -f concat \
  -safe 0 \
  -i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
  -c copy $outputfile

  if test -f "$outputfile"; then echo "$outputfile created"; fi
}

Uwaga: wypróbowałem kilka rozwiązań w tym wątku i żadne mnie nie usatysfakcjonowało


9

na podstawie odpowiedzi Rogerdpack i Ed999 stworzyłem swoją wersję .sh

#!/bin/bash

[ -e list.txt ] && rm list.txt
for f in *.mp4
do
   echo "file $f" >> list.txt
done

ffmpeg -f concat -i list.txt -c copy joined-out.mp4 && rm list.txt

łączy wszystkie *.mp4 pliki w bieżącym folderze wjoined-out.mp4

testowany na Mac.

wynikowy rozmiar pliku to dokładna suma moich 60 przetestowanych plików. Nie powinno być żadnej straty. Dokładnie to, czego potrzebowałem


9

to zadziałało dla mnie (w systemie Windows)

ffmpeg -i "concat:input1|input2" -codec copy output

przykład...

ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4

Pyton

Używając kodu Pythona, aby zrobić to z tyloma plikami mp4, które znajdują się w folderze (zainstaluj python z python.org, skopiuj i wklej i zapisz ten kod w pliku o nazwie mp4.py i uruchom go z cmd otwartego w folderze z pythonem plik mp4.py i wszystkie pliki mp4 w folderze zostaną połączone)

import glob
import os

stringa = ""
for f in glob.glob("*.mp4"):
    stringa += f + "|"
os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")

Wersja 2 z Python

Zaczerpnięte z mojego postu na moim blogu , tak to robię w Pythonie:

import os
import glob

def concatenate():
    stringa = "ffmpeg -i \"concat:"
    elenco_video = glob.glob("*.mp4")
    elenco_file_temp = []
    for f in elenco_video:
        file = "temp" + str(elenco_video.index(f) + 1) + ".ts"
        os.system("ffmpeg -i " + f + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + file)
        elenco_file_temp.append(file)
    print(elenco_file_temp)
    for f in elenco_file_temp:
        stringa += f
        if elenco_file_temp.index(f) != len(elenco_file_temp)-1:
            stringa += "|"
        else:
            stringa += "\" -c copy  -bsf:a aac_adtstoasc output.mp4"
    print(stringa)
    os.system(stringa)

concatenate()

1
Protokół concat nie powinien być używany z MP4 i nie będzie działał, jak wspomniano w zaakceptowanej odpowiedzi .
llogan

@ LordNeckbeard Zastanawiam się, czy znasz odpowiedź na to pytanie ffmpeg dotyczące łączenia 2 filmów MP4 przy określaniu wyjściowej szybkości transmisji? video.stackexchange.com/q/24569/5657 Dzięki.
Ryan

@ LordNeckbeard Domyślam się, że twoja odpowiedź byłaby najlepsza, jeśli będziesz na to gotowa! Nie jestem szczególnie zadowolony z własnego.
Ryan

Nie tylko (jak wskazuje Lord Neckbeard) konieczne jest przekonwertowanie pliku .mp4 na pośredni format .TS, aby konkatenacja się powiodła, ale - co gorsza - odpowiedź ta nawet nie zaspokaja potrzeby wprowadzania danych wejściowych pliki wideo o zgodnej przepływności, liczbie klatek na sekundę, częstotliwości próbkowania, podstawie czasu i czasie trwania. Bez wszystkich 5 z tych wspólnych czynników, plików nie można połączyć (tzn. Połączyć przy użyciu kopiowania strumieniowego ), ale zamiast tego należy je ponownie zakodować.
Ed999,

7

Dla .mp4plików, znalazłem to działa lepiej i szybciej korzystać z narzędzia wiersza polecenia opensource: mp4box. Następnie możesz użyć tego w ten sposób:

mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4

Pobierz go tutaj na większość platform: https://gpac.wp.imt.fr/mp4box/


2
Chociaż może to być przydatne dla kogoś, wymaganie było następujące: „ Próbuję połączyć dwa pliki mp4 za pomocą ffmpeg. Potrzebuję tego, aby był to proces automatyczny ”. Przeczytaj pełne pytanie i postaraj się udzielić właściwej odpowiedzi.
thvs86

5
Ta odpowiedź jest całkowicie trafna. To narzędzie FOSS, które wykonuje tę samą pracę. Można go używać w skrypcie takim jak FFmpeg. Sprawia, że ​​praca jest wykonywana prościej niż jakakolwiek odpowiedź FFmpeg. Zobacz, jak skomplikowani są! Jeden z nich używa Node.js do wywoływania FFmpeg! Niepoczytalność. Zatrzymaj się z winkismem i spróbuj ponownie uczynić StackOverflow użytecznym. Ta strona jest cieniem dawnej jaźni dzięki winks takim jak ty. Poza tym to pytanie jest przykładem „problemu XY”, z którym winny, taki jak ty, powinieneś się zapoznać.
blujay,

Nie ma znaczenia, że ​​mp4box jest narzędziem FOSS. Pytanie zadawane w celu uzyskania odpowiedzi przy użyciu ffmpeg, a nie mp4box.
jramos775

@ thvs86 Jestem tego przykładem. Używam ffmpeg, ponieważ jest to prawdziwy szwajcarski nóż dla mediów. Poszukuję także pomocy w moich konkretnych przypadkach użycia, ponieważ struktura argumentów może być dość złożona (czego dowodem są tutaj różnorodne odpowiedzi). Po raz pierwszy słyszę o mp4box i nie znalazłbym go, gdyby nie ta odpowiedź. Więc daj +1 ode mnie i proszę, pomyśl bardziej o ludziach szukających odpowiedzi niż o bezsensownych punktach internetowych i sztywnych zasadach.
Pavel

4

Oto skrypt, który napisałem, aby połączyć kilka GoPro MP4 w 720p MP4. Mam nadzieję, że to pomoże.

#!/bin/sh
cmd="( "
for i; do
    cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="${cmd} ) | ffmpeg -i - -vb 10000000 -ab 256000 -s 1280x720 -y out-`date +%F-%H%M.%S`.mp4"
echo "${cmd}"
eval ${cmd}

To NIE jest konkatenacja. Ten kod nie łączy danych wejściowych, ponownie je koduje. Spowoduje to pobranie dowolnych plików wideo i zmianę ich na wspólną szybkość transmisji audio i wideo (niezależnie od oryginalnej szybkości przesyłania plików źródłowych lub oryginalnej wielkości ramki). O / p chciał połączyć dwa pliki przy użyciu kopiowania strumieniowego, a nie ponownie je kodować, więc to nie dotyczy zadanego pytania.
Ed999

4

Z dokumentacji tutaj: https://trac.ffmpeg.org/wiki/Concatenate

Jeśli masz pliki MP4, można je bezstratnie powiązać, najpierw transkodując je do strumieni transportowych MPEG-2. W przypadku wideo H.264 i audio AAC można używać:

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

To podejście działa na wszystkich platformach.

Potrzebowałem możliwości kapsułkowania tego w skrypcie wieloplatformowym, więc skorzystałem fluent-ffmpegi wymyśliłem następujące rozwiązanie:

const unlink = path =>
  new Promise((resolve, reject) =>
    fs.unlink(path, err => (err ? reject(err) : resolve()))
  )

const createIntermediate = file =>
  new Promise((resolve, reject) => {
    const out = `${Math.random()
      .toString(13)
      .slice(2)}.ts`

    ffmpeg(file)
      .outputOptions('-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts')
      .output(out)
      .on('end', () => resolve(out))
      .on('error', reject)
      .run()
  })

const concat = async (files, output) => {
  const names = await Promise.all(files.map(createIntermediate))
  const namesString = names.join('|')

  await new Promise((resolve, reject) =>
    ffmpeg(`concat:${namesString}`)
      .outputOptions('-c', 'copy', '-bsf:a', 'aac_adtstoasc')
      .output(output)
      .on('end', resolve)
      .on('error', reject)
      .run()
  )

  names.map(unlink)
}

concat(['file1.mp4', 'file2.mp4', 'file3.mp4'], 'output.mp4').then(() =>
  console.log('done!')
)

1
ffmpeg \
  -i input_1.mp4 \
  -i input_2.mp4 \
  -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' \
  -map [vid] \
  -c:v libx264 \
  -crf 23 \
  -preset veryfast \
  output.mp4

1
Nie tylko zamieszczając odpowiedź, możesz dodać małe wyjaśnienie, które lepiej zrozumie rozwiązanie dla OP i przyszłych czytelników.
Balagurunathan Marimuthu

1
Stworzyło to nowe ciche wideo z obydwoma wejściami odtwarzanymi jednocześnie w tym samym czasie. Spodziewałem się, że konkatenacja utworzy film, w którym odtworzy się input_1.mp4, a następnie input_2.mp4
Alexx Roche

3
To była całkowicie zła odpowiedź. Nie łączyło to filmów, po prostu odtwarzało je po cichu obok siebie, jak wspomniał @AlexxRoche.
Kalob Taulien

1

Scalanie wszystkich plików MP4 z bieżącego katalogu

Osobiście lubię nie tworzyć plików zewnętrznych, które muszę później usunąć, więc moje rozwiązanie było następujące, które zawiera listę numeracji plików (np. file_1_name, file_2_name, file_10_name, file_20_name, file_100_name...)

#!/bin/bash
filesList=""
for file in $(ls -1v *.mp4);do #lists even numbered file
    filesList="${filesList}${file}|"
done
filesList=${filesList%?} # removes trailing pipe
ffmpeg -i "concat:$filesList" -c copy $(date +%Y%m%d_%H%M%S)_merged.mp4

Skopiowałem ten kod do Notatnika i nic się nie stało.
7vujy0f0hy

1
@ 7vujy0f0hy to działa na Linuksie z powłoką bash, może może działać z cygwinem
Pipo

1

Po różnych próbach poniżej skrypt działał dla mnie w Windows 10 PowerShell.

    $files=Get-ChildItem -path e:\ -Filter *.mp4


    $files| ForEach-Object  {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII


    if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}

    E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4

    # Conversion Cleanup
    Remove-Item e:\temp.txt

Tutaj pierwsze dwa wiersze tworzą plik tekstowy temp.txt, który ma następującą treść

file 'e:\first.mp4'
file 'e:\second.mp4'

Trzeci, czwarty wiersz sprawdza, czy ffmpeg jest dostępny na ścieżce i utwórz plik „join.mp4”

Kluczowe różnice w stosunku do innych odpowiedzi są następujące

usage  of -bsf:v hevc_mp4toannexb -an

w przypadku mojego powyższego pliku mp4 może być konieczne użycie innych alternatyw, takich jak poniżej, w zależności od kodowania wideo.

h264_mp4toannexb

Wszystkie takie możliwe filtry Bitstream można znaleźć na stronie https://ffmpeg.org/ffmpeg-bitstream-filters.html


Moje były MP4 pochodzące z kamery CCTV. Bez tego polecenia rozmowa nie generuje pliku wyjściowego. Używam najnowszego ffmpeg z jego strony internetowej.
rahul maindargi

0

Oto moja metoda dołączania do katalogu pełnego plików MP4 przy użyciu podstawiania poleceń i filtru concat wideo (spowoduje to ponowne kodowanie) - pomyślałem, że ktoś inny skorzysta z tego jednowierszowego, szczególnie jeśli masz wiele plików (po prostu dołączył do 17 plików za jednym zamachem):

ffmpeg $(for f in *.mp4 ; do echo -n "-i $f "; done) -filter_complex \
"$(i=0 ; for f in *.mp4 ; do echo -n "[$i:v] [$i:a] " ; i=$((i+1)) ; done \
&& echo "concat=n=$i:v=1:a=1 [v] [a]")" -map "[v]" -map "[a]" output.mp4

Uwaga: to polecenie łączy twoje pliki w kolejności, w której są nazwane (tj. W takiej samej kolejności, w jakiej są wyświetlane, jeśli uruchomisz ls *.mp4) - w moim przypadku każdy z nich miał numer ścieżki, więc działało świetnie.


0

Protokół concat opisany tutaj; https://trac.ffmpeg.org/wiki/Concatenate#protocol

Po wdrożeniu za pomocą nazwanych potoków, aby uniknąć plików pośrednich

Jest bardzo szybki (czytaj: natychmiastowy), nie ma opuszczonych ramek i działa dobrze.

Pamiętaj, aby usunąć nazwane pliki potoków i pamiętaj, aby sprawdzić, czy wideo to H264 i AAC, które możesz zrobić za pomocą ffmpeg -i filename.mp4(sprawdź h264 i wspomnienia)


-1

Akceptowana odpowiedź w formie skryptu PowerShell wielokrotnego użytku

Param(
[string]$WildcardFilePath,
[string]$OutFilePath
)
try
{
    $tempFile = [System.IO.Path]::GetTempFileName()
    Get-ChildItem -path $wildcardFilePath | foreach  { "file '$_'" } | Out-File -FilePath $tempFile -Encoding ascii
    ffmpeg.exe -safe 0 -f concat -i $tempFile -c copy $outFilePath
}
finally
{
    Remove-Item $tempFile
}
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.