From: Calin Crisan Date: Sat, 28 Jun 2014 15:42:37 +0000 (+0300) Subject: added camera frame (full screen) support X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=f5902f56fe33407b9bd8533f0575176f5294c78e;p=motioneye-debian added camera frame (full screen) support --- diff --git a/doc/todo.txt b/doc/todo.txt index 0c770cf..2de429f 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -1,4 +1,3 @@ -> in continuare o camera remote moarta blocheaza intreg sistemul la load -> use minimum_frame_time -> implement custom camera frame sizes --> add a separate full-screen camera link diff --git a/src/handlers.py b/src/handlers.py index d391ee5..8e35d79 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -563,6 +563,9 @@ class PictureHandler(BaseHandler): elif op == 'list': self.list(camera_id) + elif op == 'frame': + self.frame(camera_id) + elif op == 'download': self.download(camera_id, filename) @@ -639,6 +642,14 @@ class PictureHandler(BaseHandler): mediafiles.list_media(camera_config, media_type='picture', callback=on_media_list, prefix=self.get_argument('prefix', None)) + @BaseHandler.auth() + def frame(self, camera_id): + camera_config = config.get_camera(camera_id) + + self.render('frame.html', + camera_id=camera_id, + camera_config=camera_config) + @BaseHandler.auth() def download(self, camera_id, filename): logging.debug('downloading picture %(filename)s of camera %(id)s' % { diff --git a/src/server.py b/src/server.py index 3d6064e..181b45e 100644 --- a/src/server.py +++ b/src/server.py @@ -44,7 +44,7 @@ application = Application( (r'^/config/main/(?Pset|get)/?$', handlers.ConfigHandler), (r'^/config/(?P\d+)/(?Pget|set|rem|set_preview)/?$', handlers.ConfigHandler), (r'^/config/(?Padd|list|list_devices)/?$', handlers.ConfigHandler), - (r'^/picture/(?P\d+)/(?Pcurrent|list)/?$', handlers.PictureHandler), + (r'^/picture/(?P\d+)/(?Pcurrent|list|frame)/?$', handlers.PictureHandler), (r'^/picture/(?P\d+)/(?Pdownload|preview)/(?P.+)/?$', handlers.PictureHandler), (r'^/movie/(?P\d+)/(?Plist)/?$', handlers.MovieHandler), (r'^/movie/(?P\d+)/(?Pdownload|preview)/(?P.+)/?$', handlers.MovieHandler), diff --git a/static/css/frame.css b/static/css/frame.css new file mode 100644 index 0000000..92ac8f9 --- /dev/null +++ b/static/css/frame.css @@ -0,0 +1,109 @@ + + + /* basic */ + +* { + padding: 0px; + border: 0px solid black; + margin: 0px; + outline: 0px; + border-spacing: 0px; + border-collapse: separate; +} + +html { + height: 100%; +} + +body { + height: 100%; + color: #dddddd; + background-color: #212121; +} + + + /* layout */ + +img.main-loading-progress { + display: block; + margin: auto; + margin-top: 50px; +} + +div.add-camera-message { + text-align: center; + margin-top: 30px; +} + + + /* camera frame */ + +div.camera-frame { + position: relative; + width: 100%; + height: 100%; + transition: all 0.2s, opacity 0s; + opacity: 0; + vertical-align: top; +} + +div.camera-container { + height: 100%; +} + +img.camera { + width: 100%; + height: auto; + display: block; + transition: opacity 0.2s linear; + opacity: 1; +} + +img.camera.error, +img.camera.loading { + opacity: 0; + height: 100%; +} + +div.camera-placeholder { + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + text-align: center; + transition: opacity 0.2s linear; +} + +img.no-camera { + margin-top: 20%; + width: 30%; + opacity: 0.8; +} + +div.camera-progress { + background: rgba(0, 0, 0, 0.001); /* otherwise IE would not extend this as expected */ + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + opacity: 0; + transition: all 0.2s linear; + text-align: center; +} + +div.camera-progress.visible { + opacity: 0.4; +} + +img.camera-progress { + border: 10px solid white; + border-radius: 10px; + position: absolute; + top: 0px; + left: 0px; + bottom: 0px; + right: 0px; + margin: auto; +} diff --git a/static/js/frame.js b/static/js/frame.js new file mode 100644 index 0000000..af4997b --- /dev/null +++ b/static/js/frame.js @@ -0,0 +1,154 @@ + +var refreshDisabled = false; +var inProgress = false; +var refreshInterval = 50; /* milliseconds */ + + + /* progress */ + +function beginProgress() { + if (inProgress) { + return; /* already in progress */ + } + + inProgress = true; + + /* show the camera progress indicator */ + $('div.camera-progress').addClass('visible'); +} + +function endProgress() { + if (!inProgress) { + return; /* not in progress */ + } + + inProgress = false; + + /* hide the camera progress indicator */ + $('div.camera-progress').removeClass('visible'); +} + + + /* camera frame */ + +function setupCameraFrame() { + var cameraFrameDiv = $('div.camera-frame') + var cameraPlaceholder = cameraFrameDiv.find('div.camera-placeholder'); + var cameraProgress = cameraFrameDiv.find('div.camera-progress'); + var cameraImg = cameraFrameDiv.find('img.camera'); + var progressImg = cameraFrameDiv.find('img.camera-progress'); + + cameraFrameDiv[0].refreshDivider = 0; + cameraFrameDiv[0].streamingFramerate = parseInt(cameraFrameDiv.attr('streaming_framerate')) || 1; + cameraFrameDiv[0].streamingServerResize = cameraFrameDiv.attr('streaming_server_resize') == 'True'; + progressImg.attr('src', staticUrl + 'img/camera-progress.gif'); + + cameraProgress.addClass('visible'); + cameraPlaceholder.css('opacity', '0'); + + /* fade in */ + cameraFrameDiv.animate({'opacity': 1}, 100); + + /* error and load handlers */ + cameraImg.error(function () { + this.error = true; + this.loading = 0; + + cameraImg.addClass('error').removeClass('loading'); + cameraPlaceholder.css('opacity', 1); + cameraProgress.removeClass('visible'); + }); + cameraImg.load(function () { + if (refreshDisabled) { + return; /* refresh temporarily disabled for updating */ + } + + this.error = false; + this.loading = 0; + + cameraImg.removeClass('error').removeClass('loading'); + cameraImg.css('height', ''); + cameraPlaceholder.css('opacity', 0); + cameraProgress.removeClass('visible'); + }); + + cameraImg.addClass('loading'); +} + +function refreshCameraFrame() { + var $cameraFrame = $('div.camera-frame'); + var cameraFrame = $cameraFrame[0]; + var img = $cameraFrame.find('img.camera')[0]; + var cameraId = cameraFrame.id.substring(6); + + /* limit the refresh rate to 20 fps */ + var count = Math.max(1, 1 / cameraFrame.streamingFramerate * 1000 / refreshInterval); + + if (img.error) { + /* in case of error, decrease the refresh rate to 1 fps */ + count = 1000 / refreshInterval; + } + + if (cameraFrame.refreshDivider < count) { + cameraFrame.refreshDivider++; + } + else { + (function () { + if (refreshDisabled) { + /* camera refreshing disabled, retry later */ + + return; + } + + if (img.loading) { + img.loading++; /* increases each time the camera would refresh but is still loading */ + + if (img.loading > 2 * 1000 / refreshInterval) { /* limits the retry at one every two seconds */ + img.loading = 0; + } + else { + return; /* wait for the previous frame to finish loading */ + } + } + + var timestamp = Math.round(new Date().getTime()); + + var uri = '/picture/' + cameraId + '/current/?seq=' + timestamp; + if (cameraFrame.serverSideResize) { + uri += '&width=' + img.width; + } + + img.src = uri; + img.loading = 1; + + cameraFrame.refreshDivider = 0; + })(); + } + + setTimeout(refreshCameraFrame, refreshInterval); +} + +function checkCameraErrors() { + /* properly triggers the onerror event on the cameras whose imgs were not successfully loaded, + * but the onerror event hasn't been triggered, for some reason (seems to happen in Chrome) */ + var cameraFrame = $('div.camera-frame').find('img.camera'); + + cameraFrame.each(function () { + if (this.complete === true && this.naturalWidth === 0 && !this.error && this.src) { + $(this).error(); + } + }); + + setTimeout(checkCameraErrors, 500); +} + + + /* startup function */ + +$(document).ready(function () { + beginProgress(); + setupCameraFrame(); + refreshCameraFrame(); + checkCameraErrors(); +}); + diff --git a/static/js/main.js b/static/js/main.js index b0fe343..820a9e3 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1958,7 +1958,7 @@ function doFullScreenCamera(cameraId) { return; /* a camera is already in full screen */ } - fullScreenCameraId = -1; /* aviods successive fast toggles of fullscreen */ + fullScreenCameraId = -1; /* avoids successive fast toggles of fullscreen */ var cameraFrameDiv = $('#camera' + cameraId); var cameraName = cameraFrameDiv.find('span.camera-name').text(); diff --git a/templates/frame.html b/templates/frame.html new file mode 100644 index 0000000..6b3635a --- /dev/null +++ b/templates/frame.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block style %} + {{super()}} + +{% endblock %} + +{% block script %} + {{super()}} + +{% endblock %} + +{% block body %} +
+ +
+
+ +
+
+
+{% endblock %}