Browse Source

add support for rebroadcasting as rtmp

Blake Blackshear 4 years ago
parent
commit
1acbeb813e
3 changed files with 53 additions and 8 deletions
  1. 4 1
      docker/Dockerfile.base
  2. 32 7
      frigate/config.py
  3. 17 0
      nginx/nginx.conf

+ 4 - 1
docker/Dockerfile.base

@@ -15,7 +15,7 @@ ENV DEBIAN_FRONTEND=noninteractive
 RUN apt-get -qq update \
     && apt-get upgrade -y \
     && apt-get -qq install --no-install-recommends -y \
-    gnupg wget unzip tzdata nginx \
+    gnupg wget unzip tzdata nginx libnginx-mod-rtmp \
     && apt-get -qq install --no-install-recommends -y \
         python3-pip \
     && pip3 install -U /wheels/*.whl \
@@ -45,4 +45,7 @@ ADD frigate frigate/
 COPY run.sh /run.sh
 RUN chmod +x /run.sh
 
+EXPOSE 5000
+EXPOSE 1935
+
 CMD ["/run.sh"]

+ 32 - 7
frigate/config.py

@@ -142,6 +142,9 @@ CAMERAS_SCHEMA = vol.Schema(
                 'objects': [str],
                 vol.Optional('retain', default={}): SAVE_CLIPS_RETAIN_SCHEMA
              },
+             vol.Optional('rtmp', default={}): {
+                 vol.Required('enabled', default=True): bool
+             },
              vol.Optional('snapshots', default=DEFAULT_CAMERA_SNAPSHOTS): {
                 vol.Optional('show_timestamp', default=True): bool,
                 vol.Optional('draw_zones', default=False): bool,
@@ -425,6 +428,18 @@ class CameraSaveClipsConfig():
             'objects': self.objects,
             'retain': self.retain.to_dict()
         }
+class CameraRtmpConfig():
+    def __init__(self, config):
+        self._enabled = config['enabled']
+    
+    @property
+    def enabled(self):
+        return self._enabled
+    
+    def to_dict(self):
+        return {
+            'enabled': self.enabled
+        }
 
 class ZoneConfig():
     def __init__(self, name, config):
@@ -484,6 +499,7 @@ class CameraConfig():
         self._best_image_timeout = config['best_image_timeout']
         self._zones = { name: ZoneConfig(name, z) for name, z in config['zones'].items() }
         self._save_clips = CameraSaveClipsConfig(global_config['save_clips'], config['save_clips'])
+        self._rtmp = CameraRtmpConfig(config['rtmp'])
         self._snapshots = CameraSnapshotsConfig(config['snapshots'])
         self._objects = ObjectConfig(global_config['objects'], config.get('objects', {}))
 
@@ -518,6 +534,14 @@ class CameraConfig():
         ffmpeg_output_args = self.ffmpeg.output_args
         if self.fps:
             ffmpeg_output_args = ["-r", str(self.fps)] + ffmpeg_output_args
+        if self.rtmp.enabled:
+            ffmpeg_output_args = [
+                "-c",
+                "copy",
+                "-f",
+                "flv",
+                f"rtmp://127.0.0.1/live/{self.name}"
+            ] + ffmpeg_output_args
         if self.save_clips.enabled:
             ffmpeg_output_args = [
                 "-f",
@@ -590,6 +614,10 @@ class CameraConfig():
     def save_clips(self):
         return self._save_clips
     
+    @property
+    def rtmp(self):
+        return self._rtmp
+    
     @property
     def snapshots(self):
         return self._snapshots
@@ -619,6 +647,7 @@ class CameraConfig():
             'best_image_timeout': self.best_image_timeout,
             'zones': {k: z.to_dict() for k, z in self.zones.items()},
             'save_clips': self.save_clips.to_dict(),
+            'rtmp': self.rtmp.to_dict(),
             'snapshots': self.snapshots.to_dict(),
             'objects': self.objects.to_dict(),
             'frame_shape': self.frame_shape,
@@ -656,13 +685,9 @@ class FrigateConfig():
         return config
     
     def _ensure_dirs(self):
-        cache_dir = self.save_clips.cache_dir
-        clips_dir = self.save_clips.clips_dir
-
-        if not os.path.exists(cache_dir) and not os.path.islink(cache_dir):
-            os.makedirs(cache_dir)
-        if not os.path.exists(clips_dir) and not os.path.islink(clips_dir):
-            os.makedirs(clips_dir)
+        for d in [self.save_clips.cache_dir, self.save_clips.clips_dir]:
+            if not os.path.exists(d) and not os.path.islink(d):
+                os.makedirs(d)
 
     def _load_file(self, config_file):
         with open(config_file) as f:

+ 17 - 0
nginx/nginx.conf

@@ -3,6 +3,8 @@ worker_processes  1;
 error_log  /var/log/nginx/error.log warn;
 pid        /var/run/nginx.pid;
 
+load_module "modules/ngx_rtmp_module.so";
+
 events {
     worker_connections  1024;
 }
@@ -81,4 +83,19 @@ http {
             proxy_set_header X-Forwarded-Proto $scheme;
         }
     }
+}
+
+rtmp {
+    server {
+        listen 1935;
+        chunk_size 4096;
+        allow publish 127.0.0.1;
+        deny publish all;
+        allow play all;
+        application live {
+            live on;
+            record off;
+            meta copy;
+        }
+    }
 }