Подробная инструкция: склейка нескольких WebM/видео файлов через FFmpeg

Оглавление

  1. Когда это нужно
  2. Подготовка
  3. Шаг 1. Диагностика файлов
  4. Шаг 2. Выбор способа склейки
  5. Шаг 3. Склейка
  6. Шаг 4. Проверка результата
  7. Готовые шаблоны команд
  8. Частые ошибки и что они значат
  9. Шпаргалка по параметрам

1. Когда это нужно

Типичные сценарии:

  • Запись встречи/лекции разбита на несколько файлов (например, при превышении лимита размера или при перезапуске записи).
  • Несколько коротких видео нужно собрать в одно.
  • Нужно склеить фрагменты записи экрана.

FFmpeg умеет это двумя принципиально разными способами:

  • Без перекодирования (-c copy) — быстро (секунды), но требует идентичных параметров всех файлов.
  • С перекодированием (фильтр concat) — медленнее, но работает всегда и даёт предсказуемый результат.

2. Подготовка

Проверить, что FFmpeg установлен

ffmpeg -version

Если команда не найдена:

  • Ubuntu/Debian: sudo apt install ffmpeg
  • Fedora: sudo dnf install ffmpeg
  • macOS (Homebrew): brew install ffmpeg
  • Windows: скачать с ffmpeg.org или winget install ffmpeg

Перейти в папку с файлами

cd ~/Загрузки          # Linux/macOS
cd %USERPROFILE%\Downloads   # Windows cmd
cd $env:USERPROFILE\Downloads # Windows PowerShell

Полезно: включить автодополнение имён файлов

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


3. Шаг 1. Диагностика файлов

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

3.1. Посмотреть ключевые параметры

ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,avg_frame_rate,sample_rate,channels -of default=noprint_wrappers=1 "файл1.webm"

Повторите для каждого файла. Сравните значения:

ПараметрЧто означаетВажно для -c copy
codec_name (видео)Кодек видеоДолжен совпадать
codec_name (аудио)Кодек аудиоДолжен совпадать
width / heightРазрешениеДолжно совпадать
r_frame_rateНоминальный fpsЖелательно совпадение
avg_frame_rateСредний fpsЕсли 0/0 — VFR, значит -c copy рискован
sample_rateЧастота дискретизации аудиоДолжна совпадать
channelsКол-во каналовДолжно совпадать

3.2. Как интерпретировать

  • Все параметры совпадают и avg_frame_rate не 0/0 → можно пробовать -c copy.
  • Параметры совпадают, но avg_frame_rate=0/0 (VFR) → -c copy может дать рассинхрон и битый звук. Лучше сразу перекодировать.
  • Параметры различаются → только перекодирование.

3.3. Быстрая проверка длительности

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1 "файл1.webm"

Пригодится потом для проверки суммы.


4. Шаг 2. Выбор способа склейки

Способ A — быстрое копирование (-c copy)

Плюсы: секунды, без потери качества.
Минусы: работает только при идентичных параметрах. При VFR часто ломается.

Способ B — перекодирование через фильтр concat

Плюсы: работает всегда, даёт стабильный результат.
Минусы: занимает время (зависит от кодека и CPU).

Правило: если сомневаетесь — берите способ B. Время дороже битого файла.


5. Шаг 3. Склейка

Способ A — без перекодирования

Создайте файл со списком (порядок строк = порядок в итоговом видео):

printf "file 'файл1.webm'\nfile 'файл2.webm'\nfile 'файл3.webm'\n" > list.txt

Затем:

ffmpeg -f concat -safe 0 -i list.txt -c copy "результат.webm"
  • -f concat — использовать concat-демультиплексор.
  • -safe 0 — разрешить абсолютные/нестандартные пути.
  • -c copy — не перекодировать, копировать потоки как есть.

Способ B — с перекодированием (универсальный)

B.1. В WebM (VP9 + Opus)

Медленно, но сохраняет формат WebM:

ffmpeg -i "файл1.webm" -i "файл2.webm" \
  -filter_complex "\
[0:v]fps=30,setpts=PTS-STARTPTS[v0];\
[1:v]fps=30,setpts=PTS-STARTPTS[v1];\
[0:a]aresample=48000,asetpts=PTS-STARTPTS[a0];\
[1:a]aresample=48000,asetpts=PTS-STARTPTS[a1];\
[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libvpx-vp9 -b:v 2M -cpu-used 5 -row-mt 1 -threads 0 \
  -c:a libopus -b:a 128k \
  "результат.webm"

B.2. В MP4 (H.264 + AAC) — рекомендуется для встреч/скринкастов

Быстро, совместимо со всем:

ffmpeg -i "файл1.webm" -i "файл2.webm" \
  -filter_complex "[0:v]fps=30,setpts=PTS-STARTPTS[v0];[1:v]fps=30,setpts=PTS-STARTPTS[v1];[0:a]asetpts=PTS-STARTPTS[a0];[1:a]asetpts=PTS-STARTPTS[a1];[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libx264 -preset veryfast -crf 23 \
  -c:a aac -b:a 128k \
  -movflags +faststart \
  "результат.mp4"

B.3. Для трёх и более файлов

Добавьте входы и блоки в filter_complex:

ffmpeg -i "файл1.webm" -i "файл2.webm" -i "файл3.webm" \
  -filter_complex "\
[0:v]fps=30,setpts=PTS-STARTPTS[v0];[0:a]asetpts=PTS-STARTPTS[a0];\
[1:v]fps=30,setpts=PTS-STARTPTS[v1];[1:a]asetpts=PTS-STARTPTS[a1];\
[2:v]fps=30,setpts=PTS-STARTPTS[v2];[2:a]asetpts=PTS-STARTPTS[a2];\
[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libx264 -preset veryfast -crf 23 \
  -c:a aac -b:a 128k -movflags +faststart \
  "результат.mp4"

Обратите внимание: concat=n=3 — число файлов, и количество пар [vN][aN] должно совпадать с числом входов.


6. Шаг 4. Проверка результата

4.1. Длительность

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1 "результат.mp4"

Должна быть ≈ сумме длительностей исходников (допустимая погрешность — доли секунды).

4.2. Параметры потоков

ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,sample_rate,channels -of default=noprint_wrappers=1 "результат.mp4"

4.3. Визуальная проверка стыка (обязательно)

Откройте результат в плеере и проматайте на момент стыка — примерно на длительность первого файла от начала. Проверьте:

  • звук не «убегает» от видео;
  • картинка не замирает;
  • нет резких скачков яркости/размера (если исходники писались в разное время).

4.4. Проверка в конце

Проматайте ближе к концу файла — убедитесь, что синхрон сохраняется на всём протяжении. Если к концу накапливается рассинхрон — значит, в одном из исходников были проблемы, и поможет только покадровая обработка (уже не «просто склейка»).


7. Готовые шаблоны команд

Универсальный шаблон (MP4, H.264)

ffmpeg -i "ЧАСТЬ1" -i "ЧАСТЬ2" \
  -filter_complex "[0:v]fps=30,setpts=PTS-STARTPTS[v0];[1:v]fps=30,setpts=PTS-STARTPTS[v1];[0:a]asetpts=PTS-STARTPTS[a0];[1:a]asetpts=PTS-STARTPTS[a1];[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libx264 -preset veryfast -crf 23 \
  -c:a aac -b:a 128k -movflags +faststart \
  "РЕЗУЛЬТАТ.mp4"

Универсальный шаблон (WebM, VP9)

ffmpeg -i "ЧАСТЬ1" -i "ЧАСТЬ2" \
  -filter_complex "[0:v]fps=30,setpts=PTS-STARTPTS[v0];[1:v]fps=30,setpts=PTS-STARTPTS[v1];[0:a]aresample=48000,asetpts=PTS-STARTPTS[a0];[1:a]aresample=48000,asetpts=PTS-STARTPTS[a1];[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libvpx-vp9 -b:v 2M -cpu-used 5 -row-mt 1 -threads 0 \
  -c:a libopus -b:a 128k \
  "РЕЗУЛЬТАТ.webm"

Быстрый шаблон (только для одинаковых файлов)

printf "file 'ЧАСТЬ1'\nfile 'ЧАСТЬ2'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy "РЕЗУЛЬТАТ"

8. Частые ошибки и что они значат

Non-monotonic DTS; previous: X, current: Y

Таймстемпы второго файла конфликтуют с первым. Причина — разный fps или VFR. Решение: перекодирование с fps=30 и setpts=PTS-STARTPTS.

Error parsing Opus packet header

Повреждён аудиопоток на стыке — следствие той же проблемы. Решение: то же — перекодирование.

Unknown encoder 'libvpx-vp9'

Ваш FFmpeg собран без VP9. Решение: используйте libx264 (MP4) или переустановите FFmpeg с полным набором кодеков.

Unknown encoder 'libx264'

Аналогично — нет H.264. Решение: sudo apt install ffmpeg из официальных репозиториев обычно содержит libx264.

Invalid file index 2 in filtergraph description

В filter_complex указан вход, которого нет (например, [2:v], но задано только 2 файла с индексами 0 и 1). Решение: пересчитайте входы и concat=n=N.

Input link in1:v0 parameters (size X, SAR Y) do not match the corresponding output link

Разные разрешения или пропорции. Решение: добавьте scale в фильтр для каждого входа:

[0:v]fps=30,scale=1920:1080,setsar=1,setpts=PTS-STARTPTS[v0];

moov atom not found при воспроизведении результата

Файл записан некорректно (обычно из-за прерывания FFmpeg). Решение: запустите склейку заново, дождитесь завершения.


9. Шпаргалка по параметрам

Видео

ПараметрЗначениеКомментарий
-c:v libx264H.264 (MP4)Быстро, совместимо
-c:v libvpx-vp9VP9 (WebM)Медленно, но формат WebM
-preset veryfastСкорость x264ultrafast…veryslow
-crf 23Качество x264Меньше = лучше (18–28)
-b:v 2MБитрейт VP92 Мбит/с для 1080p встреч
-cpu-used 5Скорость VP90 (медл.)…8 (быстро)
fps=30Частота кадровДля скринкастов 30, для динамики 60
-movflags +faststartMP4Метаданные в начало файла

Аудио

ПараметрЗначениеКомментарий
-c:a aacAAC (MP4)Универсально
-c:a libopusOpus (WebM)Для WebM
-b:a 128kБитрейт128k достаточно для голоса
aresample=48000Частота48000 — стандарт для Opus

Фильтры

ФильтрЗачем
fps=30Приводит видео к постоянной частоте кадров
setpts=PTS-STARTPTSОбнуляет таймстемпы видео
asetpts=PTS-STARTPTSОбнуляет таймстемпы аудио
aresample=48000Приводит аудио к единой частоте
scale=1920:1080Приводит к единому разрешению
setsar=1Убирает разницу в aspect ratio
concat=n=N:v=1:a=1Собственно склейка N файлов

Памятка на будущее (короткая версия)

  1. Сравнить параметры файлов через ffprobe.
  2. Одинаковые и без VFR → -c copy (секунды).
  3. Разные или VFR → фильтр concat с fps=30 и setpts=PTS-STARTPTS.
  4. Формат не важен → MP4/H.264 (veryfast, crf 23) — быстрее всего.
  5. Обязателен WebM → VP9 + Opus, но долго.
  6. Всегда проверять стык на готовом файле.
  7. При ошибках Non-monotonic DTS / Opus packet header — сразу переходить к перекодированию.

Сохраните этот файл — в следующий раз сэкономите время на диагностику.

Добавить комментарий