bosh_dinion.sh

Monitoring wizyjny - CCTV, RTSP, detekcja ruchu, nagrywanie

Klasycznym podejściem do cyfrowej rejestracji nagrań z monitoringu wideo była rejestracja w oparciu o dedykowany rejestrator sprzętowy lub komputer wyposarzony w stosowną kartę wejść wideo. Rejestracji takiej mogła toważyszyć detekcja ruchu (nagrywanie tylko wtedy kiedy obraz się zmienia) oraz przesyłanie takiego obrazu przez sieć. Uciążliwością w takim podejściu była konieczność stosowania osobnego okablowania (kabel koncentryczny 75 ohmów) lub specjalych transformatorów do przesyłu obrazu z kamer po skrętce oraz moc obliczeniowa rejestratora potrzebna do kompresji wideo lub konieczność stosowania specjalistycznych kart z kompresją sprzętową.

Od czasu popularyzacji kamer IP scenariusz ten często wygląda inaczej - obraz komperowany jest sprzętowo w samej kamerze i w ten sposób przesyłany poprzez sieć komputerową. Także detekcja ruchu i nagrywanie mogą być realizowane w samej kamerze, niestety jednak kamery które potrafiłyby zapisać filmik w oparciu o detekcję (uwzględniający pre-bufor, czyli jakiś odcinek czasu przed detekcją, a także zakończyć taką rejestrację jakiś czas po ustaniu detekcji ruchu) bezpośrednio na dysku sieciowym (np. NFS) należą do rzadkości (osobiście nie trafiłem na taką). Nawet porządne kiamery dostępne na rynku (np. seria iPolis Samsunga, na której w sporej mierze bazuje ten artykuł) potrafią jedynie wysłać obrazek (pojedyńczą klatkę) na serwer FTP. Wymusza to (jeżeli chemy mieć zdalną rejestrację w postaci filmów) albo ciągłe nagrywanie strumienia RTSP, albo jego dekodowanie i detekcję ruchu z użyciem jakiegoś softu przeznaczonego do tego (np. motion, zoneminder, ...), lbo próbę implementacji tego w oparciu o bufor cylkiczny (jako pre-bufor) i wykorzystanie detekcji opartej o kamerę (informacje te dostępne są z użyciem np. http).

Odbiór/nagrywanie strumienia RTSP można zrealizować na kilka sposobów np.:

W obu wypadkach możemy zamiast zapisywać do zwykłego pliku wysyłać odebrane dane do potoku nazwanego (patrz mkfifo) lub na standardowe wyjście (w szczególności dane odebrane avconv możemy przekazać do VLC w celu np. wyświetlenia, ale nie zawsze się to udaje). Ponaddto w obu wypadkach możemy taki strumień przesyłać ponownie (robić za proxy). Coprawda live555 zawiera w sobie proste proxy rtsp z obsługą wielu strumieni - live555ProxyServer, ale z użyciem VLC możemy robić to przy okazji i dodatkowo wspierając (na wyjściu) IPv6. Takie rozwiązanie daje nam też większe możliwości konfiguracyjne (możemy użyć np. VLM) i zapewnia lepszą stabilność od live555ProxyServer (w prowadzonych testach po jakimś czasie nie można było się do niego podłączyć (vlc zwracał "live555 demux error: no data received in 10s, aborting").

Ogólna koncepcja systemu odpowiedzialnego na rejestrację RTSP w oparciu o detekcję robioną na kamerze może wyglądać następująco:

  1. Odbieramy strumień RTSP, retransmitujemy go (np. jako http lub rtsp) celem zdalnego podglądu i równoczesnie przesyłamy do narzędzi odpowiedzialnego za ngrywanie.
  2. Narzędzie takie utrzymuje bufor cykliczny (tablica + przeskakujący na jej początek gdy dojdzie do końca wskaźnik - miejsce zapisu) przechowując w nim ostatnie n sekund danych.
  3. Narzędzie to samo bada stan detekcji ruchu na kamerze lub dostaje taką informację z zewnatrz (np. poprzez wykrywanie H w wget --quiet -O - 'http://admin:4321@192.168.119.49/cgi-bin/control.cgi?msubmenu=motion&action=monitor') i w momęcie detekcji dokonuje zapisu buforu do pliku (nazwa tworzona w oparciu o aktualny czas i ajkiś prefix).
  4. Od momentu wykrycia detekcji bierzące dane dopisywane są do tego pliku aż do upłynięcia m sekund od zakończenia detekcji. Jeżli w tym czasie zajdze detekcja nie przestajemy dopisywać danych.
  5. Po upłynięciu m sekund od zakończenia detekcji kończy pisanie do pliku i zaczyna pisać do bufora cyklicznego.

Do realizacji proxy dla strumieni wideo możemy także wykożystać avserver. Umożliwia on sam w sobie realizację timeshiftu opartego na jakiemś rodzaju bufora cyklicznego, dzięki czemu może uprośckić realizację opisanego powyżej nagrywania na skutek detekcji z pre-buforem.

Koncepcje dalszego rozwoju

bosh_dinion.sh

#!/bin/bash

# set of command for Bosh Dinion IP CCTV cameras

# conversion date (or unix timestamp) to camera time stamp: 946684800 is 2000-01-01 00:00:00
# USAGE: cctv_convertDate "YYYY-mm-dd HH:MM:SS"
# USAGE: cctv_convertDate "@UNIXTIME"
cctv_convertDate() {
  printf %x $(( `date -d "$@" +%s` - 946684800 ))
}

# return session id for rtsp stream
cctv_getSession() {
  rtsp_sess=`wget -O - "http://$HOST:$PORT/rcp.xml?command=0x0ae8&type=T_DWORD&direction=READ&protocol=TCP&num=$RAND" | xmlstarlet sel -t -v '//rcp/result/hex'`
  if [ `printf %d $rtsp_sess` -ne 0 ]; then
    echo $rtsp_sess
  else
    wget -O - "http://$HOST:$PORT/rcp.xml?command=0xFF0C&type=P_OCTET&direction=WRITE&num=1&idstring=connect&payload=0x0001001000000000001327100000000001010000000000004040FFFF00000000" |
      xmlstarlet sel -t -v '//rcp/sessionid'
  fi
}

# execute commande (read or write) on camera
# USAGE: cctv_cmd command mode args_string
cctv_cmd() {
  wget -O - "http://$HOST:$PORT/rcp.xml?command=$1&sessionid=`cctv_getSession`&direction=$2&$3"
  # get SESSION_ID before any set/get operation because session_id can be changed on reset video in client
}

# command write to camera
# USAGE: cctv_set command args_string
cctv_set() {
  cctv_cmd "$1" WRITE "$2"
}

# command read from camera
# USAGE: cctv_get command args_string
cctv_get() {
  cctv_cmd "$1" READ "$2"
}

# start RTSP replay session with vlc as client
# USAGE: cctv_start host port "YYYY-mm-dd HH:MM:SS"
cctv_start() {
  HOST="$1"
  PORT="$2"
  RAND=$RANDOM
  vlc --rtsp-tcp --rtsp-http --rtsp-http-port $PORT "rtsp://$HOST:$PORT/rtsp_tunnel?&inst=1&rec=1?enableaudio=1&audio_mode=0&rnd=$RAND&seek=0x`cctv_convertDate "$3"`" &
}


# seek replay to time position
# USAGE: cctv_goToDate "YYYY-mm-dd HH:MM:SS"
# vlc can stop play after this call (when go backward?)
cctv_goToDate() {
  cctv_set  0x0905 "type=P_OCTET&payload=0x`cctv_convertDate "$1"`"
  
}

# seek replay to current position (live stream)
cctv_goToLive() {
  cctv_set 0x0963 "type=T_DWORD&payload=1"
}

# set play speed, 100 = normal
cctv_setSpeed() {
  cctv_set  0x0902 "type=T_INT&num=1&payload=$1"
}

# read time info from camera
cctv_getDate() {
  cctv_get  0x0905 "type=P_OCTET"
  
}


# get raw record info from cammera
# USAGE: cctv_getRecordInfoRaw [start_time end_time]
# optional times in "YYYY-mm-dd HH:MM:SS" format
cctv_getRecordInfoRaw() {
  if [ $# -lt 2 ]; then
    cctv_get 0x0901 "type=P_OCTET&payload=0xffffffff00000000000007ff00000000"
  else
    cctv_get 0x0901 "type=P_OCTET&payload=0x`cctv_convertDate "$1"``cctv_convertDate "$2"`000007ff00000000"
  fi
}

# get formatted record info from cammera
# USAGE: cctv_getRecordInfo [start_time end_time]
# optional times in "YYYY-mm-dd HH:MM:SS" format
cctv_getRecordInfo() {
  cctv_getRecordInfoRaw "$@" | xmlstarlet sel -t -v '//rcp/result/str' |
  awk -F '  ' '{print $1, $2; print $3, $4}' |
  awk --non-decimal-data '
    BEGIN {
      printf("   date and time   \ttime id \tlen [s]\t  flags  \t file id\n")
    }
    $1 != "" {
      start  = ("0x"$1$2$3$4)
      len    = ("0x"$5$6$7$8) - ("0x"$1$2$3$4)
      flags  = ("0x"$9$10$11$12)
      fileid = ("0x"$13$14$15$16)
      printf("%s\t%x\t%6d\t%s\t%s\n", strftime("%Y-%m-%d %H:%M:%S", start + 946684800), start, len, flags, fileid)
    }
  '
}

XHTML generated by highlight (http://www.andre-simon.de/) from bosh_dinion.sh



Copyright (c) 1999-2015, Robert Paciorek (http://www.opcode.eu.org/), BSD/MIT-type license


Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.

This text/program is free document/software. Redistribution and use in source and binary forms, with or without modification, ARE PERMITTED provided save this copyright notice. This document/program is distributed WITHOUT any warranty, use at YOUR own risk.

Valid XHTML 1.1 Dokument ten (URL: http://www.opcode.eu.org/usage_and_config/monitoring/cctv) należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek, wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: '2015-07-05 08:46:28 (UTC)' (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).