mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Remove rtmp (#8941)
* remove rtmp from python * remove rtmp from nginx * remove rtmp from docs * fix test for missing role
This commit is contained in:
		
							parent
							
								
									696434b36d
								
							
						
					
					
						commit
						d2d1278a4d
					
				@ -5,7 +5,6 @@ set -euxo pipefail
 | 
				
			|||||||
NGINX_VERSION="1.25.3"
 | 
					NGINX_VERSION="1.25.3"
 | 
				
			||||||
VOD_MODULE_VERSION="1.31"
 | 
					VOD_MODULE_VERSION="1.31"
 | 
				
			||||||
SECURE_TOKEN_MODULE_VERSION="1.5"
 | 
					SECURE_TOKEN_MODULE_VERSION="1.5"
 | 
				
			||||||
RTMP_MODULE_VERSION="1.2.2"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
cp /etc/apt/sources.list /etc/apt/sources.list.d/sources-src.list
 | 
					cp /etc/apt/sources.list /etc/apt/sources.list.d/sources-src.list
 | 
				
			||||||
sed -i 's|deb http|deb-src http|g' /etc/apt/sources.list.d/sources-src.list
 | 
					sed -i 's|deb http|deb-src http|g' /etc/apt/sources.list.d/sources-src.list
 | 
				
			||||||
@ -49,10 +48,6 @@ mkdir /tmp/nginx-secure-token-module
 | 
				
			|||||||
wget https://github.com/kaltura/nginx-secure-token-module/archive/refs/tags/${SECURE_TOKEN_MODULE_VERSION}.tar.gz
 | 
					wget https://github.com/kaltura/nginx-secure-token-module/archive/refs/tags/${SECURE_TOKEN_MODULE_VERSION}.tar.gz
 | 
				
			||||||
tar -zxf ${SECURE_TOKEN_MODULE_VERSION}.tar.gz -C /tmp/nginx-secure-token-module --strip-components=1
 | 
					tar -zxf ${SECURE_TOKEN_MODULE_VERSION}.tar.gz -C /tmp/nginx-secure-token-module --strip-components=1
 | 
				
			||||||
rm ${SECURE_TOKEN_MODULE_VERSION}.tar.gz
 | 
					rm ${SECURE_TOKEN_MODULE_VERSION}.tar.gz
 | 
				
			||||||
mkdir /tmp/nginx-rtmp-module
 | 
					 | 
				
			||||||
wget -nv https://github.com/arut/nginx-rtmp-module/archive/refs/tags/v${RTMP_MODULE_VERSION}.tar.gz
 | 
					 | 
				
			||||||
tar -zxf v${RTMP_MODULE_VERSION}.tar.gz -C /tmp/nginx-rtmp-module --strip-components=1
 | 
					 | 
				
			||||||
rm v${RTMP_MODULE_VERSION}.tar.gz
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
cd /tmp/nginx
 | 
					cd /tmp/nginx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,7 +58,6 @@ cd /tmp/nginx
 | 
				
			|||||||
    --with-threads \
 | 
					    --with-threads \
 | 
				
			||||||
    --add-module=../nginx-vod-module \
 | 
					    --add-module=../nginx-vod-module \
 | 
				
			||||||
    --add-module=../nginx-secure-token-module \
 | 
					    --add-module=../nginx-secure-token-module \
 | 
				
			||||||
    --add-module=../nginx-rtmp-module \
 | 
					 | 
				
			||||||
    --with-cc-opt="-O3 -Wno-error=implicit-fallthrough"
 | 
					    --with-cc-opt="-O3 -Wno-error=implicit-fallthrough"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
make CC="ccache gcc" -j$(nproc) && make install
 | 
					make CC="ccache gcc" -j$(nproc) && make install
 | 
				
			||||||
 | 
				
			|||||||
@ -275,18 +275,3 @@ http {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -69,16 +69,12 @@ cameras:
 | 
				
			|||||||
    ffmpeg:
 | 
					    ffmpeg:
 | 
				
			||||||
      output_args:
 | 
					      output_args:
 | 
				
			||||||
        record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -tag:v hvc1 -bsf:v hevc_mp4toannexb -c:a aac
 | 
					        record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -tag:v hvc1 -bsf:v hevc_mp4toannexb -c:a aac
 | 
				
			||||||
        rtmp: -c:v copy -c:a aac -f flv
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      inputs:
 | 
					      inputs:
 | 
				
			||||||
        - path: rtsp://user:password@camera-ip:554/H264/ch1/main/av_stream # <----- Update for your camera
 | 
					        - path: rtsp://user:password@camera-ip:554/H264/ch1/main/av_stream # <----- Update for your camera
 | 
				
			||||||
          roles:
 | 
					          roles:
 | 
				
			||||||
            - detect
 | 
					            - detect
 | 
				
			||||||
            - record
 | 
					            - record
 | 
				
			||||||
            - rtmp
 | 
					 | 
				
			||||||
    rtmp:
 | 
					 | 
				
			||||||
      enabled: False # <-- RTMP should be disabled if your stream is not H264
 | 
					 | 
				
			||||||
    detect:
 | 
					    detect:
 | 
				
			||||||
      width: # <- optional, by default Frigate tries to automatically detect resolution
 | 
					      width: # <- optional, by default Frigate tries to automatically detect resolution
 | 
				
			||||||
      height: # <- optional, by default Frigate tries to automatically detect resolution
 | 
					      height: # <- optional, by default Frigate tries to automatically detect resolution
 | 
				
			||||||
@ -181,13 +177,12 @@ go2rtc:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[See the go2rtc docs for more information](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#source-rtsp)
 | 
					[See the go2rtc docs for more information](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#source-rtsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In the Unifi 2.0 update Unifi Protect Cameras had a change in audio sample rate which causes issues for ffmpeg. The input rate needs to be set for record and rtmp if used directly with unifi protect.
 | 
					In the Unifi 2.0 update Unifi Protect Cameras had a change in audio sample rate which causes issues for ffmpeg. The input rate needs to be set for record if used directly with unifi protect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  output_args:
 | 
					  output_args:
 | 
				
			||||||
    record: preset-record-ubiquiti
 | 
					    record: preset-record-ubiquiti
 | 
				
			||||||
    rtmp: preset-rtmp-ubiquiti # recommend using go2rtc instead
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### TP-Link VIGI Cameras
 | 
					### TP-Link VIGI Cameras
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,6 @@ Each role can only be assigned to one input per camera. The options for roles ar
 | 
				
			|||||||
| `detect` | Main feed for object detection. [docs](object_detectors.md)                              |
 | 
					| `detect` | Main feed for object detection. [docs](object_detectors.md)                              |
 | 
				
			||||||
| `record` | Saves segments of the video feed based on configuration settings. [docs](record.md)      |
 | 
					| `record` | Saves segments of the video feed based on configuration settings. [docs](record.md)      |
 | 
				
			||||||
| `audio`  | Feed for audio based detection. [docs](audio_detectors.md)                               |
 | 
					| `audio`  | Feed for audio based detection. [docs](audio_detectors.md)                               |
 | 
				
			||||||
| `rtmp`   | Deprecated: Broadcast as an RTMP feed for other services to consume. [docs](restream.md) |
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
mqtt:
 | 
					mqtt:
 | 
				
			||||||
@ -29,7 +28,6 @@ cameras:
 | 
				
			|||||||
        - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2
 | 
					        - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2
 | 
				
			||||||
          roles:
 | 
					          roles:
 | 
				
			||||||
            - detect
 | 
					            - detect
 | 
				
			||||||
            - rtmp # <- deprecated, recommend using restream instead
 | 
					 | 
				
			||||||
        - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/live
 | 
					        - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/live
 | 
				
			||||||
          roles:
 | 
					          roles:
 | 
				
			||||||
            - record
 | 
					            - record
 | 
				
			||||||
 | 
				
			|||||||
@ -162,8 +162,6 @@ ffmpeg:
 | 
				
			|||||||
    detect: -threads 2 -f rawvideo -pix_fmt yuv420p
 | 
					    detect: -threads 2 -f rawvideo -pix_fmt yuv420p
 | 
				
			||||||
    # Optional: output args for record streams (default: shown below)
 | 
					    # Optional: output args for record streams (default: shown below)
 | 
				
			||||||
    record: preset-record-generic
 | 
					    record: preset-record-generic
 | 
				
			||||||
    # Optional: output args for rtmp streams (default: shown below)
 | 
					 | 
				
			||||||
    rtmp: preset-rtmp-generic
 | 
					 | 
				
			||||||
  # Optional: Time in seconds to wait before ffmpeg retries connecting to the camera. (default: shown below)
 | 
					  # Optional: Time in seconds to wait before ffmpeg retries connecting to the camera. (default: shown below)
 | 
				
			||||||
  # If set too low, frigate will retry a connection to the camera's stream too frequently, using up the limited streams some cameras can allow at once
 | 
					  # If set too low, frigate will retry a connection to the camera's stream too frequently, using up the limited streams some cameras can allow at once
 | 
				
			||||||
  # If set too high, then if a ffmpeg crash or camera stream timeout occurs, you could potentially lose up to a maximum of retry_interval second(s) of footage
 | 
					  # If set too high, then if a ffmpeg crash or camera stream timeout occurs, you could potentially lose up to a maximum of retry_interval second(s) of footage
 | 
				
			||||||
@ -386,13 +384,6 @@ snapshots:
 | 
				
			|||||||
  # Optional: quality of the encoded jpeg, 0-100 (default: shown below)
 | 
					  # Optional: quality of the encoded jpeg, 0-100 (default: shown below)
 | 
				
			||||||
  quality: 70
 | 
					  quality: 70
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Optional: RTMP configuration
 | 
					 | 
				
			||||||
# NOTE: RTMP is deprecated in favor of restream
 | 
					 | 
				
			||||||
# NOTE: Can be overridden at the camera level
 | 
					 | 
				
			||||||
rtmp:
 | 
					 | 
				
			||||||
  # Optional: Enable the RTMP stream (default: False)
 | 
					 | 
				
			||||||
  enabled: False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Optional: Restream configuration
 | 
					# Optional: Restream configuration
 | 
				
			||||||
# Uses https://github.com/AlexxIT/go2rtc (v1.8.3)
 | 
					# Uses https://github.com/AlexxIT/go2rtc (v1.8.3)
 | 
				
			||||||
go2rtc:
 | 
					go2rtc:
 | 
				
			||||||
@ -449,14 +440,13 @@ cameras:
 | 
				
			|||||||
        # Required: the path to the stream
 | 
					        # Required: the path to the stream
 | 
				
			||||||
        # NOTE: path may include environment variables or docker secrets, which must begin with 'FRIGATE_' and be referenced in {}
 | 
					        # NOTE: path may include environment variables or docker secrets, which must begin with 'FRIGATE_' and be referenced in {}
 | 
				
			||||||
        - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2
 | 
					        - 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: audio,detect,record,rtmp
 | 
					          # Required: list of roles for this stream. valid values are: audio,detect,record
 | 
				
			||||||
          # NOTICE: In addition to assigning the audio, record, and rtmp roles,
 | 
					          # NOTICE: In addition to assigning the audio, detect, and record roles
 | 
				
			||||||
          # they must also be enabled in the camera config.
 | 
					          # they must also be enabled in the camera config.
 | 
				
			||||||
          roles:
 | 
					          roles:
 | 
				
			||||||
            - audio
 | 
					            - audio
 | 
				
			||||||
            - detect
 | 
					            - detect
 | 
				
			||||||
            - record
 | 
					            - record
 | 
				
			||||||
            - rtmp
 | 
					 | 
				
			||||||
          # Optional: stream specific global args (default: inherit)
 | 
					          # Optional: stream specific global args (default: inherit)
 | 
				
			||||||
          # global_args:
 | 
					          # global_args:
 | 
				
			||||||
          # Optional: stream specific hwaccel args (default: inherit)
 | 
					          # Optional: stream specific hwaccel args (default: inherit)
 | 
				
			||||||
 | 
				
			|||||||
@ -38,10 +38,6 @@ go2rtc:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
**NOTE:** This does not apply to localhost requests, there is no need to provide credentials when using the restream as a source for frigate cameras.
 | 
					**NOTE:** This does not apply to localhost requests, there is no need to provide credentials when using the restream as a source for frigate cameras.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## RTMP (Deprecated)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In previous Frigate versions RTMP was used for re-streaming. RTMP has disadvantages however including being incompatible with H.265, high bitrates, and certain audio codecs. RTMP is deprecated and it is recommended use the built in go2rtc config for restreaming.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Reduce Connections To Camera
 | 
					## Reduce Connections To Camera
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Some cameras only support one active connection or you may just want to have a single connection open to the camera. The RTSP restream allows this to be possible.
 | 
					Some cameras only support one active connection or you may just want to have a single connection open to the camera. The RTSP restream allows this to be possible.
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ Use of the bundled go2rtc is optional. You can still configure FFmpeg to connect
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- WebRTC or MSE for live viewing with higher resolutions and frame rates than the jsmpeg stream which is limited to the detect stream
 | 
					- WebRTC or MSE for live viewing with higher resolutions and frame rates than the jsmpeg stream which is limited to the detect stream
 | 
				
			||||||
- Live stream support for cameras in Home Assistant Integration
 | 
					- Live stream support for cameras in Home Assistant Integration
 | 
				
			||||||
- RTSP (instead of RTMP) relay for use with other consumers to reduce the number of connections to your camera streams
 | 
					- RTSP relay for use with other consumers to reduce the number of connections to your camera streams
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Setup a go2rtc stream
 | 
					# Setup a go2rtc stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -124,10 +124,6 @@ https://HA_URL/api/frigate/notifications/<event-id>/clip.mp4
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<a name="streams"></a>
 | 
					<a name="streams"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## RTMP stream
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RTMP is deprecated and it is recommended to switch to use RTSP restreams.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## RTSP stream
 | 
					## RTSP stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In order for the live streams to function they need to be accessible on the RTSP
 | 
					In order for the live streams to function they need to be accessible on the RTSP
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@ from frigate.ffmpeg_presets import (
 | 
				
			|||||||
    parse_preset_hardware_acceleration_scale,
 | 
					    parse_preset_hardware_acceleration_scale,
 | 
				
			||||||
    parse_preset_input,
 | 
					    parse_preset_input,
 | 
				
			||||||
    parse_preset_output_record,
 | 
					    parse_preset_output_record,
 | 
				
			||||||
    parse_preset_output_rtmp,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from frigate.plus import PlusApi
 | 
					from frigate.plus import PlusApi
 | 
				
			||||||
from frigate.util.builtin import (
 | 
					from frigate.util.builtin import (
 | 
				
			||||||
@ -582,7 +581,6 @@ DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT = [
 | 
				
			|||||||
    "-pix_fmt",
 | 
					    "-pix_fmt",
 | 
				
			||||||
    "yuv420p",
 | 
					    "yuv420p",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
RTMP_FFMPEG_OUTPUT_ARGS_DEFAULT = "preset-rtmp-generic"
 | 
					 | 
				
			||||||
RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = "preset-record-generic"
 | 
					RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = "preset-record-generic"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -595,10 +593,6 @@ class FfmpegOutputArgsConfig(FrigateBaseModel):
 | 
				
			|||||||
        default=RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT,
 | 
					        default=RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT,
 | 
				
			||||||
        title="Record role FFmpeg output arguments.",
 | 
					        title="Record role FFmpeg output arguments.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    rtmp: Union[str, List[str]] = Field(
 | 
					 | 
				
			||||||
        default=RTMP_FFMPEG_OUTPUT_ARGS_DEFAULT,
 | 
					 | 
				
			||||||
        title="RTMP role FFmpeg output arguments.",
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FfmpegConfig(FrigateBaseModel):
 | 
					class FfmpegConfig(FrigateBaseModel):
 | 
				
			||||||
@ -624,7 +618,6 @@ class FfmpegConfig(FrigateBaseModel):
 | 
				
			|||||||
class CameraRoleEnum(str, Enum):
 | 
					class CameraRoleEnum(str, Enum):
 | 
				
			||||||
    audio = "audio"
 | 
					    audio = "audio"
 | 
				
			||||||
    record = "record"
 | 
					    record = "record"
 | 
				
			||||||
    rtmp = "rtmp"
 | 
					 | 
				
			||||||
    detect = "detect"
 | 
					    detect = "detect"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -733,10 +726,6 @@ class CameraMqttConfig(FrigateBaseModel):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RtmpConfig(FrigateBaseModel):
 | 
					 | 
				
			||||||
    enabled: bool = Field(default=False, title="RTMP restreaming enabled.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CameraLiveConfig(FrigateBaseModel):
 | 
					class CameraLiveConfig(FrigateBaseModel):
 | 
				
			||||||
    stream_name: str = Field(default="", title="Name of restream to use as live view.")
 | 
					    stream_name: str = Field(default="", title="Name of restream to use as live view.")
 | 
				
			||||||
    height: int = Field(default=720, title="Live camera view height")
 | 
					    height: int = Field(default=720, title="Live camera view height")
 | 
				
			||||||
@ -772,9 +761,6 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
    record: RecordConfig = Field(
 | 
					    record: RecordConfig = Field(
 | 
				
			||||||
        default_factory=RecordConfig, title="Record configuration."
 | 
					        default_factory=RecordConfig, title="Record configuration."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    rtmp: RtmpConfig = Field(
 | 
					 | 
				
			||||||
        default_factory=RtmpConfig, title="RTMP restreaming configuration."
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    live: CameraLiveConfig = Field(
 | 
					    live: CameraLiveConfig = Field(
 | 
				
			||||||
        default_factory=CameraLiveConfig, title="Live playback settings."
 | 
					        default_factory=CameraLiveConfig, title="Live playback settings."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@ -819,7 +805,6 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # add roles to the input if there is only one
 | 
					        # add roles to the input if there is only one
 | 
				
			||||||
        if len(config["ffmpeg"]["inputs"]) == 1:
 | 
					        if len(config["ffmpeg"]["inputs"]) == 1:
 | 
				
			||||||
            has_rtmp = "rtmp" in config["ffmpeg"]["inputs"][0].get("roles", [])
 | 
					 | 
				
			||||||
            has_audio = "audio" in config["ffmpeg"]["inputs"][0].get("roles", [])
 | 
					            has_audio = "audio" in config["ffmpeg"]["inputs"][0].get("roles", [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            config["ffmpeg"]["inputs"][0]["roles"] = [
 | 
					            config["ffmpeg"]["inputs"][0]["roles"] = [
 | 
				
			||||||
@ -830,9 +815,6 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
            if has_audio:
 | 
					            if has_audio:
 | 
				
			||||||
                config["ffmpeg"]["inputs"][0]["roles"].append("audio")
 | 
					                config["ffmpeg"]["inputs"][0]["roles"].append("audio")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if has_rtmp:
 | 
					 | 
				
			||||||
                config["ffmpeg"]["inputs"][0]["roles"].append("rtmp")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        super().__init__(**config)
 | 
					        super().__init__(**config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
@ -872,15 +854,7 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ffmpeg_output_args = scale_detect_args + ffmpeg_output_args + ["pipe:"]
 | 
					            ffmpeg_output_args = scale_detect_args + ffmpeg_output_args + ["pipe:"]
 | 
				
			||||||
        if "rtmp" in ffmpeg_input.roles and self.rtmp.enabled:
 | 
					 | 
				
			||||||
            rtmp_args = get_ffmpeg_arg_list(
 | 
					 | 
				
			||||||
                parse_preset_output_rtmp(self.ffmpeg.output_args.rtmp)
 | 
					 | 
				
			||||||
                or self.ffmpeg.output_args.rtmp
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ffmpeg_output_args = (
 | 
					 | 
				
			||||||
                rtmp_args + [f"rtmp://127.0.0.1/live/{self.name}"] + ffmpeg_output_args
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        if "record" in ffmpeg_input.roles and self.record.enabled:
 | 
					        if "record" in ffmpeg_input.roles and self.record.enabled:
 | 
				
			||||||
            record_args = get_ffmpeg_arg_list(
 | 
					            record_args = get_ffmpeg_arg_list(
 | 
				
			||||||
                parse_preset_output_record(self.ffmpeg.output_args.record)
 | 
					                parse_preset_output_record(self.ffmpeg.output_args.record)
 | 
				
			||||||
@ -967,11 +941,6 @@ def verify_config_roles(camera_config: CameraConfig) -> None:
 | 
				
			|||||||
            f"Camera {camera_config.name} has record enabled, but record is not assigned to an input."
 | 
					            f"Camera {camera_config.name} has record enabled, but record is not assigned to an input."
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if camera_config.rtmp.enabled and "rtmp" not in assigned_roles:
 | 
					 | 
				
			||||||
        raise ValueError(
 | 
					 | 
				
			||||||
            f"Camera {camera_config.name} has rtmp enabled, but rtmp is not assigned to an input."
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if camera_config.audio.enabled and "audio" not in assigned_roles:
 | 
					    if camera_config.audio.enabled and "audio" not in assigned_roles:
 | 
				
			||||||
        raise ValueError(
 | 
					        raise ValueError(
 | 
				
			||||||
            f"Camera {camera_config.name} has audio events enabled, but audio is not assigned to an input."
 | 
					            f"Camera {camera_config.name} has audio events enabled, but audio is not assigned to an input."
 | 
				
			||||||
@ -1082,9 +1051,6 @@ class FrigateConfig(FrigateBaseModel):
 | 
				
			|||||||
    snapshots: SnapshotsConfig = Field(
 | 
					    snapshots: SnapshotsConfig = Field(
 | 
				
			||||||
        default_factory=SnapshotsConfig, title="Global snapshots configuration."
 | 
					        default_factory=SnapshotsConfig, title="Global snapshots configuration."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    rtmp: RtmpConfig = Field(
 | 
					 | 
				
			||||||
        default_factory=RtmpConfig, title="Global RTMP restreaming configuration."
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    live: CameraLiveConfig = Field(
 | 
					    live: CameraLiveConfig = Field(
 | 
				
			||||||
        default_factory=CameraLiveConfig, title="Live playback settings."
 | 
					        default_factory=CameraLiveConfig, title="Live playback settings."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@ -1138,7 +1104,6 @@ class FrigateConfig(FrigateBaseModel):
 | 
				
			|||||||
                "birdseye": ...,
 | 
					                "birdseye": ...,
 | 
				
			||||||
                "record": ...,
 | 
					                "record": ...,
 | 
				
			||||||
                "snapshots": ...,
 | 
					                "snapshots": ...,
 | 
				
			||||||
                "rtmp": ...,
 | 
					 | 
				
			||||||
                "live": ...,
 | 
					                "live": ...,
 | 
				
			||||||
                "objects": ...,
 | 
					                "objects": ...,
 | 
				
			||||||
                "motion": ...,
 | 
					                "motion": ...,
 | 
				
			||||||
@ -1272,11 +1237,6 @@ class FrigateConfig(FrigateBaseModel):
 | 
				
			|||||||
            verify_zone_objects_are_tracked(camera_config)
 | 
					            verify_zone_objects_are_tracked(camera_config)
 | 
				
			||||||
            verify_autotrack_zones(camera_config)
 | 
					            verify_autotrack_zones(camera_config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if camera_config.rtmp.enabled:
 | 
					 | 
				
			||||||
                logger.warning(
 | 
					 | 
				
			||||||
                    "RTMP restream is deprecated in favor of the restream role, recommend disabling RTMP."
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # generate the ffmpeg commands
 | 
					            # generate the ffmpeg commands
 | 
				
			||||||
            camera_config.create_ffmpeg_cmds()
 | 
					            camera_config.create_ffmpeg_cmds()
 | 
				
			||||||
            config.cameras[name] = camera_config
 | 
					            config.cameras[name] = camera_config
 | 
				
			||||||
 | 
				
			|||||||
@ -446,28 +446,3 @@ def parse_preset_output_record(arg: Any) -> list[str]:
 | 
				
			|||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return PRESETS_RECORD_OUTPUT.get(arg, None)
 | 
					    return PRESETS_RECORD_OUTPUT.get(arg, None)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PRESETS_RTMP_OUTPUT = {
 | 
					 | 
				
			||||||
    "preset-rtmp-generic": ["-c", "copy", "-f", "flv"],
 | 
					 | 
				
			||||||
    "preset-rtmp-mjpeg": ["-c:v", "libx264", "-an", "-f", "flv"],
 | 
					 | 
				
			||||||
    "preset-rtmp-jpeg": ["-c:v", "libx264", "-an", "-f", "flv"],
 | 
					 | 
				
			||||||
    "preset-rtmp-ubiquiti": [
 | 
					 | 
				
			||||||
        "-c:v",
 | 
					 | 
				
			||||||
        "copy",
 | 
					 | 
				
			||||||
        "-f",
 | 
					 | 
				
			||||||
        "flv",
 | 
					 | 
				
			||||||
        "-ar",
 | 
					 | 
				
			||||||
        "44100",
 | 
					 | 
				
			||||||
        "-c:a",
 | 
					 | 
				
			||||||
        "aac",
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def parse_preset_output_rtmp(arg: Any) -> list[str]:
 | 
					 | 
				
			||||||
    """Return the correct preset if in preset format otherwise return None."""
 | 
					 | 
				
			||||||
    if not isinstance(arg, str):
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return PRESETS_RTMP_OUTPUT.get(arg, None)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -653,7 +653,7 @@ class TestConfig(unittest.TestCase):
 | 
				
			|||||||
                        "inputs": [
 | 
					                        "inputs": [
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					                                "path": "rtsp://10.0.0.1:554/video",
 | 
				
			||||||
                                "roles": ["detect", "rtmp"],
 | 
					                                "roles": ["detect"],
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            {"path": "rtsp://10.0.0.1:554/record", "roles": ["record"]},
 | 
					                            {"path": "rtsp://10.0.0.1:554/record", "roles": ["record"]},
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
@ -930,7 +930,7 @@ class TestConfig(unittest.TestCase):
 | 
				
			|||||||
                        "width": 1920,
 | 
					                        "width": 1920,
 | 
				
			||||||
                        "fps": 5,
 | 
					                        "fps": 5,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    "rtmp": {"enabled": True},
 | 
					                    "audio": {"enabled": True},
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1167,122 +1167,6 @@ class TestConfig(unittest.TestCase):
 | 
				
			|||||||
        assert runtime_config.cameras["back"].snapshots.height == 150
 | 
					        assert runtime_config.cameras["back"].snapshots.height == 150
 | 
				
			||||||
        assert runtime_config.cameras["back"].snapshots.enabled
 | 
					        assert runtime_config.cameras["back"].snapshots.enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_global_rtmp_disabled(self):
 | 
					 | 
				
			||||||
        config = {
 | 
					 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					 | 
				
			||||||
            "cameras": {
 | 
					 | 
				
			||||||
                "back": {
 | 
					 | 
				
			||||||
                    "ffmpeg": {
 | 
					 | 
				
			||||||
                        "inputs": [
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					 | 
				
			||||||
                                "roles": ["detect"],
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        ]
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "detect": {
 | 
					 | 
				
			||||||
                        "height": 1080,
 | 
					 | 
				
			||||||
                        "width": 1920,
 | 
					 | 
				
			||||||
                        "fps": 5,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**config)
 | 
					 | 
				
			||||||
        assert config == frigate_config.dict(exclude_unset=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        runtime_config = frigate_config.runtime_config()
 | 
					 | 
				
			||||||
        assert not runtime_config.cameras["back"].rtmp.enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_default_not_rtmp(self):
 | 
					 | 
				
			||||||
        config = {
 | 
					 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					 | 
				
			||||||
            "cameras": {
 | 
					 | 
				
			||||||
                "back": {
 | 
					 | 
				
			||||||
                    "ffmpeg": {
 | 
					 | 
				
			||||||
                        "inputs": [
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					 | 
				
			||||||
                                "roles": ["detect"],
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        ]
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "detect": {
 | 
					 | 
				
			||||||
                        "height": 1080,
 | 
					 | 
				
			||||||
                        "width": 1920,
 | 
					 | 
				
			||||||
                        "fps": 5,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**config)
 | 
					 | 
				
			||||||
        assert config == frigate_config.dict(exclude_unset=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        runtime_config = frigate_config.runtime_config()
 | 
					 | 
				
			||||||
        assert not runtime_config.cameras["back"].rtmp.enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_global_rtmp_merge(self):
 | 
					 | 
				
			||||||
        config = {
 | 
					 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					 | 
				
			||||||
            "rtmp": {"enabled": False},
 | 
					 | 
				
			||||||
            "cameras": {
 | 
					 | 
				
			||||||
                "back": {
 | 
					 | 
				
			||||||
                    "ffmpeg": {
 | 
					 | 
				
			||||||
                        "inputs": [
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					 | 
				
			||||||
                                "roles": ["detect", "rtmp"],
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        ]
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "detect": {
 | 
					 | 
				
			||||||
                        "height": 1080,
 | 
					 | 
				
			||||||
                        "width": 1920,
 | 
					 | 
				
			||||||
                        "fps": 5,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "rtmp": {
 | 
					 | 
				
			||||||
                        "enabled": True,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**config)
 | 
					 | 
				
			||||||
        assert config == frigate_config.dict(exclude_unset=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        runtime_config = frigate_config.runtime_config()
 | 
					 | 
				
			||||||
        assert runtime_config.cameras["back"].rtmp.enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_global_rtmp_default(self):
 | 
					 | 
				
			||||||
        config = {
 | 
					 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					 | 
				
			||||||
            "cameras": {
 | 
					 | 
				
			||||||
                "back": {
 | 
					 | 
				
			||||||
                    "ffmpeg": {
 | 
					 | 
				
			||||||
                        "inputs": [
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					 | 
				
			||||||
                                "roles": ["detect"],
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video2",
 | 
					 | 
				
			||||||
                                "roles": ["record"],
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        ]
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "detect": {
 | 
					 | 
				
			||||||
                        "height": 1080,
 | 
					 | 
				
			||||||
                        "width": 1920,
 | 
					 | 
				
			||||||
                        "fps": 5,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**config)
 | 
					 | 
				
			||||||
        assert config == frigate_config.dict(exclude_unset=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        runtime_config = frigate_config.runtime_config()
 | 
					 | 
				
			||||||
        assert not runtime_config.cameras["back"].rtmp.enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_global_jsmpeg(self):
 | 
					    def test_global_jsmpeg(self):
 | 
				
			||||||
        config = {
 | 
					        config = {
 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					            "mqtt": {"host": "mqtt"},
 | 
				
			||||||
@ -1428,7 +1312,6 @@ class TestConfig(unittest.TestCase):
 | 
				
			|||||||
    def test_global_timestamp_style_merge(self):
 | 
					    def test_global_timestamp_style_merge(self):
 | 
				
			||||||
        config = {
 | 
					        config = {
 | 
				
			||||||
            "mqtt": {"host": "mqtt"},
 | 
					            "mqtt": {"host": "mqtt"},
 | 
				
			||||||
            "rtmp": {"enabled": False},
 | 
					 | 
				
			||||||
            "timestamp_style": {"position": "br", "thickness": 2},
 | 
					            "timestamp_style": {"position": "br", "thickness": 2},
 | 
				
			||||||
            "cameras": {
 | 
					            "cameras": {
 | 
				
			||||||
                "back": {
 | 
					                "back": {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,13 +14,12 @@ class TestFfmpegPresets(unittest.TestCase):
 | 
				
			|||||||
                        "inputs": [
 | 
					                        "inputs": [
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                "path": "rtsp://10.0.0.1:554/video",
 | 
					                                "path": "rtsp://10.0.0.1:554/video",
 | 
				
			||||||
                                "roles": ["detect", "rtmp"],
 | 
					                                "roles": ["detect"],
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                        "output_args": {
 | 
					                        "output_args": {
 | 
				
			||||||
                            "detect": "-f rawvideo -pix_fmt yuv420p",
 | 
					                            "detect": "-f rawvideo -pix_fmt yuv420p",
 | 
				
			||||||
                            "record": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an",
 | 
					                            "record": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an",
 | 
				
			||||||
                            "rtmp": "-c copy -f flv",
 | 
					 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    "detect": {
 | 
					                    "detect": {
 | 
				
			||||||
@ -31,9 +30,6 @@ class TestFfmpegPresets(unittest.TestCase):
 | 
				
			|||||||
                    "record": {
 | 
					                    "record": {
 | 
				
			||||||
                        "enabled": True,
 | 
					                        "enabled": True,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    "rtmp": {
 | 
					 | 
				
			||||||
                        "enabled": True,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    "name": "back",
 | 
					                    "name": "back",
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -157,29 +153,6 @@ class TestFfmpegPresets(unittest.TestCase):
 | 
				
			|||||||
            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_ffmpeg_output_rtmp_preset(self):
 | 
					 | 
				
			||||||
        self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
 | 
					 | 
				
			||||||
            "rtmp"
 | 
					 | 
				
			||||||
        ] = "preset-rtmp-jpeg"
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
					 | 
				
			||||||
        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
					 | 
				
			||||||
        assert "preset-rtmp-jpeg" not in (
 | 
					 | 
				
			||||||
            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        assert "-c:v libx264" in (
 | 
					 | 
				
			||||||
            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_ffmpeg_output_rtmp_not_preset(self):
 | 
					 | 
				
			||||||
        self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
 | 
					 | 
				
			||||||
            "rtmp"
 | 
					 | 
				
			||||||
        ] = "-some output"
 | 
					 | 
				
			||||||
        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
					 | 
				
			||||||
        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
					 | 
				
			||||||
        assert "-some output" in (
 | 
					 | 
				
			||||||
            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    unittest.main(verbosity=2)
 | 
					    unittest.main(verbosity=2)
 | 
				
			||||||
 | 
				
			|||||||
@ -262,7 +262,6 @@ def process(path, label, output, debug_path):
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "rtmp": {"enabled": False},
 | 
					 | 
				
			||||||
                "record": {"enabled": False},
 | 
					                "record": {"enabled": False},
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user