Last active
November 28, 2019 23:45
-
-
Save x0a/8784b504a4ae94ac45df31bb1ee410fb to your computer and use it in GitHub Desktop.
Zmodo Viewer, bash: View multiple cams in a grid with MPlayer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
server="securitysystem" # my router-defined hostname for my dvr, use ip instead | |
port=8000 | |
res_x=960 # cam resolution, mine is 960H grabbed from running show_cam once w/o -really-silent and watching the output | |
res_y=480 | |
cams=(1 3 4) #show cams 1, 3, and 4, skipping 2 since mine isn't connected | |
function get_current_workspace() { | |
workspace=`wmctrl -d | grep '*' | cut -d ' ' -f1` | |
} | |
function move_to_workspace() { | |
local window_id=`wmctrl -lp | grep $1 | awk '{print $1}'` | |
echo "Moving window $window_id (PID: $1) to workspace $workspace" | |
wmctrl -i -r $window_id -t $workspace | |
} | |
function set_screen_res() { | |
screenx=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1) | |
screeny=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2) | |
} | |
function set_grid() { # args: $1 = number of cams, $2 = round to nearest | |
local grid_size=$(( (($1 + $2 - 1) / $2) * $2 )) | |
cols=$(( $grid_size / 2 )) # if you wanted, you could set a custom number of columns per row | |
rows=$(( $grid_size / $cols )) # and a custom number of rows | |
} | |
function do_math(){ # does math in floating point and returns a regular int | |
last_math=`echo "scale=6; x=$1; scale=0; x / 1" | bc`; | |
} | |
function set_cam_dimensions() { # resize cams so they fit into their cell size, maintaining aspect ratio | |
local cell_x=$(( $screenx / $cols )) | |
local cell_y=$(( $screeny / $rows )) | |
do_math "(($cell_x / $cell_y) > ($res_x / $res_y))" | |
if [ $last_math -eq 1 ]; then | |
cam_y=$(( $cell_y )) | |
do_math "($cell_y / $res_y) * $res_x" | |
cam_x=$(( $last_math )) | |
else | |
cam_x=$(( $cell_x )) | |
do_math "($cell_x / $res_x) * $res_y" | |
cam_y=$(( $last_math )) | |
fi | |
} | |
function show_cam() { # args: $1 = cam number, $2 = x position, #3 = y position | |
local cam=$(($1 - 1)) | |
# send header requesting 720p stream for $cam | |
# then trim first 12 bytes of received data, which is only an echo of what we sent | |
# then add magic bytes to identify as the first NAL unit the h264 stream | |
# finally, open borderless mplayer in stdin mode, with specific position and dimensions | |
echo "Requesting cam $cam at $server:$port $cam_x by $cam_y $2:$3" | |
echo -ne "\x55\x55\xaa\xaa\x00\x00\x00\x00\x00\x$cam\x00\x50" \ | |
| nc $server $port \ | |
| tail -c +12 \ | |
| (echo -ne '\x00\x00\x00\x01' && cat) \ | |
| mplayer -really-quiet -noborder -demuxer h264es -x $cam_x -y $cam_y -geometry "$2:$3" -fps 25 - & | |
# mplayer is run in background to get it's PID, used to move to initial workspace | |
# then we go back to synchrous mode by waiting on that PID | |
local job_id=$! | |
sleep 1 | |
move_to_workspace $job_id | |
wait $job_id | |
} | |
function show_cam_persist() { # re-open cam if connection is lost | |
while true; do | |
show_cam $2 $3 $4 | |
if kill -0 $1 > /dev/null 2>&1 ; then # check parent process still exists | |
echo "Cam connection closed, checking again in 10 seconds" | |
sleep 10 # Zmodo DVR disconnects around midnight fsr, blocks connections that happen too soon after that. | |
# i've experimented with 1s and 5s, both lead to infinite disconnects/reconnects. 10s works | |
else | |
echo "Parent process killed, ending session" | |
break | |
fi | |
done | |
} | |
function main() { # args: $1 = parent PID, $2: boolean = persist | |
local row=0 | |
local col=0 | |
local index=0 | |
local posx=0; | |
local posy=0; | |
for i in ${cams[@]}; do | |
row=$(( $index / $cols )) | |
col=$(( $index % $cols )) | |
posx=$(( $col * $cam_x )) | |
posy=$(( ($row * $cam_y) + 48 )) # offset y position by height of gnome title bar | |
if $2; then | |
show_cam_persist $1 $i $posx $posy & | |
else | |
show_cam $i $posx $posy & | |
fi | |
index=$(( $index + 1 )) | |
done | |
} | |
get_current_workspace | |
set_screen_res | |
set_grid ${#cams[@]} 4 # 1-4 cams = 4 cells, 4-8 = 8 cells total, etc. | |
set_cam_dimensions | |
if [ "$1" == "--persist" ]; then | |
persist=true | |
else | |
persist=false | |
fi | |
main $$ $persist | |
wait |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
3-cam example. If you plan on having these running 24/7, I recommend you keep them in their own workspace. Run with --persist argument to reopen cams if connection closes.