From ec379bdeeeac080cd4e7c9d8765909e50f2971ee Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Sat, 23 Nov 2013 11:19:43 +0200 Subject: [PATCH] added current picture server resizing support --- src/handlers.py | 29 +++++++++++++---------------- src/mediafiles.py | 27 +++++++++++++++++++++++++++ src/mjpgclient.py | 6 +++++- src/remote.py | 17 +++++++++++++---- static/js/main.js | 2 +- 5 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/handlers.py b/src/handlers.py index 7fac412..0bbbb50 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -24,10 +24,8 @@ from tornado.web import RequestHandler, HTTPError, asynchronous import config import mediafiles -import mjpgclient import motionctl import remote -import settings import template import update import v4l2ctl @@ -545,27 +543,26 @@ class PictureHandler(BaseHandler): camera_config = config.get_camera(camera_id) if camera_config['@proto'] == 'v4l2': - jpg = mjpgclient.get_jpg(camera_id) - if jpg is None: - return self.finish() - - self.finish(jpg) + picture = mediafiles.get_current_picture(camera_config, + width=self.get_argument('width', None), + height=self.get_argument('height', None)) + + self.finish(picture) else: - def on_response(jpg): - if jpg is None: - self.finish() - - else: - self.finish(jpg) + def on_response(picture): + self.finish(picture) - remote.current_picture( + remote.get_current_picture( camera_config['@host'], camera_config['@port'], camera_config['@username'], camera_config['@password'], - camera_config['@remote_camera_id'], on_response) - + camera_config['@remote_camera_id'], + on_response, + width=self.get_argument('width', None), + height=self.get_argument('height', None)) + @BaseHandler.auth() def list(self, camera_id): logging.debug('listing pictures for camera %(id)s' % {'id': camera_id}) diff --git a/src/mediafiles.py b/src/mediafiles.py index d453ddc..5d2ecca 100644 --- a/src/mediafiles.py +++ b/src/mediafiles.py @@ -24,6 +24,7 @@ import subprocess from PIL import Image import config +import mjpgclient import utils @@ -275,3 +276,29 @@ def get_media_preview(camera_config, path, media_type, width, height): image.save(sio, format='JPEG') return sio.getvalue() + + +def get_current_picture(camera_config, width, height): + jpg = mjpgclient.get_jpg(camera_config['@id']) + + if jpg is None: + return None + + if width is height is None: + return jpg + + sio = StringIO.StringIO(jpg) + image = Image.open(sio) + + width = width and int(width) or image.size[0] + height = height and int(height) or image.size[1] + + if width >= image.size[0] and height >= image.size[1]: + return jpg # no enlarging of the picture on the server side + + image.thumbnail((width, height), Image.ANTIALIAS) + + sio = StringIO.StringIO() + image.save(sio, format='JPEG') + + return sio.getvalue() diff --git a/src/mjpgclient.py b/src/mjpgclient.py index 2dea7f9..0638961 100644 --- a/src/mjpgclient.py +++ b/src/mjpgclient.py @@ -54,7 +54,11 @@ class MjpgClient(iostream.IOStream): except KeyError: pass - iostream.IOStream.close(self) + try: + iostream.IOStream.close(self) + + except: + pass # already closed, nevermind def _check_error(self): if self.error is None: diff --git a/src/remote.py b/src/remote.py index 532439b..83536f1 100644 --- a/src/remote.py +++ b/src/remote.py @@ -173,7 +173,7 @@ def set_preview(host, port, username, password, camera_id, controls, callback): http_client.fetch(request, on_response) -def current_picture(host, port, username, password, camera_id, callback): +def get_current_picture(host, port, username, password, camera_id, callback, width, height): global _snapshot_cache logging.debug('getting current picture for remote camera %(id)s on %(host)s:%(port)s' % { @@ -181,15 +181,24 @@ def current_picture(host, port, username, password, camera_id, callback): 'host': host, 'port': port}) - request = _make_request(host, port, username, password, '/picture/%(id)s/current/' % {'id': camera_id}) + query = {} + + if width: + query['width'] = str(width) + + if height: + query['height'] = str(height) + + request = _make_request(host, port, username, password, '/picture/%(id)s/current/' % {'id': camera_id}, query=query) - cached = _snapshot_cache.setdefault(request.url, {'pending': 0, 'jpg': None}) + cache_key = (host, port, camera_id) + cached = _snapshot_cache.setdefault(cache_key, {'pending': 0, 'jpg': None}) if cached['pending'] > 0: # a pending request for this snapshot exists return callback(cached['jpg']) def on_response(response): cached['pending'] -= 1 - cached['jpg'] = response.body + cached['picture'] = response.body if response.error: logging.error('failed to get current picture for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % { diff --git a/static/js/main.js b/static/js/main.js index 438c55e..628c4c2 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1842,7 +1842,7 @@ function refreshCameraFrames() { timestamp /= 500; } timestamp = Math.round(timestamp); - img.src = '/picture/' + cameraId + '/current/?_=' + timestamp; + img.src = '/picture/' + cameraId + '/current/?_=' + timestamp + '&width=' + img.width; img.loading = true; } -- 2.39.5