Як об'єднати два файли MP4 за допомогою FFmpeg?


443

Я намагаюся об'єднати два файли 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

Це відбувається приблизно на півдорозі кодування, що змушує мене думати, що ви не можете скопіювати два.

Відповіді:


786

FFmpeg має три способи конкатенації:

1. Фільтр лаконічного відео

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

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, через характер цих форматів та спрощену конкатенацію, виконану цим методом.


Якщо ви сумніваєтесь у тому, який метод використовувати, спробуйте демаксер-конмат.

Також див


3
Символ втечі командного рядка Windows - ^; Я також зіткнувся з проблемами з лапками, так що це стало: ffmpeg -i concat: input1 ^ | input2 -codec вихід копії
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, які скаржаться на ім'я файлу Unsafe , і -type fє лише для переліку файлів. Я додав | sortдля сортування файлів за алфавітом; тому що findчитає їх у порядку, як збережено у файловій системі. Працює також для файлів з пробілами.
Ерік

1
Для мене, в Windows, двічі лапки працювали (замість одного в вашому прикладі): ffmpeg -i "concat:input1|input2" -codec copy output. Не потрібно уникати символу труби.
Шовалт

83

ДЛЯ ФАЙЛІВ 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, у пакетному файлі. Не намагайтеся використовувати його в командному рядку, оскільки він працює лише у пакетному файлі!


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 читати з труби

(зауважте - у моїх файлах не було пробілів або дивних речей у них - вам знадобиться відповідне втеча з оболонок, якщо ви хочете зробити цю ідею з "жорсткими" файлами).


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, які скаржаться на ім'я файлу Unsafe , і -type fє лише для переліку файлів. Я додав | sortдля сортування файлів за алфавітом; тому що findчитає їх у порядку, як збережено у файловій системі. Працює також для файлів з пробілами.
Ерік

13
Мені довелося додати цей параметр, щоб ffmpegвін працював:-protocol_whitelist file,tcp,http,pipe
Bensge

44

для файлів 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

ПРИМІТКА! : Вихід буде як перший файл (а не другий)


2
Як показано у моїй відповіді, нижче перекодування файлів не є необхідним. FFmpeg може об'єднати декілька файлів mp4 в один файл mp4 - без проміжних кроків і без повторного кодування. Єдиний випадок, коли потрібно було б перекодування, якщо вихідні файли не є mp4-файлами, але намір створити файл mp4 як вихідний файл.
Ed999

@T. Todua: Мені було б цікаво дізнатися, які саме відмінності між вашими двома вихідними файлами mp4. Вони використовують різні частоти вибірки (наприклад, 44 100 Гц і 48 000 Гц)? Або вони використовують різні бітові швидкості (наприклад, 128 кбіт / с і 64 кбіт / с)? У будь-якому такому випадку я не зовсім розумію, як команда -c копія (посібник копіювання потоку) змінює вихідні файли, щоб зробити їх сумісними.
Ed999

4
@ T.Todua Привіт, команда працює добре, коли відео без аудіозапису. Однак, коли myfile1.mp4 є без звуку, а myfile2.mp4 - зі звуком, результат output.mp4 - без звуку. Очікуваний вихід.mp4 повинен містити звук. Як я можу це вирішити?
ВідповідьZhao

2
@ T.Todua er .... Це дуже погано. Файл1 | файл2 генерує різні відео з файлом2 | файл1. порядок важливий.
ВідповідьZhao

1
Я спробував вашу команду на файлах concat 2 mp4. Це працює. Однак аудіо другого файлу стає хитким, як голоси Ah-oh-Ee у новому конкатенації. у вас є виправлення на це?
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 всі параметри друку (включаючи всі параметри формату та специфічного кодеку, дуже довгі)


1
Якщо я використаю це, -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"то це буде коротко, але коли деякі відео з аудіо, а деякі без аудіо, це не працює, як я можу це розібрати. Спасибі -
Ахмад

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 вище.
Randall Cook

8
Звідки це прийнята відповідь? Це дуже поганий метод.
Відображати ім'я

4
@SargeBorsch Тому що це працює. Я спробував все інше на сторінці - жоден з них не працює.

14

Детальну документацію про різні способи конкатенації у ffmpeg можна знайти тут .

Ви можете використовувати "фільтр Concat" для швидкого з'єднання.

Він виконує перекодування. Цей варіант найкращий, коли входи мають різні відео / аудіо формати.

Для об'єднання 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

Це працює так само, як і для декількох типів вхідних файлів.


чи можете ви вказати більше деталей щодо параметрів, які ви маєте в цьому прикладі?
Розробник

@Developer: для пояснення варіантів -> Concat filter wiki
SJ00

4
При об'єднанні 3-х файлів слід використовувати concat = n = 3: v = 1: a = 1 не n = 2
Cynapsis

1
Я не отримую збиток без втрат, моє ouput.mp4відео бітрейт значно нижче, ніж бітрейт вхідного відео
Jasan

Дякуємо Cynapsis за те, що вказав на це та georgiecasey за оновлення команди
SJ00

10

Я виявив, що оператор труби не працює для мене під час використання варіанту 3 для отримання декількох MP4 на Mac у прийнятій відповіді.

Наступний однокласник працює на Mac (High Sierra), щоб об'єднати mp4, без необхідності створення файлу посередника.

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


2
Ця проста відповідь - єдина, яка насправді працювала на мене. Сторінки на сторінках документації тут і в інших місцях, в той час як цей простий однокласник - це все, що потрібно - і фактично працює. Дякую.
blujay

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 тестованих файлів. Не повинно бути ніяких втрат. Тільки те, що мені було потрібно


9

це працювало для мене (на windows)

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()

1
Протокол concat не повинен використовуватися з MP4 і не працюватиме, як зазначено у прийнятій відповіді .
логіан

@LordNeckbeard Цікаво, чи знаєте ви відповідь на це питання ffmpeg про об'єднання відео у форматі 2 MP4, визначаючи вихідний бітрейт? video.stackexchange.com/q/24569/5657 Дякую
Райан

@LordNeckbeard Я гадаю, що ваша відповідь була б найкращою, все-таки, якщо ви готові до цього! Я не особливо задоволений своїм.
Райан

Мало того, що (як вказує лорд Некбард), необхідно конвертувати файл .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! Божевілля. Зупиніться на winkism та спробуйте зробити StackOverflow знову корисним. Цей сайт є тінню свого колишнього самоврядування завдяки підморгуванням, як ви. Крім того, це питання є прикладом "Проблеми XY", з якою ви, начебто, повинні ознайомитись.
blujay

Не має значення, що mp4box є інструментом FOSS. Питання, на яке було запропоновано відповіді, використовуючи ffmpeg, а не mp4box.
jramos775

@ thvs86 Я один із прикладів цього. Я використовую ffmpeg, оскільки це справжній швейцарський ніж для ЗМІ. Я також шукаю допомоги у своїх конкретних випадках використання, оскільки структура аргументів може бути досить складною (про що свідчать різноманітні відповіді тут). Це перший раз, коли я чую про mp4box, і я б не знайшов його, якби не ця відповідь. Тому +1 від мене, і, будь ласка, більше думайте про людей, які шукають відповідей, ніж про безглузді точки Інтернет та жорсткі правила.
Павло

4

Ось сценарій, який я створив для об'єднання декількох GoPro mp4 в 720p mp4. Сподіваюся, це допоможе.

#!/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!')
)

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
Не лише публікуючи відповідь, ви можете додати мало пояснень, які краще розуміють рішення як ОП, так і майбутнім читачам.
Балагурутана Марімутху

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

Я скопіював цей код у Блокнот, і нічого не сталося.
7vujy0f0hy

1
@ 7vujy0f0hy це працює на Linux з bash оболонкою, можливо, це може працювати з cygwin
Pipo

1

Після різних спроб нижче сценарій працював для мене на Windows 10 powerhell.

    $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 доступний у шляху і створює "joined.mp4"

Ключові відмінності від інших відповідей наведені нижче

usage  of -bsf:v hevc_mp4toannexb -an

для мого файлу mp4, який працював вище, вам може знадобитися використовувати інші альтернативи, як нижче, залежно від кодування відео.

h264_mp4toannexb

Усі такі можливі фільтри Bitstream можна знайти на веб- сайті https://ffmpeg.org/ffmpeg-bitstream-filters.html


Мої були MP4, що надходили від камери відеоспостереження. Без цієї команди розмова не може генерувати вихідний файл. Я використовую останній ffmpeg з його веб-сайту.
rahul maindargi

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

Конкретний протокол, описаний тут; 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.