From: Calin Crisan Date: Sun, 29 Sep 2013 15:04:41 +0000 (+0300) Subject: added mjpgclient X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=dc0b01d4bd8739aeb67b0665ebe00cd77816e72c;p=motioneye-debian added mjpgclient --- diff --git a/src/config.py b/src/config.py index a87b4c4..e84fb27 100644 --- a/src/config.py +++ b/src/config.py @@ -172,6 +172,7 @@ def get_camera(camera_id, as_lines=False): main_config = get_main() threads = main_config.get('thread', []) data['@enabled'] = _CAMERA_CONFIG_FILE_NAME % {'id': camera_id} in threads + data['@id'] = camera_id _set_default_motion_camera(data) diff --git a/src/handlers.py b/src/handlers.py index 79768e6..a78901b 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -5,6 +5,7 @@ import logging from tornado.web import RequestHandler, HTTPError import config +import mjpgclient import template import v4l2ctl @@ -295,6 +296,7 @@ class ConfigHandler(BaseHandler): # device 'name': data['@name'], 'enabled': data['@enabled'], + 'id': data['@id'], 'device': data['@proto'] + '://' + data['videodevice'], 'light_switch_detect': data['lightswitch'] > 0, 'auto_brightness': data['auto_brightness'], @@ -440,19 +442,24 @@ class ConfigHandler(BaseHandler): class SnapshotHandler(BaseHandler): def get(self, camera_id, op, filename=None): if op == 'current': - self.current() + self.current(camera_id) elif op == 'list': self.list(camera_id) elif op == 'download': - self.download(filename) + self.download(camera_id, filename) else: raise HTTPError(400, 'unknown operation') - def current(self): - pass + def current(self, camera_id): + jpg = mjpgclient.get_jpg(camera_id) + if jpg is None: + return self.finish() + + self.set_header('Content-Type', 'image/jpeg') + self.finish(jpg) def list(self, camera_id): logging.debug('listing snapshots for camera %(id)s' % {'id': camera_id}) diff --git a/src/mjpgclient.py b/src/mjpgclient.py new file mode 100644 index 0000000..9280bdb --- /dev/null +++ b/src/mjpgclient.py @@ -0,0 +1,115 @@ + +import logging +import re +import socket + +from tornado import iostream + +import config + + + +class MjpgClient(iostream.IOStream): + clients = {} # dictionary of clients indexed by camera id + last_jpgs = {} # dictionary of jpg contents indexed by camera id + + def __init__(self, camera_id, port): + self._camera_id = camera_id + self._port = port + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + iostream.IOStream.__init__(self, s) + + def connect(self): + iostream.IOStream.connect(self, ('localhost', self._port), self._on_connect) + MjpgClient.clients[self._camera_id] = self + + logging.debug('mjpg client connecting on port %(port)s...' % {'port': self._port}) + + def close(self): + try: + del MjpgClient.clients[self._camera_id] + + logging.debug('mjpg client on port %(port)s removed' % {'port': self._port}) + + except KeyError: + pass + + iostream.IOStream.close(self) + + def _check_error(self): + if self.error is None: + return False + + self._error(self.error) + + return True + + def _error(self, error): + logging.error('mjpg client error: %(msg)s' % { + 'msg': unicode(error)}) + + try: + self.close() + + except: + pass + + def _on_connect(self): + logging.debug('mjpg client connected on port %(port)s...' % {'port': self._port}) + + self.write(b"GET / HTTP/1.0\r\n\r\n") + self._seek_content_length() + + def _seek_content_length(self): + if self._check_error(): + return + + self.read_until('Content-Length:', self._on_before_content_length) + + def _on_before_content_length(self, data): + if self._check_error(): + return + + self.read_until('\r\n\r\n', self._on_content_length) + + def _on_content_length(self, data): + if self._check_error(): + return + + matches = re.findall('(\d+)', data) + if not matches: + self._error('could not find content length in mjpg header line "%(header)s"' % { + 'header': data}) + + return + + length = int(matches[0]) + + self.read_bytes(length, self._on_jpg) + + def _on_jpg(self, data): + MjpgClient.last_jpgs[self._camera_id] = data + self._seek_content_length() + + +def get_jpg(camera_id): + if camera_id not in MjpgClient.clients: + # TODO implement some kind of timeout before retry here + logging.debug('creating mjpg client for camera id %(camera_id)s' % { + 'camera_id': camera_id}) + + camera_config = config.get_camera(camera_id) + if not camera_config['@enabled'] or camera_config['@proto'] != 'v4l2': + logging.error('could not start mjpg client for camera id %(camera_id)s: not enabled or not local' % { + 'camera_id': camera_id}) + + return None + + port = camera_config['webcam_port'] + client = MjpgClient(camera_id, port) + client.connect() + + return None + + return MjpgClient.last_jpgs.get(camera_id) diff --git a/static/css/main.css b/static/css/main.css index c4d7768..5c10d41 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -277,8 +277,7 @@ div.camera-frame { display: inline-block; padding: 0px 5px 5px 5px; border-radius: 3px; - transition: all 0.2s; - transition: opacity 0s; + transition: all 0.2s, opacity 0s; margin: 2px; opacity: 0; }