From 59c8f0051a6874e045e4edeee1845ccf4e66ebbc Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Sun, 29 Sep 2013 19:08:02 +0300 Subject: [PATCH] added preview controls --- src/config.py | 3 +- src/handlers.py | 97 +++++++++++++++++++++++++++++++++++++++-------- src/server.py | 2 +- src/v4l2ctl.py | 6 +-- static/js/main.js | 29 ++++++++++++++ 5 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/config.py b/src/config.py index e84fb27..8624660 100644 --- a/src/config.py +++ b/src/config.py @@ -483,11 +483,12 @@ def _set_default_motion_camera(data): data.setdefault('webcam_localhost', False) data.setdefault('webcam_port', 8080) data.setdefault('webcam_maxrate', 1) - data.setdefault('webcam_quality', 50) + data.setdefault('webcam_quality', 75) data.setdefault('webcam_motion', False) data.setdefault('text_left', '') data.setdefault('text_right', '') + data.setdefault('text_double', True) data.setdefault('text_changes', False) data.setdefault('locate', False) diff --git a/src/handlers.py b/src/handlers.py index a78901b..06f9927 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -11,6 +11,23 @@ import v4l2ctl class BaseHandler(RequestHandler): + def get_data(self): + keys = self.request.arguments.keys() + data = dict([(key, self.get_argument(key)) for key in keys]) + + for key in self.request.files: + files = self.request.files[key] + if len(files) > 1: + data[key] = files + + elif len(files) > 0: + data[key] = files[0] + + else: + continue + + return data + def render(self, template_name, content_type='text/html', **context): self.set_header('Content-Type', content_type) @@ -51,6 +68,9 @@ class ConfigHandler(BaseHandler): if op == 'set': self.set_config(camera_id) + elif op == 'set_preview': + self.set_preview(camera_id) + elif op == 'add': self.add_camera() @@ -68,7 +88,12 @@ class ConfigHandler(BaseHandler): if camera_id not in camera_ids: raise HTTPError(404, 'no such camera') - ui_config = self._camera_dict_to_ui(config.get_camera(camera_id)) + camera_config = config.get_camera(camera_id) + ui_config = self._camera_dict_to_ui(camera_config) + resolutions = v4l2ctl.list_resolutions(camera_config['videodevice']) + resolutions = [(str(w) + 'x' + str(h)) for (w, h) in resolutions] + + ui_config['available_resolutions'] = resolutions self.finish_json(ui_config) else: @@ -110,6 +135,42 @@ class ConfigHandler(BaseHandler): data = self._main_ui_to_dict(data) config.set_main(data) + def set_preview(self, camera_id): + try: + controls = json.loads(self.request.body) + + except Exception as e: + logging.error('could not decode json: %(msg)s' % {'msg': unicode(e)}) + + raise + + camera_config = config.get_camera(camera_id) + device = camera_config['videodevice'] + + if 'brightness' in controls: + value = int(controls['brightness']) + logging.debug('setting brightness to %(value)s...' % {'value': value}) + + v4l2ctl.set_brightness(device, value) + + if 'contrast' in controls: + value = int(controls['contrast']) + logging.debug('setting contrast to %(value)s...' % {'value': value}) + + v4l2ctl.set_brightness(device, value) + + if 'saturation' in controls: + value = int(controls['saturation']) + logging.debug('setting saturation to %(value)s...' % {'value': value}) + + v4l2ctl.set_brightness(device, value) + + if 'hue' in controls: + value = int(controls['hue']) + logging.debug('setting hue to %(value)s...' % {'value': value}) + + v4l2ctl.set_brightness(device, value) + def list_cameras(self): logging.debug('listing cameras') @@ -177,10 +238,10 @@ class ConfigHandler(BaseHandler): 'videodevice': video_device, 'lightswitch': int(ui.get('light_switch_detect', False) * 5), 'auto_brightness': ui.get('auto_brightness', False), - 'brightness': int(int(ui.get('brightness', 0)) * 2.55), - 'contrast': int(int(ui.get('contrast', 0)) * 2.55), - 'saturation': int(int(ui.get('saturation', 0)) * 2.55), - 'hue': int(int(ui.get('hue', 0))), + 'brightness': max(1, int(round(int(ui.get('brightness', 0)) * 2.55))), + 'contrast': max(1, int(round(int(ui.get('contrast', 0)) * 2.55))), + 'saturation': max(1, int(round(int(ui.get('saturation', 0)) * 2.55))), + 'hue': max(1, int(round(int(ui.get('hue', 0)) * 2.55))), 'width': int(ui['resolution'].split('x')[0]), 'height': int(ui['resolution'].split('x')[1]), 'framerate': int(ui.get('framerate', 1)), @@ -201,7 +262,7 @@ class ConfigHandler(BaseHandler): 'webcam_localhost': not ui.get('video_streaming', True), 'webcam_port': int(ui.get('streaming_port', 8080)), 'webcam_maxrate': int(ui.get('streaming_framerate', 1)), - 'webcam_quality': max(1, int(ui.get('streaming_quality', 50))), + 'webcam_quality': max(1, int(ui.get('streaming_quality', 75))), 'webcam_motion': ui.get('streaming_motion', False), # still images @@ -244,7 +305,7 @@ class ConfigHandler(BaseHandler): data['text_left'] = ui.get('name') elif left_text == 'timestamp': - data['text_left'] = '%Y-%m-%d\n%T' + data['text_left'] = '%Y-%m-%d\\n%T' else: data['text_left'] = ui.get('custom_left_text', '') @@ -254,10 +315,14 @@ class ConfigHandler(BaseHandler): data['text_right'] = ui.get('name') elif right_text == 'timestamp': - data['text_right'] = '%Y-%m-%d\n%T' + data['text_right'] = '%Y-%m-%d\\n%T' else: data['text_right'] = ui.get('custom_right_text', '') + + if not ui.get('video_streaming', True): + data['webcam_maxrate'] = 5 + data['webcam_quality'] = 75 if ui.get('still_images', False): capture_mode = ui.get('capture_mode', 'motion-triggered') @@ -276,7 +341,7 @@ class ConfigHandler(BaseHandler): data['quality'] = max(1, int(ui.get('image_quality', 75))) if ui.get('motion_movies', False): - data['ffmpeg_variable_bitrate'] = 2 + int((100 - int(ui.get('movie_quality', 50))) * 0.29) + data['ffmpeg_variable_bitrate'] = 2 + int((100 - int(ui.get('movie_quality', 75))) * 0.29) data['movie_filename'] = ui.get('movie_file_name', '%Y-%m-%d-%H-%M-%S-%q') if ui.get('working_schedule', False): @@ -300,10 +365,10 @@ class ConfigHandler(BaseHandler): 'device': data['@proto'] + '://' + data['videodevice'], 'light_switch_detect': data['lightswitch'] > 0, 'auto_brightness': data['auto_brightness'], - 'brightness': int(int(data['brightness']) / 2.55), - 'contrast': int(int(data['contrast']) / 2.55), - 'saturation': int(int(data['saturation']) / 2.55), - 'hue': int(int(data['hue'])), + 'brightness': int(round(int(data['brightness']) / 2.55)), + 'contrast': int(round(int(data['contrast']) / 2.55)), + 'saturation': int(round(int(data['saturation']) / 2.55)), + 'hue': int(round(int(data['hue']) / 2.55)), 'resolution': str(data['width']) + 'x' + str(data['height']), 'framerate': int(data['framerate']), @@ -339,7 +404,7 @@ class ConfigHandler(BaseHandler): # motion movies 'motion_movies': False, - 'movie_quality': 50, + 'movie_quality': 75, 'movie_file_name': '%Y-%m-%d-%H-%M-%S-%q', 'preserve_movies': data['@preserve_movies'], @@ -375,7 +440,7 @@ class ConfigHandler(BaseHandler): if text_left == data['@name']: ui['left_text'] = 'camera-name' - elif text_left == '%Y-%m-%d\n%T': + elif text_left == '%Y-%m-%d\\n%T': ui['left_text'] = 'timestamp' else: @@ -385,7 +450,7 @@ class ConfigHandler(BaseHandler): if text_right == data['@name']: ui['right_text'] = 'camera-name' - elif text_right == '%Y-%m-%d\n%T': + elif text_right == '%Y-%m-%d\\n%T': ui['right_text'] = 'timestamp' else: diff --git a/src/server.py b/src/server.py index de0edb0..908cc86 100644 --- a/src/server.py +++ b/src/server.py @@ -10,7 +10,7 @@ application = Application( [ (r'^/$', handlers.MainHandler), (r'^/config/main/(?Pset|get)/?$', handlers.ConfigHandler), - (r'^/config/(?P\d+)/(?Pget|set|rem)/?$', handlers.ConfigHandler), + (r'^/config/(?P\d+)/(?Pget|set|rem|set_preview)/?$', handlers.ConfigHandler), (r'^/config/(?Padd|list|list_devices)/?$', handlers.ConfigHandler), (r'^/snapshot/(?P\d+)/(?Pcurrent|list)/?$', handlers.SnapshotHandler), (r'^/snapshot/(?P\d+)/(?Pdownload)/(?P.+)/?$', handlers.SnapshotHandler), diff --git a/src/v4l2ctl.py b/src/v4l2ctl.py index e634b9d..52f4258 100644 --- a/src/v4l2ctl.py +++ b/src/v4l2ctl.py @@ -80,7 +80,7 @@ def _set_ctrl(device, control, value): min_value = int(properties['min']) max_value = int(properties['max']) - value = min_value + value * float(max_value - min_value) / 255 + value = min_value + value * float(max_value - min_value) / 100 else: logging.warn('min and max values not found for control %(control)s of device %(device)s' % { @@ -94,11 +94,11 @@ def _set_ctrl(device, control, value): def _list_ctrls(device): - output = subprocess.call('v4l2-ctl -d %(device)s --list-ctrls' % { + output = subprocess.check_output('v4l2-ctl -d %(device)s --list-ctrls' % { 'device': device}, shell=True) controls = {} - for line in output: + for line in output.split('\n'): if not line: continue diff --git a/static/js/main.js b/static/js/main.js index f7416b3..fbaef3e 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -220,6 +220,12 @@ function initUI() { 'input.notifications, select.notifications, ' + 'input.working-schedule, select.working-schedule').change(pushCameraConfig); + /* preview controls */ + $('#brightnessSlider').change(pushPreview); + $('#contrastSlider').change(pushPreview); + $('#saturationSlider').change(pushPreview); + $('#hueSlider').change(pushPreview); + /* apply button */ $('#applyButton').click(function () { if ($(this).hasClass('progress')) { @@ -502,7 +508,13 @@ function dict2CameraUi(dict) { $('#contrastSlider').val(dict['contrast']); $('#saturationSlider').val(dict['saturation']); $('#hueSlider').val(dict['hue']); + + $('#resolutionSelect').html(''); + dict['available_resolutions'].forEach(function (resolution) { + $('#resolutionSelect').append(''); + }); $('#resolutionSelect').val(dict['resolution']); + $('#rotationSelect').val(dict['rotation']); $('#framerateSlider').val(dict['framerate']); @@ -740,6 +752,23 @@ 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 data = { + 'brightness': brightness, + 'contrast': contrast, + 'saturation': saturation, + 'hue': hue + }; + + ajax('POST', '/config/' + cameraId + '/set_preview/', data); +} + /* camera frames */ -- 2.39.5