73

FFmpeg может захватывать изображения из видео, которые можно использовать в качестве эскизов для представления видео. Наиболее распространенные способы сделать это описаны в FFmpeg Wiki.

Но я не хочу выбирать случайные кадры через определенные промежутки времени. Я нашел несколько вариантов использования фильтров в FFmpeg для захвата изменений сцены:

thumbnail фильтра пытается найти наиболее представительные кадры в видео:

ffmpeg -i input.mp4 -vf  "thumbnail,scale=640:360" -frames:v 1 thumb.png

и следующая команда выбирает только кадры, которые имеют более 40% изменений по сравнению с предыдущими (и, вероятно, являются изменениями сцены), и генерирует последовательность из 5 PNG.

ffmpeg -i input.mp4 -vf  "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png

Информационный кредит для вышеуказанных команд Фабио Соннати. Второй показался мне лучше, так как я мог получить n изображений и выбрать лучшее. Я попробовал это, и это произвело то же самое изображение 5 раз.

Еще одно расследование привело меня к:

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr  out%02d.png

-vsync vfr гарантирует, что вы получите разные изображения. Это по-прежнему всегда выбирает первый кадр видео, в большинстве случаев первый кадр имеет титры / логотип и не имеет смысла, поэтому я добавил -ss 3, чтобы отбросить первые 3 секунды видео.

Моя последняя команда выглядит так:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg

Это было лучшее, что я мог сделать. Я заметил, что, поскольку я выбираю только 5 видео, все они в основном с начала видео и могут упустить важные сцены, которые происходят позже в видео

Я хотел бы выбрать ваши мозги для любых других лучших вариантов.

5 ответов5

24

Как насчет поиска, в идеале, первого> 40% сменного кадра в каждом из 5 временных интервалов, где временные интервалы составляют 1, 2, 3, 4 и 5–20% видео.

Вы также можете разделить его на 6 временных периодов и игнорировать 1-й, чтобы избежать кредитов.

На практике это будет означать установку низкого значения fps при применении вашей проверки смены сцены и вашего аргумента для удаления первого бита видео.

...что-то вроде:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg
6

Трудно определить значимые значения, но если вы хотите, чтобы N миниатюр эффективно охватывало весь видеофайл, это то, что я использую для создания миниатюр при работе с загруженным пользователем контентом.

Псевдо-код

for X in 1..N
  T = integer( (X - 0.5) * D / N )  
  run `ffmpeg -ss <T> -i <movie>
              -vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg`

Куда:

  • D - длительность видео, считываемого только из ffmpeg -i <movie> или из ffprobe с хорошей записывающей записью JSON, кстати
  • N - общее количество миниатюр, которые вы хотите
  • X - номер миниатюры, от 1 до N
  • T - момент времени для миниатюры

Просто вышеупомянутое записывает центральный ключевой кадр каждого раздела фильма. Например, если фильм имеет длину 300 с и вам нужно 3 миниатюры, тогда он занимает один ключевой кадр после 50 с, 150 с и 250 с. Для 5 миниатюр это будет 30, 90, 150, 210, 270. Вы можете отрегулировать N в зависимости от продолжительности видеоролика D, например, в 5-минутном фильме будет 3 миниатюры, а в течение 1 часа - 20 миниатюр.

Спектакль

Каждый вызов вышеуказанной команды ffmpeg занимает доли секунды (!) для ~ 1 ГБ H.264. Это связано с тем, что он мгновенно переходит в положение <time> (mind -ss before -i) и занимает первый ключевой кадр, практически полный JPEG. Нет времени, потраченного на рендеринг фильма в соответствии с точным положением времени.

Постобработка

Вы можете смешать выше с scale или любым другим методом изменения размера. Вы также можете удалить сплошные цветные рамки или попробовать смешать их с другими фильтрами, такими как thumbnail .

2

Однажды я сделал нечто подобное, но я экспортировал все кадры видео (в 1 кадр / с) и сравнил их с обнаруженной мной утилитой perl, которая вычисляет разницу между изображениями. Я сравнил каждый кадр с предыдущими миниатюрами, и если он отличался от всех миниатюр, я добавил его в коллекцию миниатюр. Преимущество здесь в том, что если ваше видео перемещается со сцены A на B, а оно возвращается на A, ffmpeg будет экспортировать 2 кадра A.

2

Попробуй это

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png

С помощью этой команды я могу сгенерировать необходимое количество миниатюр, которые представляют все видео.

1

Вот что я делаю для создания периодической миниатюры для живых потоков m3u8 для использования в качестве постера. Я обнаружил, что выполнение непрерывной задачи ffmpeg просто для генерации миниатюр приводит к израсходованию всего моего процессора, поэтому вместо этого я запускаю cronjob каждые 60 секунд, который генерирует все миниатюры для моих потоков.

#!/usr/bin/env bash

## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files)
#-vf thumbnail,scale=640:360 -frames:v 1 poster.png

## this is faster but thumbnails are random (takes about 8 seconds for 20 files)
#-vf scale=640:360 -frames:v 1 poster.png
cd ~/path/to/streams

find . -type f \
  -name "*.m3u8" \
  -execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \
  {} \;

Если вам нужно сделать более часто , чем за 60 секунд (ограничение по cronjob), то вы можете сделать while цикла в сценарии , и он будет выполнять вечно. Просто добавьте sleep 30 чтобы изменить частоту до 30 секунд. Я не рекомендую делать это с большим количеством видео, поскольку предыдущий запуск может не завершиться до начала следующего.

В идеале с cronjob я просто запускаю его каждые 5 минут.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .