суббота, 5 декабря 2009 г.

Видеонаблюдение и Motion

Брать здесь http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome
Ему требуется ffmpeg (вроде заточенный под него)

http://www.lavrsen.dk/foswiki/bin/view/Motion/VideoFourLinuxLoopbackDevice
http://www.lavrsen.dk/foswiki/bin/view/Motion/LoopbackDevice
video loopback
mplayer tv:// -tv device=/dev/video9:driver=v4l:input=0:width=640:height=480:normal=pal -fps 25

Video loopback (http://novotorg.net/motonpublic/15-motion-vloopback)


MjpgStreamer
(http://www.lavrsen.dk/foswiki/bin/view/Motion/MjpgStreamer)
Ну в общем-то работает. И даже вещает по заданному порту. Только у меня нужно было с video loopback девайса взять сигнал, так вот плагин input_uvc отказался с ним работать (типа не смог опросить устройство), а у плагина input_gspcav1 была проблемма с установкой palette, ну в общем пришлось его исходники варварски допилить и он таки заработал. В настоящем девайсе наверное проблеммы такой не будет.
Запускалось все это вроде так =
mjpg_streamer --input "input_gspcav1.so -d /dev/video9" --output "output_http.so -p 8084"
Ну и еще допилить плагин output_http, в нем "фишек" разных много реализовано, кот. мне не нужны были (типа доп. параметров - вывод статической картинки, вывод потока и прочего). А мне просто нужно было как в motion сделать, "присосался" к нужному порту и получай поток. Еще из минусов input_gspcav1 - он не умеет ограничивать fps как в плагине input_uvc, в итоге firefox на удаленной машине получает поток реальных кадров (к примеру 25fps) и начинает дико кушать ресурсы (память и проц). И практически виснет через короткое время. В общем надо будет самому прикрутить делитель fps.

И пару слов, а на кой мне это все надо было пробовать.
Не знаю как у вас, а у меня motion (версия 3.2.11.1) когда почуял движение выдает загрузку проца что-то около 27-33% (htop). Так вот если в этот момент брать поток (в смысле смотреть через "сетку") на удаленном компьютере, загрузка motion возрастает практически в 2 раза. Даже если ограничить webcam_maxrate 2. Казалось бы куда уж ниже (1 и так по умолчанию). Вот с помощью video loopback и mjpg_streamer и удалось "решить" эту проблему. При это связке загрузка проца вырастала дополнительно на 5-10%, что конечно гораздо меньше чем было с одним motion и его встроенном сервере.
Затем покопав исходник motion.c нашел там интересный момент, при сработке детектора он начинает отправлять ВСЕ полученные кадры в функцию webcam_put (что в webcam.c), та выделяет память под буфер, формирует его, список клиентов и пр. и уже только ПОСЛЕ этого "принимается" решение а вообще его слать или нет в соответствии с заданным webcam_maxrate (расчитывается время прошлого кадра, теперешнее време - что-то вроде этого). Сделано там с одной стороны все правильно и логично, НО! зачем к примеру при fps=2 обрабатывать 25 кадров, выделяя под них динамически память и копируя туда-сюда. ну в общем как-то так. Более детально я в исходник не лез, мало времени, а заказчику надо уже сдаваться.
Так что на скору руку подкрутил здесь строку, добавив в нее инструкцию по отправлению каждого 5 кадра в функцию webcum_put(). Что при условии fps=25 на входе, на выходе (webcam) получим:
первый кадр отправляем в любом случае, а дальше 5,10,15,20 -- fps=5

вот что было
if (conf->webcam_motion && !conf->setup_mode && img->shot != 1)
event(cnt, EVENT_WEBCAM, img->image, NULL, NULL, &img->timestamp_tm);

вот что получилось
if (conf->webcam_motion && !conf->setup_mode && img->shot != 1 && img->shot%5 == 0)
event(cnt, EVENT_WEBCAM, img->image, NULL, NULL, &img->timestamp_tm);

При этом загрузка проца при просмотре со встроенного в motion сервера возрастает с 30% (засекли движение, но не смотрим с порта) до 40% (есть движение и смотрим). что для меня вполне приемлемо. топорное и "тупое" решение. Можно было бы сделать все это поизящнее, но время поджимает и главное лень. работает ведь.
Будут мысли или уточнения, критика? Может кто уже наступал на эти грабли?

В общем можно на скору руку именно в webcam.c (stream.c) в функции webcam_put (stream_put) после переменных и строки
Код:
char len[20]; /* will be used for sprintf, must be >= 16 */

добавить что-то вроде этого:
Код:
if (! (( cnt->shots%3 ==0 && cnt->shots != 0 ) || cnt->shots == 1 )) return;

т.е. примитивно выпрыгиваем из функции ничего не делая если не удвлетворяем условиям отбора кадров. (а еще раскрыть скобки в условии и применить not и записать по-людски)
В данном примере будет на порт выводиться примерно каждый 3 кадр. При этом motion.c не трогаем, пусть живет.

Посмотрел на загрузку проца, такая же как и при правке motion.c (а с чего ей и изменяться существенно, принцип фильтрации кадров тот же).

Комментариев нет:

Отправить комментарий