2016-12-15 16 views
2

Я знаю, как извлечь набор кадров как JPG файлы из видео с помощью FFmpeg, если вы знаете, номера кадров (ниже)Как извлечь ключевые кадры, наиболее близкие к данным номерам кадров от H264 видео с FFmpeg

Extracting Frames: [40, 59, 73, 110] 
/usr/bin/ffmpeg -y -hide_banner -nostats -loglevel error -i /home/pi/movie.mp4 -vf select='eq(n\,40)+eq(n\,59)+eq(n\,73)+eq(n\,110)',scale=640:-1 -vsync 0 /tmp/%04d.jpg 

Это будет извлекать кадры [40, 59, 73, 110] в виде файлов /tmp/0000.jpg, /tmp/0001.jpg и т.д.

Я также знаю, как извлечь все ключевые кадры для данного период времени:

ffmpeg -ss <start_time> -i video.mp4 -t <duration> -q:v 2 -vf select="eq(pict_type\,PICT_TYPE_I)" -vsync 0 frame%03d.jpg 

Это позволит получить все I-кадры от start_time до start_time+duration.

Но то, что я хотел бы сделать, это предоставить список номеров кадров и ffmpeg извлечь самые близкие ключевые кадры для каждого номера кадра. Есть ли способ сделать это с помощью ffmpeg или мне нужно написать свою собственную программу ontop libavcodec, чтобы сделать это?

+0

Все ключевые кадры в заданном радиусе целевого кадра или только ближайшие? До и после? – Mulvya

+0

Просто ближайший, поэтому, если ключевые кадры находятся в [0, 5, 10, 15, 20], и я хочу кадров [3, 6, 12], он вернется. Фактически это зависит от алгоритма. Он может выбрать кадр 5 как самый близкий для 3, кадр 10 как ближайший слева до 6, а затем 15, как ближайший слева до 12.Идеальный сценарий (путем суммарного расстояния до ключевого кадра по всем элементам) будет возвращать кадры [0, 5, 10]. –

ответ

3

Сначала нам нужны некоторые данные испытаний. Обратите внимание, что вы можете пропустить команды FFmpeg, если вы делаете это самостоятельно ; это просто, как я пришел о заключительных команд:

ffprobe -select_streams v -show_entries frame=pict_type -of flat \ 
'Breaking Bad 5x4 Fifty-One.mp4' > pict_type.txt 

Теперь найдем наибольшее окно:

#!/usr/bin/awk -f 
BEGIN { 
    FS = "[.\42]" 
} 
$5 != "I" { 
    pa++ 
} 
$5 == "I" { 
    qu = pa > qu ? pa : qu 
    pa = 1 
} 
END { 
    print qu 
} 

Запуск это дает 240, что означает, что радиус 120. Если наша цель рама 1000:

ffmpeg -i 'Breaking Bad 5x4 Fifty-One.mp4' \ 
-vf "select='eq(pict_type,I)*lt(abs(n-1000),120)'" -frames 1 outfile.jpg 

Если наши целевые кадры 1000 и 2000:

ffmpeg -i 'Breaking Bad 5x4 Fifty-One.mp4' \ 
-vf "select='eq(pict_type,I)*(lt(abs(n-1000),120)+lt(abs(n-2000),120))'" \ 
-frames 2 -vsync 0 %d.jpg 

http://ffmpeg.org/ffmpeg-utils.html#Expression-Evaluation

+0

Я смог попробовать ваши предложения и получил некоторые неожиданные результаты. Вот два примера и их выходы. 'time ffmpeg -y -hide_banner -nostats -loglevel error -i movie.mp4 -vf" select = 'eq (pict_type, I) * (lt (abs (n-36), 120) + lt (abs (n -56), 120) + л (абс (п-103), 120) + л (абс (п-160), 120) + л (абс (п-172), 120)), шкала = 640: - 2" -реперов 5 -vsync 0/TMP/кадры% 03d.jpg' реального \t 0m0.761s пользователя \t 0m2.232s SYS \t 0m0.052s –

+0

по сравнению с тем, как перечисленные в OP без 'ЛТ (abs' заявления: реального \t 0m0.749s пользователя \t 0m2.244s SYS \t 0m0.056s –

+0

@JohnAllard, что разница пренебрежимо мала –

3

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

ffmpeg -discard nokey -i video.mp4 -q:v 2 -vf select="eq(pict_type\,PICT_TYPE_I)" -vsync 0 frame%03d.jpg 

Это должно обеспечить скорость 20-100x.

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

ffmpeg -discard nokey -i video.mp4 -q:v 2 -vf select="eq(pict_type\,PICT_TYPE_I)*(lt(abs(t-14),3)+lt(abs(t-107),3)+lt(abs(t-2113),3))" -vsync 0 frame%03d.jpg 

Здесь ключевые кадры с радиусом 3 секунды раз т = 14s, 107S и 2113s будут выбраны.

Вы не можете ссылаться на n с discard, так как нумерация будет неправильно -> FFmpeg только отправка ключевых кадров в фильтре и n представляет счет в отфильтрованных кадров. Таким образом, все переменные и значения находятся в секундах. Если ваше видео является постоянной частотой кадров, то t просто n/ fps

+0

Я добавил оператор '-discard nokey' к моему запросу выбора кадра и не смог произвести заметного ускорения. Я использовал эту команду для извлечения кадров 36, 56, 104, 160 и 174: 'ffmpeg -discard nokey -y -hide_banner -nostats -loglevel error -i /home/pi/test_movies/C42F90E9CDF0.0_2016-12-15T01:00: 56.015236_19bb8bcf-7cf2-4e2b-9b2a-43e452865d44.mp4 -vf select = 'eq (n \, 36) + eq (n \, 56) + eq (n \, 103) + eq (n \, 160) + eq (n \, 172) ', scale = 640: -1 -vsync 0/tmp/frames% 03d.jpg'. Если я добавлю '-discard nokey' заявление в начало этого, никаких изменений во время выполнения нет. –

+0

Я только что запустил вашу команду с и без nokey на 20-минутном видео, и результаты с '-benchmark' составили 56 секунд против 6 секунд. Какую версию вы используете? И вы используете это на телефоне? – Mulvya

+0

Я думаю, что это может быть так, что я должен запустить это, чтобы извлечь в среднем 3 или 4 кадра из 12-секундного клипа, но я должен делать это из множества разных клипов как можно чаще. Может ли это исказить результаты? Да, это работает на среднем ARM-чипе среднего уровня. –