Как объединить два файла MP4 с помощью FFmpeg?

445

Я пытаюсь объединить два файла mp4 с помощью ffmpeg. Мне нужно, чтобы это был автоматический процесс, поэтому я выбрал ffmpeg. Я конвертирую эти два файла в файлы .ts, затем объединяю их, а затем пытаюсь кодировать этот объединенный файл .ts. Файлы имеют кодировку h264 и aac, и я надеюсь сохранить качество на том же уровне или максимально приближенным к оригинальному.

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

К сожалению, я получаю следующее сообщение об ошибке от ffmpeg во время кодирования:

[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

Это происходит примерно в середине кодирования, что заставляет меня думать, что нельзя объединить два файла .ts и заставить его работать.

Марк Л
источник

Ответы:

790

FFmpeg имеет три метода конкатенации:

1. Concat видео фильтр

Используйте этот метод, если ваши входные данные не имеют одинаковых параметров (ширина, высота и т. Д.), Или не имеют одинаковые форматы / кодеки, или если вы хотите выполнить какую-либо фильтрацию. (Вы можете перекодировать только те входные данные, которые не совпадают, чтобы они использовали один и тот же кодек и другие параметры, а затем использовать демультиплексор concat, чтобы избежать перекодирования других входных данных).

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

Обратите внимание, что этот метод выполняет перекодирование.

2. concat demuxer

Используйте этот метод, если вы хотите избежать перекодирования, и ваш формат не поддерживает конкатенацию на уровне файлов (большинство файлов, используемых обычными пользователями, не поддерживают конкатенацию на уровне файлов).

$ 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

Для 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. согласованный протокол

Используйте этот метод с форматами, которые поддерживают конкатенацию на уровне файлов (MPEG-1, MPEG-2 PS, DV). Как не использовать с MP4.

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

Этот метод не работает для многих форматов, включая MP4, из-за природы этих форматов и упрощенной конкатенации, выполняемой этим методом.


Если вы сомневаетесь в том, какой метод использовать, попробуйте демоверсию concat.

Также см

rogerdpack
источник
3
Экранирующий символ командной строки Windows - ^; Я также столкнулся с проблемами с кавычками, поэтому он стал: ffmpeg -i concat: input1 ^ | input2 -codec copy output
user423430
1
Полезный ответ. И это стало для меня еще более логичным, когда я прочитал этот вариант: superuser.com/a/607384/74576
Райан,
3
concat demuxer работает для видео, но я теряю звук
Loïc
24
Для использования oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv принимает больше кодеков, чем mp4, но вы также можете попробовать это с mp4). Это -safe 0для последних версий ffmpeg, жалующихся на небезопасное имя файла , и -type fтолько для перечисления файлов. Я добавил | sortсортировать файлы по алфавиту; потому что findчитает их по порядку как сохраненные в файловой системе. Работает также для файлов с пробелами.
Эрик
1
Для меня, в Windows, дважды кавычки работали (вместо одного в вашем примере): ffmpeg -i "concat:input1|input2" -codec copy output. Не нужно убегать от персонажа трубы.
Шовальт
85

ДЛЯ MP4 ФАЙЛОВ

Для файлов .mp4 (которые я получил от DailyMotion.com: 50-минутный телевизионный эпизод, загружаемый только из трех частей, как три видеофайла .mp4), следующее было эффективным решением для Windows 7 и НЕ предполагает перекодирования файлы.

Я переименовал файлы (как file1.mp4 , file2.mp4 , file3.mp4 ) так, чтобы части были в правильном порядке для просмотра полного телевизионного эпизода.

Затем я создал простой командный файл (concat.bat) со следующим содержимым:

:: 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

Пакетный файл , и ffmpeg.exe , оба должны быть помещены в той же папке, что файлы .mp4 быть объединены. Затем запустите пакетный файл. Обычно это займет не более десяти секунд.
,

Приложение (2018/10/21) -

Если вы искали метод указания всех файлов mp4 в текущей папке без повторного ввода, попробуйте это вместо этого в командном файле Windows ( НЕОБХОДИМО включить опцию -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

Это работает на Windows 7, в пакетном файле. Не пытайтесь использовать его в командной строке, потому что он работает только в командном файле!

Ed999
источник
5
Самое простое решение на сегодняшний день.
1934286
Это должен быть лучший и самый простой ответ. Хорошая работа, мой братан. Ты спас мой день.
DysaniazzZ
Это хорошее решение, но разговор о пакетном файле делает этот звук примитивным (как это было сделано в пакетном режиме) и более сложным, чем он есть (поскольку пакетный файл совершенно не нужен). Гораздо понятнее, если вы просто покажете C:\blah>type mylist.txt<ENTER>(чтобы они увидели содержимое этого файла). Тогда ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> также вы должны включить ссылку trac.ffmpeg.org/wiki/Concatenate (эта ссылка даже использует то же имя файла, mylist.txt)
barlop
Это очень хорошее решение, потому что оно избавляет вас от необходимости вводить длинные списки файлов для -iпараметра. На Linux я сделал это: ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtчто даже круче, чем кодирование пакетного скрипта. Во всяком случае, -c copyвыполняет очень быстро (о чем я не знал), и это настоящая магия этого ответа.
Würgspaß
1
С моими файлами mp4 в выходном файле вообще нет звука после запуска вашего concat-кода на Mac с использованием ffmpeg v3.2.2.
kakyo
60

Вот быстрый (занимает менее 1 минуты) и способ без потерь, не требующий промежуточных файлов:

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

«Ls» содержит файлы для присоединения. «Perl» создает файл конкатенации на лету в канал. Часть «-i -» указывает ffmpeg читать из канала

(обратите внимание - в моих файлах не было пробелов или странных вещей - вам нужно соответствующее экранирование оболочки, если вы хотите реализовать эту идею с «жесткими» файлами).

CND
источник
2
Сделал это на OSX, и он работал отлично! Потрясающее, быстрое решение без потерь с небольшими требованиями.
GM Lucid
1
С правильным экранированием для файлов, содержащих пробелы: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
Томас Бачем
4
Вы также можете просто сделать, ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4если ваши файлы с хорошим именем и в порядке. Отлично работал для меня на OS X, именно то, что я хотел.
natebeaty
3
В Linux я использовал этот oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv принимает больше кодеков, чем mp4, но вы также можете попробовать это с mp4). Это -safe 0для последних версий ffmpeg, жалующихся на небезопасное имя файла , и -type fтолько для перечисления файлов. Я добавил | sortсортировать файлы по алфавиту; потому что findчитает их по порядку как сохраненные в файловой системе. Работает также для файлов с пробелами.
Эрик
13
Я должен был добавить этот параметр, чтобы ffmpegон работал:-protocol_whitelist file,tcp,http,pipe
Bensge
45

для файлов MP4:

Если они не совсем одинаковые (100% одинаковый кодек, то же разрешение, тот же тип) MP4-файлы, то сначала вам нужно транскодировать их в промежуточные потоки:

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

НОТА! : Вывод будет похож на первый файл (а не второй)

T.Todua
источник
2
Как показано в моем ответе ниже, перекодирование файлов не является необходимым. FFmpeg может объединять несколько файлов mp4 в один файл mp4 - без каких-либо промежуточных шагов и без какой-либо перекодировки. Единственный случай, когда потребуется какая-либо перекодировка, - это если исходные файлы не являются файлами mp4, но предполагается создать файл mp4 в качестве выходного файла.
Ed999
@T. Тодуа: Мне было бы интересно узнать, какие именно различия между вашими исходными файлами mp4. Используют ли они разные частоты дискретизации (например, 44100 Гц и 48000 Гц)? Или они используют разные скорости передачи данных (например, 128 кбит / с и 64 кбит / с)? В любом случае я не совсем понимаю, как команда -c copy (инструкция stream-copy) изменила бы исходные файлы, чтобы сделать их совместимыми.
Ed999
4
@ T.Todua Привет, команда работает хорошо, когда видео без звуковой дорожки. Однако когда myfile1.mp4 без звука, а myfile2.mp4 со звуком, результат output.mp4 - без звука. Ожидаемый файл output.mp4 должен содержать аудио. Как я могу решить это?
Ответ Чжао
2
@ T.Todua er .... Это очень плохо. Файл1 | файл2 генерирует другое видео с файлом2 | файл1. порядок важен.
Ответ Zhao
1
Я попробовал вашу команду на concat 2 mp4 файлах. Оно работает. Однако звук второго файла становится прерывистым, как голоса Ах-ой-Ээ в произведенной новой конкатенации. у вас есть решение?
superlinux
35

Я пытался объединить три .mp3аудиофайла в один .m4aфайл, и эта команда ffmpeg работает.

Входная команда:

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

Значения: -filter_complex "concat = n = 3: v = 0: a = 1" :

concat означает использование функции конкатенации медиа (соединения).
n означает подтверждение общего количества входных файлов.
v значит есть видео ? используйте 0 = нет видео, 1 = содержит видео.
а средство имеет аудио ? использовать 0 = нет звука, 1 = содержать аудио.
-f означает принудительно установить формат файла (чтобы увидеть все поддерживаемые форматы, используйте ffmpeg -formats)
-vn означает отключить видео (а также -anотключит аудио, если не требуется)
-y означает перезаписать выходные файлы (если выходной файл уже существует).

Для получения дополнительной информации: используйте параметр ffmpeg -h full print all (включая все параметры формата и кодека, очень долго)

Элли Там
источник
1
Если использовать это, -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"оно будет согласовано, но когда некоторые видео со звуком, а некоторые без звука, это не работает, как я могу разобраться в этом. Спасибо -
Ahmad
1
Это работает. Спасибо за подробное объяснение в вашем ответе. Это очень полезно.
Джо Т. Бока
31

В итоге я использовал mpg в качестве промежуточного формата, и это сработало (ПРИМЕЧАНИЕ: это опасный пример, -qscale 0 перекодирует видео ...)

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
По состоянию на этот комментарий -sameqбыл удален. Используйте -qscale 0вместо этого.
Ксавье Хо,
6
-sameqне означает «то же качество» и был удален из ffmpeg, как упомянуто @XavierHo.
Llogan
3
Кажется, стыдно перекодировать видео в промежуточный формат, чтобы объединить два файла. Вы получите потерю поколения. Лучше не углубляться в формат контейнера и использовать concatкоманду в ffmpeg, как это делает @rogerdpack выше.
Рэндалл Кук
8
Почему это принятый ответ? Это очень плохой метод.
Отображаемое имя
4
@SargeBorsch Потому что это работает. Я попробовал все остальное на странице - Ни один из них не работает.
15

Подробную документацию по различным способам объединения в ffmpeg можно найти здесь .

Вы можете использовать «Конкат фильтр» для быстрой конкатенации.

Он выполняет перекодирование. Эта опция лучше всего подходит, когда входы имеют разные видео / аудио форматы.

Для объединения 2 файлов:

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

Для объединения 3 файлов:

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

Это работает как для нескольких типов входных файлов.

SJ00
источник
Можете ли вы указать более подробную информацию о параметрах, которые есть в этом примере?
Разработчик
@Developer: Для объяснения вариантов -> Вики-фильтр
Concat
4
При объединении 3 файлов вы должны использовать concat = n = 3: v = 1: a = 1, а не n = 2
Cynapsis
1
я не получаю конкатенацию без потерь, мой ouput.mp4битрейт видео значительно ниже, чем битрейт входного видео
jasan
Спасибо Cynapsis за указание на это и georgiecasey за обновление команды
SJ00
10

Я обнаружил, что оператор pipe не работает для меня при использовании варианта 3 для объединения нескольких MP4 на Mac в принятом ответе.

Следующий однострочный текст работает на Mac (High Sierra) для объединения mp4s без создания промежуточного файла.

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

Бен Сивер
источник
2
Этот простой ответ - единственный, который действительно работал для меня. Страницы на страницах документации здесь и в других местах, в то время как этот простой однострочный текст - все, что требуется - и фактически работает. Спасибо.
Блюджей,
10

Здесь 2 чистых решения Bash, используя только ffmpegи не используя

  • промежуточный файл
  • Perl, Python, ни JavaScript

Однострочное решение с использованием 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

Функция, которая принимает 0 или 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
}

Примечание: пробовал некоторые решения в этой теме, и никто не удовлетворил меня

Флоран Рокес
источник
9

основываясь на ответах rogerdpack и Ed999, я создал свою версию .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

он объединяет все *.mp4файлы в текущей папке вjoined-out.mp4

проверено на Mac.

полученный размер файла является точной суммой моих 60 проверенных файлов. Не должно быть никаких потерь. Как раз то, что мне было нужно

Александр перфилов
источник
8

это работало для меня (на окнах)

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

пример...

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

питон

Используя некоторый код Python, чтобы сделать это с таким количеством mp4, которое есть в папке (установите python с python.org, скопируйте и вставьте и сохраните этот код в файл с именем mp4.py и запустите его из cmd, открытого в папке с python mp4.py и все mp4 в папке будут объединены)

import glob
import os

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

Версия 2 с Python

Взято из моего поста в моем блоге , вот как я делаю это в python:

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()
Giovanni G. PY
источник
2
Протокол concat не должен использоваться с MP4 и не будет работать, как указано в принятом ответе .
Llogan
@LordNeckbeard Интересно, знаете ли вы ответ на этот вопрос ffmpeg о объединении 2 видео MP4 при указании битрейта на выходе? video.stackexchange.com/q/24569/5657 Спасибо.
Райан
@LordNeckbeard Я думаю, что ваш ответ будет лучшим, если вы готовы к этому! Я не особенно доволен своим собственным.
Райан
1
Мало того (как указывает Лорд Некберд), необходимо преобразовать файл .mp4 в промежуточный формат .TS, чтобы конкатенация была успешной, но, возможно, даже хуже, этот ответ даже не начинает удовлетворять потребность в вводе видеофайлы должны соответствовать битрейту, частоте кадров, частоте дискретизации, временной базе и длительности. Без всех 5 из этих общих факторов файлы не могут быть объединены (т.е. объединены с использованием потокового копирования ), но вместо этого должны быть перекодированы.
Ed999
7

Для .mp4файлов, я нашел , что это работает лучше и быстрее использовать инструмент командной строки с открытым исходным кодом: mp4box. Тогда Вы можете использовать это так:

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

Загрузите его здесь для большинства платформ: https://gpac.wp.imt.fr/mp4box/

Марио
источник
2
Хотя это может быть полезно для кого-то, требование было: « Я пытаюсь объединить два файла mp4 с помощью ffmpeg. Мне нужно, чтобы это был автоматический процесс ». Пожалуйста, прочитайте полный вопрос и попробуйте дать ответ, который на месте.
thvs86
5
Этот ответ полностью уместен. Это инструмент FOSS, который делает ту же работу. Он может быть использован в скрипте, как FFmpeg. Это делает работу проще, чем любой из ответов FFmpeg. Посмотрите, как они сложны! Один из них использует Node.js для вызова FFmpeg! Insanity. Пожалуйста, остановитесь на вонкизме и попробуйте снова использовать StackOverflow. Этот сайт - тень своего прежнего я благодаря таким чудесам, как ты. Кроме того, этот вопрос является примером «проблемы XY», с которой должен быть знаком такой вон, как вы.
Блюджей
Неважно, что mp4box - это инструмент FOSS. Вопрос задавался для ответов, используя ffmpeg, а не mp4box.
jramos775
@ thvs86 Я один из примеров этого. Я использую ffmpeg, так как это настоящий швейцарский нож для СМИ. Я также ищу помощь в моих конкретных случаях использования, так как структура аргументов может быть довольно сложной (что подтверждается различными ответами здесь). Это первый раз, когда я слышу о mp4box, и я не нашел бы его, если бы не этот ответ. Так что +1 от меня и, пожалуйста, пожалуйста, больше думайте о людях, ищущих ответы, чем о бессмысленных пунктах Интернета и жестких правилах.
Павел
4

Вот скрипт, который я сделал, чтобы объединить несколько MP4 в GoPro в MP4 в формате 720p. Надеюсь, это поможет.

#!/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}
Рейд Эллис
источник
Это НЕ объединяет. Этот код не объединяет входы, он перекодирует их. Это берет любые произвольные видеофайлы и изменяет их на общий битрейт аудио и видео (независимо от исходного битрейта исходных файлов или исходного размера кадра). O / p хотел объединить два файла, используя потоковое копирование, а не перекодировать их, так что это не решает заданный вопрос.
Ed999
4

Из документации здесь: https://trac.ffmpeg.org/wiki/Concatenate

Если у вас есть файлы MP4, их можно объединить без потерь , сначала перекодировав их в транспортные потоки MPEG-2. С видео H.264 и аудио AAC можно использовать следующее:

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

Этот подход работает на всех платформах.

Мне нужна была возможность инкапсулировать это в кроссплатформенный скрипт, поэтому я использовал fluent-ffmpegи придумал следующее решение:

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!')
)
itslittlejohn
источник
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
Не просто опубликовав ответ, вы можете добавить небольшое объяснение, которое лучше понимает решение для OP и будущих читателей.
Балагурунатан Маримуту
1
Это создало новое беззвучное видео с обоими входами, воспроизводящимися в одно и то же время рядом друг с другом. Я ожидал, что конкатенация создаст видео, где воспроизводится input_1.mp4, а затем input_2.mp4
Alexx Roche
3
Это был неправильный ответ полностью. Это не относится к видео, а просто воспроизводит их молча рядом, как упомянул @AlexxRoche.
Калоб Таульен
1

Слияние всех файлов mp4 из текущего каталога

Мне лично не нравится создавать внешний файл, который я должен затем удалить, поэтому мое решение было следующим: список нумерации файлов (например 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
Pipo
источник
Я скопировал этот код в Блокнот, и ничего не произошло.
7vujy0f0hy
1
@ 7vujy0f0hy это работает на linux с оболочкой bash, может быть, это может работать и с cygwin
Pipo
1

После различных попыток ниже скрипт работал на 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

Здесь первые две строки создают текстовый файл temp.txt, который имеет следующий контент

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

3-я, 4-я строки проверяют, доступен ли ffmpeg в path, и создают «join.mp4»

Основные отличия от других ответов приведены ниже

usage  of -bsf:v hevc_mp4toannexb -an

для моего файла mp4 выше, возможно, вам придется использовать другие альтернативы, как показано ниже, в зависимости от вашей кодировки видео.

h264_mp4toannexb

Все такие возможные фильтры битового потока можно найти по адресу https://ffmpeg.org/ffmpeg-bitstream-filters.html.

Рахул Майндарги
источник
Мои были MP4 с камеры видеонаблюдения. Без этой команды диалог не может генерировать выходной файл. Я использую последнюю версию ffmpeg со своего веб-сайта.
Рахул Майндарги
0

Вот мой метод соединения каталога, заполненного файлами MP4, с использованием подстановки команд и фильтра видео concat (это перекодирует) - я подумал, что кому-то еще пригодится эта строка, особенно если у вас много файлов (я просто присоединился 17 файлов одним махом)

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

Обратите внимание, что эта команда объединяет ваши файлы в том порядке, в котором они названы (то есть в том же порядке, в котором они представлены, если вы запускаете ls *.mp4) - в моем случае у каждого из них был номер дорожки, поэтому она отлично работала.

Питер
источник
0

Протокол Concat описан здесь; https://trac.ffmpeg.org/wiki/Concatenate#protocol

При реализации с использованием именованных каналов, чтобы избежать промежуточных файлов

Очень быстрый (читай: мгновенный), без пропущенных кадров и работает хорошо.

Не забудьте удалить файлы именованных каналов и не забудьте проверить, является ли видео H264 и AAC, что вы можете сделать просто ffmpeg -i filename.mp4(проверьте h264 и упоминания aac)

Роэль Ван де Паар
источник
-1

Принятый ответ в виде многоразового скрипта PowerShell

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
}
fjch1997
источник