Éppen el voltam havazva munkákkal, és azt reméltem, pár órán belül megoldom a feladatot. Amikor kezdett elszállni a reményem, hogy kész megoldást találjak a problémára, szomorúan beláttam, hogy az előzetesen reméltnél több időt fog elvinni ez a munka, de még mindig nem sejtettem, mennyi küzdelemnek nézek még elébe...
Az első ötletem az volt, hogy Raspberry Pi-vel emulálok egy USB háttértárat, ezt rádugom az eszközre, és ezen, illetve a hálózaton keresztül menti a képet a távoli épületben levő Linux szerverre. Ehhez a megoldáshoz nem állt rendelkezésre a megfelelő pénzügyi keret, így olyan irányba indultam el, ami egy fillér befektetést sem igényel (a munkaidőmön kívül).
Az eszköznek van webes felülete, ahol valós időben nézhetők a kamerák képei, de ez csak Windows és Internet Explorer alatt nézhető, mivel a videojel lekérését és megjelenítését ActiveX vezérlővel végzi. A Linuxos munkaállomásomon VirtualBoxba feltelepítettem egy Windows 7-est, és WireSharkkal figyeltem az ActiveX kommunikációját.
Azt láttam, hogy a nézőprogram bináris parancsokat küld az eszköznek, az pedig válaszul egy olyan adatfolyamot küld, ahol nyers h.264 stream van valamilyen egyedi(?) metainformációt hordozó adatcsomagokba ágyazva.
Megpróbáltam tehát írni egy olyan programot, ami az általam nem teljesen értett bináris parancsokat a megfelelő TCP csatornán elküldi az eszköznek, a válaszul kapott adatfolyamról pedig lefejti az egyedi keretfejléceket, hogy csak a nyers h.264 adatfolyam maradjon. Bash shell scriptben készült el az alkotás! Sajnos még mindig nem végzi teljesen tökéletesen a keretfejlécek eltávolítását, mert az mplayer és az ffplay időnként (átlagosan kb. fél óra folyamatos nézés után) elveszti a képet, és újra kell indítani. A lemezre mentett nyers adat azonban érdekes módon mindig jól konvertálható (mondjuk AVI-ba), és nem is biztos, hogy az én programomban van a hiba.
Néhány általánosan ismert segédprogramon kívül (pl. netcat, ffmpeg) fontos szerepet kapott a bbe (Binary Block Editor: http://bbe-.sourceforge.net/) nevű parancs is. Ez vágja ki a keretfejléceket az adatfolyamból. A kész szkript a következőképpen néz ki:
#!/bin/bash
#########################################################################
# TechSon TC-DVR LN40xx tipusu eszkozok elo videokepenek
# megtekintesere es mentesere szolgalo segedprogram
#
# A szkript a kovetkezo GNU stilusu opciokat fogadja el:
#
# --dvr=IPCIM_vagy_HOSZTNEV:
# Kotelezo opcio. A kezelendo DVR eszkoz elerhetoseget kell itt megadni.
#
# --cam=KAMERA_SORSZAM
# Nem kotelezo opcio. A figyelendo kamera sorszama 1-tol 16-ig.
# Az alapertelmezett sorszam 1.
#
# --quality=MINOSEG
# Nem kotelezo opcio. Ha erteke low, kis felbontasu kepet kapunk,
# ha erteke high, nagy felbontasut. Az alapertelmezett ertek "high".
#
# --username=FELHASZNALONEV:
# Kotelezo opcio. A szkript ezzel a felhasznalonevvel csatlakozik a DVR
# eszkozhoz. Hossza legfeljebb 8 ASCII karakter.
#
# --password=JELSZO:
# Kotelezo opcio. A szkript ezzel a jelszoval csatlakozik a DVR
# eszkozhoz. Hossza legfeljebb 8 ASCII karakter.
#
# --duration=IDOTARTAM
# Nem kotelezo opcio. Ennyi masodperc utan a szkript kilep.
# Alapertelmezett erteke 0, ami vegtelen mukodest jelent.
#
# --recode=ATKODOLAS:
# Nem kotelezo opcio. Haromfele erteket vehet fel:
#
# avi: A szkript AVI formatumu adatfolyamot ad ki a standard outputon.
# Elo megtekinteshez ez az opcio ajanlott.
#
# avc: A szkript a gyartospecifikus metaadatot eltavolitva nyers H264
# adatfolyamot ad ki a standard outputon. Ez az alapertelmezett ertek.
#
# raw: A szkript a kamera altal kuldott adatfolyamot valtozatlan
# formaban adja ki. Bar nagy a tarhelyigenye, folyamatos menteshez ez
# az opcio ajanlott a bbe szurosbol adodo esetleges adatvesztesek
# elkerulese erdekeben, illetve azert, hogy a lementett fajlbol
# indexelheto (azaz keresheto/tekerheto) videofajlt keszithessunk,
# mert az ffmpeg erre streambol nem, csak lementett fajlbol kepes.
# Keresheto fajl keszitese raw fajlbol (cam1.264):
#
# bbe -b '/1111/:6' -e 'r 4 \x00\x00' cam1.264 |\
# bbe -b ':/1111\x00\x00\x00\x00PACK/' -e 'L 8' -e D |\
# bbe -e 'I 1111\x00\x00\x00\x00PACK' |\
# bbe -b '/1111\x00\x00\x00\x00/:36' -e D -o cam1.avc
# ffmpeg -f h264 -r 25 -i cam1.avc -vcodec copy cam1.avi
#
# Alternativ megoldas az ffmeg helyett (Windows-os segedprogrammal):
# avc2avi.exe -i cam1.avc -o cam1.avi
#
#########################################################################
sender () {
sleep 2
echo -ne "$AUTH"
sleep 2
echo -ne "$INIT"
sleep 5
echo -ne "$CAM"
while true
do
sleep 10
echo -ne "$KEEPALIVE"
if (( DURATION > 0 ))
then
NOW="$(date +%s)"
(( NOW > DURATION )) && exit 0
fi
done
}
INIT='\x31\x31\x31\x31\x10\x01\x00\x00\x03\x04\x00\x00\x20\xb6\x7c\x07\x3e\x0a\x3c\x63\x00\x01\x00\x00\x00\xf8\x20\x6e\x61\x6d\x65\x3d\x01\xf8\x6f\x6e\x66\x69\x67\x5f\x02\xf8\x71\x75\x65\x73\x74\x5f\x03\xf8\x74\x22\x3e\x0a\x3c\x70\x04\xf8\x61\x6d\x65\x74\x65\x72\x05\xf8\x61\x6d\x65\x3d\x22\x63\x06\xf8\x66\x69\x67\x5f\x69\x74\x07\xf8\x22\x3e\x70\x74\x7a\x5f\x08\xf8\x65\x73\x65\x74\x5f\x69\x09\xf8\x6f\x3c\x2f\x70\x61\x72\x0a\xf8\x65\x74\x65\x72\x3e\x0a\x0b\xf8\x61\x72\x61\x6d\x65\x74\x0c\xf8\x20\x6e\x61\x6d\x65\x3d\x0d\xf8\x6f\x6e\x66\x69\x67\x5f\x0e\xf8\x65\x6d\x22\x3e\x70\x74\x0f\xf8\x63\x72\x75\x69\x73\x65\x40\xf8\x6e\x66\x6f\x3c\x2f\x70\x41\xf8\x61\x6d\x65\x74\x65\x72\x42\xf8\x3c\x2f\x63\x6f\x6d\x6d\x43\xf8\x64\x3e\x0a\x3c\x2f\x72\x44\xf8\x75\x65\x73\x74\x3e\x0a\x45\xf8\x30\x35\x00\x00\x00\x00\x46\xf8\x00\xb3\x0b\xf3\x02\x00\x47\xf8\x7d\x07\x08\xb6\x7c\x07\x48\xf8\x00\x00\x00\x00\x00\x00\x49\xf8\x24\x00\x43\x41\x4d\x45\x4a\xf8\x30\x36\x00\x00\x00\x00\x4b\xf8\x00\x00\x00\x00\x00\x00\x4c\xf8\x00\x00\x00\x00\x00\x00\x4d\xf8\x00\x00\x00\x00\x00\x00\x4e\xf8\x24\x00\x43\x41\x4d\x45\x4f\xf8\x30\x37\x00\x00\x00\x00'
KEEPALIVE='\x31\x31\x31\x31\x00\x00\x00\x00'
DVR=''
CAM=1
QUALITY='high'
USERNAME=''
PASSWORD=''
PAD='\x00\x00\x00\x00\x00\x00\x00\x00'
RECODE='bbe'
DURATION=0
for i in $@
do
if [[ "$i" =~ ^--dvr= ]]
then
DVR="${i:6}"
elif [[ "$i" =~ ^--cam= ]]
then
CAM="${i:6}"
elif [[ "$i" =~ ^--quality= ]]
then
QUALITY="${i:10}"
elif [[ "$i" =~ ^--username= ]]
then
USERNAME="${i:11}"
elif [[ "$i" =~ ^--password= ]]
then
PASSWORD="${i:11}"
elif [[ "$i" =~ ^--recode= ]]
then
RECODE="${i:9}"
elif [[ "$i" =~ ^--duration= ]]
then
DURATION="${i:11}"
if (( DURATION > 0 ))
then
(( DURATION += $(date +%s) ))
fi
else
echo "Ismeretlen opció: $i" >/dev/stderr
exit 1
fi
done
[[ $DVR == '' ]] || [[ $USERNAME == '' ]] || [[ $PASSWORD == '' ]] && exit 1
USERNAME=$(echo -n $USERNAME | hexdump -ve '/1 "_%02x"' | sed 's/_/\\x/g')
LEN=$((32-${#USERNAME}))
USERNAME=${USERNAME:0:32}${PAD:0:$LEN}
PASSWORD=$(echo -n $PASSWORD | hexdump -ve '/1 "_%02x"' | sed 's/_/\\x/g')
LEN=$((32-${#PASSWORD}))
PASSWORD=${PASSWORD:0:32}${PAD:0:$LEN}
AUTH="\x31\x31\x31\x31\x88\x00\x00\x00\x01\x01\x00\x00\x02\x01\x00\x00\x01\x00\x00\x00\x78\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00${USERNAME}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00${PASSWORD}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x27\x9a\xf1\xa6\x00\x00\x04\x00\x00\x00"
CAM=$(( echo -n 0000 ; echo "obase=16; 2^(${CAM}-1)" | bc ) | sed -r 's/^.*(.{2})(.{2})$/\\x\2\\x\1/')
if [[ $QUALITY == low ]]
then
CAM="\x31\x31\x31\x31\x34\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00${CAM}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
else
CAM="\x31\x31\x31\x31\x34\x00\x00\x00\x03\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31\x31\x31\x31\x34\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00${CAM}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31\x31\x31\x31\x10\x00\x00\x00\x0c\x05\x00\x00\xd2\x04\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
fi
case "$RECODE" in
raw)
sender | netcat "$DVR" 7000
;;
avi)
{ echo -ne '1111\x00\x00\x00\x00PACK' ; sender | netcat "$DVR" 7000 | bbe -b '/1111/:6' -e 'r 4 \x00\x00' | bbe -b ':/1111\x00\x00\x00\x00PACK/' -e 'L 8; D' ; } |\
bbe -b '/1111\x00\x00\x00\x00/:36' -e D |\
ffmpeg -f h264 -i - -vcodec copy -f avi -
;;
*)
{ echo -ne '1111\x00\x00\x00\x00PACK' ; sender | netcat "$DVR" 7000 | bbe -b '/1111/:6' -e 'r 4 \x00\x00' | bbe -b ':/1111\x00\x00\x00\x00PACK/' -e 'L 8; D' ; } |\
bbe -b '/1111\x00\x00\x00\x00/:36' -e D
;;
esac
Következzék egy példa a program indítására! A 192.168.0.1 IP című eszköz 1-es számú kamerájának élőképét nézzük magas minőségben "jozsi" felhasználónévvel és a megfelelő jelszóval:
./techson.sh --dvr=192.168.0.1 --username=jozsi --password=jozsi_jelszava --quality=high --cam=1 | ffplay -f h264 -i -
Az éles képrögzítő szerveren egyébként nem teljesen így paraméterezem a szkriptet: A cron démon segítségével óránként újraindítom, és a --duration paramétert megadva 1 óra 2 percre korlátozom a futásidőt. A szkript standard outputját fájlba irányítom. A fájlok óránként keletkeznek, és egymást - a biztonság kedvéért - két perccel átfedő videoanyagot tartalmaznak.
Érdekességképpen írtam egy másik szkriptet, amely lehetővé teszi, hogy másik kamera képére váltsunk egy folyamatban levő stream-ben. Ehhez a futó nézőszkript által indított netcat processz PID-jére van szükségünk. Ennek a szkripten a meghívása a következőképpen történhet:
tamas@kisgep:~/Dokumentumok/biztonsági kamerák> ps -A | grep netcat
12681 pts/1 00:00:00 netcat
tamas@kisgep:~/Dokumentumok/biztonsági kamerák> ./changecam.sh --pid=12681 --quality=high --cam=5
Maga a szkript pedig így néz ki:
#!/bin/bash
CAM=1
QUALITY='high'
for i in $@
do
if [[ "$i" =~ ^--pid= ]]
then
NETCATPID="${i:6}"
elif [[ "$i" =~ ^--cam= ]]
then
CAM="${i:6}"
elif [[ "$i" =~ ^--quality= ]]
then
QUALITY="${i:10}"
else
echo "Ismeretlen opció: $i" >/dev/stderr
exit 1
fi
done
(( NETCATPID > 0 )) || exit 1
CAM=$(( echo -n 0000 ; echo "obase=16; 2^(${CAM}-1)" | bc ) | sed -r 's/^.*(.{2})(.{2})$/\\x\2\\x\1/')
if [[ $QUALITY == low ]]
then
CAM="\x31\x31\x31\x31\x34\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00${CAM}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
else
CAM="\x31\x31\x31\x31\x34\x00\x00\x00\x03\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31\x31\x31\x31\x34\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00${CAM}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31\x31\x31\x31\x10\x00\x00\x00\x0c\x05\x00\x00\xd2\x04\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
fi
echo -ne "$CAM" > "/proc/$NETCATPID/fd/0"
- nice blogja
- A hozzászóláshoz be kell jelentkezni
- 1575 megtekintés
Hozzászólások
Minden tiszteletem!
------------------------
{0} ok boto
boto ?
- A hozzászóláshoz be kell jelentkezni
+1, asztakurta - remélem ezért fizettek neki rendesen
"Jegyezze fel a vádhoz - utasította Metcalf őrnagy a tizedest, aki tudott gyorsírni. - Tiszteletlenül beszélt a feljebbvalójával, amikor nem pofázott közbe."
- A hozzászóláshoz be kell jelentkezni
A fizetésemen felül külön jutalmat nem kaptam. Ez mondjuk nem zavar, de meg sem köszönték. De az sem zavar olyan nagyon.
- A hozzászóláshoz be kell jelentkezni
"Beállítható, hogy a mozgás kezdete előtt hány másodperccel induljon a felvétel ..."
És ezt hogy? :)
- A hozzászóláshoz be kell jelentkezni
Úgy, hogy természetesen pufferben megvannak a korábbi képkockák is, csak nincsenek fájlba kiírva, ha nem szükségesek.
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
:D
Van egy angluar js-re épülő predict.js lib (jQuery kell még hozzá)..
- A hozzászóláshoz be kell jelentkezni
Egyébként leteszteltem, mi történik, ha hirtelen megszakad a kapcsolat a TechSon eszköz és a szkriptet futtató rögzítőszerver közötti kapcsolat, azaz mondjuk befut egy szabotőr az eszköznek helyet adó szobába, és szétveri, vagy simán kihúzza a konnektorból. Úgy találtam, hogy a kapcsolat megszakadása előtt kevesebb, mint egy másodperccel ér véget a lementett videofelvétel, ami nem rossz eredmény. Remélem, jó módszerrel mértem.
- A hozzászóláshoz be kell jelentkezni
A metaadat esetleg rtp, MPEG transport stream? (utóbbi kevésbé valószínű)
- A hozzászóláshoz be kell jelentkezni
Köszi a tippet. Lehet, hogy majd egyszer a távoli jövőben ránézek.
- A hozzászóláshoz be kell jelentkezni
nice! :D
Dahua is hasonlót csinál, van is rá opensource project, hogy mplayerbe lehessen Pipe-olni a képet:
http://tanidvr.sourceforge.net/
Látom itt a jelszó plaintextben utazik, én nem voltam ilyen szerencsés:
http://hup.hu/node/141894
Egyszer már nekiestem megIDA-zni, de nem jutottam messzire (az ASM tudásom csekély volt a problémához).
- A hozzászóláshoz be kell jelentkezni
Ha jól látom, a mi eszközünket nem támogatja a tanidvr. Én pedig tényleg mákos voltam hozzád képest, leszámítva, hogy nálam viszont a streamet nem értelmezik a videolejátszók, amíg meg nem szerkesztem. Azóta sincs megoldásod a jelszókódolásra?
- A hozzászóláshoz be kell jelentkezni
Nem sajnos nem jutottam előbbre. Írtam egy "szerver emulátort" hogy lehessen DVR nélkül is tesztelni. Behúztam IDA-ba, meg nagyjából meg is van hol van a DLL-ben az enkódoló rutin, de visszafejtenem még nem sikerült. Van egy ismerősöm aki pro x86 ASM-ben majd megkérem, hogy segítsen.
- A hozzászóláshoz be kell jelentkezni
Szép munka! :)
---------------------------------------
Devmeme - fejlesztői pillanatok
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
Szép munka
--
TH
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
A kamerák belső HDD-re mentik a videót. Azt lehet tudni, hogy a kamerákon milyen rendszer fut? Van soros portja? A burkolatát megbontva lehet hogy hozzá lehet férni soros porthoz a panelján, de kívülről nem látható.
____________________________________
Ha vita van, számoljanak órajelciklusokat. Egyesével.
- A hozzászóláshoz be kell jelentkezni
Mire tudnám használni a soros portot?
- A hozzászóláshoz be kell jelentkezni
Például olyat lehetne csinálni, hogy nem a kamerától kéred el a képet, hanem maga a kamera adja oda. Feltölti egy szerverre például.
Scriptet írni a kamerára.
____________________________________
Ha vita van, számoljanak órajelciklusokat. Egyesével.
- A hozzászóláshoz be kell jelentkezni
Érdekes! Milyen rendszerek támogatnak ilyet?
- A hozzászóláshoz be kell jelentkezni
A kérdésem erre irányult volna, hogy a kamerák amikkel dolgozol, támogatnak-e ilyet.
____________________________________
Ha vita van, számoljanak órajelciklusokat. Egyesével.
- A hozzászóláshoz be kell jelentkezni