35

У меня есть куча сегментов ts, описанных одним файлом index.m3u8:

index.m3u8        
segment1_0_av.ts  
segment2_0_av.ts  
segment3_0_av.ts  
segment4_0_av.ts  
segment5_0_av.ts

Я знаю, что все они закодированы одинаково. ffprobe дает мне следующее:

Input #0, mpegts, from 'segment1_0_av.ts':
  Duration: 00:00:10.00, start: 0.100511, bitrate: 1251 kb/s
  Program 1 
    Stream #0:0[0x100]: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 960x540 [SAR 1:1 DAR 16:9], 12.50 fps, 25 tbr, 90k tbn, 25 tbc
    Stream #0:1[0x101]: Audio: aac ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 105 kb/s
    Stream #0:2[0x102]: Unknown: none ([21][0][0][0] / 0x0015)

Я хотел бы объединить их в один контейнер mp4. Но когда я пытаюсь команды как:

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

где файл filelist.txt создается из файла index.m3u8, он жалуется на невозможность чтения различных файлов. Но преобразование файлов TS само по себе работает нормально. Я думаю, что я не использую ffmpeg должным образом.

Как использовать ffmpeg для объединения файлов ts, описанных index.m3u8, в один контейнер mp4 с использованием кодека копирования?

7 ответов7

50

Я не уверен, почему ffmpeg выдает ошибку. Однако ts является одним из немногих форматов, которые можно просто объединить. Затем, как только у вас будет один ts, преобразуйте в mp4.

Под окнами:

copy /b segment1_0_av.ts+segment2_0_av.ts+segment3_0_av.ts all.ts
ffmpeg -i all.ts -acodec copy -vcodec copy all.mp4

Под GNU/Linux, используя bash:

cat segment1_0_av.ts segment2_0_av.ts segment3_0_av.ts > all.ts
ffmpeg -i all.ts -acodec copy -vcodec copy all.mp4
19

Использование copy или cat для объединения файлов, как в случае с текущим верхним ответом szatmary, может привести к тому, что у вас будет файл, который проигрывает далеко за пределом и не может искать вместе с проблемами воспроизведения.

Вместо этого, чтобы правильно объединить эти файлы, используйте ffmpeg, как указано в https://trac.ffmpeg.org/wiki/Concatenate. (Установите ffmpeg здесь, если у вас его еще нет https://github.com/adaptlearning/adapt_authoring/wiki/Install-FFmpeg.)

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

file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

Вот копия вставки из моей первой ссылки об одном способе создания текстового файла, если у вас, например, в командной строке Windows, но, очевидно, вы можете создать файл вручную или по своему усмотрению:

(for %i in (*.ts) do @echo file '%i') > mylist.txt

Дважды проверьте, что ваш .txt файл выглядит хорошо и правильно отформатирован!

После этого в командной строке запустите:

ffmpeg -f concat -i mylist.txt -c copy all.ts

где «mylist.txt» - это только что созданный файл .txt.

Проверьте, правильно ли воспроизводится результирующий файл. Отсюда вы можете преобразовать в mp4 как обычно, если хотите:

ffmpeg -i all.ts -acodec copy -vcodec copy all.mp4
6

Ответ 2017

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

Когда я выполняю ffmpeg -i some.ts -c copy some.mp4 для определенного видео, я получаю следующее сообщение об ошибке:

Malformed AAC bitstream detected: use the audio bitstream filter 
'aac_adtstoasc' to fix it ('-bsf:a aac_adtstoasc' option with ffmpeg)

av_interleaved_write_frame(): Operation not permitted

Не удивительно, что выполнение ffmpeg -i some.ts -c copy -bsf:a aac_adtstoasc some.mp4 исправляет это.

3

Собираем все вместе

Используя ответ Хуана Акино (и исправляя первую команду для совместимости с Bash и используя естественное упорядочение файлов), а также ответ 7vujy0f0hy, простой рабочий сценарий для оболочки Linux Bash:

#!/bin/bash
for i in `ls *.ts | sort -V`; do echo "file $i"; done >> mylist.txt
ffmpeg -f concat -i mylist.txt -c copy -bsf:a aac_adtstoasc video.mp4
2

Вы можете сделать объединение просто так (с помощью bash):

for f in ./{0..<number>}.ts; do cat $f >> out.ts; done

Замените <number> на наибольшее число (очевидно). Варианты с ffmpeg не работали должным образом. Выходной видеофайл будет странно заикаться.

Я использую цикл for, чтобы обеспечить правильный порядок файлов. Может быть, вам это не нужно. Возможно, можно даже передать вывод в ffmpeg и преобразовать его в mp4 на лету.

0

Все популярные ответы на этот вопрос, которые вводят читателей в заблуждение относительно объединения файлов TS перед запуском ffmpeg, неверны. Чтобы гарантировать, что аудио и видео не будут не синхронизированы во время сборки потока mp4, следует использовать плохо документированную, но важную функцию -f concat в ffmpeg.

    delimiterBeforeFileNumber="-"
    ls |egrep '[.]ts$' \
        |sort "-t$delimiterBeforeFileNumber" -k2,2n \
        |sed -r "s/(.*)/file '\1'/" >ts.files.txt

    ffmpeg -f concat -i ts.files.txt -c copy tsw.014.ts.mp4

Две подготовительные строки кода просто создают файл, содержащий список файлов TS в этом формате строки:

    file 'seg-37-a.ts'
0

Правильный способ объединения нескольких видеофайлов из списка воспроизведения m3u8:

ffmpeg -i "index.m3u8" -codec copy output.mp4


  • плейлист m3u8 может быть в сети или локально в каталоге
    • он содержит список путей к файлам относительно списка воспроизведения
  • -codec copy чтобы избежать кодирования
  • Тип контейнера имеет значение:
    • *.mp4 в порядке, но, кажется, он немного медленный, когда плейлист выбирается из сети
    • *.mkv или *.ts работали лучше всего для меня

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .