Приєднуйтесь до файлів mp4 в Linux


31

Я хочу приєднати два файли mp4, щоб створити один. Відеопотоки кодуються в h264, а аудіо в AAC. Я не можу перекодувати відео в інший формат через обчислювальні причини. Крім того, я не можу використовувати жодні програми GUI, вся обробка повинна виконуватися з утилітами командного рядка Linux. FFmpeg не може цього зробити для файлів mpeg4, тому замість цього я використовував MP4Box:

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

На жаль, звук все змішується. Я подумав, що проблема полягає в тому, що аудіо було в AAC, тому я перекодував його в mp3 і знову використовував MP4Box. У цьому випадку звук чудово підходить для першої половини newvideo.mp4(що відповідає video1.mp4), але потім їх немає звуку, і я також не можу орієнтуватися у відео.

Наступною моєю думкою було те, що аудіо- та відеопотоки мали невеликі розбіжності в їх довжині, які я повинен виправити. Тому для кожного вхідного відео я розділив потоки відео та аудіо, а потім з'єднав їх із найкоротшим варіантом у FFmpeg.

Таким чином, для першого відео я запустив:

 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

Аналогічно для другого відео, а потім використовується MP4Box, як раніше. На жаль, і це не спрацювало. Єдиний успіх у мене був, коли я приєднався до відеопотоків окремо (тобто videostream1.mp4 та videostream2.mp4) та аудіо потоків (тобто audiostream1.m4a та audiostream2.m4a), а потім приєднався до відео та аудіо у фінальному файлі. Однак синхронізація втрачена для другої половини відео. Конкретно, є затримка аудіо та відео на 1 секунду. Будь-які пропозиції дійсно вітаються.


"FFmpeg не може цього зробити для файлів mpeg4, тому замість цього я використовував MP4Box" ти маєш на увазі файл MP4? чи обидва аудіо-відео потоки використовують однакові параметри кодування (ширина, висота, SPS, PPS, частота кадрів, вибірки, кількість каналів?

використовуючи ffprobe, я бачу, що аудіопотоки мають однакові атрибути. Відеопотоки мають однакові розміри, але різну швидкість. Для першого відео Відео: h264, 720x592, 277 кб / с, PAR 18944: 12915 DAR 512: 287, 24,97 fps, 45k tbr, 90k tbn, 90k tbc, а для другого Відео: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24,91 fps, 45k tbr, 90k tbn, 90k tbc. Чи вірите ви, що це джерело моїх проблем?

MP4 підтримує приєднання відео / аудіо з різними характеристиками, використовуючи різні доріжки для різних відео, але програвач не такий розумний.
rajneesh


На ваше запитання вже відповіли в ffmpeg FAQ: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Відповіді:


31

Найкращий спосіб зробити це на даний момент за допомогою демаксера . Спочатку створіть файл під назвою inputs.txtвідформатований так:

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

Потім просто запустіть цю команду ffmpeg:

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

Дивіться також конкатенацію в ffmpegFAQ .


Я зберігаю наступне тут для вигоди тих, хто використовує старіші версії ffmpeg.

Останні версії ffmpeg можуть це зробити: вам доведеться спочатку перетворити файли в транспортні потоки mpeg (досить процесорне світло, оскільки це лише змінює формат контейнера):

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

Якщо це видає помилку щодо h264, можливо, вам доведеться скористатися:

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

Вам доведеться робити це окремо з кожним вхідним файлом. Щоб об'єднати файли разом, використовуйте:

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

Якщо це видає помилку про Aac, можливо, вам доведеться скористатися

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

Якщо ваша система підтримує названі труби, ви можете це зробити без створення проміжних файлів.

mkfifo temp0 temp1

Вам потрібно буде виконати наступне в трьох окремих віртуальних терміналах:

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

Якщо output.mp4 вже існує, третій ffmpeg запитає вас, чи хочете ви його перезаписати, але це зробить це після того, як він отримає доступ до FIFO , і це зробить перший ffmpegs закритим. Тому переконайтесь, що ви вибрали невикористане ім'я для вихідного файлу.

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


багато товаришів THX, працювали як шарм
Хосе Армандо

2
@DaveJarvis Не так; це повідомлення, навмисне та зловмисно розповсюджене командою libav, яка є купою розробників, які відійшли від проекту ffmpeg для розробки avconv (і змінили ім'я, оскільки не змогли захистити авторські права на ім'я ffmpeg). Дивіться, хто може мені сказати різницю та відношення між ffmpeg, libav та avconv? для отримання додаткової інформації.
зол

2
*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.- це повідомлення, яке я зараз бачу під час запускуffmpeg
лорд Лох.

@LordLoh. Дивіться посилання в моєму попередньому коментарі.
evilsoup

1
Ця відповідь не відповідає - як об'єднати mp4 зavconv
лорд Лох.

7

Для mp4 єдине робоче рішення, яке я знайшов, було з MP4Box з пакету 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

або команда є

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

з mencoder та avconv я не міг змусити його працювати :-(


2

Дякую за сценарій двоє. Це було чудовою відправною точкою для мене. У мене не було проблем із використанням названих труб, тому я адаптував сценарій для їх використання. Плюс я зафіксував це для роботи з іменами файлів з пробілами в них. Вихід з названих труб не "йде", поки ви не почнете читати з них, отже, потрібно передумати початкові завдання ремуксації перед & остаточним викликом до avconv. Плюс до цього, не забудьте скопіювати -c-копію, інакше ви перезашифруєте всю партію.

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

Чомусь це дає мені "concat: first.m4v.fifo | second.m4v.fifo: Немає такого помилки у файлі чи каталозі". Навіть з цитатами (-i concat: "$ IN" або -i "concat: $ IN "). MP4Box, запропонований в іншій відповіді нижче, проте працює чудово!
vorburger

2

На Mac (macOS 10.13 High Sierra) я успішно використовував наступне:

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

Якщо потрібно, упорядкуйте так само, як зазначено вище (зауважте, що ./ був видалений - шлях викликав помилку імені файлу ffmpeg).

Тоді мені довелося видалити кодек і бітрейт, вказані для MacPorts за замовчуванням ffmpeg, щоб він сподобався:

ffmpeg -f concat -i mylist.txt  output.m4a

Ласкаво просимо до Супер Користувача !, Прочитайте запитання ще раз уважно. Ваша відповідь не відповідає на початкове запитання про Linux. Якщо ви вірите, що це буде працювати на Linux, будь ласка, додайте, що таким чином майбутні читачі матимуть чітке розуміння, окрім того, що знову вітається супер-користувачем та дякую за ваш внесок. Будь ласка, пройдіть кілька хвилин і прочитайте: - superuser.com/help. Відповідь: superuser.com/help/how-to-answer .
mic84

2

Ось однолінійний вклад, який робить це набагато простіше. Він робить усе необхідне для того, щоб нарешті надати вам один отриманий відеофайл. Ура!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts

1

Спасибі злу; ось невеликий сценарій для автоматизації процесу, використовуючи новітні avconv.
BTW, названі труби для мене не працювали (вихід на них застряг).

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

0

Насолоджувався великим успіхом с

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

можливо, вам доведеться трохи змінити порядок mylist.txt

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

ffmpeg версія 2.2.3

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