Allow segment length override

This commit is contained in:
Ilya Bursov
2025-12-30 16:41:15 -05:00
parent fb9604fbcc
commit a2e010e220
9 changed files with 103 additions and 13 deletions
+2
View File
@@ -263,6 +263,8 @@ ffmpeg:
detect: -threads 2 -f rawvideo -pix_fmt yuv420p
# Optional: output args for record streams (default: shown below)
record: preset-record-generic
# Optional: Set segment length for recording stream. (default: shown below)
segment_time : 10
# 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 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
+1
View File
@@ -214,6 +214,7 @@ class CameraConfig(FrigateBaseModel):
parse_preset_output_record(
self.ffmpeg.output_args.record,
self.ffmpeg.apple_compatibility,
self.ffmpeg.output_args.segment_time,
)
or self.ffmpeg.output_args.record
)
+1
View File
@@ -41,6 +41,7 @@ class FfmpegOutputArgsConfig(FrigateBaseModel):
default=RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT,
title="Record role FFmpeg output arguments.",
)
segment_time: int = Field(default=10, title="Segment length for recording stream.")
class FfmpegConfig(FrigateBaseModel):
+2
View File
@@ -76,6 +76,8 @@ FFMPEG_HWACCEL_VULKAN = "preset-vulkan"
FFMPEG_HWACCEL_RKMPP = "preset-rkmpp"
FFMPEG_HWACCEL_AMF = "preset-amd-amf"
FFMPEG_HVC1_ARGS = ["-tag:v", "hvc1"]
FFMPEG_SEGMENT_TIME_PARAM = "-segment_time"
FFMPEG_SEGMENT_TIME_VALUE = "10"
# RKNN constants
SUPPORTED_RK_SOCS = ["rk3562", "rk3566", "rk3568", "rk3576", "rk3588"]
+20 -13
View File
@@ -12,6 +12,8 @@ from frigate.const import (
FFMPEG_HWACCEL_RKMPP,
FFMPEG_HWACCEL_VAAPI,
FFMPEG_HWACCEL_VULKAN,
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
LIBAVFORMAT_VERSION_MAJOR,
)
from frigate.util.services import vainfo_hwaccel
@@ -446,8 +448,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-generic": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -461,8 +463,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-generic-audio-aac": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -477,8 +479,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-generic-audio-copy": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -491,8 +493,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-mjpeg": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -506,8 +508,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-jpeg": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -521,8 +523,8 @@ PRESETS_RECORD_OUTPUT = {
"preset-record-ubiquiti": [
"-f",
"segment",
"-segment_time",
"10",
FFMPEG_SEGMENT_TIME_PARAM,
FFMPEG_SEGMENT_TIME_VALUE,
"-segment_format",
"mp4",
"-reset_timestamps",
@@ -539,7 +541,7 @@ PRESETS_RECORD_OUTPUT = {
}
def parse_preset_output_record(arg: Any, force_record_hvc1: bool) -> list[str]:
def parse_preset_output_record(arg: Any, force_record_hvc1: bool, segment_time: int = -1) -> list[str] | None:
"""Return the correct preset if in preset format otherwise return None."""
if not isinstance(arg, str):
return None
@@ -549,6 +551,11 @@ def parse_preset_output_record(arg: Any, force_record_hvc1: bool) -> list[str]:
if not preset:
return None
if 0 < segment_time <= 60 and FFMPEG_SEGMENT_TIME_PARAM in preset:
idx = preset.index(FFMPEG_SEGMENT_TIME_PARAM)
if idx + 1 < len(preset):
preset[idx + 1] = str(segment_time)
if force_record_hvc1:
# Apple only supports HEVC if it is hvc1 (vs. hev1)
return preset + FFMPEG_HVC1_ARGS
+69
View File
@@ -128,6 +128,75 @@ class TestConfig(unittest.TestCase):
}
self.assertRaises(ValidationError, lambda: FrigateConfig(**config))
def test_default_segment_length(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 frigate_config.cameras["back"].ffmpeg.output_args.segment_time == 10
def test_inherit_segment_length(self):
config = {
"mqtt": {"host": "mqtt"},
"ffmpeg": {"output_args": {"segment_time": 15}},
"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 frigate_config.cameras["back"].ffmpeg.output_args.segment_time == 15
def test_override_segment_length(self):
config = {
"mqtt": {"host": "mqtt"},
"ffmpeg": {"output_args": {"segment_time": 15}},
"cameras": {
"back": {
"ffmpeg": {
"inputs": [
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
],
"output_args": {"segment_time": 25}
},
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
frigate_config = FrigateConfig(**config)
assert frigate_config.cameras["back"].ffmpeg.output_args.segment_time == 25
def test_inherit_tracked_objects(self):
config = {
"mqtt": {"host": "mqtt"},
@@ -158,6 +158,9 @@
},
"record": {
"label": "Record role FFmpeg output arguments."
},
"segment_time": {
"label": "Segment length for recording stream."
}
}
},
+3
View File
@@ -21,6 +21,9 @@
},
"record": {
"label": "Record role FFmpeg output arguments."
},
"segment_time": {
"label": "Segment length for recording stream."
}
}
},
+2
View File
@@ -87,6 +87,7 @@ export interface CameraConfig {
detect: string[];
record: string;
rtmp: string;
segment_time: number;
};
retry_interval: number;
};
@@ -418,6 +419,7 @@ export interface FrigateConfig {
detect: string[];
record: string;
rtmp: string;
segment_time: number;
};
retry_interval: number;
};