Add initial support for local MMAL cameras
authorinodlite <1023852+inodlite@users.noreply.github.com>
Sat, 19 Aug 2017 06:57:48 +0000 (23:57 -0700)
committerinodlite <1023852+inodlite@users.noreply.github.com>
Sat, 19 Aug 2017 06:57:48 +0000 (23:57 -0700)
motioneye/config.py
motioneye/handlers.py
motioneye/static/js/main.js
motioneye/utils.py

index b87fe8d6080c43463bcb1455e29f806e90f4ce89..9d4e31077d769c595e550b45d006ac9cb5ff6636 100644 (file)
@@ -117,7 +117,8 @@ _KNOWN_MOTION_OPTIONS = {
     'text_right',
     'threshold',
     'videodevice',
-    'width'
+    'width',
+    'mmalcam_name'
 }
 
 
@@ -540,7 +541,7 @@ def add_camera(device_details):
     while camera_id in camera_ids:
         camera_id += 1
 
-    logging.info('adding new camera with id %(id)s...' % {'id': camera_id})
+    logging.info('adding new %(prt)s camera with id %(id)s...' % {'prt': proto, 'id': camera_id})
 
     # prepare a default camera config
     camera_config = {'@enabled': True}
@@ -564,6 +565,11 @@ def add_camera(device_details):
         camera_config['@password'] = device_details['password']
         camera_config['@remote_camera_id'] = device_details['remote_camera_id']
 
+    elif proto == 'mmal':
+        camera_config['mmalcam_name'] = device_details['path']
+        camera_config['width'] = 640
+        camera_config['height'] = 480
+
     elif proto == 'netcam':
         camera_config['netcam_url'] = device_details['url']
         camera_config['text_double'] = True
@@ -812,10 +818,13 @@ def motion_camera_ui_to_dict(ui, old_config=None):
     if utils.is_v4l2_camera(old_config):
         proto = 'v4l2'
 
+    elif utils.is_mmal_camera(old_config):
+        proto = 'mmal'     
+   
     else:
         proto = 'netcam'
 
-    if proto == 'v4l2':
+    if (proto == 'v4l2') or (proto == 'mmal'):
         # leave videodevice unchanged
 
         # resolution
@@ -1234,6 +1243,17 @@ def motion_camera_dict_to_ui(data):
             # we have no other choice but use something like 640x480 as reference
             threshold = data['threshold'] * 100.0 / (640 * 480)
 
+    elif utils.is_mmal_camera(data):
+        ui['device_url'] = data['mmalcam_name']
+        ui['proto'] = 'mmal'
+        
+        resolutions = utils.RPI_MMAL_RESOLUTIONS
+        resolutions = [r for r in resolutions if motionctl.resolution_is_valid(*r)]
+        ui['available_resolutions'] = [(str(w) + 'x' + str(h)) for (w, h) in resolutions]
+        ui['resolution'] = str(data['width']) + 'x' + str(data['height'])
+
+        threshold = data['threshold'] * 100.0 / (data['width'] * data['height'])
+
     else:  # assuming v4l2
         ui['device_url'] = data['videodevice']
         ui['proto'] = 'v4l2'
index e483e2b91649a1b0ce664f84680322619a4a3668..022b82f110f22f9cb3c7a9ac6886dcf67bfde8ba 100644 (file)
@@ -651,6 +651,20 @@ class ConfigHandler(BaseHandler):
             
             self.finish_json({'cameras': cameras})
 
+        elif proto == 'mmal':
+            configured_devices = set()
+            for camera_id in config.get_camera_ids():
+                data = config.get_camera(camera_id)
+                if utils.is_mmal_camera(data):
+                    configured_devices.add(data['mmalcam_name'])
+
+            if "vc.ril.camera" not in configured_devices:
+                cameras = [{'id': "vc.ril.camera", 'name': "VideoCore Camera (vc.ril.camera)"}]
+            else:
+                               cameras = []
+            
+            self.finish_json({'cameras': cameras})
+
         else:  # assuming local motionEye camera listing
             cameras = []
             camera_ids = config.get_camera_ids()
index 329bc781f2c0dcb5f7b3f3dd16a0c0223063bc1d..d32f4003f2fbd3959b7db32b6dad3c005fc405f0 100644 (file)
@@ -2059,6 +2059,10 @@ function dict2CameraUi(dict) {
         case 'netcam':
             prettyType = 'Network Camera';
             break;
+            
+        case 'mmal':
+            prettyType = 'MMAL Camera';
+            break;
 
         case 'motioneye':
             prettyType = 'Remote motionEye Camera';
@@ -3316,7 +3320,7 @@ function getCameraIdsByInstance() {
     var cameraIdsByInstance = {};
     getCameraFrames().each(function () {
         var instance;
-        if (this.config.proto == 'netcam' || this.config.proto == 'v4l2') {
+        if (this.config.proto == 'netcam' || this.config.proto == 'v4l2' || this.config.proto == 'mmal') {
             instance = '';
         }
         else if (this.config.proto == 'motioneye') {
@@ -3563,6 +3567,7 @@ function runAddCameraDialog() {
                     '<td class="dialog-item-label"><span class="dialog-item-label">Camera Type</span></td>' +
                     '<td class="dialog-item-value"><select class="styled" id="typeSelect">' +
                         (hasLocalCamSupport ? '<option value="v4l2">Local Camera</option>' : '') +
+                        (hasLocalCamSupport ? '<option value="mmal">Local MMAL Camera</option>' : '') +
                         (hasNetCamSupport ? '<option value="netcam">Network Camera</option>' : '') +
                         '<option value="motioneye">Remote motionEye Camera</option>' +
                         '<option value="mjpeg">Simple MJPEG Camera</option>' +
@@ -3584,15 +3589,15 @@ function runAddCameraDialog() {
                     '<td class="dialog-item-value"><input type="password" class="styled" id="passwordEntry" placeholder="password..."></td>' +
                     '<td><span class="help-mark" title="the password for the URL, if required">?</span></td>' +
                 '</tr>' +
-                '<tr class="v4l2 motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg mmal">' +
                     '<td class="dialog-item-label"><span class="dialog-item-label">Camera</span></td>' +
                     '<td class="dialog-item-value"><select class="styled" id="addCameraSelect"></select><span id="cameraMsgLabel"></span></td>' +
                     '<td><span class="help-mark" title="the camera you wish to add">?</span></td>' +
                 '</tr>' +
-                '<tr class="v4l2 motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg mmal">' +
                     '<td colspan="100"><div class="dialog-item-separator"></div></td>' +
                 '</tr>' +
-                '<tr class="v4l2 motioneye netcam mjpeg">' +
+                '<tr class="v4l2 motioneye netcam mjpeg mmal">' +
                     '<td class="dialog-item-value" colspan="100"><div id="addCameraInfo"></div></td>' +
                 '</tr>' +
             '</table>');
@@ -3614,7 +3619,7 @@ function runAddCameraDialog() {
     
     /* ui interaction */
     function updateUi() {
-        content.find('tr.v4l2, tr.motioneye, tr.netcam, tr.mjpeg').css('display', 'none');
+        content.find('tr.v4l2, tr.motioneye, tr.netcam, tr.mjpeg, tr.mmal').css('display', 'none');
 
         if (typeSelect.val() == 'motioneye') {
             content.find('tr.motioneye').css('display', 'table-row');
@@ -3640,6 +3645,12 @@ function runAddCameraDialog() {
                     'Network cameras (or IP cameras) are devices that natively stream RTSP or MJPEG videos or plain JPEG images. ' +
                     "Consult your device's manual to find out the correct RTSP, MJPEG or JPEG URL.");
         }
+        else if (typeSelect.val() == 'mmal') {
+            content.find('tr.mmal').css('display', 'table-row');
+            addCameraInfo.html(
+                    'Local MMAL cameras are devices that are connected directly to your motionEye system. ' +
+                    'These are usually board-specific cameras.');
+        }
         else if (typeSelect.val() == 'mjpeg') {
             usernameEntry.removeAttr('readonly');
             
@@ -3827,6 +3838,10 @@ function runAddCameraDialog() {
                 data.proto = 'netcam';
                 data.camera_index = addCameraSelect.val();
             }
+            else if (typeSelect.val() == 'mmal') {
+                data.path = addCameraSelect.val();
+                data.proto = 'mmal';
+            }
             else if (typeSelect.val() == 'mjpeg') {
                 data = splitCameraUrl(urlEntry.val());
                 data.username = usernameEntry.val();
index e00b3d65a444caee9b9f06f363d2f0a09164e146..34f0dff4a1fa42efbd1160ea62719821ee4eb570 100644 (file)
@@ -67,6 +67,15 @@ COMMON_RESOLUTIONS = [
     (1920, 1080)
 ]
 
+RPI_MMAL_RESOLUTIONS = [
+    (640, 480),
+    (1280, 720),
+    (1280, 960),
+    (1920, 1080),
+    (1920, 1088),
+    (2592, 1944)
+]
+
 
 def _(x):
     return x  # this could later be replaced by a proper translate function
@@ -336,8 +345,7 @@ def get_disk_usage(path):
 
 def is_local_motion_camera(config):
     """Tells if a camera is managed by the local motion instance."""
-    return bool(config.get('videodevice') or config.get('netcam_url'))
-
+    return bool(config.get('videodevice') or config.get('netcam_url') or config.get('mmalcam_name'))
 
 def is_remote_camera(config):
     """Tells if a camera is managed by a remote motionEye server."""
@@ -348,6 +356,9 @@ def is_v4l2_camera(config):
     """Tells if a camera is a v4l2 device managed by the local motion instance."""
     return bool(config.get('videodevice'))
 
+def is_mmal_camera(config):
+    '''Tells if a camera is mmal device managed by the local motion instance.'''
+    return bool(config.get('mmalcam_name'))
 
 def is_net_camera(config):
     """Tells if a camera is a network camera managed by the local motion instance."""