Привет, мне нужно извлечь кадры из видео с помощью ffmpeg.. Есть ли более быстрый способ сделать это, чем это:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
Привет, мне нужно извлечь кадры из видео с помощью ffmpeg.. Есть ли более быстрый способ сделать это, чем это:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
Если шаг кодирования JPEG слишком интенсивен, он всегда может сохранять несжатые кадры в виде изображений BMP:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
Это также имеет преимущество, заключающееся в том, что при квантовании путем перекодирования в JPEG не происходит потери качества. (PNG также без потерь, но имеет тенденцию занимать гораздо больше времени, чем JPEG для кодирования.)
Перешел через этот вопрос, так что здесь быстрое сравнение. Сравните эти два разных способа извлечения одного кадра в минуту из видео длиной 38 м07:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1m36.029s
Это занимает много времени, потому что ffmpeg анализирует весь видеофайл, чтобы получить нужные кадры.
time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4 -frames:v 1 period_down_$i.bmp ; done
0m4.689s
Это примерно в 20 раз быстрее. Мы быстро используем быстрый поиск индекса времени и извлекаем кадр, затем вызываем ffmpeg несколько раз для каждого временного индекса. Обратите внимание, что -accurate_seek
по умолчанию
, и убедитесь, что вы добавили -ss
перед исходным видео -i
.
Обратите внимание, что лучше использовать -filter:v -fps=fps=...
вместо -r
как последнее может быть неточным. Хотя билет отмечен как фиксированный, я все еще испытывал некоторые проблемы, поэтому лучше безопасно играть.
Если вы точно знаете, какие кадры извлечь, например, 1, 200, 400, 600, 800, 1000, попробуйте использовать:
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
-vsync vfr -q:v 2
Я использую это с конвейером к монтажу Imagemagick, чтобы получить 10 кадров предварительного просмотра из любого видео. Очевидно, что номера кадров вам нужно выяснить с помощью ffprobe
ffmpeg -i myVideo.mov -vf \
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,100)',scale=320:-1 \
-vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \
| montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png
,
Маленькое объяснение:
+
обозначает OR и *
обозначает AND\,
Просто побег ,
характер-vsync vfr -q:v 2
, похоже, не работает, но я не знаю почему - кто-нибудь?В моем случае мне нужны кадры хотя бы каждую секунду. Я использовал подход "искать" выше, но задавался вопросом, могу ли я распараллелить задачу. Я использовал N процессов с подходом FIFO здесь: https://unix.stackexchange.com/questions/103920/parallelize-a-bash-for-loop/216475#216475
open_sem(){
mkfifo /tmp/pipe-$$
exec 3<>/tmp/pipe-$$
rm /tmp/pipe-$$
local i=$1
for((;i>0;i--)); do
printf %s 000 >&3
done
}
run_with_lock(){
local x
read -u 3 -n 3 x && ((0==x)) || exit $x
(
"[email protected]"
printf '%.3d' $? >&3
)&
}
N=16
open_sem $N
time for i in {0..39} ; do run_with_lock ffmpeg -ss 'echo $i' -i /tmp/input/GOPR1456.MP4 -frames:v 1 /tmp/output/period_down_$i.jpg & done
По сути, я разветкил процесс с &, но ограничил число одновременных потоков до N.
Это улучшило подход к поиску в моем случае с 26 до 16 секунд. Единственная проблема заключается в том, что основной поток не выходит чисто обратно в терминал, так как stdout загружается.
Я попробовал это. 3600 кадров за 32 секунды. Ваш метод действительно медленный. Вы должны попробовать это.
ffmpeg -i file.mpg -s 240x135 -vf fps = 1% d.jpg