Подтвердить что ты не робот

Ffmpeg - удалить последовательно повторяющиеся кадры

Есть ли способ обнаружить дубликаты кадров в видео с помощью ffmpeg.

Я попробовал флаг -vf с select=gt(scene\,0.xxx) для смены сцены. Но это не помогло мне.

4b9b3361

Ответ 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 vs decimate

  • 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), настройте для использования)