From 3a3afe14bf408d55d1f1bc4138e2da363a5a67d4 Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Sun, 8 Dec 2019 15:46:43 -0600 Subject: [PATCH] change the ffmpeg config for global defaults and overrides --- README.md | 2 +- config/config.example.yml | 86 +++++++++++++++++++++++---------------- detect_objects.py | 25 +++++++++++- docs/DEVICES.md | 74 +++++++++++++++++++++++++++++++++ frigate/video.py | 34 +++++----------- 5 files changed, 161 insertions(+), 60 deletions(-) create mode 100644 docs/DEVICES.md diff --git a/README.md b/README.md index 6008448a0..9370009eb 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Example docker-compose: FRIGATE_RTSP_PASSWORD: "password" ``` -A `config.yml` file must exist in the `config` directory. See example [here](config/config.yml). +A `config.yml` file must exist in the `config` directory. See example [here](config/config.yml) and device specific info can be found [here](docs/DEVICES.md). Access the mjpeg stream at `http://localhost:5000/` and the best person snapshot at `http://localhost:5000//best_person.jpg` diff --git a/config/config.example.yml b/config/config.example.yml index 25facacfd..330f0cadb 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -7,11 +7,60 @@ mqtt: # user: username # Optional -- Uncomment for use # password: password # Optional -- Uncomment for use +################# +# Default ffmpeg args. Optional and can be overwritten per camera. +# Should work with most RTSP cameras that send h264 video +# Built from the properties below with: +# "ffmpeg" + global_args + input_args + "-i" + input + output_args +################# +# ffmpeg: +# global_args: +# - -hide_banner +# - -loglevel +# - panic +# hwaccel_args: [] +# input_args: +# - -avoid_negative_ts +# - make_zero +# - -fflags +# - nobuffer +# - -flags +# - low_delay +# - -strict +# - experimental +# - -fflags +# - +genpts+discardcorrupt +# - -vsync +# - drop +# - -rtsp_transport +# - tcp +# - -stimeout +# - '5000000' +# - -use_wallclock_as_timestamps +# - '1' +# output_args: +# - -vf +# - mpdecimate +# - -f +# - rawvideo +# - -pix_fmt +# - rgb24 + cameras: back: - # Source passed to ffmpeg after the -i parameter. Supports anything compatible with OpenCV and FFmpeg. - # Environment variables that begin with 'FRIGATE_' may be referenced in {} - ffmpeg_input: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 + ffmpeg: + ################ + # Source passed to ffmpeg after the -i parameter. Supports anything compatible with OpenCV and FFmpeg. + # Environment variables that begin with 'FRIGATE_' may be referenced in {} + ################ + input: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 + ################# + # These values will override default values for just this camera + ################# + # global_args: [] + # hwaccel_args: [] + # input_args: [] + # output_args: [] ################ ## Optional mask. Must be the same dimensions as your video feed. @@ -29,37 +78,6 @@ cameras: # 3 every 3rd frame, etc. ################ take_frame: 1 - - ################ - # Optional hardware acceleration parameters for ffmpeg. If your hardware supports it, it can - # greatly reduce the CPU power used to decode the video stream. You will need to determine which - # parameters work for your specific hardware. These may work for those with Intel hardware that - # supports QuickSync. - ################ - # ffmpeg_hwaccel_args: - # - -hwaccel - # - vaapi - # - -hwaccel_device - # - /dev/dri/renderD128 - # - -hwaccel_output_format - # - yuv420p - - ################ - # FFmpeg log level. Default is "panic". https://ffmpeg.org/ffmpeg.html#Generic-options - ################ - # ffmpeg_log_level: panic - - ################ - # Optional custom input args. Some cameras may need custom ffmpeg params to work reliably. Specifying - # these will replace the default input params. - ################ - # ffmpeg_input_args: [] - - ################ - # Optional custom output args. Some cameras may need custom ffmpeg params to work reliably. Specifying - # these will replace the default output params. - ################ - # ffmpeg_output_args: [] ################ # size: size of the region in pixels diff --git a/detect_objects.py b/detect_objects.py index 0a6a6de99..86c69d057 100644 --- a/detect_objects.py +++ b/detect_objects.py @@ -19,6 +19,29 @@ MQTT_USER = CONFIG.get('mqtt', {}).get('user') MQTT_PASS = CONFIG.get('mqtt', {}).get('password') MQTT_CLIENT_ID = CONFIG.get('mqtt', {}).get('client_id', 'frigate') +# Set the default FFmpeg config +FFMPEG_CONFIG = CONFIG.get('ffmpeg', {}) +FFMPEG_DEFAULT_CONFIG = { + 'global_args': FFMPEG_CONFIG.get('global_args', + ['-hide_banner','-loglevel','panic']), + 'hwaccel_args': FFMPEG_CONFIG.get('hwaccel_args', + []), + 'input_args': FFMPEG_CONFIG.get('input_args', + ['-avoid_negative_ts', 'make_zero', + '-fflags', 'nobuffer', + '-flags', 'low_delay', + '-strict', 'experimental', + '-fflags', '+genpts+discardcorrupt', + '-vsync', 'drop', + '-rtsp_transport', 'tcp', + '-stimeout', '5000000', + '-use_wallclock_as_timestamps', '1']), + 'output_args': FFMPEG_CONFIG.get('output_args', + ['-vf', 'mpdecimate', + '-f', 'rawvideo', + '-pix_fmt', 'rgb24']) +} + WEB_PORT = CONFIG.get('web_port', 5000) DEBUG = (CONFIG.get('debug', '0') == '1') @@ -51,7 +74,7 @@ def main(): cameras = {} for name, config in CONFIG['cameras'].items(): - cameras[name] = Camera(name, config, prepped_frame_queue, client, MQTT_TOPIC_PREFIX) + cameras[name] = Camera(name, FFMPEG_DEFAULT_CONFIG, config, prepped_frame_queue, client, MQTT_TOPIC_PREFIX) prepped_queue_processor = PreppedQueueProcessor( cameras, diff --git a/docs/DEVICES.md b/docs/DEVICES.md new file mode 100644 index 000000000..b2f4b5983 --- /dev/null +++ b/docs/DEVICES.md @@ -0,0 +1,74 @@ +# Configuration Examples + +### Default (most RTSP cameras) +This is the default ffmpeg command and should work with most RTSP cameras that send h264 video +```yaml +ffmpeg: + global_args: + - -hide_banner + - -loglevel + - panic + hwaccel_args: [] + input_args: + - -avoid_negative_ts + - make_zero + - -fflags + - nobuffer + - -flags + - low_delay + - -strict + - experimental + - -fflags + - +genpts+discardcorrupt + - -vsync + - drop + - -rtsp_transport + - tcp + - -stimeout + - '5000000' + - -use_wallclock_as_timestamps + - '1' + output_args: + - -vf + - mpdecimate + - -f + - rawvideo + - -pix_fmt + - rgb24 +``` + +### RTMP Cameras +The input parameters need to be adjusted for RTMP cameras +```yaml +ffmpeg: +input_args: + - -avoid_negative_ts + - make_zero + - -fflags + - nobuffer + - -flags + - low_delay + - -strict + - experimental + - -fflags + - +genpts+discardcorrupt + - -vsync + - drop + - -use_wallclock_as_timestamps + - '1' +``` + + +### Hardware Acceleration + +Intel Quicksync +```yaml +ffmpeg: + hwaccel_args: + - -hwaccel + - vaapi + - -hwaccel_device + - /dev/dri/renderD128 + - -hwaccel_output_format + - yuv420p +``` \ No newline at end of file diff --git a/frigate/video.py b/frigate/video.py index 5dfb3faf1..7a1d7ae70 100644 --- a/frigate/video.py +++ b/frigate/video.py @@ -111,30 +111,20 @@ class CameraCapture(threading.Thread): self.camera.frame_ready.notify_all() class Camera: - def __init__(self, name, config, prepped_frame_queue, mqtt_client, mqtt_prefix): + def __init__(self, name, ffmpeg_config, config, prepped_frame_queue, mqtt_client, mqtt_prefix): self.name = name self.config = config self.detected_objects = [] self.recent_frames = {} - self.ffmpeg_input = get_ffmpeg_input(self.config['ffmpeg_input']) + + self.ffmpeg = config.get('ffmpeg', {}) + self.ffmpeg_input = get_ffmpeg_input(self.ffmpeg['input']) + self.ffmpeg_global_args = self.ffmpeg.get('global_args', ffmpeg_config['global_args']) + self.ffmpeg_hwaccel_args = self.ffmpeg.get('hwaccel_args', ffmpeg_config['hwaccel_args']) + self.ffmpeg_input_args = self.ffmpeg.get('input_args', ffmpeg_config['input_args']) + self.ffmpeg_output_args = self.ffmpeg.get('output_args', ffmpeg_config['output_args']) + self.take_frame = self.config.get('take_frame', 1) - self.ffmpeg_log_level = self.config.get('ffmpeg_log_level', 'panic') - self.ffmpeg_hwaccel_args = self.config.get('ffmpeg_hwaccel_args', []) - self.ffmpeg_input_args = self.config.get('ffmpeg_input_args', [ - '-avoid_negative_ts', 'make_zero', - '-fflags', 'nobuffer', - '-flags', 'low_delay', - '-strict', 'experimental', - '-fflags', '+genpts+discardcorrupt', - '-vsync', 'drop', - '-rtsp_transport', 'tcp', - '-stimeout', '5000000', - '-use_wallclock_as_timestamps', '1' - ]) - self.ffmpeg_output_args = self.config.get('ffmpeg_output_args', [ - '-f', 'rawvideo', - '-pix_fmt', 'rgb24' - ]) self.regions = self.config['regions'] self.frame_shape = get_frame_shape(self.ffmpeg_input) self.frame_size = self.frame_shape[0] * self.frame_shape[1] * self.frame_shape[2] @@ -232,12 +222,8 @@ class Camera: self.capture_thread.start() def start_ffmpeg(self): - ffmpeg_global_args = [ - '-hide_banner', '-loglevel', self.ffmpeg_log_level - ] - ffmpeg_cmd = (['ffmpeg'] + - ffmpeg_global_args + + self.ffmpeg_global_args + self.ffmpeg_hwaccel_args + self.ffmpeg_input_args + ['-i', self.ffmpeg_input] +