diff --git a/README.md b/README.md index 012a856af..94f80db2d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Use of a [Google Coral Accelerator](https://coral.ai/products/) is optional, but - Uses a very low overhead motion detection to determine where to run object detection - Object detection with TensorFlow runs in separate processes for maximum FPS - Communicates over MQTT for easy integration into other systems -- Records video clips of detected objects +- Records video with retention settings based on detected objects - 24/7 recording - Re-streaming via RTMP to reduce the number of connections to your camera @@ -23,16 +23,20 @@ Use of a [Google Coral Accelerator](https://coral.ai/products/) is optional, but View the documentation at https://blakeblackshear.github.io/frigate ## Donations + If you would like to make a donation to support development, please use [Github Sponsors](https://github.com/sponsors/blakeblackshear). ## Screenshots + Integration into Home Assistant +
Also comes with a builtin UI: +
diff --git a/docs/docs/configuration/advanced.md b/docs/docs/configuration/advanced.md index 14dcb73de..eafc91d99 100644 --- a/docs/docs/configuration/advanced.md +++ b/docs/docs/configuration/advanced.md @@ -81,15 +81,15 @@ environment_vars: ### `database` -Event and clip information is managed in a sqlite database at `/media/frigate/clips/frigate.db`. If that database is deleted, clips will be orphaned and will need to be cleaned up manually. They also won't show up in the Media Browser within Home Assistant. +Event and recording information is managed in a sqlite database at `/media/frigate/frigate.db`. If that database is deleted, recordings will be orphaned and will need to be cleaned up manually. They also won't show up in the Media Browser within Home Assistant. -If you are storing your clips on a network share (SMB, NFS, etc), you may get a `database is locked` error message on startup. You can customize the location of the database in the config if necessary. +If you are storing your database on a network share (SMB, NFS, etc), you may get a `database is locked` error message on startup. You can customize the location of the database in the config if necessary. -This may need to be in a custom location if network storage is used for clips. +This may need to be in a custom location if network storage is used for the media folder. ```yaml database: - path: /media/frigate/clips/frigate.db + path: /media/frigate/frigate.db ``` ### `detectors` diff --git a/docs/docs/configuration/cameras.md b/docs/docs/configuration/cameras.md index 4093d1524..7592a5560 100644 --- a/docs/docs/configuration/cameras.md +++ b/docs/docs/configuration/cameras.md @@ -5,7 +5,7 @@ title: Cameras ## Setting Up Camera Inputs -Up to 4 inputs can be configured for each camera and the role of each input can be mixed and matched based on your needs. This allows you to use a lower resolution stream for object detection, but create clips from a higher resolution stream, or vice versa. +Up to 4 inputs can be configured for each camera and the role of each input can be mixed and matched based on your needs. This allows you to use a lower resolution stream for object detection, but create recordings from a higher resolution stream, or vice versa. Each role can only be assigned to one input per camera. The options for roles are as follows: @@ -30,7 +30,6 @@ cameras: - rtmp - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/live roles: - - clips - record detect: width: 1280 @@ -136,7 +135,7 @@ objects: 24/7 recordings can be enabled and are stored at `/media/frigate/recordings`. The folder structure for the recordings is `YYYY-MM/DD/HH//MM.SS.mp4`. These recordings are written directly from your camera stream without re-encoding and are available in Home Assistant's media browser. Each camera supports a configurable retention policy in the config. -Clips are also created off of these recordings. Frigate chooses the largest matching retention value between the recording retention and the event retention when determining if a recording should be removed. +Exported clips are also created off of these recordings. Frigate chooses the largest matching retention value between the recording retention and the event retention when determining if a recording should be removed. These recordings will not be playable in the web UI or in Home Assistant's media browser unless your camera sends video as h264. @@ -158,16 +157,16 @@ record: # NOTE: If an object is being tracked for longer than this amount of time, the cache # will begin to expire and the resulting clip will be the last x seconds of the event unless retain_days under record is > 0. max_seconds: 300 - # Optional: Number of seconds before the event to include in the clips (default: shown below) + # Optional: Number of seconds before the event to include in the event (default: shown below) pre_capture: 5 - # Optional: Number of seconds after the event to include in the clips (default: shown below) + # Optional: Number of seconds after the event to include in the event (default: shown below) post_capture: 5 - # Optional: Objects to save clips for. (default: all tracked objects) + # Optional: Objects to save event for. (default: all tracked objects) objects: - person - # Optional: Restrict clips to objects that entered any of the listed zones (default: no required zones) + # Optional: Restrict event to objects that entered any of the listed zones (default: no required zones) required_zones: [] - # Optional: Retention settings for clips + # Optional: Retention settings for event retain: # Required: Default retention days (default: shown below) default: 10 @@ -262,8 +261,8 @@ cameras: # Required: the path to the stream # NOTE: Environment variables that begin with 'FRIGATE_' may be referenced in {} - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 - # Required: list of roles for this stream. valid values are: detect,record,clips,rtmp - # NOTICE: In addition to assigning the record, clips, and rtmp roles, + # Required: list of roles for this stream. valid values are: detect,record,rtmp + # NOTICE: In addition to assigning the record, and rtmp roles, # they must also be enabled in the camera config. roles: - detect @@ -328,34 +327,33 @@ cameras: max_area: 100000 threshold: 0.7 - # Optional: save clips configuration - clips: - # Required: enables clips for the camera (default: shown below) - # This value can be set via MQTT and will be updated in startup based on retained value - enabled: False - # Optional: Number of seconds before the event to include in the clips (default: shown below) - pre_capture: 5 - # Optional: Number of seconds after the event to include in the clips (default: shown below) - post_capture: 5 - # Optional: Objects to save clips for. (default: all tracked objects) - objects: - - person - # Optional: Restrict clips to objects that entered any of the listed zones (default: no required zones) - required_zones: [] - # Optional: Camera override for retention settings (default: global values) - retain: - # Required: Default retention days (default: shown below) - default: 10 - # Optional: Per object retention days - objects: - person: 15 - # Optional: 24/7 recording configuration record: # Optional: Enable recording (default: global setting) enabled: False # Optional: Number of days to retain (default: global setting) retain_days: 30 + # Optional: Event recording settings + events: + # Required: enables event recordings for the camera (default: shown below) + # This value can be set via MQTT and will be updated in startup based on retained value + enabled: False + # Optional: Number of seconds before the event to include (default: shown below) + pre_capture: 5 + # Optional: Number of seconds after the event to include (default: shown below) + post_capture: 5 + # Optional: Objects to save events for. (default: all tracked objects) + objects: + - person + # Optional: Restrict events to objects that entered any of the listed zones (default: no required zones) + required_zones: [] + # Optional: Camera override for retention settings (default: global values) + retain: + # Required: Default retention days (default: shown below) + default: 10 + # Optional: Per object retention days + objects: + person: 15 # Optional: RTMP re-stream configuration rtmp: @@ -483,12 +481,11 @@ input_args: - "1" ``` -Note that mjpeg cameras require encoding the video into h264 for clips, recording, and rtmp roles. This will use significantly more CPU than if the cameras supported h264 feeds directly. +Note that mjpeg cameras require encoding the video into h264 for recording, and rtmp roles. This will use significantly more CPU than if the cameras supported h264 feeds directly. ```yaml output_args: record: -f segment -segment_time 60 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -an - clips: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -an rtmp: -c:v libx264 -an -f flv ``` diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index d923ff1c3..9128fead5 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -127,7 +127,7 @@ logger: Can be overridden at the camera level. 24/7 recordings can be enabled and are stored at `/media/frigate/recordings`. The folder structure for the recordings is `YYYY-MM/DD/HH//MM.SS.mp4`. These recordings are written directly from your camera stream without re-encoding and are available in Home Assistant's media browser. Each camera supports a configurable retention policy in the config. -Clips are also created off of these recordings. Frigate chooses the largest matching retention value between the recording retention and the event retention when determining if a recording should be removed. +Exported clips are also created off of these recordings. Frigate chooses the largest matching retention value between the recording retention and the event retention when determining if a recording should be removed. These recordings will not be playable in the web UI or in Home Assistant's media browser unless your camera sends video as h264. @@ -149,16 +149,16 @@ record: # NOTE: If an object is being tracked for longer than this amount of time, the cache # will begin to expire and the resulting clip will be the last x seconds of the event unless retain_days under record is > 0. max_seconds: 300 - # Optional: Number of seconds before the event to include in the clips (default: shown below) + # Optional: Number of seconds before the event to include (default: shown below) pre_capture: 5 - # Optional: Number of seconds after the event to include in the clips (default: shown below) + # Optional: Number of seconds after the event to include (default: shown below) post_capture: 5 - # Optional: Objects to save clips for. (default: all tracked objects) + # Optional: Objects to save recordings for. (default: all tracked objects) objects: - person - # Optional: Restrict clips to objects that entered any of the listed zones (default: no required zones) + # Optional: Restrict recordings to objects that entered any of the listed zones (default: no required zones) required_zones: [] - # Optional: Retention settings for clips + # Optional: Retention settings for events retain: # Required: Default retention days (default: shown below) default: 10 @@ -201,8 +201,6 @@ ffmpeg: detect: -f rawvideo -pix_fmt yuv420p # Optional: output args for record streams (default: shown below) record: -f segment -segment_time 60 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an - # Optional: output args for clips streams (default: shown below) - clips: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an # Optional: output args for rtmp streams (default: shown below) rtmp: -c copy -f flv ``` diff --git a/docs/docs/contributing.md b/docs/docs/contributing.md index cfd70ad66..a818000b4 100644 --- a/docs/docs/contributing.md +++ b/docs/docs/contributing.md @@ -63,17 +63,17 @@ cameras: roles: - detect - rtmp - - clips - height: 1080 - width: 1920 - fps: 5 + detect: + height: 1080 + width: 1920 + fps: 5 ``` These input args tell ffmpeg to read the mp4 file in an infinite loop. You can use any valid ffmpeg input here. #### 3. Gather some mp4 files for testing -Create and place these files in a `debug` folder in the root of the repo. This is also where clips and recordings will be created if you enable them in your test config. Update your config from step 2 above to point at the right file. You can check the `docker-compose.yml` file in the repo to see how the volumes are mapped. +Create and place these files in a `debug` folder in the root of the repo. This is also where recordings will be created if you enable them in your test config. Update your config from step 2 above to point at the right file. You can check the `docker-compose.yml` file in the repo to see how the volumes are mapped. #### 4. Open the repo with Visual Studio Code diff --git a/docs/docs/hardware.md b/docs/docs/hardware.md index 5cf20df87..a68a5e120 100644 --- a/docs/docs/hardware.md +++ b/docs/docs/hardware.md @@ -5,7 +5,7 @@ title: Recommended hardware ## Cameras -Cameras that output H.264 video and AAC audio will offer the most compatibility with all features of Frigate and Home Assistant. It is also helpful if your camera supports multiple substreams to allow different resolutions to be used for detection, streaming, clips, and recordings without re-encoding. +Cameras that output H.264 video and AAC audio will offer the most compatibility with all features of Frigate and Home Assistant. It is also helpful if your camera supports multiple substreams to allow different resolutions to be used for detection, streaming, and recordings without re-encoding. ## Computer diff --git a/docs/docs/installation.md b/docs/docs/installation.md index c3f916ad1..67e8252ae 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -5,7 +5,7 @@ title: Installation Frigate is a Docker container that can be run on any Docker host including as a [HassOS Addon](https://www.home-assistant.io/addons/). See instructions below for installing the HassOS addon. -For Home Assistant users, there is also a [custom component (aka integration)](https://github.com/blakeblackshear/frigate-hass-integration). This custom component adds tighter integration with Home Assistant by automatically setting up camera entities, sensors, media browser for clips and recordings, and a public API to simplify notifications. +For Home Assistant users, there is also a [custom component (aka integration)](https://github.com/blakeblackshear/frigate-hass-integration). This custom component adds tighter integration with Home Assistant by automatically setting up camera entities, sensors, media browser for recordings, and a public API to simplify notifications. Note that HassOS Addons and custom components are different things. If you are already running Frigate with Docker directly, you do not need the Addon since the Addon would run another instance of Frigate. diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 12eb55bc6..15ec9332b 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -7,9 +7,9 @@ title: Troubleshooting and FAQ A solid green image means that frigate has not received any frames from ffmpeg. Check the logs to see why ffmpeg is exiting and adjust your ffmpeg args accordingly. -### How can I get sound or audio in my clips and recordings? +### How can I get sound or audio in my recordings? -By default, Frigate removes audio from clips and recordings to reduce the likelihood of failing for invalid data. If you would like to include audio, you need to override the output args to remove `-an` for where you want to include audio. The recommended audio codec is `aac`. Not all audio codecs are supported by RTMP, so you may need to re-encode your audio with `-c:a aac`. The default ffmpeg args are shown [here](/frigate/configuration/index#ffmpeg). +By default, Frigate removes audio from recordings to reduce the likelihood of failing for invalid data. If you would like to include audio, you need to override the output args to remove `-an` for where you want to include audio. The recommended audio codec is `aac`. Not all audio codecs are supported by RTMP, so you may need to re-encode your audio with `-c:a aac`. The default ffmpeg args are shown [here](/frigate/configuration/index#ffmpeg). ### My mjpeg stream or snapshots look green and crazy @@ -17,17 +17,13 @@ This almost always means that the width/height defined for your camera are not c ![mismatched-resolution](/img/mismatched-resolution.jpg) -### I have clips and snapshots in my clips folder, but I can't view them in the Web UI. +### I can't view events or recordings in the Web UI. -This is usually caused one of two things: - -- The permissions on the parent folder don't have execute and nginx returns a 403 error you can see in the browser logs - - In this case, try mounting a volume to `/media/frigate` inside the container instead of `/media/frigate/clips`. -- Your cameras do not send h264 encoded video and the mp4 files are not playable in the browser +Ensure your cameras send h264 encoded video ### "[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5639eeb6e140] moov atom not found" -These messages in the logs are expected in certain situations. Frigate checks the integrity of the video cache before assembling clips. Occasionally these cached files will be invalid and cleaned up automatically. +These messages in the logs are expected in certain situations. Frigate checks the integrity of the recordings before storing. Occasionally these cached files will be invalid and cleaned up automatically. ### "On connect called" diff --git a/docs/docs/usage/api.md b/docs/docs/usage/api.md index 86824b5a8..b5d0eaa94 100644 --- a/docs/docs/usage/api.md +++ b/docs/docs/usage/api.md @@ -206,10 +206,6 @@ Accepts the following query string parameters, but they are only applied when an | `crop` | int | Crop the snapshot to the (0 or 1) | | `quality` | int | Jpeg encoding quality (0-100). Defaults to 70. | -### `/clips/-.mp4` - -Video clip for the given camera and event id. - ### `/clips/-.jpg` JPG snapshot for the given camera and event id. diff --git a/docs/docs/usage/home-assistant.md b/docs/docs/usage/home-assistant.md index bf0b577b1..5342ec98a 100644 --- a/docs/docs/usage/home-assistant.md +++ b/docs/docs/usage/home-assistant.md @@ -64,14 +64,14 @@ Home Assistant > Configuration > Integrations > Frigate > Options | --------------- | --------------------------------------------------------------------------------- | | `camera` | Live camera stream (requires RTMP), camera for image of the last detected object. | | `sensor` | States to monitor Frigate performance, object counts for all zones and cameras. | -| `switch` | Switch entities to toggle detection, clips and snapshots. | +| `switch` | Switch entities to toggle detection, recordings and snapshots. | | `binary_sensor` | A "motion" binary sensor entity per camera/zone/object. | ## Media Browser Support The integration provides: -- Rich UI with thumbnails for browsing event clips +- Rich UI with thumbnails for browsing event recordings - Rich UI for browsing 24/7 recordings by month, day, camera, time This is accessible via "Media Browser" on the left menu panel in Home Assistant. diff --git a/frigate/app.py b/frigate/app.py index 42c94d3c5..bf3f12989 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -90,15 +90,6 @@ class FrigateApp: assigned_roles = list( set([r for i in camera.ffmpeg.inputs for r in i.roles]) ) - if not camera.clips.enabled and "clips" in assigned_roles: - logger.warning( - f"Camera {name} has clips assigned to an input, but clips is not enabled." - ) - elif camera.clips.enabled and not "clips" in assigned_roles: - logger.warning( - f"Camera {name} has clips enabled, but clips is not assigned to an input." - ) - if not camera.record.enabled and "record" in assigned_roles: logger.warning( f"Camera {name} has record assigned to an input, but record is not enabled." diff --git a/frigate/config.py b/frigate/config.py index e466abc22..c68d6df93 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -445,7 +445,6 @@ class CameraConfig(BaseModel): zones: Dict[str, ZoneConfig] = Field( default_factory=dict, title="Zone configuration." ) - clips: ClipsConfig = Field(default_factory=ClipsConfig, title="Clip configuration.") record: RecordConfig = Field( default_factory=RecordConfig, title="Record configuration." ) @@ -526,9 +525,7 @@ class CameraConfig(BaseModel): ffmpeg_output_args = ( rtmp_args + [f"rtmp://127.0.0.1/live/{self.name}"] + ffmpeg_output_args ) - if any(role in ["clips", "record"] for role in ffmpeg_input.roles) and ( - self.record.enabled or self.clips.enabled - ): + if "record" in ffmpeg_input.roles and self.record.enabled: record_args = ( self.ffmpeg.output_args.record if isinstance(self.ffmpeg.output_args.record, list) @@ -638,9 +635,6 @@ class FrigateConfig(BaseModel): logger: LoggerConfig = Field( default_factory=LoggerConfig, title="Logging configuration." ) - clips: ClipsConfig = Field( - default_factory=ClipsConfig, title="Global clips configuration." - ) record: RecordConfig = Field( default_factory=RecordConfig, title="Global record configuration." ) @@ -676,7 +670,6 @@ class FrigateConfig(BaseModel): # Global config to propegate down to camera level global_config = config.dict( include={ - "clips": ..., "record": ..., "snapshots": ..., "objects": ..., @@ -751,21 +744,6 @@ class FrigateConfig(BaseModel): config.cameras[name] = camera_config - # Merge Clips configuration for backward compatibility - if camera_config.clips.enabled: - logger.warn( - "Clips configuration is deprecated. Configure clip settings under record -> events." - ) - if not camera_config.record.enabled: - camera_config.record.enabled = True - camera_config.record.retain_days = 0 - camera_config.record.events = ClipsConfig.parse_obj( - deep_merge( - camera_config.clips.dict(exclude_unset=True), - camera_config.record.events.dict(exclude_unset=True), - ) - ) - return config @validator("cameras") diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 9db5d3401..20fda3a05 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -349,7 +349,9 @@ class TestConfig(unittest.TestCase): def test_inherit_clips_retention(self): config = { "mqtt": {"host": "mqtt"}, - "clips": {"retain": {"default": 20, "objects": {"person": 30}}}, + "record": { + "events": {"retain": {"default": 20, "objects": {"person": 30}}} + }, "cameras": { "back": { "ffmpeg": { @@ -369,12 +371,16 @@ class TestConfig(unittest.TestCase): assert config == frigate_config.dict(exclude_unset=True) runtime_config = frigate_config.runtime_config - assert runtime_config.cameras["back"].clips.retain.objects["person"] == 30 + assert ( + runtime_config.cameras["back"].record.events.retain.objects["person"] == 30 + ) def test_roles_listed_twice_throws_error(self): config = { "mqtt": {"host": "mqtt"}, - "clips": {"retain": {"default": 20, "objects": {"person": 30}}}, + "record": { + "events": {"retain": {"default": 20, "objects": {"person": 30}}} + }, "cameras": { "back": { "ffmpeg": { @@ -396,7 +402,9 @@ class TestConfig(unittest.TestCase): def test_zone_matching_camera_name_throws_error(self): config = { "mqtt": {"host": "mqtt"}, - "clips": {"retain": {"default": 20, "objects": {"person": 30}}}, + "record": { + "events": {"retain": {"default": 20, "objects": {"person": 30}}} + }, "cameras": { "back": { "ffmpeg": { @@ -418,7 +426,9 @@ class TestConfig(unittest.TestCase): def test_zone_assigns_color_and_contour(self): config = { "mqtt": {"host": "mqtt"}, - "clips": {"retain": {"default": 20, "objects": {"person": 30}}}, + "record": { + "events": {"retain": {"default": 20, "objects": {"person": 30}}} + }, "cameras": { "back": { "ffmpeg": { @@ -447,7 +457,9 @@ class TestConfig(unittest.TestCase): def test_clips_should_default_to_global_objects(self): config = { "mqtt": {"host": "mqtt"}, - "clips": {"retain": {"default": 20, "objects": {"person": 30}}}, + "record": { + "events": {"retain": {"default": 20, "objects": {"person": 30}}} + }, "objects": {"track": ["person", "dog"]}, "cameras": { "back": { @@ -461,7 +473,7 @@ class TestConfig(unittest.TestCase): "width": 1920, "fps": 5, }, - "clips": {"enabled": True}, + "record": {"events": {"enabled": True}}, } }, } @@ -470,8 +482,8 @@ class TestConfig(unittest.TestCase): runtime_config = frigate_config.runtime_config back_camera = runtime_config.cameras["back"] - assert back_camera.clips.objects is None - assert back_camera.clips.retain.objects["person"] == 30 + assert back_camera.record.events.objects is None + assert back_camera.record.events.retain.objects["person"] == 30 def test_role_assigned_but_not_enabled(self): config = {