MyTetra Share
Делитесь знаниями!
Motion: видеонаблюдение в Linux своими руками
Время создания: 09.02.2016 11:02
Раздел: Компьютер - Linux - Видео в Linux - Motion
Запись: xintrea/mytetra_syncro/master/base/1455004927xeoxo8v0in/text.html на raw.github.com

После переезда в новый офис, дабы не расслаблять сотрудников, было решено установить систему видеонаблюдения. Но, как обычно, основным условием было: дешево и сердито :) После обдумывания и подсчетов было решено остановиться на следующем: IP-камеры и компьютер в качестве регистратора.


Для начала попробовали небезызвестный ZoneMinder. Но отчего-то с 9 камерами он грузил систему нещадно. После некоторой борьбы с ним, было решено отказаться от него. Поискав на просторах Internet была найдена программка под названием motion (http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome). Почитав немного про нее, было решено остановиться на ней.

Итак, у нас были IP камеры, компьютер в качестве регистратора, motion в качестве софта и желание подружить весь этот колхоз. И что же умеет motion из того, что нам надо? :)


  1. Работа с камерами, подключенными через карты захвата либо с IP камерами.
  2. Выполнять скрипты при наступлении и окончании события.


Ну чтож, приступим. Для начала попробуем с одной камерой. Устанавливаем motion.

Далее, в папке /etc/motion/ копируем файл с конфигурацией (motion.conf) в файл для нашей камеры, например motion1.conf. А теперь начинаем его править под себя:


1. закомментируем строчку


videodevice /dev/video0


2. в строке netcam_url прописываем URL для доступа к нашей камере. Мы использовали IP камеры Axis, модель 207 (со встроенным микрофоном).


Для нашего случая выглядело так:


netcam_url http://camera_ip/axis-cgi/mjpg/video.cgi?resolution=640x480


где camera_ip — IP адрес камеры.


3. далее находим строку target_dir — здесь указываем путь к папке, где будемхранить данные с камеры.


4. а теперь начинается самое интересное. Находим строку on_event_start. Здесь мы прописываем команду, которая будет выполняться при наступлении события, то есть при движении. Что нам это дает? А дает нам это то, что мы не будем постояно вести запись, а только по необходимости — есть движение, идет запись, закончилось, остановились и мы. Таким образом получается экономия. Для сравнения — у нас ведется запись с 10 камер — цветная картинка 640х480 со звуком, записи хранятся 21 день и все это дело занимает на диске в среднем 135GB, а всесте с фото, которые делает motion около 200 GB.


5. следующая строка: on_event_end — это для команды, отрабатывающей по окончанию события.


6. И еще один нюанс, motion поднимает небольшой http сервер, а так как для каждой камеры запускается своя инстанция программы с отдельным конфигом, то важно, чтобы он слушал на разных портах. Для этого проверяем, чтобы следующие строки отличались в каждом файле:


webcam_port и control_port

Для примера: для первой камеры ставим значения


webcam_port 8081
control_port 8080
для второй
webcam_port 8083
control_port 8082
и так далее.


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


Теперь вернемся к скриптам, которые отрабатывают при начале и окончании события. Так как нам надо писать видео с камеры, то для этого я использовал mencoder. В папке /root/bin/ создаем скрипты recordstart.sh и recordstop.sh, которые будут запускаться при наступлеии и окончании события соответсвенно. Давайте заглянем внутрь recordstart.sh:


[root@video bin]# cat /root/bin/recordstart.sh
#!/bin/bash

# We are using two variables
# 1 — camera name
# 2 — directory name (where file will be stored)

# Generate filename
start=«cam${1}»
dt=`date +%Y%m%d%H%M%S`
FILENAME="${start}-${dt}.avi"
echo $FILENAME

if [ "$1" -eq 218 ]
then
`/usr/bin/mencoder -ovc copy -oac pcm -delay 1.5 -mc 10 -o
/video/motion/$2/$FILENAME rtsp://192.168.95.218/mpeg4/media.amp > /dev/null`
elif [ "$1" -eq 219 ]
then
`/usr/bin/mencoder -ovc copy -oac pcm -delay 1.5 -mc 10 -o
/video/motion/$2/$FILENAME rtsp://192.168.95.219/mpeg4/media.amp > /dev/null`
else
`/usr/bin/mencoder -ovc copy -oac pcm -mc 10 -o /video/motion/$2/$FILENAME
rtsp://192.168.95.$1/mpeg4/media.amp > /dev/null`
fi


Скрипт принимает два параметра:


1 — имя камеры, хотя имя не совсем верно, так как это последний октет из IP адреса камеры. То есть, как в нашем случае (мы используем 95 подсеть — 192.168.95.0/24). Таким образом, при передаче значения 211 — будет ясно, что хотим обратиться к камере с IP 192.168.95.211
2 — директория, где будет храниться записанный файл. Сделано для того, чтобы легче было искать. Опять же в нашем случае: имеется папка /video/motion в которой хранятся записи, но для того, чтобы не мешать все в кучу, она содержит поддиректории зон: kuhnya, balkon и т.д. Значит при передаче значения balcon — запись будеть производиться в директорию /video/motion/balkon.


Итак, при вызове скрипта в виде /root/bin/recordstart.sh 211 balkon — скрипт будет писать с камеры с IP 192.168.95.211 в директорию /video/motion/balkon. Надеюсь тут все более-неменее ясно.

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


  • start — номер камеры, вернее последний октет из ее IP с предшествующим ей cam.
  • dt — текущая дата в формате ГГГГММДДччммсс.


Пример имени файла: cam218-20090924131847.avi — то есть, пишется с камеры с IP 192.168.95.218, дата начала: 2009 год, 09 месяц, 24 число, 13 часов, 18 минут, 47 секунд.

Небольшое пояснение: так уж оказалось, что у нас разные модели камер, которые предоставляют разные способы доступа к потоку видео данных, из-за этого пришлось ввести в скрипте проверки.


Теперь пройдемся по mencoder-у:


  • -ovc copy — означает, что видеоряд копируем, так как с камеры сразу идет в mpeg4
  • -oac pcm — какой кодек использовать для звуковой дорожки, если камера позволяет писать звук.
  • -mc 10 — Максимальная величина корректировки A-V синхронизации на один кадр (в секундах)
  • -delay 1.5 — Задержка в мс, которая должна вноситься в каждый канал


Если у вас проблемы с синхронизацией видео и звукового ряда, тогда надо менять значения для последних двух параметров — mc и delay. Для теста можно использовать mplayer.

Ну вот, теперь при наступлении события, мы можем запускать данный скрипт. Таким образом в конфиге для motion для нашей камеры прописываем в строке on_event_start что-то похожее:


on_event_start "/root/bin/recordstart.sh 210 koridor1"


И он начнет писать. Но ведь это все еще надо остановить. Для этого используем второй скрипт /root/bin/recordstop.sh.


[root@video bin]# cat /root/bin/recordstop.sh
#!/bin/bash

# We are using one variable
# 1 — camera name

# Get string with mencoder process PID
MPID=`ps ax | grep mencoder | grep cam${1} | awk '{ print $1 }'`

# Kill process
`kill -15 $MPID`


Скрипт принимает один параметр — все тот же последний октет из IP адреса камеры.

Соответсвенно в строке on_event_end файла конфигурации прописываем что-то вроде:

on_event_end "/root/bin/recordstop.sh 210"Ну вот примерно и все, что касается конфигурации.


Теперь перейдем к рутинным операциям. У меня используются две, которые отрабатывают по крону.

  1. Удаляет устаревшие файлы, которые страрше 21 дня.
  2. Объединяет все файлы за день в один.


Рассмотрим скрипт для чистки. У меня он располагается в директории /root/sbin и, для того, чтобы враги не догадались, называется clean.sh


[root@video ~]# cat /root/sbin/clean.sh
#!/bin/sh

/bin/find /video/balkon -name "*.*" -mtime +21 -delete
/bin/find /video/motion/balkon -name "*.*" -mtime +21 -delete


В первой директории хранятся фотографии, сделанные motion — это параметр из файла конфигурации в строке target_dir. Вторая директория — куда пишется видео, запущенное из скрипта recordstart.sh


А вот второй скрипт посложнее.


[root@video ~]# cat /root/sbin/concatfiles.py
import os, stat, types, commands

workDir = '/video/motion/'
dirs = os.listdir(workDir)
oldDate = summaryFile = summaryFileTmp = ''
for dir in dirs:
filesList = os.listdir(workDir + dir)
filesList.sort()

for file in filesList:
tmpN = file.split('.')
nm = tmpN[0]
tmpN = nm.split('-')
if tmpN[0] != 'S':
nm = tmpN[1]
year = nm[0:4]
month = nm[4:6]
day = nm[6:8]
date = year + month + day

if oldDate != date:
summaryFile = workDir + dir + '/S-' + tmpN[0] + '-' + year +month + day + '.avi'
summaryFileTmp = workDir + dir + '/S-' + tmpN[0] + '-' + year +month + day + '-tmp.avi'

#conactenate files
command = '/usr/bin/mencoder -oac copy -ovc copy ' + workDir + dir + '/' + tmpN[0] + '-' + date + '*.avi -o ' + summaryFileTmp
os.system(command)


#fix key frame
command = 'ffmpeg -i ' + summaryFileTmp + ' -ss 0.04 -vcodec
copy -acodec copy -vcodec copy -acodec copy ' + summaryFile
os.system(command)

#remove tmp file
command = '/bin/rm -f ' + summaryFileTmp
os.system(command)

#remove old files
command = '/bin/rm -f ' + workDir + dir + '/'+ tmpN[0] + '-' +
date + '*.avi'
os.system(command)
oldDate = date


Это для объединения коротких роликов за день в один суммарный. (Для тех кто не в курсе — он на питоне). Единственное, что нужно менять — это переменная workDir — путь, куда mencoder пишет свои файлы, все из того же recordstart.sh

Прописываем их в крон на выполнение раз в сутки, желательно ночью, пока карета не превратится в тыкву :)

Запускаем motion следующим образом:


motion -c /path/to/config/file


где

/path/to/config/file — путь к нашему файлу с конфигом :)

А далее запускаем их при загрузке системы.

Ну вот наверное и все. Если будут вопросы — задавайте.

UPD: будьте внимательны с скриптом на питоне, так как сбилась вся табуляция, что для него очень критично.


UPD2: отступы восстановлены, но не факт что правильно.


 
MyTetra Share v.0.59
Яндекс индекс цитирования