{"id":50,"date":"2007-11-07T17:58:04","date_gmt":"2007-11-07T22:58:04","guid":{"rendered":"http:\/\/blogs.cae.tntech.edu\/mwr\/2007\/11\/07\/grabbing-stills-and-making-flv-movies-from-axis-ip-cameras\/"},"modified":"2024-10-27T14:26:19","modified_gmt":"2024-10-27T14:26:19","slug":"grabbing-stills-and-making-flv-movies-from-axis-ip-cameras","status":"publish","type":"post","link":"https:\/\/sites.tntech.edu\/renfro\/2007\/11\/07\/grabbing-stills-and-making-flv-movies-from-axis-ip-cameras\/","title":{"rendered":"Grabbing Stills and Making FLV Movies from Axis IP Cameras"},"content":{"rendered":"<p>About a week and a half ago, I was reminded of a long-dormant project to archive still images from an Axis IP camera. I started this up a few years ago as a favor to a coworker, but it never really got finished. Previously, it was a pretty simple cron job that would just authenticate to the camera and download the current still. At some point, it would also use ImageMagick to convert the captured JPEGs to an MPEG or similar, but it was decidedly non-optimal.<\/p>\n<p>So now that I was reminded by people who were <strong>very<\/strong> interested in seeing the results (i.e., monitoring their remotely-located labs), I took another stab at it. Much better results this time. Now my customers get:<\/p>\n<ul>\n<li>Still images captured every 30 seconds<\/li>\n<li>FLV movies of the day&#8217;s stills made every 5 minutes<\/li>\n<li>A playlist that lets them browse through previous days&#8217; activity for as long as we keep the movies around<\/li>\n<\/ul>\n<p>The programs and pages that make this mini-site follow below:<br \/>\n<!--more--><br \/>\naxisgrab.py &#8212; extracts current image from the designated Axis camera, encodes today&#8217;s images into an FLV<\/p>\n<pre>\n#!\/usr\/bin\/python\n\nbasename='denso'\naxisip='192.168.0.1'\naxisuser='someuser'\naxispass='somepassword'\nflvcreator='TTU ME Department'\n\nimport urllib2, time, os, re, getopt, sys\n\ndef usage():\n    print \"\"\"axisgrab.py -- grab or encode images from an Axis IP camera\nUsage: axisgrab.py --grab\n       axisgrab.py --encode\n\"\"\"\n\ndef main():\n\n    try:\n        optlist, args = getopt.getopt(sys.argv[1:], 'g:e:',\n                                      [ 'grab', 'encode' ])\n    except getopt.GetoptError:\n        usage()\n        sys.exit(2)\n\n    for opt, junk in optlist:\n        if (opt=='--grab'):    \n            auth_handler = urllib2.HTTPBasicAuthHandler()\n            auth_handler.add_password('\/',axisip,axisuser,axispass)\n            opener = urllib2.build_opener(auth_handler)\n            urllib2.install_opener(opener)\n            axis_jpg=urllib2.urlopen('http:\/\/%s\/axis-cgi\/jpg\/image.cgi' % ( axisip ) )\n    \n            filename='%s_%s_%s.jpg' % ( basename, time.strftime('%Y%m%d'), time.strftime('%H%M%S') )\n            local_jpg=open(filename,'w')\n            local_jpg.write(axis_jpg.read())\n            local_jpg.close()\n            os.chmod(filename,0644)\n\n        if (opt=='--encode'):\n            os.system('mencoder -really-quiet -ovc lavc -lavcopts vcodec=flv -mf fps=25:type=jpg \\\\'mf:\/\/%s_%s*.jpg\\\\' -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -o %s_%s.flv &gt;&amp;\/dev\/null' % ( basename, time.strftime('%Y%m%d'), basename, time.strftime('%Y%m%d') ))\n    \n            playlistname=\"playlist-%s.xml\" % ( basename )\n            playlist=open(playlistname,'w');\n            playlist.write(\"\"\"\n            &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\n            &lt;playlist version=\"1\" xmlns=\"http:\/\/xspf.org\/ns\/0\/\"&gt;\n            &lt;trackList&gt;\n            \"\"\")\n\n    \n            files=os.listdir(\".\")\n            files.sort()\n            repattern=\"%s.+flv\" % ( basename )\n            recompiled=re.compile(repattern)\n            for file in files:\n                if recompiled.search(file):\n                    playlist.write(\"    &lt;track&gt;\\n\")\n                    playlist.write(\"      &lt;title&gt;%s&lt;\/title&gt;\\n\" % (file))\n                    playlist.write(\"      &lt;creator&gt;%s&lt;\/creator&gt;\\n\" % (flvcreator))\n                    playlist.write(\"      &lt;location&gt;%s&lt;\/location&gt;\\n\" % (file))\n                    playlist.write(\"      &lt;info&gt;force_download.php?file=%s&lt;\/info&gt;\\n\" % (file))\n                    playlist.write(\"    &lt;\/track&gt;\\n\")\n\n            playlist.write(\"\"\"\n            &lt;\/trackList&gt;\n            &lt;\/playlist&gt;\n            \"\"\")\n\nif __name__ == \"__main__\":\n    main()\n<\/pre>\n<p>index.php &#8212; main web interface to the images and movies<\/p>\n<pre>\n&lt;?php\n  \/\/ If I did all this correctly, you shouldn't have to change\n  \/\/ anything but the basename variable.\n$basename = \"denso\";\n\n$today = date(\"Ymd\"); \/\/ e.g., 20070901\n$mediabase = $basename.\"_\".$today; \/\/ axisgrab.py stores images with this naming scheme\n$imagewidth = 480; \/\/ Controlled on the camera video\/image settings\n$imageheight = 360; \/\/ Controlled on the camera video\/image settings\n?&gt;\n\n&lt;!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\"&gt;\n&lt;html&gt;\n&lt;head&gt;\n&lt;title&gt;Denso Lab Camera Feed&lt;title&gt;\n&lt;script type=\"text\/javascript\" src=\"swfobject.js\"&gt;&lt;\/script&gt;\n&lt;script type=\"text\/javascript\"&gt;\nvar browser = navigator.appName;\nvar version = parseInt(navigator.appVersion);\n\nfunction showImage(object) {\n  var imageToShow = object.options[object.selectedIndex].value;\n\n  if (browser == 'Netscape') {\n    if (version &gt;= 3) document.dropImage.src = imageToShow;\n    else              alert('Your browser does not support the image object - sorry');\n  }\n  else if (browser == 'Microsoft Internet Explorer') {\n    if (version &gt;= 4) document.dropImage.src = imageToShow;\n    else              frames[0].location.href = imageToShow;\n  }\n}\n\/\/--&gt;&lt;\/script&gt;\n&lt;meta http-equiv=\"refresh\" content=\"300\"&gt;\n\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;table&gt;\n&lt;tr valign=\"top\"&gt;\n&lt;td&gt;\n&lt;h1&gt;Denso Lab Camera Footage&lt;\/h1&gt;\n\n&lt;p&gt;Select a day from the list below to play, or click the icon at the right of the filename to download.&lt;\/p&gt;\n&lt;p id=\"player1\"&gt;&lt;a href=\"http:\/\/www.macromedia.com\/go\/getflashplayer\"&gt;Get the Flash Player&lt;\/a&gt; to see this player.&lt;\/p&gt;\n&lt;script type=\"text\/javascript\"&gt;\n   var s1 = new SWFObject(\"mediaplayer.swf\",\"single\",\"480\",\"480\",\"7\");\ns1.addParam(\"allowfullscreen\",\"true\");\ns1.addParam('allowscriptaccess','always');\ns1.addVariable(\"file\",\"&lt;?php echo \"playlist-\".$basename.\".xml\"; ?&gt;\");\ns1.addVariable('displayheight','360');\ns1.write(\"player1\");\n&lt;\/script&gt;\n&lt;\/td&gt;\n&lt;td&gt;\n&lt;h1&gt;Still Images&lt;\/h1&gt;\n&lt;form name=\"imageForm\"&gt;\n&lt;select name=\"imageSelect\"&gt;\n&lt;?php\nif ($dh = opendir('.\/')) {\n  $files = array();\n  while (($file = readdir($dh)) !== false) {\n    if (substr($file, strlen($file) - 4) == '.jpg') {\n      array_push($files, $file);\n    }\n  }\n  closedir($dh);\n}\n\n\/\/ Sort the files and display\nsort($files);\n\nforeach ($files as $file) {\n  echo \"&lt;option value=$file&gt;$file&lt;\/option&gt;\\n\";\n}\n?&gt;\n&lt;\/select&gt;\n&lt;input name=\"submitName\" type=\"button\" value=\"Show\" onClick=\"showImage(document.imageForm.imageSelect)\"&gt;\n&lt;\/form&gt;\n\n&lt;SCRIPT LANGUAGE=\"JavaScript\"&gt;&lt;!--\nif (browser == 'Netscape')\n  document.write('&lt;IMG SRC=\"&lt;?php echo $mediabase.\"_0000.jpg\"; ?&gt;\" NAME=\"dropImage\" WIDTH=&lt;?php echo $imagewidth;?&gt; HEIGHT=&lt;?php echo $imageheight;?&gt;&gt;');\n else if (browser == 'Microsoft Internet Explorer') {\n   if (version &gt;= 4)\n     document.write('&lt;IMG SRC=\"&lt;?php echo $mediabase.\"_0000.jpg\"; ?&gt;\" NAME=\"dropImage\" WIDTH=&lt;?php echo $imagewidth;?&gt; HEIGHT=&lt;?php echo $imageheight;?&gt;&gt;');\n    else\n      document.write('&lt;IFRAME FRAMEBORDER=0 WIDTH=&lt;?php echo $imagewidth;?&gt; HEIGHT=&lt;?php echo $imageheight\n;?&gt; MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=no SRC=\"&lt;?php echo $mediabase.\"_0000.jpg\"; ?&gt;\"&gt;&lt;\/IFRAME&gt;');\n }\n\/\/--&gt;&lt;\/SCRIPT&gt;\n&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;\/table&gt;\n<\/pre>\n<p>swfobject.js and mediaplayer.swf are part of <a href=\"http:\/\/www.jeroenwijering.com\/?item=JW_Media_Player\">Jeroen Wijering&#8217;s JW Media Player<\/a>.<\/p>\n<p>Cron jobs on the webserver (to grab 2 images per minute):<\/p>\n<pre>\n* * * * * (cd \/path\/to\/axis\/folder &amp;&amp; .\/axisgrab.py --grab &amp;&amp; sleep 30 &amp;&amp; .\/axisgrab.py --grab)\n0,5,10,15,20,25,30,35,40,45,50,55 * * * * (cd \/path\/to\/axis\/folder &amp;&amp; .\/axisgrab.py --encode)\n<\/pre>\n<p>The results:<br \/>\n<a href='http:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2007\/11\/axisscreenshot.png' title='axisscreenshot.png'><img src='http:\/\/blogs.cae.tntech.edu\/mwr\/files\/2007\/11\/axisscreenshot.thumbnail.png' alt='axisscreenshot.png' \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>About a week and a half ago, I was reminded of a long-dormant project to archive still images from an Axis IP camera. I started this up a few years ago as a favor to a coworker, but it never really got finished. Previously, it was a pretty simple cron job that would just authenticate &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/sites.tntech.edu\/renfro\/2007\/11\/07\/grabbing-stills-and-making-flv-movies-from-axis-ip-cameras\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Grabbing Stills and Making FLV Movies from Axis IP Cameras&#8221;<\/span><\/a><\/p>\n","protected":false},"author":87,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,14,17],"tags":[],"class_list":["post-50","post","type-post","status-publish","format-standard","hentry","category-javascript","category-php","category-python","entry"],"_links":{"self":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/50","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/comments?post=50"}],"version-history":[{"count":1,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/50\/revisions"}],"predecessor-version":[{"id":478,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/50\/revisions\/478"}],"wp:attachment":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/media?parent=50"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/categories?post=50"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/tags?post=50"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}