Difference between revisions of "External Live Stream"
(24 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Here | Here are some examples of embedding the ZM camera stream in a webpage. | ||
==Webpage to View Streams (non-API)== | ==Webpage to View Streams (non-API)== | ||
Line 40: | Line 34: | ||
==Webpage to View Streams (API)== | ==Webpage to View Streams (API)== | ||
Here's an example of setting up a stream on a webpage using the API. This is better if you use ZMNinja, as it doesn't require adjusting the auth configs as above (which will break zmninja). First, understand there are three parts to this. | Here's an example of setting up a stream on a webpage using the API. This is better if you use ZMNinja, as it doesn't require adjusting the auth configs as above (which will break zmninja). This is taken in part from: https://zoneminder.readthedocs.io/en/stable/api.html#getting-an-api-key First, understand there are three parts to this. | ||
* A script that runs on the server, obtains a recent valid token for the stream, and stream edits (sed) it into an index.php file | * A script that runs on the server, obtains a recent valid token for the stream, and stream edits (sed) it into an index.php file | ||
* An index.php file that is always available online | * An index.php file that is always available online | ||
Line 78: | Line 72: | ||
*/15 * * * * root /etc/zmscript/script.sh | */15 * * * * root /etc/zmscript/script.sh | ||
</pre> | </pre> | ||
==Imagemap of Cameras== | |||
[[File:Output5.gif|300px|thumb|right|Imagemap as the GUI for Zoneminder is very effective, albeit this example is blurred for privacy sake. Trust me that it is better than it appears here.]] | |||
If you only have 1 or 2 cameras, this probably isn't relevant, however if you have a larger installation, it can be slow and cumbersome to use the ZM gui to view cameras. The solution is to make an HTML imagemap, and an iframe, and view the cameras from a custom webpage. | |||
===Overview=== | |||
Using the API instructions above, we can add basic auth and have a webpage to view streams. It's a reasonable next step to take an imagemap and put links for each video on the map, with an iframe at the top which will display one stream at a time. Let's get started. | |||
====Imagemap==== | |||
First you will need a map of your property. It can be an architectural drawing, or googlemap image, or perhaps an overhead drone view. Take that image, load it in GIMP and add circles where the cameras are. Next you will need the generate the HTML code. | |||
You wouldn't want to make the code from scratch, that would be tedious, so instead use an imagemap generator. The one I used which worked well was https://github.com/n-peugnet/image-map-creator and the live instance here: https://n-peugnet.github.io/image-map-creator/ | |||
Unfortunately I wasn't easily able to find one that could be self-hosted (which is preferred). Import your graphic and make circles (a 2nd time) where your circles on the graphic are. Make sure to add labels to all the circles (right click) this way you can find them in the code later. Let's use the following map image. | |||
[[File:Map.png|400px|||]] | |||
You don't need a realistic looking map. Anything that is remotely similar will be functional. Import it into the above generator and create the circles. If you do it properly you will have something that looks like this in html code: | |||
<pre> | |||
<map name="map.png" id="map.png"> | |||
<area shape="circle" coords="229,73,23" nohref alt="" title="shedinside" /> | |||
<area shape="circle" coords="354,134,29" nohref alt="" title="shedoutside" /> | |||
<area shape="circle" coords="185,183,27" nohref alt="" title="mainrearleft" /> | |||
<area shape="circle" coords="152,347,28" nohref alt="" title="mainoutsidefrontleft" /> | |||
<area shape="circle" coords="534,356,28" nohref alt="" title="mainoutsidefrontright" /> | |||
<area shape="circle" coords="506,185,25" nohref alt="" title="mainrearright" /> | |||
<area shape="circle" coords="715,180,25" nohref alt="" title="garageinside" /> | |||
<area shape="circle" coords="728,301,28" nohref alt="" title="garageoutside" /> | |||
</map> | |||
</pre> | |||
This image map HTML will need some editing after the fact. In particular, you will want to delete the nohref, as we will be filling in the details for the URLs later. Also the URLs will go at the end of the tag, so the sed command mentioned above for the API works properly. | |||
====Webpage with iframe==== | |||
I'm going to jump ahead with an example for brevity's sake. This page will include the bare minimum to get a working page similar to the gif above. We will use the javascript reload from the API example above, as well as the script to refresh the tokens on the webpage. It's assumed you are hosting the page on the same server as the cameras. Please read the comments on the HTML for important notes on this setup if this is new to you. | |||
<pre> | |||
<html> | |||
<head> | |||
<script type="text/javascript" > | |||
setInterval(function() { | |||
window.location.reload(); | |||
}, 1800000); | |||
</script> | |||
</head> | |||
<body> | |||
<center> | |||
<!-- IFRAME --> | |||
<iframe id="mainframe" | |||
name="iframetarget" | |||
title="Inline Frame Example" | |||
src="introimagerecommended" | |||
style="height: 420px;width: 500px;border: 0px;" > | |||
</iframe> | |||
<!-- to target anchor links to iframe, target of imagemap (or any anchor link) must be the name of the iframe --> | |||
<!-- https://stackoverflow.com/questions/740816/open-link-in-iframe --><!-- note: that height x width doesn't seem to work --> | |||
<div style="transform: scale(0.7); margin: 0px;"> | |||
<!-- IMAGEMAP --> | |||
<img src="./map.png" alt="Workplace" usemap="#mymap" style="position: relative; top: -200px"> | |||
<!-- note that the img here has the usemap and #mymap values, which correspond to the map's name --> | |||
<map name="mymap" id="mymap"> | |||
<area shape="circle" coords="229,73,23" target="iframtarget" title="shedinside" href="https://myzmserver/zm/cgi-bin/nph-zms?scale=100&width=640px&height=480px&mode=jpeg&maxfps=12&buffer=1000&&monitor=1&token=thisismytoken" /> | |||
<area shape="circle" coords="354,134,29" target="iframetarget" title="shedoutside" href="https://myzmserver/zm/cgi-bin/nph-zms?scale=100&width=640px&height=480px&mode=jpeg&maxfps=12&buffer=1000&&monitor=2&token=thisismytoken" /> | |||
</map> | |||
</div> | |||
</center> | |||
</body> | |||
</html> | |||
</pre> | |||
That's it. Javascript is technically not required, unless you want the tokens to update. PHP is also not required. The sed command may need to account for double slashes in the URL, so it can be edited from | |||
sed -i -e "s|token=.*|token=$res' \\>|" /var/www/nginx/index.html | |||
to | |||
sed -i -e "s|token=.*|token=$res\" \\>|" /var/www/nginx/index.html | |||
====See Also==== | |||
https://forums.zoneminder.com/viewtopic.php?t=31702 - Map code from another user that was imported into ZM, and should be ready for 1.38. | |||
==Tips== | ==Tips== | ||
Line 91: | Line 174: | ||
Js isn't necessarily needed here, since you will only be refreshing every couple of minutes. Though you can use js for a more seamless transition. | Js isn't necessarily needed here, since you will only be refreshing every couple of minutes. Though you can use js for a more seamless transition. | ||
===Scale may be required for large numbers of cameras or SBCs=== | ===Scale may be required for large numbers of cameras or resource constrained hardware (SBCs)=== | ||
See that scale=100 option in the URL? That is used to downscale or downsample the video stream resolution. But, since you set the height and width, it won't make the video smaller. If you have a 2K stream, but you are viewing it at 640x480, you don't need 100% scaling. Lower the number to keep the bandwidth / memory usage down. | See that scale=100 option in the URL? That is used to downscale or downsample the video stream resolution. But, since you set the height and width, it won't make the video smaller. If you have a 2K stream, but you are viewing it at 640x480, you don't need 100% scaling. Lower the number to keep the bandwidth / memory usage down. | ||
Line 126: | Line 209: | ||
==See Also== | ==See Also== | ||
* https://forums.zoneminder.com/viewtopic.php?t=33241 keyboard shortcuts for PTZ | |||
* https://greasyfork.org/en/scripts/500524-zoneminder-ptz-arrow-keys/code per previous link | |||
* https://wiki.zoneminder.com/How_to_view_the_latest_frame_of_a_camera | * https://wiki.zoneminder.com/How_to_view_the_latest_frame_of_a_camera | ||
* [[Dummies_Guide#Watching_the_Cameras]] | |||
[[Category:Dummies_Guide]] | [[Category:Dummies_Guide]] |
Latest revision as of 20:40, 15 July 2024
Here are some examples of embedding the ZM camera stream in a webpage.
Webpage to View Streams (non-API)
In 1.32 and 1.34, you may have to adjust the following setting for auth_relay if authentication is used. Note that this conflicts with ZMNinja, which requires auth_relay to be set to hashed, I believe.
Post by rockedge» Fri Jun 30, 2017 8:09 pm in a WordPress page or post I use something like this: Remember that with certain authorizations set, the URL would be slightly different. this URL works when : Options->System->OPT_USE_AUTH = ON Options->System->AUTH_TYPE = Builtin Options->System->AUTH_RELAY = NONE <h2><img class="aligncenter" src="http://your_zm_server/cgi-bin/nph-zms?mode=jpeg&scale=100&maxfps=5&buffer=1000&monitor=1&user=admin" alt="stream down" width="420" height="340" /></h2>
ref:https://forums.zoneminder.com/viewtopic.php?f=36&t=26292
Note that this URL omits password. But it is given in the top example.
Example Webpage
<html><body bgcolor="black"> <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=1&scale=100"&user="watchinguser"&pass="somepassword" > <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=2&scale=100"&user="watchinguser"&pass="somepassword" > <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=3&scale=100"&user="watchinguser"&pass="somepassword" > <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=4&scale=100"&user="watchinguser"&pass="somepassword" > <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=5&scale=100"&user="watchinguser"&pass="somepassword" > <img width="412px" height="268px" src="http://IPOFZMSERVER/zm/cgi-bin/nph-zms?mode=jpeg&monitor=6&scale=100"&user="watchinguser"&pass="somepassword" > </body> </html>
Webpage to View Streams (API)
Here's an example of setting up a stream on a webpage using the API. This is better if you use ZMNinja, as it doesn't require adjusting the auth configs as above (which will break zmninja). This is taken in part from: https://zoneminder.readthedocs.io/en/stable/api.html#getting-an-api-key First, understand there are three parts to this.
- A script that runs on the server, obtains a recent valid token for the stream, and stream edits (sed) it into an index.php file
- An index.php file that is always available online
- A crontab entry to periodically run the script
For reference, see the zoneminder.readthedocs.org section regarding the API. Also, you may want to password protect / setup basic auth on the webserver if this is wan-accessible. If you do put this behind basic auth, and you want to 'save' the password in the browser, modern browsers require an HTTPS certificate as well, so in that case you might use dynamic dns and lets encrypt (that will be outside the scope of this guide).
- script
#!/bin/bash -x cd /etc/zmscript && curl -X POST -d "user=username&pass=password" http://localhost/zm/api/host/login.json > cred cd /etc/zmscript && cat cred | jq .access_token | tr -d \" > token cd /etc/zmscript && res=$(cat token) # sed -i -e 's/whole line/whole line' sed -i -e "s|token=.*|token=$res' \\>|" /var/www/nginx/index.php
- index.php
<html> <head> ==Image Map of Cameras== <title>OK</title> <script type="text/javascript" > setInterval(function() { window.location.reload(); }, 1800000); </script> </head> <body> <img src='https://yourserverwanipordns/zm/cgi-bin/nph-zms?scale=200&width=640p&height=480px&mode=jpeg&maxfps=12&buffer=1000&&monitor=1&token=sometokengoeshere' > </body> </html>
- /etc/crontab entry
*/15 * * * * root /etc/zmscript/script.sh
Imagemap of Cameras
If you only have 1 or 2 cameras, this probably isn't relevant, however if you have a larger installation, it can be slow and cumbersome to use the ZM gui to view cameras. The solution is to make an HTML imagemap, and an iframe, and view the cameras from a custom webpage.
Overview
Using the API instructions above, we can add basic auth and have a webpage to view streams. It's a reasonable next step to take an imagemap and put links for each video on the map, with an iframe at the top which will display one stream at a time. Let's get started.
Imagemap
First you will need a map of your property. It can be an architectural drawing, or googlemap image, or perhaps an overhead drone view. Take that image, load it in GIMP and add circles where the cameras are. Next you will need the generate the HTML code.
You wouldn't want to make the code from scratch, that would be tedious, so instead use an imagemap generator. The one I used which worked well was https://github.com/n-peugnet/image-map-creator and the live instance here: https://n-peugnet.github.io/image-map-creator/ Unfortunately I wasn't easily able to find one that could be self-hosted (which is preferred). Import your graphic and make circles (a 2nd time) where your circles on the graphic are. Make sure to add labels to all the circles (right click) this way you can find them in the code later. Let's use the following map image.
You don't need a realistic looking map. Anything that is remotely similar will be functional. Import it into the above generator and create the circles. If you do it properly you will have something that looks like this in html code:
<map name="map.png" id="map.png"> <area shape="circle" coords="229,73,23" nohref alt="" title="shedinside" /> <area shape="circle" coords="354,134,29" nohref alt="" title="shedoutside" /> <area shape="circle" coords="185,183,27" nohref alt="" title="mainrearleft" /> <area shape="circle" coords="152,347,28" nohref alt="" title="mainoutsidefrontleft" /> <area shape="circle" coords="534,356,28" nohref alt="" title="mainoutsidefrontright" /> <area shape="circle" coords="506,185,25" nohref alt="" title="mainrearright" /> <area shape="circle" coords="715,180,25" nohref alt="" title="garageinside" /> <area shape="circle" coords="728,301,28" nohref alt="" title="garageoutside" /> </map>
This image map HTML will need some editing after the fact. In particular, you will want to delete the nohref, as we will be filling in the details for the URLs later. Also the URLs will go at the end of the tag, so the sed command mentioned above for the API works properly.
Webpage with iframe
I'm going to jump ahead with an example for brevity's sake. This page will include the bare minimum to get a working page similar to the gif above. We will use the javascript reload from the API example above, as well as the script to refresh the tokens on the webpage. It's assumed you are hosting the page on the same server as the cameras. Please read the comments on the HTML for important notes on this setup if this is new to you.
<html> <head> <script type="text/javascript" > setInterval(function() { window.location.reload(); }, 1800000); </script> </head> <body> <center> <!-- IFRAME --> <iframe id="mainframe" name="iframetarget" title="Inline Frame Example" src="introimagerecommended" style="height: 420px;width: 500px;border: 0px;" > </iframe> <!-- to target anchor links to iframe, target of imagemap (or any anchor link) must be the name of the iframe --> <!-- https://stackoverflow.com/questions/740816/open-link-in-iframe --><!-- note: that height x width doesn't seem to work --> <div style="transform: scale(0.7); margin: 0px;"> <!-- IMAGEMAP --> <img src="./map.png" alt="Workplace" usemap="#mymap" style="position: relative; top: -200px"> <!-- note that the img here has the usemap and #mymap values, which correspond to the map's name --> <map name="mymap" id="mymap"> <area shape="circle" coords="229,73,23" target="iframtarget" title="shedinside" href="https://myzmserver/zm/cgi-bin/nph-zms?scale=100&width=640px&height=480px&mode=jpeg&maxfps=12&buffer=1000&&monitor=1&token=thisismytoken" /> <area shape="circle" coords="354,134,29" target="iframetarget" title="shedoutside" href="https://myzmserver/zm/cgi-bin/nph-zms?scale=100&width=640px&height=480px&mode=jpeg&maxfps=12&buffer=1000&&monitor=2&token=thisismytoken" /> </map> </div> </center> </body> </html>
That's it. Javascript is technically not required, unless you want the tokens to update. PHP is also not required. The sed command may need to account for double slashes in the URL, so it can be edited from
sed -i -e "s|token=.*|token=$res' \\>|" /var/www/nginx/index.html
to
sed -i -e "s|token=.*|token=$res\" \\>|" /var/www/nginx/index.html
See Also
https://forums.zoneminder.com/viewtopic.php?t=31702 - Map code from another user that was imported into ZM, and should be ready for 1.38.
Tips
Quickly Change pixel settings for page
It should be possible to use CSS and have the videos fill the page appropriately (I haven't gotten around to it. Contributions welcome.) but it's also possible to use sed here to adjust the pixels as needed:
sed -e 's/oldpx/newpx/g' -i cameras.html
Refresh Page Periodically
Refreshing the page is a good idea, so that any streams don't drop out for any reason. You can do this with xdotool (see Dedicated_SBC_Camera_Monitor#Refresh_Screen_Periodically )or possibly with html:[1]
Js isn't necessarily needed here, since you will only be refreshing every couple of minutes. Though you can use js for a more seamless transition.
Scale may be required for large numbers of cameras or resource constrained hardware (SBCs)
See that scale=100 option in the URL? That is used to downscale or downsample the video stream resolution. But, since you set the height and width, it won't make the video smaller. If you have a 2K stream, but you are viewing it at 640x480, you don't need 100% scaling. Lower the number to keep the bandwidth / memory usage down.
Where this is required, is when you have a lot of monitors, say 20+ cameras. Or you have an SBC that can't handle full res streams. In these scenarios, if you don't scale, you will either see the CPU max out on the watching computer, or you will see video feeds drop in and out periodically. For more details, see how ZM handles the URL for montage.
Single Snapshot URL
The URL for a single snapshot is:
http://serverip/zm/cgi-bin/nph-zms?mode=single&monitor=2&scale=100&maxfps=5&buffer=1000&user=somename&pass=somepass
Adjust Monitor # as needed. (Also see note in setup section above).
Alternative Single Snapshop JPG via ZMU
zmu is a binary, along with zma, and zmc that can do various functions. One of them is creating a jpeg.
/usr/bin# zmu -h zmu <-d device_path> [-v] [function] [-U<username> -P<password>] zmu <-m monitor_id> [-v] [function] [-U<username> -P<password>] General options: -h, --help : This screen -v, --verbose : Produce more verbose output ... -i, --image [image_index] : Write captured image to disk as <monitor_name>.jpg, last image captured or specified ring buffer index if given.
I put a full usage example here: https://wiki.zoneminder.com/How_to_view_the_latest_frame_of_a_camera
ffplay
It is possible to use ffplay to directly stream a single camera feed (bypassing ZM) to the desktop. Although refreshing may be more involved.
ffplay -i rtsp://user:Password@ipaddress:554/video