Browse Source

app container and config schema

Blake Blackshear 4 years ago
parent
commit
180baeba50

+ 1 - 1
README.md

@@ -231,7 +231,7 @@ objects:
     person:
       # Optional: minimum width*height of the bounding box for the detected object (default: 0)
       min_area: 5000
-      # Optional: maximum width*height of the bounding box for the detected object (default: max_int)
+      # Optional: maximum width*height of the bounding box for the detected object (default: 24000000)
       max_area: 100000
       # Optional: minimum score for the object to initiate tracking (default: shown below)
       min_score: 0.5

+ 2 - 1
docker/Dockerfile.wheels

@@ -33,7 +33,8 @@ RUN pip3 wheel --wheel-dir=/wheels \
     PyYAML \
     matplotlib \
     click \
-    tinydb
+    peewee \
+    voluptuous
 
 FROM scratch
 

+ 2 - 1
docker/Dockerfile.wheels.aarch64

@@ -43,7 +43,8 @@ RUN pip3 wheel --wheel-dir=/wheels \
     PyYAML \
     matplotlib \
     click \
-    tinydb
+    peewee \
+    voluptuous
 
 FROM scratch
 

+ 0 - 0
frigate/__init__.py


+ 54 - 11
frigate/__main__.py

@@ -1,13 +1,3 @@
-# load config
-# init database
-# connect to mqtt
-# start detection processes
-# start frame processor
-# start camera processes
-# start event processor
-# start capture processes
-# start web app
-
 import faulthandler; faulthandler.enable()
 import os
 import signal
@@ -37,6 +27,7 @@ from frigate.object_processing import TrackedObjectProcessor
 from frigate.events import EventProcessor
 from frigate.util import EventsPerSecond
 from frigate.edgetpu import EdgeTPUProcess
+from frigate.config import FRIGATE_CONFIG_SCHEMA
 
 FRIGATE_VARS = {k: v for k, v in os.environ.items() if k.startswith('FRIGATE_')}
 
@@ -326,7 +317,6 @@ def main():
     frigate_watchdog.start()
 
     def receiveSignal(signalNumber, frame):
-        print('Received:', signalNumber)
         stop_event.set()
         event_processor.join()
         object_processor.join()
@@ -477,6 +467,59 @@ def main():
 
     object_processor.join()
 
+class FrigateApp():
+    def __init__(self, stop: mp.Event):
+        self.stop = stop
+        self.config = None
+    
+    def init_config(self):
+        config_file = os.environ.get('CONFIG_FILE', '/config/config.yml')
+
+        if config_file.endswith(".yml"):
+            with open(config_file) as f:
+                config = yaml.safe_load(f)
+        elif config_file.endswith(".json"):
+            with open(config_file) as f:
+                config = json.load(f)
+        
+        self.config = FRIGATE_CONFIG_SCHEMA(config)
+
+    def init_web_server(self):
+        pass
+
+    def init_database(self):
+        pass
+
+    def init_mqtt(self):
+        pass
+
+    def start_detectors(self):
+        pass
+
+    def start_detection_processor(self):
+        pass
+
+    def start_frame_processors(self):
+        pass
+
+    def start_camera_capture_processes(self):
+        pass
+
+    def start_watchdog(self):
+        pass
+
+    def start(self):
+        self.init_config()
+        self.init_web_server()
+        self.init_database()
+        self.init_mqtt()
+        self.start_detectors()
+        self.start_detection_processor()
+        self.start_frame_processors()
+        self.start_camera_capture_processes()
+        self.start_watchdog()
+
 if __name__ == '__main__':
+    # register stop handler
     init_db()
     main()

+ 142 - 0
frigate/config.py

@@ -0,0 +1,142 @@
+import voluptuous as vol
+
+DETECTORS_SCHEMA = vol.Schema(
+    {
+        vol.Required(str): {
+            vol.Required('type', default='edgetpu'): vol.In(['cpu', 'edgetpu']), 
+            vol.Optional('device', default='usb'): str
+        }
+    }
+)
+
+DEFAULT_DETECTORS = {
+    'coral': {
+        'type': 'edgetpu',
+        'device': 'usb'
+    }
+}
+
+MQTT_SCHEMA = vol.Schema(
+    {
+        vol.Required('host'): str,
+        vol.Optional('port', default=1883): int,
+        vol.Optional('topic_prefix', default='frigate'): str,
+        vol.Optional('client_id', default='frigate'): str,
+        'user': str,
+        'password': str
+    }
+)
+
+SAVE_CLIPS_SCHEMA = vol.Schema(
+    {
+        vol.Optional('max_seconds', default=300): int,
+        vol.Optional('clips_dir', default='/clips'): str,
+        vol.Optional('cache_dir', default='/cache'): str
+    }
+)
+
+FFMPEG_GLOBAL_ARGS_DEFAULT = ['-hide_banner','-loglevel','panic']
+FFMPEG_INPUT_ARGS_DEFAULT = ['-avoid_negative_ts', 'make_zero',
+    '-fflags', 'nobuffer',
+    '-flags', 'low_delay',
+    '-strict', 'experimental',
+    '-fflags', '+genpts+discardcorrupt',
+    '-rtsp_transport', 'tcp',
+    '-stimeout', '5000000',
+    '-use_wallclock_as_timestamps', '1']
+FFMPEG_OUTPUT_ARGS_DEFAULT = ['-f', 'rawvideo',
+    '-pix_fmt', 'yuv420p']
+
+GLOBAL_FFMPEG_SCHEMA = vol.Schema(
+    { 
+        vol.Optional('global_args', default=FFMPEG_GLOBAL_ARGS_DEFAULT):  [str],
+        vol.Optional('hwaccel_args', default=[]): [str],
+        vol.Optional('input_args', default=FFMPEG_INPUT_ARGS_DEFAULT): [str],
+        vol.Optional('output_args', default=FFMPEG_OUTPUT_ARGS_DEFAULT): [str]
+    }
+)
+
+FILTER_SCHEMA = vol.Schema(
+    { 
+        str: {
+                vol.Optional('min_area', default=0): int,
+                vol.Optional('max_area', default=24000000): int,
+                vol.Optional('threshold', default=0.85): float
+            }
+    }
+)
+
+OBJECTS_SCHEMA = vol.Schema(
+    {
+        vol.Optional('track', default=['person']): [str],
+        'filters': FILTER_SCHEMA.extend({vol.Optional('min_score', default=0.5): float})
+    }
+)
+
+DEFAULT_CAMERA_MQTT = {
+    'crop_to_region': True
+}
+DEFAULT_CAMERA_SAVE_CLIPS = {
+    'enabled': False
+}
+DEFAULT_CAMERA_SNAPSHOTS = {
+    'show_timestamp': True,
+    'draw_zones': False,
+    'draw_bounding_boxes': True
+}
+
+CAMERA_FFMPEG_SCHEMA = vol.Schema(
+    { 
+        vol.Required('input'): str, 
+        'global_args':  [str],
+        'hwaccel_args': [str],
+        'input_args': [str],
+        'output_args': [str]
+    }
+)
+
+CAMERAS_SCHEMA = vol.Schema(
+    {
+        str: {
+            vol.Required('ffmpeg'): CAMERA_FFMPEG_SCHEMA,
+            'height': int,
+            'width': int,
+            'fps': int,
+            'mask': str,
+            vol.Optional('best_image_timeout', default=60): int,
+            vol.Optional('mqtt', default=DEFAULT_CAMERA_MQTT): {
+                vol.Optional('crop_to_region', default=True): bool,
+                'snapshot_height': int
+            },
+            vol.Optional('zones', default={}):  {
+                str: {
+                    vol.Required('coordinates'): vol.Any(str, [str]),
+                    'filters': FILTER_SCHEMA
+                }
+             },
+             vol.Optional('save_clips', default=DEFAULT_CAMERA_SAVE_CLIPS): {
+                vol.Optional('enabled', default=False): bool,
+                vol.Optional('pre_capture', default=30): int,
+                'objects': [str],
+             },
+             vol.Optional('snapshots', default=DEFAULT_CAMERA_SNAPSHOTS): {
+                vol.Optional('show_timestamp', default=True): bool,
+                vol.Optional('draw_zones', default=False): bool,
+                vol.Optional('draw_bounding_boxes', default=True): bool
+             },
+             'objects': OBJECTS_SCHEMA
+        }
+    }
+)
+
+FRIGATE_CONFIG_SCHEMA = vol.Schema(
+    {
+        vol.Optional('web_port', default=5000): int,
+        vol.Optional('detectors', default=DEFAULT_DETECTORS): DETECTORS_SCHEMA,
+        'mqtt': MQTT_SCHEMA,
+        vol.Optional('save_clips', default={}): SAVE_CLIPS_SCHEMA,
+        vol.Optional('ffmpeg', default={}): GLOBAL_FFMPEG_SCHEMA,
+        vol.Optional('objects', default={}): OBJECTS_SCHEMA,
+        vol.Required('cameras', default={}): CAMERAS_SCHEMA
+    }
+)

+ 0 - 0
frigate/test/__init__.py


+ 26 - 0
frigate/test/test_config.py

@@ -0,0 +1,26 @@
+import json
+from unittest import TestCase, main
+import voluptuous as vol
+from frigate.config import FRIGATE_CONFIG_SCHEMA
+
+class TestConfig(TestCase):
+    def test_empty(self):
+        FRIGATE_CONFIG_SCHEMA({})
+
+    def test_minimal(self):
+        minimal = {
+            'mqtt': {
+                'host': 'mqtt'
+            },
+            'cameras': {
+                'back': {
+                    'ffmpeg': {
+                        'input': 'rtsp://10.0.0.1:554/video'
+                    }
+                }
+            }
+        }
+        FRIGATE_CONFIG_SCHEMA(minimal)
+
+if __name__ == '__main__':
+    main(verbosity=2)