Как извлечь несколько коротких фрагментов из каждого видео и собрать их в один файл (FFmpeg)
Проблема
У вас есть сотни видео по 5–15 минут, и из каждого нужно взять несколько коротких отрезков (примерно по 8–12 секунд) и сохранить их как один итоговый файл для каждого исходного видео. Нужна автоматизация: задать несколько стартов/длительностей для каждого видео и получить один файл с конкатенированными отрывками, по возможности с подписью — именем исходного файла.
Пример входных данных (для первого видео):
1: ;00:01:45; AA ;00:02:00; BB ;00:03:00; CC
Базовая идея решения
Самый простой подход — «подать» один и тот же файл на вход ffmpeg несколько раз, указать для каждого входа соответствующие -ss (start) и -t (duration), а затем в filter_complex объединить все сегменты через concat. Это даёт один итоговый файл с несколькими отрезками в нужной последовательности. При этом можно сразу применить фильтр drawtext, чтобы подписать итог текстом (например, названием исходного файла).
Пример команды (шаблон):
ffmpeg -ss S1 -t D1 -i INPUT_X -ss S2 -t D2 -i INPUT_X -ss S3 -t D3 -i INPUT_X -filter_complex «[0:v][0:a][1:v][1:a][2:v][2:a]concat=n=3:v=1:a=1[v][a];[v]drawtext=text=»Input_X»[v]» -map [v] -map [a] samples_X.mp4
Разбор команды и рекомендации
— -ss S1 -t D1 -i INPUT_X — первый вход: начать в S1 и взять длительность D1 из INPUT_X. Повторяем для всех сегментов, подавая INPUT_X несколько раз (по одному входу на сегмент).
— В filter_complex: перечисляются видеo/аудио потоки каждого входа в нужном порядке [0:v][0:a][1:v][1:a]… затем concat указывается с n=число сегментов, v=1 (один видеопоток в выходе), a=1 (один аудиопоток).
— После concat можно применить другие фильтры, например drawtext для подписи:
— drawtext=text=»Input_X» — вставит текст поверх видео (требует перекодирования).
— -map [v] -map [a] — указываем, какие выходные дорожки использовать.
— samples_X.mp4 — итоговый файл для INPUT_X.
Практические нюансы
1. Точность и скорость поиска (-ss):
— Если поместить -ss перед -i (как в примере), ffmpeg выполняет «быстрый» seek (по ключевым кадрам) — быстрее, но не всегда точный до кадра. Для точного поиска можно использовать -ss после -i (или дополнительно выполнить точную обрезку фильтром), но это замедляет обработку.
2. Копирование (stream copy) vs перекодирование:
— Если вы хотите точные кадры и наложение текста (drawtext), потребуется перекодирование (иначе фильтр наложить нельзя).
— Для простого склеивания без изменений формата можно попробовать -c copy, но это работает корректно только если сегменты начинаются на ключевых кадрах и кодеки одинаковы.
3. Количество входов:
— Если сегментов много (например, 10+), команда будет длинной — это нормально, но на каждый вход ffmpeg будет открывать файл заново.
4. Аудио/синхронизация:
— При использовании concat в filter_complex concat объединяет и видео и аудио. Если сегменты разной частоты/формата, лучше сначала привести их к одинаковым параметрам или перекодировать.
Альтернативы (варианты)
Вариант 1 — (самый простой) feed input multiple times + concat (описано выше)
— Плюсы: простая концепция и команда; легко добавить drawtext.
— Минусы: при большом числе сегментов команда получается громоздкой; ffmpeg открывает файл много раз.
Вариант 2 — использовать однократный вход и фильтры trim/atrim + setpts/asepts + concat
— Идея: один раз открыть INPUT_X и внутри filter_complex отрезать нужные диапазоны через trim и atrim, затем объединить их через concat. Это эффективнее, т.к. файл открывается один раз, и точность выше.
— Преимущества: скорость и точность; меньше операций ввода/вывода.
— Недостатки: синтаксис фильтров сложнее; требуется явное управление временными метками (setpts/asetpts); тоже потребуется перекодирование, если применяются фильтры (например drawtext).
Вариант 3 — сначала вырезать сегменты в отдельные временные файлы, затем склеить их через concat demuxer
— Шаг 1: для каждого сегмента создать файл segment001.mp4, segment002.mp4 и т.д. (можно использовать -ss/-t с -c copy для скорости, если позволяют ключевые кадры).
— Шаг 2: создать файл list.txt со списком сегментов в нужном порядке и применить ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4 (либо перекодировать, если нужны фильтры).
— Плюсы: простой и надёжный workflow; удобно для отладки и промежуточных проверок.
— Минусы: требуется место на диске для временных файлов; два прохода (вырезание + конкатенация).
Что выбрать
— Если вам важна простота и вы берёте только несколько сегментов (например 2–4) из каждого файла — вариант с подачей входа несколько раз + concat удобен и понятен.
— Если у каждого файла много сегментов (скажем 8–12) и таких файлов много (сотни), лучше делать trim/atrim в одном запуске ffmpeg или предварительно вырезать сегменты и затем склеивать (вариант 2 или 3) для повышения производительности.
— Если нужно наложить подпись (drawtext) — требуется перекодирование, поэтому эффективность метода «-c copy» не применима в этом случае.
Рекомендации по рабочему процессу
1. Подготовьте для каждого видео список стартов и длительностей (CSV, JSON или простой текст).
2. Для теста выполните команду на одном файле, проверьте синхронизацию и качество.
3. Если всё ок — автоматизируйте с помощью скрипта (bash, PowerShell, Python), формируя для каждого файла ffmpeg-команду по шаблону.
4. Если скорость критична и у вас много сегментов, реализуйте вариант с trim/atrim или сначала вырезайте сегменты в tmp-файлы, а затем используйте concat demuxer.
Короткое резюме
— Самый простой шаблон: подать файл на вход несколько раз и объединить сегменты через filter_complex concat (приведённый выше).
— Для большей эффективности и при большом количестве сегментов используйте trim/atrim + concat в одном filter_complex или подход с временными файлами и concat demuxer.
— Помните про нюансы -ss (точность vs скорость) и про необходимость перекодирования при применении фильтров (например drawtext).
Удачи с автоматизацией — при желании помогу составить скрипт для ваших конкретных списков времени или показать пример команды с trim/atrim для одного файла.