Вопрос или проблема
У меня есть следующая команда, составленная на данный момент:
ffmpeg -i input.mp4 -filter_complex "\
[0:v]trim=start=175.2:end=200.9,setpts=PTS-STARTPTS[v1]; \
[0:a]atrim=start=175.2:end=200.9,asetpts=PTS-STARTPTS[a1]; \
[0:v]trim=start=214.3:end=324,setpts=PTS-STARTPTS[v2]; \
[0:a]atrim=start=214.3:end=324,asetpts=PTS-STARTPTS[a2]; \
[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mp4
Извлечение клипов и объединение их в одно видео работает хорошо. Однако эта команда перекодирует видео в 25fps, о чем свидетельствует предупреждение:
[fc#0 @ 0000029e38732840] [vo0->#0:0 @ 0000029e38739b80] Нет информации о частоте кадров входного потока. Переход на значение по умолчанию 25fps. Используйте опцию -r, если хотите другую частоту кадров.
Я хочу, чтобы она сохраняла частоту кадров оригинального видео, независимо от того, какая она, и не сбрасывала или не вставляла кадры для изменения частоты кадров. Если я использую несколько входных файлов, я хочу, чтобы она просто использовала частоту кадров первого (поскольку они все равно будут одинаковыми).
Как мне это добиться?
Похоже, это ошибка в версии FFmpeg 7.0
Мы можем исправить это, добавив аргумент -fps_mode passthrough
.
Согласно документации:
passthrough (0) Каждый кадр передается с его временной меткой от демультиплексора к мультиплексору.
Тестирование:
Создайте синтетический видеофайл 5fps (для тестирования):
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=5 -f lavfi -i sine=frequency=400 -vcodec libx264 -acodec aac -pix_fmt yuv420p -t 400 input.mp4
Выполняем оригинальную команду с FFmpeg 5.1.2:
ffmpeg -y -i input.mp4 -filter_complex "[0:v]trim=start=175.2:end=200.9,setpts=PTS-STARTPTS[v1];[0:a]atrim=start=175.2:end=200.9,asetpts=PTS-STARTPTS[a1];[0:v]trim=start=214.3:end=324,setpts=PTS-STARTPTS[v2];[0:a]atrim=start=214.3:end=324,asetpts=PTS-STARTPTS[a2];[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4
С предупреждающим сообщением с FFmpeg 5.1.2 нет.
Проверяем частоту кадров файла output.mp4
с помощью MediaInfo:
Режим частоты кадров : Постоянный
Частота кадров : 5.000 FPS
Выполняем оригинальную команду с FFmpeg 7.0:
./ffmpeg-7.0-full_build/bin/ffmpeg -y -i input.mp4 -filter_complex "[0:v]trim=start=175.2:end=200.9,setpts=PTS-STARTPTS[v1];[0:a]atrim=start=175.2:end=200.9,asetpts=PTS-STARTPTS[a1];[0:v]trim=start=214.3:end=324,setpts=PTS-STARTPTS[v2];[0:a]atrim=start=214.3:end=324,asetpts=PTS-STARTPTS[a2];[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4
Существует предупреждающее сообщение “Нет информации о частоте кадров входного потока”.
Проверяем частоту кадров файла output.mp4
с помощью MediaInfo:
Режим частоты кадров : Постоянный
Частота кадров : 25.000 FPS
FFmpeg 7.0 изменил частоту кадров на 25 fps.
Выполняем обновленную (с -fps_mode passthrough
) команду с FFmpeg 7.0:
./ffmpeg-7.0-full_build/bin/ffmpeg -y -i input.mp4 -fps_mode passthrough -filter_complex "[0:v]trim=start=175.2:end=200.9,setpts=PTS-STARTPTS[v1];[0:a]atrim=start=175.2:end=200.9,asetpts=PTS-STARTPTS[a1];[0:v]trim=start=214.3:end=324,setpts=PTS-STARTPTS[v2];[0:a]atrim=start=214.3:end=324,asetpts=PTS-STARTPTS[a2];[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4
Существует новое предупреждающее сообщение: “MB rate (84000000) > уровень ограничения (16711680)” (другая ошибка?).
Проверяем частоту кадров файла output.mp4
с помощью MediaInfo:
Профиль формата : [email protected]
...
Режим частоты кадров : Постоянный
Частота кадров : 5.000 FPS
Большинство видеоплееров игнорируют “уровень”, но если уровень 6.2 проблематичен, попробуйте использовать другую версию FFmpeg.
Я считаю, что фильтр setpts=PTS-STARTPTS является виновником.
Пример:
ffmpeg \
-i input.mp4 -filter_complex "\
[0:v]scale=640x360,trim=start=13:end=14,setpts=PTS-STARTPTS[v1];\
[0:a]atrim=start=13:end=14,asetpts=PTS-STARTPTS[a1];\
[0:v]scale=640x360,trim=start=16:end=17,setpts=PTS-STARTPTS[v2];\
[0:a]atrim=start=16:end=17,asetpts=PTS-STARTPTS[a2];\
[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" \
-c:v:0 libsvtav1 output1.mp4
Это приведет к
Svt[error]: Instance 1: Максимально разрешенная частота кадров составляет 240 fps
Это говорит нам о том, что кодировщик не получает информации о fps/pts. Почему она потеряна?
Теперь, если вы пропустите все эти setpts=PTS-STARTPTS и asetpts=PTS-STARTPTS, кодировщик будет работать, но результат будет неаккуратным, не тем, что вы хотите.
Существует обходной путь:
ffmpeg \
-ss 13 -t 1 -i input.mp4 \
-ss 16 -t 1 -i input.mp4 \
-filter_complex "\
[0:v:0]scale=640x360[v1];\
[0:a:0]aresample=async=1[a1];\
[1:v:0]scale=640x360[v2];\
[1:a:0]aresample=async=1[a2];\
[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" \
-c:v:0 libsvtav1 output2.mp4
удваивайте свой ввод, используйте -ss и -t, чтобы обрезать ваш ввод вместо этого
-ss 13 сообщает ffmpeg начать чтение ввода с 00:00:13.
-t 1 сообщает ffmpeg, что продолжительность этого ввода составляет одну секунду.
Использование “-fps_mode passthrough” с libx264, давая предупреждение, работает на моей машине, но libsvtav1 – нет.
И избегание использования фильтра сэкономит много времени и памяти.
Ответ или решение
Как конкатенировать видео с помощью FFmpeg, сохраняя частоту кадров прежнего видео
При использовании FFmpeg для соединения видеороликов возникла ситуация, когда команда, создающая новое видео, переустанавливает частоту кадров в 25 кадров в секунду. Это часто вызвано отсутствием четкой информации о частоте кадров исходного видеофайла. В данной статье мы рассмотрим правильные методы конкатенации видео, сохраняя исходную частоту кадров, а также возможные ошибки и способы их устранения.
Проблема
Как указывалось, при выполнении следующей команды в FFmpeg 7.0 появилась ошибка:
[fc#0 @ 0000029e38732840] [vo0->#0:0 @ 0000029e38739b80] No information about the input framerate is available. Falling back to a default value of 25fps.
Это происходит, потому что FFmpeg не получает информацию о частоте кадров из исходного видеопотока и применяет значение по умолчанию.
Решения
1. Использование флага -fps_mode passthrough
Для решения проблемы с частотой кадров можно воспользоваться флагом -fps_mode passthrough
. Этот параметр позволяет сохранить временные метки кадров без изменений.
Вот как будет выглядеть ваша команда с учетом этого флага:
ffmpeg -y -i input.mp4 -fps_mode passthrough -filter_complex "\
[0:v]trim=start=175.2:end=200.9,setpts=PTS-STARTPTS[v1];\
[0:a]atrim=start=175.2:end=200.9,asetpts=PTS-STARTPTS[a1];\
[0:v]trim=start=214.3:end=324,setpts=PTS-STARTPTS[v2];\
[0:a]atrim=start=214.3:end=324,asetpts=PTS-STARTPTS[a2];\
[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mp4
2. Избегание изменения PTS
Другим методом решения может быть избегание использования фильтров setpts
и asetpts
, что может привести к потере информации о частоте кадров. Вместо этого можно использовать -ss
и -t
, чтобы обрезать видео:
ffmpeg -ss 175.2 -t 25.7 -i input.mp4 -ss 214.3 -t 109.7 -i input.mp4 -filter_complex "\
[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mp4
Проверка результата
Для проверки частоты кадров выходного файла рекомендуется использовать утилиту MediaInfo
. Это позволит убедиться, что частота кадров сохранена корректно. Вы можете выполнить следующую команду:
mediainfo output.mp4
Итог
При конкатенации видео с помощью FFmpeg важно сохранять исходную частоту кадров, чтобы обеспечить качественное воспроизведение без нежелательных артефактов. Использование флага -fps_mode passthrough
или правильно сформированные команды с опциями -ss
и -t
поможет вам добиться необходимого результата. Если после применения данных методов возникнут новые ошибки, возможно, стоит обратиться к другой версии FFmpeg, так как в некоторых версиях могут наблюдаться баги, влияющие на производительность.