add support for rebroadcasting as rtmp

This commit is contained in:
Blake Blackshear 2020-11-28 07:58:27 -06:00
parent 32a66fe5e8
commit 4502ca8e80
3 changed files with 53 additions and 8 deletions

View File

@ -15,7 +15,7 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -qq update \ RUN apt-get -qq update \
&& apt-get upgrade -y \ && apt-get upgrade -y \
&& apt-get -qq install --no-install-recommends -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 \ && apt-get -qq install --no-install-recommends -y \
python3-pip \ python3-pip \
&& pip3 install -U /wheels/*.whl \ && pip3 install -U /wheels/*.whl \
@ -45,4 +45,7 @@ ADD frigate frigate/
COPY run.sh /run.sh COPY run.sh /run.sh
RUN chmod +x /run.sh RUN chmod +x /run.sh
EXPOSE 5000
EXPOSE 1935
CMD ["/run.sh"] CMD ["/run.sh"]

View File

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

View File

@ -3,6 +3,8 @@ worker_processes 1;
error_log /var/log/nginx/error.log warn; error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid; pid /var/run/nginx.pid;
load_module "modules/ngx_rtmp_module.so";
events { events {
worker_connections 1024; worker_connections 1024;
} }
@ -81,4 +83,19 @@ http {
proxy_set_header X-Forwarded-Proto $scheme; 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;
}
}
} }