Присоединяйтесь к mp4 файлам в Linux

31

Я хочу объединить два файла mp4, чтобы создать один. Видеопотоки кодируются в h264, а аудио - в aac. Я не могу перекодировать видео в другой формат по вычислительным причинам. Кроме того, я не могу использовать какие-либо программы с графическим интерфейсом, вся обработка должна выполняться с помощью утилит командной строки Linux. FFmpeg не может сделать это для файлов mpeg4, поэтому вместо этого я использовал MP4Box:

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

К сожалению, звук все перепутал. Я думал, что проблема была в том, что звук был в aac, поэтому я перекодировал его в mp3 и снова использовал MP4Box. В этом случае звук подходит для первой половины newvideo.mp4(соответствует video1.mp4), но затем звук отсутствует, и я не могу перемещаться по видео также.

Моей следующей мыслью было, что аудио и видео потоки имеют небольшие несоответствия в их длине, которые я должен исправить. Поэтому для каждого входного видео я разделял видео и аудио потоки, а затем соединял их с опцией -shortest в 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 я вижу, что аудиопотоки имеют идентичные атрибуты. Видеопотоки имеют одинаковые размеры, но разные скорости. Для 1-го видео Видео: h264, 720x592, 277 кбит / с, PAR 18944: 12915 DAR 512: 287, 24,97 кадр / с, 45 тыс. Тбр, 90 тыс. Тбит / с, 90 тыс. Тбит / с, а для второго видео: h264, 720х592, 226 кбит / с, PAR 481: 330 DAR 39:22, 24,91 кадр / с, 45 тыс. Тбр, 90 тыс. Тбн, 90 тыс. Тбит / с. Вы верите, что это источник моих проблем?
MP4 поддерживает объединение видео / аудио с разными характеристиками, используя разные дорожки для разных видео, но плеер не настолько умен.
Раджниш
попробуйте этот stackoverflow.com/questions/5415006/...
Дайя
На ваш вопрос уже есть ответы в ffmpeg FAQ: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Ответы:

31

Лучший способ сделать это в настоящее время - использовать демоверсию concat . Сначала создайте файл с именем 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. Поэтому убедитесь, что вы выбрали неиспользуемое имя для выходного файла.

Это может не сработать, если ваши входные файлы отличаются - я считаю, что различия в скорости передачи в порядке, но размер кадра, частота кадров и т. Д. Должны совпадать

evilsoup
источник
много спасибо друг, работал как шарм
Хосе Армандо
2
@DaveJarvis Не так; Это сообщение было преднамеренно и злонамеренно распространено командой libav, которая является группой разработчиков, которые отошли от проекта ffmpeg для разработки avconv (и изменили имя, потому что не смогли защитить авторские права на имя ffmpeg). См. Кто может сказать мне разницу и отношения между ffmpeg, libav и avconv? для немного больше информации.
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.это сообщение, которое я вижу сейчас на бегу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

Спасибо за сценарий dvo. Это была отличная отправная точка для меня. У меня не было проблем с использованием именованных каналов, поэтому я адаптировал скрипт для их использования. Плюс я исправил это, чтобы работать с именами файлов с пробелами в них. Вывод в именованные каналы не «идет» до тех пор, пока вы не начнете читать из них, следовательно, необходимо задавать фоновые задачи первоначального remux с помощью & перед последним вызовом avconv. Кроме того, не забывайте использовать -c copy, иначе вы перекодируете всю партию.

#!/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 выдавать ошибку небезопасного имени файла).

Затем мне пришлось удалить кодек и битрейт, указанные для fPmpeg MacPorts по умолчанию, чтобы он мне понравился:

ffmpeg -f concat -i mylist.txt  output.m4a
Роберт Коул
источник
Добро пожаловать в Super User! Пожалуйста, внимательно прочитайте вопрос. Ваш ответ не отвечает на первоначальный вопрос о Linux. Если вы считаете, что он будет работать на Linux, добавьте, чтобы у будущих читателей было четкое понимание, кроме этого, снова добро пожаловать в superuser и спасибо за ваш вклад. Пожалуйста, уделите пару минут и прочитайте: - 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.
Кстати, именованные каналы у меня не сработали (вывод на них застрял).

   #!/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
источник
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

Вениамин
источник