Ffmpeg - удалить последовательно повторяющиеся кадры
Есть ли способ обнаружить дубликаты кадров в видео с помощью ffmpeg
.
Я попробовал флаг -vf
с select=gt(scene\,0.xxx)
для смены сцены. Но это не помогло мне.
Ответы
Ответ 1
Используйте фильтр mpdecimate, целью которого является "Отбросить кадры, которые не сильно отличаются от предыдущего кадра, чтобы уменьшить частоту кадров".
-
Это создаст консольное показание, показывающее, какие кадры, которые, по мнению фильтра, являются дублирующими.
ffmpeg -i input.mp4 -vf mpdecimate -loglevel debug -f null -
-
Чтобы создать видео с удалением дубликатов
ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mp4
Выражение фильтра th set генерирует ровные метки времени для видео в FRAME_RATE fps. См. Объяснение временных меток в разделе Что такое временные рамки видео, временная база или временная метка в ffmpeg?
Ответ 2
У меня также была эта проблема, и превосходный ответ Gyan выше меня начал, но результатом было десинхронизированное аудио, поэтому мне пришлось изучить дополнительные возможности:
-
mpdecimate
- это стандартная рекомендация, которую я нашел во всем SO и в Интернете, но я не думаю, что это должен быть первый выбор - он использует эвристику, чтобы он мог и пропустил некоторые дубликаты кадров
- вы можете настроить обнаружение с помощью параметра
frac
, но эту дополнительную работу вы можете избежать, если сможете - на самом деле это не должно работать с контейнером
mp4
(source), но я использовал mkv
поэтому это ограничение не применимо к моему делу, но хорошо знать об этом
-
decimate
удаляет кадры точно, но это полезно только для периодически встречающихся дубликатов
обнаружен против фактической частоты кадров
- поэтому у вас есть мультимедийный файл с дублирующимися кадрами, рекомендуется убедиться, что обнаруженная частота кадров соответствует фактической
-
ffprobe in.mkv
выведет обнаруженный FPS; это может выглядеть так
Stream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
-
фактическая частота кадров может быть обнаружена, если вы открываете медиа- in.mkv
в медиаплеере, который позволяет вам шагнуть на один кадр в то время; затем подсчитайте шаги, необходимые для увеличения времени воспроизведения в течение 1 секунды, в моем случае это было 30 кадров в секунду
- не большой сюрприз для меня, потому что каждый 6-й кадр был дублированным (5 хороших кадров и 1 дубликат), поэтому после 25 хороших кадров было также 5 дубликатов
что N/FRAME_RATE/TB
-
кроме использования переменной FRAME_RATE
N/FRAME_RATE/TB
равен приведенному ниже примеру документации ffmpeg (source)
Установите фиксированную скорость 25 кадров в секунду:
setpts=N/(25*TB)
-
математика за ним прекрасно объясняется в том, что такое временная шкала видео, временная база или временная метка в ffmpeg?
- он в основном вычисляет временную метку для каждого кадра и умножает ее на временную шкалу
TB
для повышения точности
Переменная FRAME_RATE
vs буквальное значение FPS (например, 25)
- поэтому важно знать ваш обнаруженный и фактический FPS
- если обнаруженный FPS соответствует вашему фактическому FPS (например, оба значения составляют 30 кадров в секунду), вы можете с радостью использовать переменную
FRAME_RATE
в N/FRAME_RATE/TB
- но если обнаруженный FPS отличается от того, что вам нужно вычислить
FRAME_RATE
самостоятельно - в моем случае мой фактический FPS составлял 30 кадров в секунду, и я удалял каждый шестой кадр, поэтому целевой FPS равен 25, что приводит к
N/25/TB
- если бы я использовал
FRAME_RATE
(и я на самом деле пробовал это), он бы принял неверные обнаруженные fps из 25 кадров, то есть FRAME_RATE=25
, запустил его через фильтр mpdecimate
который удалит каждый шестой кадр, и он будет обновляться до FRAME_RATE=20.833
так что N/FRAME_RATE/TB
самом деле будет N/20.833/TB
что совершенно неверно
использовать или не использовать настройки
- поэтому фильтр настроек уже усложнился, особенно из-за беспорядка FPS, который могут создавать дублирующие кадры
- хорошая новость: на самом деле вам может не понадобиться фильтр настроек
-
вот что я использовал с хорошими результатами
ffmpeg -i in.mkv -vf mpdecimate out.mkv
ffmpeg -i in.mkv -vf decimate =cycle=6, setpts =N/25/TB out.mkv
-
но следующее дало мне десинхронизированное аудио
ffmpeg -i in.mkv -vf mpdecimate, setpts =N/FRAME_RATE/TB out.mkv
ffmpeg -i in.mkv -vf mpdecimate, setpts =N/25/TB out.mkv
ffmpeg -i in.mkv -vf decimate =cycle=6 out.mkv
-
как вы видите
- mpdecimate и decimate не работают одинаково
- mpdecimate работал лучше для меня без фильтра setpts
- в то время как decimate необходимый фильтр настроек, и, кроме того, мне нужно избежать переменной
FRAME_RATE
и использовать N/25/TB
вместо этого, потому что фактический FPS не был обнаружен должным образом
обратите внимание на asetpts
- он выполняет ту же работу, что и настройки, но для аудио
- это действительно не исправляло звук desync для меня, но вы хотите использовать его что-то вроде этого
-af asetpts =N/SAMPLE_RATE/TB
- возможно, вы должны настроить
SAMPLE_RATE
соответствии с соотношением дублированных кадров, но мне кажется, что это лишняя ненужная работа, особенно когда у моего видео было синхронизированное аудио в начале, поэтому лучше использовать команды, которые будут содержать его таким образом, вместо того, чтобы фиксировать его позже
ТЛ; др
Если обычно рекомендуемая команда ffmpeg -i in.mkv -vf mpdecimate, setpts =N/FRAME_RATE/TB out.mkv
не работает, попробуйте это:
ffmpeg -i in.mkv -vf mpdecimate out.mkv
или же
ffmpeg -i in.mkv -vf decimate =cycle=6, setpts =N/25/TB out.mkv
(cycle=6
потому что каждый 6-й кадр дублируется и N/25/TB
потому что после удаления дубликатов видео будет иметь 25 кадров в секунду (FRAME_RATE
переменную FRAME_RATE
), настройте для использования)