]> www.vanbest.org Git - motioneye-debian/commitdiff
added mjpgclient
authorCalin Crisan <ccrisan@gmail.com>
Sun, 29 Sep 2013 15:04:41 +0000 (18:04 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Sun, 29 Sep 2013 15:04:41 +0000 (18:04 +0300)
src/config.py
src/handlers.py
src/mjpgclient.py [new file with mode: 0644]
static/css/main.css

index a87b4c4dbbacfedc9b39227323256ea92fcfc536..e84fb27a8cf632d8a0f2d0e48c9137410b0fab5a 100644 (file)
@@ -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)
     
index 79768e6f6b907c47beed7cb35e56cf21f2352499..a78901bd1628418b61c7de92dc603a4d8afb45e6 100644 (file)
@@ -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 (file)
index 0000000..9280bdb
--- /dev/null
@@ -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)
index c4d776847326546ee1243208c223f3e4b8e28244..5c10d41a4eb999e50ecc189feae704f7e3e385d2 100644 (file)
@@ -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;
 }