![Точно извлекайте кадры каждые N секунд с помощью FFmpeg](https://rvso.com/image/1672321/%D0%A2%D0%BE%D1%87%D0%BD%D0%BE%20%D0%B8%D0%B7%D0%B2%D0%BB%D0%B5%D0%BA%D0%B0%D0%B9%D1%82%D0%B5%20%D0%BA%D0%B0%D0%B4%D1%80%D1%8B%20%D0%BA%D0%B0%D0%B6%D0%B4%D1%8B%D0%B5%20N%20%D1%81%D0%B5%D0%BA%D1%83%D0%BD%D0%B4%20%D1%81%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E%20FFmpeg.png)
Использование
Я извлекаю изображения из видео с помощью ffmpeg
.
Я выгружаю одно уменьшенное изображение каждые 10 секунд включительно, которое объединяю в монтажи с помощью imagemagick
. Эти монтажи снова используются для показа предварительного просмотра видео при наведении ползунка в веб-видеоплеере. (Вычисление того, какое изображение в монтаже показывать).
Команда
Поэкспериментировав, я пришел к следующей команде, в которой скорость важнее качества:
ffmpeg \
-loglevel error \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$video_file" \
-r 0.1 \
-filter:v "scale_cuda=w=-1:h=100,thumbnail_cuda=2,hwdownload,format=nv12" \
-color_range 2 \
f%09d.jpg
Кажется, это сработало нормально. Кадры сбиваются на ± 0,5 - 1 секунду тут и там, но это терпимо.
Проблема
Проблема в том, что ffmpeg
в начале видео появляется одно лишнее изображение. Например, файлы:
file time
f000000001.jpg 00:00:00
f000000002.jpg 00:00:00
f000000003.jpg 00:00:10
f000000004.jpg 00:00:20
f000000005.jpg 00:00:30
...
Иногда первое и второе отличаются на несколько миллисекунд.
Насколько я знаю (сейчас), я могу просто удалить первое изображение и продолжить работу с остальными, но не уверен, почему это происходит и является ли это ошибкой или чем-то еще.
Другими словами: мне нужно знать, является ли «эффект» двух первых кадровнадежныйчтобы я мог удалить его ffmpeg
и в других версиях.
Поскольку я использую изображения для показа 10-секундного кадра из видео в указанное времяон выключен на 10 секундесли я не удаляю первое сгенерированное изображение. Если по какой-то причине это должно произойти, тонетсоздайте дубликат при запуске, другой версии или чего-то еще, удаление первого изображения создаст ту же проблему.
Монтаж
(Если интересно, то монтажи создаются примерно так):
montage -tile 5x -geometry +0+0 -background none [file1 - file50 ] montage01.jpg
montage -tile 5x -geometry +0+0 -background none [file51 - file100] montage02.jpg
...
Команда, которую я использую сейчас, основываясь на ответе (shell):
# Set on call or global:
file_in=sample.mp4
pix_fmt=yuvj420p
sec_snap_interval=10
nr_start=1
pfx_out=snap
ffmpeg \
-loglevel warning \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$file_in" \
-pix_fmt "$pix_fmt" \
-filter:v "
scale_cuda=
w = -1 :
h = 100,
thumbnail_cuda = 2,
hwdownload,
format = nv12,
select = 'bitor(
gte(t - prev_selected_t, $sec_snap_interval),
isnan(prev_selected_t)
)'
" \
-vsync passthrough \
-color_range 2 \
-start_number "$nr_start" \
"$pfx_out%09d.jpg"
решение1
При использовании -r 0.1
устанавливается выходная частота кадров 0,1 Гц, но это не гарантирует получение кадров из входного видео ровно каждые 10 секунд (я не уверен, почему).
Одним из способов решения этой проблемы является использованиевыберите фильтр.
Пример (без ускорения GPU):
ffmpeg -i input.mp4 -vf "select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" -vsync 0 f%09d.jpg
bitor(gte(t-prev_selected_t\,10)
когда1
разница между "прошедшими" временными метками больше 10 секунд.
Когда выражение оценивается как1
, кадр "выбирается" и передается на выход.bitor
сisnan(prev_selected_t)
пропусками первого кадра, гдеprev_selected_t
естьNaN
(не имеет значения).-vsync 0
применяется «сквозная передача» — каждый кадр передается со своей временной меткой от демультиплексора к мультиплексору.
Вот пример с scale_cuda
и thumbnail_cuda
:
ffmpeg \
-loglevel error \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$video_file" \
-filter:v "scale_cuda=w=-1:h=100,thumbnail_cuda=2,hwdownload,format=nv12,select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" \
-vsync 0 \
-color_range 2 \
f%09d.jpg
- Из-за использования
thumbnail_cuda
фильтра нам придется разместитьselect
фильтр в конце.
Тестирование:
Создание синтетического видео со счетчиком кадров при 10 кадрах в секунду:
ffmpeg -y -f lavfi -r 10 -i testsrc=size=128x72:rate=1:duration=1000 -vf setpts=N/10/TB -vcodec libx264 -pix_fmt yuv420p input.mp4
Выходные кадры после выполнения вышеуказанной команды:
Как видите, выбранные кадры следуют ровно каждые 10 секунд.