Dołącz pliki MP4 w systemie Linux

31

Chcę połączyć dwa pliki MP4, aby utworzyć jeden. Strumienie wideo są kodowane w h264, a dźwięk w aac. Nie mogę ponownie zakodować filmów do innego formatu ze względów obliczeniowych. Ponadto nie mogę używać żadnych programów GUI, wszystkie operacje muszą być wykonywane za pomocą narzędzi wiersza poleceń systemu Linux. FFmpeg nie może tego zrobić dla plików MPEG4, więc zamiast tego użyłem MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

Niestety wszystko się pomieszało. Pomyślałem, że problem polega na tym, że dźwięk był w aac, więc transkodowałem go w formacie mp3 i ponownie użyłem MP4Box. W tym przypadku dźwięk jest w porządku przez pierwszą połowę newvideo.mp4(odpowiadający video1.mp4), ale wtedy nie ma dźwięku i nie mogę również nawigować w filmie.

Moja kolejna myśl była taka, że ​​w strumieniach audio i wideo występowały niewielkie rozbieżności w długości, które powinienem naprawić. Tak więc dla każdego wejściowego wideo podzieliłem strumienie wideo i audio, a następnie połączyłem je z opcją -shortest w FFmpeg.

Tak więc dla pierwszego filmu uruchomiłem:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

Podobnie w przypadku drugiego wideo, a następnie wykorzystano MP4Box jak poprzednio. Niestety to też nie działało. Jedyny sukces, jaki odniosłem, to dołączenie strumieni wideo osobno (tj. Videostream1.mp4 i videostream2.mp4) oraz strumieni audio (tj. Audiostream1.m4a i audiostream2.m4a), a następnie dołączyłem do wideo i audio w końcowym pliku. Jednak synchronizacja zostanie utracona w drugiej połowie filmu. Konkretnie, istnieje 1 sekundowe opóźnienie audio i wideo. Wszelkie sugestie są bardzo mile widziane.

Jose Armando
źródło
„FFmpeg nie może tego zrobić dla plików MPEG4, więc zamiast tego użyłem MP4Box”. Czy masz na myśli plik MP4? czy oba strumienie audio-wideo używają tych samych parametrów kodowania (szerokość, wysokość, SPS, PPS, liczba klatek na sekundę,
za pomocą ffprobe widzę, że strumienie audio mają identyczne atrybuty. Strumienie wideo mają te same wymiary, ale różne szybkości. Dla pierwszego filmu wideo: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24,97 fps, 45k tbr, 90k tbn, 90k tbc, natomiast dla drugiego wideo: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24.91 fps, 45k tbr, 90k tbn, 90k tbc. Czy wierzysz, że to jest źródło moich problemów?
MP4 obsługuje łączenie wideo / audio o różnych charakterystykach przy użyciu różnych ścieżek dla różnych filmów, ale odtwarzacze nie są tak inteligentne.
rajneesh
Odpowiedź na twoje pytanie znajduje się już w FAQ ffmpeg: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Odpowiedzi:

31

Najlepszym obecnie sposobem na to jest demuxer konkat . Najpierw utwórz plik o nazwie inputs.txttak sformatowany:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

Następnie po prostu uruchom następującą komendę ffmpeg:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

Zobacz także konkatenację w ffmpegFAQ .


Trzymam poniższe dla korzyści każdego, kto używa starszych wersji ffmpeg.

Najnowsze wersje ffmpeg potrafią to zrobić: najpierw musisz przełożyć pliki na strumienie transportowe MPEG (dość lekki procesor, ponieważ zmienia tylko format kontenera):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Jeśli to powoduje błąd dotyczący h264, może być konieczne użycie:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Musisz to zrobić osobno dla każdego pliku wejściowego. Aby połączyć pliki razem, użyj:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

Jeśli spowoduje to błąd dotyczący AAC, być może będziesz musiał użyć

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

Jeśli twój system obsługuje nazwane potoki, możesz to zrobić bez tworzenia plików pośrednich.

mkfifo temp0 temp1

Będziesz musiał wykonać następujące czynności w trzech oddzielnych wirtualnych terminalach:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

Jeśli output.mp4 już istnieje, trzeci ffmpeg zapyta, czy chcesz go zastąpić, ale zrobi to po uzyskaniu dostępu do FIFO , a to spowoduje zamknięcie pierwszego ffmpegs. Upewnij się więc, że wybrałeś nieużywaną nazwę pliku wyjściowego.

Może to nie działać, jeśli pliki wejściowe są różne - uważam, że różnice w szybkości transmisji są OK, ale rozmiar klatki, częstotliwość klatek itp. Muszą się zgadzać.

zła
źródło
wielu thx mate, pracował jak urok
Jose Armando
2
@DaveJarvis Nie tak; to wiadomość celowo i złośliwie rozpowszechniana przez zespół libav, który jest grupą programistów, którzy odeszli od projektu ffmpeg, aby opracować avconv (i zmienili nazwę, ponieważ nie mogli zabezpieczyć praw autorskich do nazwy ffmpeg). Zobacz, kto może mi powiedzieć różnicę i relacje między ffmpeg, libav i avconv? po nieco więcej informacji.
evilsoup
2
*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.to wiadomość, którą widzę teraz podczas bieganiaffmpeg
Lord Loh.
@LordLoh. Zobacz link w moim poprzednim komentarzu.
evilsoup
1
Ta odpowiedź nie odpowiada - jak połączyć MP4 zavconv
Lordem Loh.
7

W przypadku mp4 jedynym działającym rozwiązaniem, jakie znalazłem, było MP4Box z pakietu gpac

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

lub polecenie jest

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

z mencoderem i avconvem nie mogłem sprawić, by działało :-(

Philippe Gachoud
źródło
2

Dzięki za skrypt dvo. To był dla mnie świetny punkt wyjścia. Nie miałem problemu z używaniem nazwanych potoków, więc dostosowałem skrypt do ich używania. Dodatkowo poprawiłem go, aby działał z nazwami plików ze spacjami. Dane wyjściowe do nazwanych potoków nie są przesyłane, dopóki nie zaczniesz z nich czytać, stąd potrzeba podłożenia początkowych zadań remuxu znakiem & przed ostatnim wywołaniem avconv. Ponadto nie zapomnij użyć opcji -c copy, bo w końcu przekodujesz całą partię.

#!/bin/bash
for FILE in "$@"; do
   TAG=$(echo "$FILE" | sed -e s/[^A-Za-z0-9.]/_/g)
   mkfifo $TAG.mp4concatpipe
   avconv -loglevel "quiet" -i "$FILE"  -f mpegts -c copy -bsf h264_mp4toannexb -y $TAG.mp4concatpipe &
   IN=$IN\|$TAG.fifo
done

IN=${IN#\|}
avconv -i concat:$IN -c copy out.mp4
rm *.mp4concatpipe
znak
źródło
Z jakiegoś powodu daje mi to komunikat „concat: first.m4v.fifo | second.m4v.fifo: Błąd takiego pliku lub katalogu”. Nawet z cudzysłowami (-i concat: „$ IN” lub -i ”concat: $ IN ”). MP4Box sugeruje w innej odpowiedzi poniżej, jednak działa świetnie!
vorburger
2

Na komputerze Mac (macOS 10.13 High Sierra) z powodzeniem zastosowałem następujące:

for f in *.m4a; do echo "file '$f'" >> mylist.txt; done

Zmień kolejność jak wyżej, jeśli to konieczne, podobnie (zwróć uwagę, że plik ./ został usunięty - ścieżka spowodowała, że ​​ffmpeg zgłosi błąd niebezpiecznej nazwy pliku).

Następnie musiałem usunąć kodek i szybkość transmisji określoną dla domyślnego ffmpeg MacPorts, aby go polubić:

ffmpeg -f concat -i mylist.txt  output.m4a
Robert Cole
źródło
Witamy w Super User !, Przeczytaj uważnie pytanie ponownie. Twoja odpowiedź nie odpowiada na pierwotne pytanie dotyczące Linuksa. Jeśli uważasz, że to zadziała na Linuksie, dodaj to, aby przyszli czytelnicy mieli jasne zrozumienie, poza tym ponownie witamy superużytkownika i dziękuję za twój wkład. Poświęć kilka minut i przeczytaj: - superuser.com/help. Odpowiedź: superuser.com/help/how-to-answer .
mic84
2

Oto jedna linijka, która sprawia, że ​​jest to o wiele łatwiejsze. Robi wszystko, co trzeba zrobić, aby w końcu dostarczyć Ci jeden wynikowy plik wideo. Twoje zdrowie!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts
Anonimowy
źródło
1

Dzięki evilsoup; oto mały skrypt automatyzujący proces, wykorzystujący najnowszą wersję avconv.
BTW, nazwane potoki nie działały dla mnie (wyjście do nich utknęło).

   #!/bin/bash

    for FILE in $@; do
      avconv -i $FILE -map 0 -f mpegts -bsf h264_mp4toannexb -c:v copy -y $FILE.tmp
      IN=$IN\|$FILE.tmp
    done

    IN=${IN#\|}
    avconv -i concat:"$IN" out.mp4

    for FILE in $@; do
      rm $FILE.tmp
    done
dvo
źródło
0

Cieszę się wielkim sukcesem z

for f in ./*.m4a; do echo "file '$f'" >> mylist.txt; done

być może trzeba nieco zmienić kolejność mylist.txt

ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a

wersja ffmpeg 2.2.3

Benzoes
źródło