From 5de7928471bb5d208ce3d352bc6812c398c09b51 Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Sun, 29 Sep 2013 20:24:03 +0300 Subject: [PATCH] added camera refresh code --- doc/todo.txt | 4 +++ src/config.py | 1 + src/handlers.py | 8 +++--- static/css/main.css | 21 +++++++++++++-- static/js/main.js | 66 ++++++++++++++++++++++++++++++++++++++------- templates/main.html | 8 +++--- 6 files changed, 90 insertions(+), 18 deletions(-) diff --git a/doc/todo.txt b/doc/todo.txt index 2ff1d97..d1032ac 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -1,3 +1,7 @@ +-> camera not available background and icon design +-> remove current snapshot GET logs +-> a nice shadow behind the header + -> group @config rules to top -> browser compatibility test -> requirements test diff --git a/src/config.py b/src/config.py index 8624660..8e3c617 100644 --- a/src/config.py +++ b/src/config.py @@ -472,6 +472,7 @@ def _set_default_motion_camera(data): data.setdefault('width', 352) data.setdefault('height', 288) data.setdefault('framerate', 1) + data.setdefault('rotate', 0) data.setdefault('@storage_device', 'local-disk') data.setdefault('@network_server', '') diff --git a/src/handlers.py b/src/handlers.py index 06f9927..17f9e8f 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -157,19 +157,19 @@ class ConfigHandler(BaseHandler): value = int(controls['contrast']) logging.debug('setting contrast to %(value)s...' % {'value': value}) - v4l2ctl.set_brightness(device, value) + v4l2ctl.set_contrast(device, value) if 'saturation' in controls: value = int(controls['saturation']) logging.debug('setting saturation to %(value)s...' % {'value': value}) - v4l2ctl.set_brightness(device, value) + v4l2ctl.set_saturation(device, value) if 'hue' in controls: value = int(controls['hue']) logging.debug('setting hue to %(value)s...' % {'value': value}) - v4l2ctl.set_brightness(device, value) + v4l2ctl.set_hue(device, value) def list_cameras(self): logging.debug('listing cameras') @@ -245,6 +245,7 @@ class ConfigHandler(BaseHandler): 'width': int(ui['resolution'].split('x')[0]), 'height': int(ui['resolution'].split('x')[1]), 'framerate': int(ui.get('framerate', 1)), + 'rotate': int(ui.get('rotation', 0)), # file storage '@storage_device': ui.get('storage_device', 'local-disk'), @@ -371,6 +372,7 @@ class ConfigHandler(BaseHandler): 'hue': int(round(int(data['hue']) / 2.55)), 'resolution': str(data['width']) + 'x' + str(data['height']), 'framerate': int(data['framerate']), + 'rotation': int(data['rotate']), # file storage 'storage_device': data['@storage_device'], diff --git a/static/css/main.css b/static/css/main.css index 5c10d41..efe24fc 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -328,12 +328,29 @@ div.camera-button.configure { } div.camera-container { + position: relative; padding: 0px; } img.camera { + position: relative; width: 100%; display: block; + transition: opacity 0.2s linear; + opacity: 1; +} + +img.camera.error { + opacity: 0; +} + +div.camera-placeholder { + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + background-color: #555; } @@ -371,7 +388,7 @@ img.camera { @media all and (max-width: 1900px) { /* a bit smaller screens */ - div.video-frame { + div.camera-frame { width: 48%; } } @@ -379,7 +396,7 @@ img.camera { @media all and (max-width: 1150px) { /* even smaller screens */ - div.video-frame { + div.camera-frame { width: 98%; } } diff --git a/static/js/main.js b/static/js/main.js index fbaef3e..c6ae76f 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -755,9 +755,9 @@ function pushCameraConfig() { function pushPreview() { var cameraId = $('#videoDeviceSelect').val(); var brightness = $('#brightnessSlider').val(); - var contrast= $('#brightnessSlider').val(); - var saturation = $('#brightnessSlider').val(); - var hue = $('#brightnessSlider').val(); + var contrast= $('#contrastSlider').val(); + var saturation = $('#saturationSlider').val(); + var hue = $('#hueSlider').val(); var data = { 'brightness': brightness, @@ -772,7 +772,7 @@ function pushPreview() { /* camera frames */ -function addCameraFrameUi(cameraId, cameraName) { +function addCameraFrameUi(cameraId, cameraName, framerate) { var cameraFrameDiv = $( '
' + '
' + @@ -783,6 +783,7 @@ function addCameraFrameUi(cameraId, cameraName) { '
' + '
' + '
' + + '
' + '' + '
' + ''); @@ -793,6 +794,8 @@ function addCameraFrameUi(cameraId, cameraName) { var cameraImg = cameraFrameDiv.find('img.camera'); cameraFrameDiv.attr('id', 'camera' + cameraId); + cameraFrameDiv[0].framerate = framerate; + cameraFrameDiv[0].refreshDivider = 0; nameSpan.html(cameraName); /* insert the new camera frame at the right position, @@ -827,8 +830,17 @@ function addCameraFrameUi(cameraId, cameraName) { doCloseCamera(cameraId); }); - /* add content to the frame */ - cameraImg.attr('src', staticUrl + 'img/video1.jpg'); + /* error and load handlers */ + cameraImg.error(function () { + this.error = true; + cameraImg.addClass('error'); + cameraImg.height(Math.round(cameraImg.width() * 0.75)); + }); + cameraImg.load(function () { + this.error = false; + cameraImg.removeClass('error'); + cameraImg.css('height', ''); + }); } function remCameraFrameUi(cameraId) { @@ -855,12 +867,17 @@ function recreateCameraFrames(cameras) { } } - /* add new camera frames */ + /* add new camera frames and update existing camera params */ for (i = 0; i < cameras.length; i++) { camera = cameras[i]; - if (pageContainer.find('div.camera-frame#camera' + camera.id).length === 0) { - addCameraFrameUi(camera.id); + var cameraFrame = pageContainer.find('div.camera-frame#camera' + camera.id); + if (cameraFrame.length === 0) { /* not existing, add a new one */ + addCameraFrameUi(camera.id, camera.name, camera.streaming_framerate); + } + else { /* existing, update params */ + cameraFrame[0].framerate = camera.streaming_framerate; } + } } @@ -895,6 +912,36 @@ function doCloseCamera(cameraId) { }); } +function refreshCameraFrames() { + function refreshCameraFrame(cameraId, img) { + img.src = '/snapshot/' + cameraId + '/current/?_=' + new Date().getTime(); + } + + var cameraFrames = $('div.page-container').find('div.camera-frame'); + cameraFrames.each(function () { + /* limit the refresh rate to 10 fps */ + var count = Math.max(1, 10 / this.framerate); + var img = $(this).find('img.camera')[0]; + + if (img.error) { + /* in case of error, decrease the refresh rate to 1 fps */ + count = 10; + } + + if (this.refreshDivider < count) { + this.refreshDivider++; + } + else { + var cameraId = this.id.substring(6); + refreshCameraFrame(cameraId, img); + + this.refreshDivider = 0; + } + }); + + setTimeout(refreshCameraFrames, 100); +} + /* startup function */ @@ -922,4 +969,5 @@ $(document).ready(function () { initUI(); fetchCurrentConfig(); + refreshCameraFrames(); }); diff --git a/templates/main.html b/templates/main.html index 10c0532..04bf770 100644 --- a/templates/main.html +++ b/templates/main.html @@ -119,10 +119,10 @@ Video Rotation ? -- 2.39.5