mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	FEAT: Support for ffmpeg presets (#3840)
* Add hwaccel presets * Use hwaccel presets * Add input arg presets * Use input arg presets * Make util to clean up redundant code * Add support for output arg presets * Add tests * Update camera specific to use presets * Update hwaccel to use presets * Format files and fix tests * Rewrite tests to test record correctly * Move presets from string to list to avoid manually separating into a list * Add mjpeg cuvid decoder preset * Fix tests * Fix comment
This commit is contained in:
		
							parent
							
								
									69560c8bde
								
							
						
					
					
						commit
						87144cd572
					
				@ -8,15 +8,15 @@ title: Camera Specific Configurations
 | 
				
			|||||||
The input and output parameters need to be adjusted for MJPEG cameras
 | 
					The input and output parameters need to be adjusted for MJPEG cameras
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
input_args: -avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -use_wallclock_as_timestamps 1 -c:v mjpeg
 | 
					input_args: preset-http-mjpeg-generic
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.
 | 
					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
 | 
					```yaml
 | 
				
			||||||
output_args:
 | 
					output_args:
 | 
				
			||||||
  record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -an
 | 
					  record: preset-record-mjpeg
 | 
				
			||||||
  rtmp: -c:v libx264 -an -f flv
 | 
					  rtmp: preset-rtmp-mjpeg
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## JPEG Stream Cameras
 | 
					## JPEG Stream Cameras
 | 
				
			||||||
@ -24,25 +24,7 @@ output_args:
 | 
				
			|||||||
Cameras using a live changing jpeg image will need input parameters as below
 | 
					Cameras using a live changing jpeg image will need input parameters as below
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
input_args:
 | 
					input_args: preset-http-jpeg-generic
 | 
				
			||||||
- -r
 | 
					 | 
				
			||||||
- 5 # << enter FPS here
 | 
					 | 
				
			||||||
- -stream_loop
 | 
					 | 
				
			||||||
- -1
 | 
					 | 
				
			||||||
- -f
 | 
					 | 
				
			||||||
- image2
 | 
					 | 
				
			||||||
- -avoid_negative_ts
 | 
					 | 
				
			||||||
- make_zero
 | 
					 | 
				
			||||||
- -fflags
 | 
					 | 
				
			||||||
- nobuffer
 | 
					 | 
				
			||||||
- -flags
 | 
					 | 
				
			||||||
- low_delay
 | 
					 | 
				
			||||||
- -strict
 | 
					 | 
				
			||||||
- experimental
 | 
					 | 
				
			||||||
- -fflags
 | 
					 | 
				
			||||||
- +genpts+discardcorrupt
 | 
					 | 
				
			||||||
- -use_wallclock_as_timestamps
 | 
					 | 
				
			||||||
- 1
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Outputting the stream will have the same args and caveats as per [MJPEG Cameras](#mjpeg-cameras)
 | 
					Outputting the stream will have the same args and caveats as per [MJPEG Cameras](#mjpeg-cameras)
 | 
				
			||||||
@ -53,7 +35,7 @@ The input parameters need to be adjusted for RTMP cameras
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  input_args: -avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -rw_timeout 5000000 -use_wallclock_as_timestamps 1 -f live_flv
 | 
					  input_args: preset-rtmp-generic
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## UDP Only Cameras
 | 
					## UDP Only Cameras
 | 
				
			||||||
@ -62,7 +44,7 @@ If your cameras do not support TCP connections for RTSP, you can use UDP.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  input_args: -avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport udp -timeout 5000000 -use_wallclock_as_timestamps 1
 | 
					  input_args: preset-rtsp-udp
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Model/vendor specific setup
 | 
					## Model/vendor specific setup
 | 
				
			||||||
@ -99,7 +81,7 @@ You will need to remove `nobuffer` flag for Blue Iris RTSP cameras
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  input_args: -avoid_negative_ts make_zero -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -rtsp_transport tcp -timeout 5000000 -use_wallclock_as_timestamps 1
 | 
					  input_args: preset-rtsp-blue-iris
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Reolink 410/520 (possibly others)
 | 
					### Reolink 410/520 (possibly others)
 | 
				
			||||||
@ -112,21 +94,7 @@ According to [this discussion](https://github.com/blakeblackshear/frigate/issues
 | 
				
			|||||||
cameras:
 | 
					cameras:
 | 
				
			||||||
  reolink:
 | 
					  reolink:
 | 
				
			||||||
    ffmpeg:
 | 
					    ffmpeg:
 | 
				
			||||||
      input_args:
 | 
					      input_args: preset-http-reolink
 | 
				
			||||||
        - -avoid_negative_ts
 | 
					 | 
				
			||||||
        - make_zero
 | 
					 | 
				
			||||||
        - -fflags
 | 
					 | 
				
			||||||
        - +genpts+discardcorrupt
 | 
					 | 
				
			||||||
        - -flags
 | 
					 | 
				
			||||||
        - low_delay
 | 
					 | 
				
			||||||
        - -strict
 | 
					 | 
				
			||||||
        - experimental
 | 
					 | 
				
			||||||
        - -analyzeduration
 | 
					 | 
				
			||||||
        - 1000M
 | 
					 | 
				
			||||||
        - -probesize
 | 
					 | 
				
			||||||
        - 1000M
 | 
					 | 
				
			||||||
        - -rw_timeout
 | 
					 | 
				
			||||||
        - "5000000"
 | 
					 | 
				
			||||||
      inputs:
 | 
					      inputs:
 | 
				
			||||||
        - path: http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=username&password=password
 | 
					        - path: http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=username&password=password
 | 
				
			||||||
          roles:
 | 
					          roles:
 | 
				
			||||||
@ -148,6 +116,6 @@ In the Unifi 2.0 update Unifi Protect Cameras had a change in audio sample rate
 | 
				
			|||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  output_args:
 | 
					  output_args:
 | 
				
			||||||
    record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -ar 44100 -c:a aac
 | 
					    record: preset-record-ubiquiti
 | 
				
			||||||
    rtmp: -c:v copy -f flv -ar 44100 -c:a aac
 | 
					    rtmp: preset-rtmp-ubiquiti
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@ -12,14 +12,14 @@ Ensure you increase the allocated RAM for your GPU to at least 128 (raspi-config
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  hwaccel_args: -c:v h264_v4l2m2m
 | 
					  hwaccel_args: preset-rpi-64-h264
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Intel-based CPUs (<10th Generation) via Quicksync
 | 
					### Intel-based CPUs (<10th Generation) via Quicksync
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  hwaccel_args: -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format yuv420p
 | 
					  hwaccel_args: preset-intel-vaapi
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
**NOTICE**: With some of the processors, like the J4125, the default driver `iHD` doesn't seem to work correctly for hardware acceleration. You may need to change the driver to `i965` by adding the following environment variable `LIBVA_DRIVER_NAME=i965` to your docker-compose file or [in the frigate.yml for HA OS users](advanced.md#environment_vars).
 | 
					**NOTICE**: With some of the processors, like the J4125, the default driver `iHD` doesn't seem to work correctly for hardware acceleration. You may need to change the driver to `i965` by adding the following environment variable `LIBVA_DRIVER_NAME=i965` to your docker-compose file or [in the frigate.yml for HA OS users](advanced.md#environment_vars).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,7 +27,7 @@ ffmpeg:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  hwaccel_args: -c:v h264_qsv
 | 
					  hwaccel_args: preset-intel-qsv-h264
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### AMD/ATI GPUs (Radeon HD 2000 and newer GPUs) via libva-mesa-driver
 | 
					### AMD/ATI GPUs (Radeon HD 2000 and newer GPUs) via libva-mesa-driver
 | 
				
			||||||
@ -36,7 +36,7 @@ ffmpeg:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  hwaccel_args: -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format yuv420p
 | 
					  hwaccel_args: preset-amd-vaapi
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### NVIDIA GPU
 | 
					### NVIDIA GPU
 | 
				
			||||||
@ -79,11 +79,11 @@ A list of supported codecs (you can use `ffmpeg -decoders | grep cuvid` in the c
 | 
				
			|||||||
 V..... vp9_cuvid            Nvidia CUVID VP9 decoder (codec vp9)
 | 
					 V..... vp9_cuvid            Nvidia CUVID VP9 decoder (codec vp9)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For example, for H264 video, you'll select `h264_cuvid`.
 | 
					For example, for H264 video, you'll select `preset-nvidia-h264`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
ffmpeg:
 | 
					ffmpeg:
 | 
				
			||||||
  hwaccel_args: -c:v h264_cuvid
 | 
					  hwaccel_args: preset-nvidia-h264
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If everything is working correctly, you should see a significant improvement in performance.
 | 
					If everything is working correctly, you should see a significant improvement in performance.
 | 
				
			||||||
 | 
				
			|||||||
@ -21,10 +21,17 @@ from frigate.const import (
 | 
				
			|||||||
from frigate.util import (
 | 
					from frigate.util import (
 | 
				
			||||||
    create_mask,
 | 
					    create_mask,
 | 
				
			||||||
    deep_merge,
 | 
					    deep_merge,
 | 
				
			||||||
 | 
					    get_ffmpeg_arg_list,
 | 
				
			||||||
    escape_special_characters,
 | 
					    escape_special_characters,
 | 
				
			||||||
    load_config_with_no_duplicates,
 | 
					    load_config_with_no_duplicates,
 | 
				
			||||||
    load_labels,
 | 
					    load_labels,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					from frigate.ffmpeg_presets import (
 | 
				
			||||||
 | 
					    parse_preset_hardware_acceleration,
 | 
				
			||||||
 | 
					    parse_preset_input,
 | 
				
			||||||
 | 
					    parse_preset_output_record,
 | 
				
			||||||
 | 
					    parse_preset_output_rtmp,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -646,11 +653,8 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
    def _get_ffmpeg_cmd(self, ffmpeg_input: CameraInput):
 | 
					    def _get_ffmpeg_cmd(self, ffmpeg_input: CameraInput):
 | 
				
			||||||
        ffmpeg_output_args = []
 | 
					        ffmpeg_output_args = []
 | 
				
			||||||
        if "detect" in ffmpeg_input.roles:
 | 
					        if "detect" in ffmpeg_input.roles:
 | 
				
			||||||
            detect_args = (
 | 
					            detect_args = get_ffmpeg_arg_list(self.ffmpeg.output_args.detect)
 | 
				
			||||||
                self.ffmpeg.output_args.detect
 | 
					
 | 
				
			||||||
                if isinstance(self.ffmpeg.output_args.detect, list)
 | 
					 | 
				
			||||||
                else self.ffmpeg.output_args.detect.split(" ")
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            ffmpeg_output_args = (
 | 
					            ffmpeg_output_args = (
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
                    "-r",
 | 
					                    "-r",
 | 
				
			||||||
@ -663,19 +667,18 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
                + ["pipe:"]
 | 
					                + ["pipe:"]
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        if "rtmp" in ffmpeg_input.roles and self.rtmp.enabled:
 | 
					        if "rtmp" in ffmpeg_input.roles and self.rtmp.enabled:
 | 
				
			||||||
            rtmp_args = (
 | 
					            rtmp_args = get_ffmpeg_arg_list(
 | 
				
			||||||
                self.ffmpeg.output_args.rtmp
 | 
					                parse_preset_output_rtmp(self.ffmpeg.output_args.rtmp)
 | 
				
			||||||
                if isinstance(self.ffmpeg.output_args.rtmp, list)
 | 
					                or self.ffmpeg.output_args.rtmp
 | 
				
			||||||
                else self.ffmpeg.output_args.rtmp.split(" ")
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ffmpeg_output_args = (
 | 
					            ffmpeg_output_args = (
 | 
				
			||||||
                rtmp_args + [f"rtmp://127.0.0.1/live/{self.name}"] + 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 = (
 | 
					            record_args = get_ffmpeg_arg_list(
 | 
				
			||||||
                self.ffmpeg.output_args.record
 | 
					                parse_preset_output_record(self.ffmpeg.output_args.record)
 | 
				
			||||||
                if isinstance(self.ffmpeg.output_args.record, list)
 | 
					                or self.ffmpeg.output_args.record
 | 
				
			||||||
                else self.ffmpeg.output_args.record.split(" ")
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ffmpeg_output_args = (
 | 
					            ffmpeg_output_args = (
 | 
				
			||||||
@ -688,18 +691,18 @@ class CameraConfig(FrigateBaseModel):
 | 
				
			|||||||
        if len(ffmpeg_output_args) == 0:
 | 
					        if len(ffmpeg_output_args) == 0:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        global_args = ffmpeg_input.global_args or self.ffmpeg.global_args
 | 
					        global_args = get_ffmpeg_arg_list(
 | 
				
			||||||
        hwaccel_args = ffmpeg_input.hwaccel_args or self.ffmpeg.hwaccel_args
 | 
					            ffmpeg_input.global_args or self.ffmpeg.global_args
 | 
				
			||||||
        input_args = ffmpeg_input.input_args or self.ffmpeg.input_args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        global_args = (
 | 
					 | 
				
			||||||
            global_args if isinstance(global_args, list) else global_args.split(" ")
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        hwaccel_args = (
 | 
					        hwaccel_args = get_ffmpeg_arg_list(
 | 
				
			||||||
            hwaccel_args if isinstance(hwaccel_args, list) else hwaccel_args.split(" ")
 | 
					            ffmpeg_input.hwaccel_args
 | 
				
			||||||
 | 
					            or parse_preset_hardware_acceleration(self.ffmpeg.hwaccel_args)
 | 
				
			||||||
 | 
					            or self.ffmpeg.hwaccel_args
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        input_args = (
 | 
					        input_args = get_ffmpeg_arg_list(
 | 
				
			||||||
            input_args if isinstance(input_args, list) else input_args.split(" ")
 | 
					            ffmpeg_input.input_args
 | 
				
			||||||
 | 
					            or parse_preset_input(self.ffmpeg.input_args, self.detect.fps)
 | 
				
			||||||
 | 
					            or self.ffmpeg.input_args
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cmd = (
 | 
					        cmd = (
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										277
									
								
								frigate/ffmpeg_presets.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								frigate/ffmpeg_presets.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,277 @@
 | 
				
			|||||||
 | 
					"""Handles inserting and maintaining ffmpeg presets."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRESETS_HW_ACCEL = {
 | 
				
			||||||
 | 
					    "preset-rpi-32-h264": ["-c:v", "h264_v4l2m2m"],
 | 
				
			||||||
 | 
					    "preset-rpi-64-h264": ["-c:v", "h264_v4l2m2m"],
 | 
				
			||||||
 | 
					    "preset-intel-vaapi": [
 | 
				
			||||||
 | 
					        "-hwaccel",
 | 
				
			||||||
 | 
					        "vaapi",
 | 
				
			||||||
 | 
					        "-hwaccel_device",
 | 
				
			||||||
 | 
					        "/dev/dri/renderD128",
 | 
				
			||||||
 | 
					        "-hwaccel_output_format",
 | 
				
			||||||
 | 
					        "yuv420p",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-intel-qsv-h264": ["-c:v", "h264_qsv"],
 | 
				
			||||||
 | 
					    "preset-intel-qsv-h265": ["-c:v", "hevc_qsv"],
 | 
				
			||||||
 | 
					    "preset-amd-vaapi": [
 | 
				
			||||||
 | 
					        "-hwaccel",
 | 
				
			||||||
 | 
					        "vaapi",
 | 
				
			||||||
 | 
					        "-hwaccel_device",
 | 
				
			||||||
 | 
					        "/dev/dri/renderD128",
 | 
				
			||||||
 | 
					        "-hwaccel_output_format",
 | 
				
			||||||
 | 
					        "yuv420p",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-nvidia-h264": ["-c:v", "h264_cuvid"],
 | 
				
			||||||
 | 
					    "preset-nvidia-h265": ["-c:v", "hevc_cuvid"],
 | 
				
			||||||
 | 
					    "preset-nvidia-mjpeg": ["-c:v", "mjpeg_cuvid"],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_preset_hardware_acceleration(arg: Any) -> list[str]:
 | 
				
			||||||
 | 
					    """Return the correct preset if in preset format otherwise return None."""
 | 
				
			||||||
 | 
					    if not isinstance(arg, str):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return PRESETS_HW_ACCEL.get(arg, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRESETS_INPUT = {
 | 
				
			||||||
 | 
					    "preset-http-jpeg-generic": [
 | 
				
			||||||
 | 
					        "-r",
 | 
				
			||||||
 | 
					        "{}",
 | 
				
			||||||
 | 
					        "-stream_loop",
 | 
				
			||||||
 | 
					        "-1",
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "image2",
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "nobuffer",
 | 
				
			||||||
 | 
					        "-flags",
 | 
				
			||||||
 | 
					        "low_delay",
 | 
				
			||||||
 | 
					        "-strict",
 | 
				
			||||||
 | 
					        "experimental",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-http-mjpeg-generic": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "nobuffer",
 | 
				
			||||||
 | 
					        "-flags",
 | 
				
			||||||
 | 
					        "low_delay",
 | 
				
			||||||
 | 
					        "-strict",
 | 
				
			||||||
 | 
					        "experimental",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-http-reolink": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-flags",
 | 
				
			||||||
 | 
					        "low_delay",
 | 
				
			||||||
 | 
					        "-strict",
 | 
				
			||||||
 | 
					        "experimental",
 | 
				
			||||||
 | 
					        "-analyzeduration",
 | 
				
			||||||
 | 
					        "1000M",
 | 
				
			||||||
 | 
					        "-probesize",
 | 
				
			||||||
 | 
					        "1000M",
 | 
				
			||||||
 | 
					        "-rw_timeout",
 | 
				
			||||||
 | 
					        "5000000",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-rtmp-generic": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "nobuffer",
 | 
				
			||||||
 | 
					        "-flags",
 | 
				
			||||||
 | 
					        "low_delay",
 | 
				
			||||||
 | 
					        "-strict",
 | 
				
			||||||
 | 
					        "experimental",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-rw_timeout",
 | 
				
			||||||
 | 
					        "5000000",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "live_flv",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-rtsp-generic": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-rtsp_transport",
 | 
				
			||||||
 | 
					        "tcp",
 | 
				
			||||||
 | 
					        "-timeout",
 | 
				
			||||||
 | 
					        "5000000",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-rtsp-udp": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-rtsp_transport",
 | 
				
			||||||
 | 
					        "udp",
 | 
				
			||||||
 | 
					        "-timeout",
 | 
				
			||||||
 | 
					        "5000000",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-rtsp-blue-iris": [
 | 
				
			||||||
 | 
					        "-avoid_negative_ts",
 | 
				
			||||||
 | 
					        "make_zero",
 | 
				
			||||||
 | 
					        "-flags",
 | 
				
			||||||
 | 
					        "low_delay",
 | 
				
			||||||
 | 
					        "-strict",
 | 
				
			||||||
 | 
					        "experimental",
 | 
				
			||||||
 | 
					        "-fflags",
 | 
				
			||||||
 | 
					        "+genpts+discardcorrupt",
 | 
				
			||||||
 | 
					        "-rtsp_transport",
 | 
				
			||||||
 | 
					        "tcp",
 | 
				
			||||||
 | 
					        "-timeout",
 | 
				
			||||||
 | 
					        "5000000",
 | 
				
			||||||
 | 
					        "-use_wallclock_as_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_preset_input(arg: Any, detect_fps: int) -> list[str]:
 | 
				
			||||||
 | 
					    """Return the correct preset if in preset format otherwise return None."""
 | 
				
			||||||
 | 
					    if not isinstance(arg, str):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if arg == "preset-jpeg-generic":
 | 
				
			||||||
 | 
					        return PRESETS_INPUT[arg].format(f"{detect_fps}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return PRESETS_INPUT.get(arg, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRESETS_RECORD_OUTPUT = {
 | 
				
			||||||
 | 
					    "preset-record-generic": [
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "segment",
 | 
				
			||||||
 | 
					        "-segment_time",
 | 
				
			||||||
 | 
					        "10",
 | 
				
			||||||
 | 
					        "-segment_format",
 | 
				
			||||||
 | 
					        "mp4",
 | 
				
			||||||
 | 
					        "-reset_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-strftime",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-c",
 | 
				
			||||||
 | 
					        "copy",
 | 
				
			||||||
 | 
					        "-an",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-record-generic-audio": [
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "segment",
 | 
				
			||||||
 | 
					        "-segment_time",
 | 
				
			||||||
 | 
					        "10",
 | 
				
			||||||
 | 
					        "-segment_format",
 | 
				
			||||||
 | 
					        "mp4",
 | 
				
			||||||
 | 
					        "-reset_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-strftime",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-c:v",
 | 
				
			||||||
 | 
					        "copy",
 | 
				
			||||||
 | 
					        "-c:a",
 | 
				
			||||||
 | 
					        "aac",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-record-mjpeg": [
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "segment",
 | 
				
			||||||
 | 
					        "-segment_time",
 | 
				
			||||||
 | 
					        "10",
 | 
				
			||||||
 | 
					        "-segment_format",
 | 
				
			||||||
 | 
					        "mp4",
 | 
				
			||||||
 | 
					        "-reset_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-strftime",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-c:v",
 | 
				
			||||||
 | 
					        "libx264",
 | 
				
			||||||
 | 
					        "-an",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-record-jpeg": [
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "segment",
 | 
				
			||||||
 | 
					        "-segment_time",
 | 
				
			||||||
 | 
					        "10",
 | 
				
			||||||
 | 
					        "-segment_format",
 | 
				
			||||||
 | 
					        "mp4",
 | 
				
			||||||
 | 
					        "-reset_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-strftime",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-c:v",
 | 
				
			||||||
 | 
					        "libx264",
 | 
				
			||||||
 | 
					        "-an",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "preset-record-ubiquiti": [
 | 
				
			||||||
 | 
					        "-f",
 | 
				
			||||||
 | 
					        "segment",
 | 
				
			||||||
 | 
					        "-segment_time",
 | 
				
			||||||
 | 
					        "10",
 | 
				
			||||||
 | 
					        "-segment_format",
 | 
				
			||||||
 | 
					        "mp4",
 | 
				
			||||||
 | 
					        "-reset_timestamps",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-strftime",
 | 
				
			||||||
 | 
					        "1",
 | 
				
			||||||
 | 
					        "-c:v",
 | 
				
			||||||
 | 
					        "copy",
 | 
				
			||||||
 | 
					        "-ar",
 | 
				
			||||||
 | 
					        "44100",
 | 
				
			||||||
 | 
					        "-c:a",
 | 
				
			||||||
 | 
					        "aac",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_preset_output_record(arg: Any) -> list[str]:
 | 
				
			||||||
 | 
					    """Return the correct preset if in preset format otherwise return None."""
 | 
				
			||||||
 | 
					    if not isinstance(arg, str):
 | 
				
			||||||
 | 
					        return 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)
 | 
				
			||||||
							
								
								
									
										152
									
								
								frigate/test/test_ffmpeg_presets.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								frigate/test/test_ffmpeg_presets.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,152 @@
 | 
				
			|||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from frigate.config import FrigateConfig
 | 
				
			||||||
 | 
					from frigate.ffmpeg_presets import parse_preset_input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestFfmpegPresets(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg = {
 | 
				
			||||||
 | 
					            "mqtt": {"host": "mqtt"},
 | 
				
			||||||
 | 
					            "cameras": {
 | 
				
			||||||
 | 
					                "back": {
 | 
				
			||||||
 | 
					                    "ffmpeg": {
 | 
				
			||||||
 | 
					                        "inputs": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "path": "rtsp://10.0.0.1:554/video",
 | 
				
			||||||
 | 
					                                "roles": ["detect", "rtmp"],
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                        "output_args": {
 | 
				
			||||||
 | 
					                            "detect": "-f rawvideo -pix_fmt yuv420p",
 | 
				
			||||||
 | 
					                            "record": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an",
 | 
				
			||||||
 | 
					                            "rtmp": "-c copy -f flv",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "detect": {
 | 
				
			||||||
 | 
					                        "height": 1080,
 | 
				
			||||||
 | 
					                        "width": 1920,
 | 
				
			||||||
 | 
					                        "fps": 5,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "record": {
 | 
				
			||||||
 | 
					                        "enabled": True,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "rtmp": {
 | 
				
			||||||
 | 
					                        "enabled": True,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "name": "back",
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_default_ffmpeg(self):
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert self.default_ffmpeg == frigate_config.dict(exclude_unset=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_hwaccel_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
 | 
				
			||||||
 | 
					            "hwaccel_args"
 | 
				
			||||||
 | 
					        ] = "preset-rpi-64-h264"
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert "preset-rpi-64-h264" not in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        assert "-c:v h264_v4l2m2m" in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_hwaccel_not_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
 | 
				
			||||||
 | 
					            "hwaccel_args"
 | 
				
			||||||
 | 
					        ] = "-other-hwaccel args"
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert "-other-hwaccel args" in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_default_ffmpeg_input_arg_preset(self):
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
 | 
				
			||||||
 | 
					            "input_args"
 | 
				
			||||||
 | 
					        ] = "preset-rtsp-generic"
 | 
				
			||||||
 | 
					        frigate_preset_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        frigate_preset_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert (
 | 
				
			||||||
 | 
					            frigate_preset_config.cameras["back"].ffmpeg_cmds[0]["cmd"]
 | 
				
			||||||
 | 
					            == frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_input_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
 | 
				
			||||||
 | 
					            "input_args"
 | 
				
			||||||
 | 
					        ] = "preset-rtmp-generic"
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert "preset-rtmp-generic" not in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        assert (" ".join(parse_preset_input("preset-rtmp-generic", 5))) in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_input_not_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["input_args"] = "-some inputs"
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert "-some inputs" in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_output_record_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
 | 
				
			||||||
 | 
					            "record"
 | 
				
			||||||
 | 
					        ] = "preset-record-generic-audio"
 | 
				
			||||||
 | 
					        frigate_config = FrigateConfig(**self.default_ffmpeg)
 | 
				
			||||||
 | 
					        frigate_config.cameras["back"].create_ffmpeg_cmds()
 | 
				
			||||||
 | 
					        assert "preset-record-generic-audio" not in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        assert "-c:v copy -c:a aac" in (
 | 
				
			||||||
 | 
					            " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_ffmpeg_output_record_not_preset(self):
 | 
				
			||||||
 | 
					        self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
 | 
				
			||||||
 | 
					            "record"
 | 
				
			||||||
 | 
					        ] = "-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"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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__":
 | 
				
			||||||
 | 
					    unittest.main(verbosity=2)
 | 
				
			||||||
@ -13,7 +13,7 @@ from abc import ABC, abstractmethod
 | 
				
			|||||||
from collections import Counter
 | 
					from collections import Counter
 | 
				
			||||||
from collections.abc import Mapping
 | 
					from collections.abc import Mapping
 | 
				
			||||||
from multiprocessing import shared_memory
 | 
					from multiprocessing import shared_memory
 | 
				
			||||||
from typing import AnyStr
 | 
					from typing import Any, AnyStr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cv2
 | 
					import cv2
 | 
				
			||||||
import numpy as np
 | 
					import numpy as np
 | 
				
			||||||
@ -886,6 +886,11 @@ def vainfo_hwaccel() -> sp.CompletedProcess:
 | 
				
			|||||||
    return sp.run(ffprobe_cmd, capture_output=True)
 | 
					    return sp.run(ffprobe_cmd, capture_output=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_ffmpeg_arg_list(arg: Any) -> list:
 | 
				
			||||||
 | 
					    """Use arg if list or convert to list format."""
 | 
				
			||||||
 | 
					    return arg if isinstance(arg, list) else arg.split(" ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FrameManager(ABC):
 | 
					class FrameManager(ABC):
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def create(self, name, size) -> AnyStr:
 | 
					    def create(self, name, size) -> AnyStr:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user