2024-09-28 22:21:42 +03:00
import os
2025-03-23 22:30:48 +03:00
from enum import Enum
2024-09-28 22:21:42 +03:00
from typing import Optional
2025-08-26 20:15:01 +03:00
from pydantic import Field , PrivateAttr , model_validator
2024-09-28 22:21:42 +03:00
from frigate . const import CACHE_DIR , CACHE_SEGMENT_FORMAT , REGEX_CAMERA_NAME
from frigate . ffmpeg_presets import (
parse_preset_hardware_acceleration_decode ,
parse_preset_hardware_acceleration_scale ,
parse_preset_input ,
parse_preset_output_record ,
)
from frigate . util . builtin import (
escape_special_characters ,
generate_color_palette ,
get_ffmpeg_arg_list ,
)
from . . base import FrigateBaseModel
2025-03-19 18:02:40 +03:00
from . . classification import (
2025-10-09 02:06:03 +03:00
CameraAudioTranscriptionConfig ,
2025-03-19 18:02:40 +03:00
CameraFaceRecognitionConfig ,
CameraLicensePlateRecognitionConfig ,
2025-07-07 17:03:57 +03:00
CameraSemanticSearchConfig ,
2025-03-19 18:02:40 +03:00
)
2024-09-28 22:21:42 +03:00
from . audio import AudioConfig
from . birdseye import BirdseyeCameraConfig
from . detect import DetectConfig
from . ffmpeg import CameraFfmpegConfig , CameraInput
from . live import CameraLiveConfig
from . motion import MotionConfig
from . mqtt import CameraMqttConfig
2025-02-11 05:47:15 +03:00
from . notification import NotificationConfig
2024-09-28 22:21:42 +03:00
from . objects import ObjectConfig
from . onvif import OnvifConfig
Camera profile support (#22482)
* add CameraProfileConfig model for named config overrides
* add profiles field to CameraConfig
* add active_profile field to FrigateConfig
Runtime-only field excluded from YAML serialization, tracks which
profile is currently active.
* add ProfileManager for profile activation and persistence
Handles snapshotting base configs, applying profile overrides via
deep_merge + apply_section_update, publishing ZMQ updates, and
persisting active profile to /config/.active_profile.
* add profile API endpoints (GET /profiles, GET/PUT /profile)
* add MQTT and dispatcher integration for profiles
- Subscribe to frigate/profile/set MQTT topic
- Publish profile/state and profiles/available on connect
- Add _on_profile_command handler to dispatcher
- Broadcast active profile state on WebSocket connect
* wire ProfileManager into app startup and FastAPI
- Create ProfileManager after dispatcher init
- Restore persisted profile on startup
- Pass dispatcher and profile_manager to FastAPI app
* add tests for invalid profile values and keys
Tests that Pydantic rejects: invalid field values (fps: "not_a_number"),
unknown section keys (ffmpeg in profile), invalid nested values, and
invalid profiles in full config parsing.
* formatting
* fix CameraLiveConfig JSON serialization error on profile activation
refactor _publish_updates to only publish ZMQ updates for
sections that actually changed, not all sections on affected cameras.
* consolidate
* add enabled field to camera profiles for enabling/disabling cameras
* add zones support to camera profiles
* add frontend profile types, color utility, and config save support
* add profile state management and save preview support
* add profileName prop to BaseSection for profile-aware config editing
* add profile section dropdown and wire into camera settings pages
* add per-profile camera enable/disable to Camera Management view
* add profiles summary page with card-based layout and fix backend zone comparison bug
* add active profile badge to settings toolbar
* i18n
* add red dot for any pending changes including profiles
* profile support for mask and zone editor
* fix hidden field validation errors caused by lodash wildcard and schema gaps
lodash unset does not support wildcard (*) segments, so hidden fields like
filters.*.mask were never stripped from form data, leaving null raw_coordinates
that fail RJSF anyOf validation. Add unsetWithWildcard helper and also strip
hidden fields from the JSON schema itself as defense-in-depth.
* add face_recognition and lpr to profile-eligible sections
* move profile dropdown from section panes to settings header
* add profiles enable toggle and improve empty state
* formatting
* tweaks
* tweak colors and switch
* fix profile save diff, masksAndZones delete, and config sync
* ui tweaks
* ensure profile manager gets updated config
* rename profile settings to ui settings
* refactor profilesview and add dots/border colors when overridden
* implement an update_config method for profile manager
* fix mask deletion
* more unique colors
* add top-level profiles config section with friendly names
* implement profile friendly names and improve profile UI
- Add ProfileDefinitionConfig type and profiles field to FrigateConfig
- Use ProfilesApiResponse type with friendly_name support throughout
- Replace Record<string, unknown> with proper JsonObject/JsonValue types
- Add profile creation form matching zone pattern (Zod + NameAndIdFields)
- Add pencil icon for renaming profile friendly names in ProfilesView
- Move Profiles menu item to first under Camera Configuration
- Add activity indicators on save/rename/delete buttons
- Display friendly names in CameraManagementView profile selector
- Fix duplicate colored dots in management profile dropdown
- Fix i18n namespace for overridden base config tooltips
- Move profile override deletion from dropdown trash icon to footer
button with confirmation dialog, matching Reset to Global pattern
- Remove Add Profile from section header dropdown to prevent saving
camera overrides before top-level profile definition exists
- Clean up newProfiles state after API profile deletion
- Refresh profiles SWR cache after saving profile definitions
* remove profile badge in settings and add profiles to main menu
* use icon only on mobile
* change color order
* docs
* show activity indicator on trash icon while deleting a profile
* tweak language
* immediately create profiles on backend instead of deferring to Save All
* hide restart-required fields when editing a profile section
fields that require a restart cannot take effect via profile switching,
so they are merged into hiddenFields when profileName is set
* show active profile indicator in desktop status bar
* fix profile config inheritance bug where Pydantic defaults override base values
The /config API was dumping profile overrides with model_dump() which included
all Pydantic defaults. When the frontend merged these over
the camera's base config, explicitly-set base values were
lost. Now profile overrides are re-dumped with exclude_unset=True so only
user-specified fields are returned.
Also fixes the Save All path generating spurious deletion markers for
restart-required fields that are hidden during profile
editing but not excluded from the raw data sanitization in
prepareSectionSavePayload.
* docs tweaks
* docs tweak
* formatting
* formatting
* fix typing
* fix test pollution
test_maintainer was injecting MagicMock() into sys.modules["frigate.config.camera.updater"] at module load time and never restoring it. When the profile tests later imported CameraConfigUpdateEnum and CameraConfigUpdateTopic from that module, they got mock objects instead of the real dataclass/enum, so equality comparisons always failed
* remove
* fix settings showing profile-merged values when editing base config
When a profile is active, the in-memory config contains effective
(profile-merged) values. The settings UI was displaying these merged
values even when the "Base Config" view was selected.
Backend: snapshot pre-profile base configs in ProfileManager and expose
them via a `base_config` key in the /api/config camera response when a
profile is active. The top-level sections continue to reflect the
effective running config.
Frontend: read from `base_config` when available in BaseSection,
useConfigOverride, useAllCameraOverrides, and prepareSectionSavePayload.
Include formData labels in Object/Audio switches widgets so that labels
added only by a profile override remain visible when editing that profile.
* use rasterized_mask as field
makes it easier to exclude from the schema with exclude=True
prevents leaking of the field when using model_dump for profiles
* fix zones
- Fix zone colors not matching across profiles by falling back to base zone color when profile zone data lacks a color field
- Use base_config for base-layer values in masks/zones view so profile-merged values don't pollute the base config editing view
- Handle zones separately in profile manager snapshot/restore since ZoneConfig requires special serialization (color as private attr, contour generation)
- Inherit base zone color and generate contours for profile zone overrides in profile manager
* formatting
* don't require restart for camera enabled change for profiles
* publish camera state when changing profiles
* formatting
* remove available profiles from mqtt
* improve typing
2026-03-19 17:47:57 +03:00
from . profile import CameraProfileConfig
2024-09-28 22:21:42 +03:00
from . record import RecordConfig
from . review import ReviewConfig
from . snapshots import SnapshotsConfig
from . timestamp import TimestampStyleConfig
from . ui import CameraUiConfig
from . zone import ZoneConfig
__all__ = [ " CameraConfig " ]
2025-03-23 22:30:48 +03:00
class CameraTypeEnum ( str , Enum ) :
generic = " generic "
lpr = " lpr "
2024-09-28 22:21:42 +03:00
class CameraConfig ( FrigateBaseModel ) :
2026-02-27 18:55:36 +03:00
name : Optional [ str ] = Field (
None ,
title = " Camera name " ,
description = " Camera name is required " ,
pattern = REGEX_CAMERA_NAME ,
)
2025-08-26 20:15:01 +03:00
2025-08-26 23:29:52 +03:00
friendly_name : Optional [ str ] = Field (
2026-02-27 18:55:36 +03:00
None ,
title = " Friendly name " ,
description = " Camera friendly name used in the Frigate UI " ,
2025-08-26 23:29:52 +03:00
)
2025-08-26 20:15:01 +03:00
@model_validator ( mode = " before " )
@classmethod
2025-08-26 23:29:52 +03:00
def handle_friendly_name ( cls , values ) :
if isinstance ( values , dict ) and " friendly_name " in values :
2025-08-26 20:15:01 +03:00
pass
return values
2026-02-27 18:55:36 +03:00
enabled : bool = Field ( default = True , title = " Enabled " , description = " Enabled " )
2024-09-28 22:21:42 +03:00
# Options with global fallback
audio : AudioConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = AudioConfig ,
title = " Audio events " ,
description = " Settings for audio-based event detection for this camera. " ,
2024-09-28 22:21:42 +03:00
)
2025-10-09 02:06:03 +03:00
audio_transcription : CameraAudioTranscriptionConfig = Field (
default_factory = CameraAudioTranscriptionConfig ,
2026-02-27 18:55:36 +03:00
title = " Audio transcription " ,
description = " Settings for live and speech audio transcription used for events and live captions. " ,
2025-05-27 18:26:00 +03:00
)
2024-09-28 22:21:42 +03:00
birdseye : BirdseyeCameraConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = BirdseyeCameraConfig ,
title = " Birdseye " ,
description = " Settings for the Birdseye composite view that composes multiple camera feeds into a single layout. " ,
2024-09-28 22:21:42 +03:00
)
detect : DetectConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = DetectConfig ,
title = " Object Detection " ,
description = " Settings for the detection/detect role used to run object detection and initialize trackers. " ,
2024-09-28 22:21:42 +03:00
)
2025-03-19 18:02:40 +03:00
face_recognition : CameraFaceRecognitionConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = CameraFaceRecognitionConfig ,
title = " Face recognition " ,
description = " Settings for face detection and recognition for this camera. " ,
)
ffmpeg : CameraFfmpegConfig = Field (
title = " FFmpeg " ,
description = " FFmpeg settings including binary path, args, hwaccel options, and per-role output args. " ,
2025-03-19 18:02:40 +03:00
)
2024-09-28 22:21:42 +03:00
live : CameraLiveConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = CameraLiveConfig ,
title = " Live playback " ,
description = " Settings used by the Web UI to control live stream selection, resolution and quality. " ,
2024-09-28 22:21:42 +03:00
)
2025-03-19 18:02:40 +03:00
lpr : CameraLicensePlateRecognitionConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = CameraLicensePlateRecognitionConfig ,
title = " License Plate Recognition " ,
description = " License plate recognition settings including detection thresholds, formatting, and known plates. " ,
)
motion : MotionConfig = Field (
None ,
title = " Motion detection " ,
description = " Default motion detection settings for this camera. " ,
2025-03-19 18:02:40 +03:00
)
2024-09-28 22:21:42 +03:00
objects : ObjectConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = ObjectConfig ,
title = " Objects " ,
description = " Object tracking defaults including which labels to track and per-object filters. " ,
2024-09-28 22:21:42 +03:00
)
record : RecordConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = RecordConfig ,
title = " Recording " ,
description = " Recording and retention settings for this camera. " ,
2024-09-28 22:21:42 +03:00
)
review : ReviewConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = ReviewConfig ,
title = " Review " ,
description = " Settings that control alerts, detections, and GenAI review summaries used by the UI and storage for this camera. " ,
2024-09-28 22:21:42 +03:00
)
2025-07-07 17:03:57 +03:00
semantic_search : CameraSemanticSearchConfig = Field (
default_factory = CameraSemanticSearchConfig ,
2026-02-27 18:55:36 +03:00
title = " Semantic Search " ,
description = " Settings for semantic search which builds and queries object embeddings to find similar items. " ,
2025-07-07 17:03:57 +03:00
)
2024-09-28 22:21:42 +03:00
snapshots : SnapshotsConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = SnapshotsConfig ,
title = " Snapshots " ,
2026-03-22 22:33:04 +03:00
description = " Settings for API-generated snapshots of tracked objects for this camera. " ,
2024-09-28 22:21:42 +03:00
)
timestamp_style : TimestampStyleConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = TimestampStyleConfig ,
title = " Timestamp style " ,
description = " Styling options for in-feed timestamps applied to recordings and snapshots. " ,
2024-09-28 22:21:42 +03:00
)
# Options without global fallback
best_image_timeout : int = Field (
default = 60 ,
2026-02-27 18:55:36 +03:00
title = " Best image timeout " ,
description = " How long to wait for the image with the highest confidence score. " ,
2024-09-28 22:21:42 +03:00
)
mqtt : CameraMqttConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = CameraMqttConfig ,
title = " MQTT " ,
description = " MQTT image publishing settings. " ,
2024-09-28 22:21:42 +03:00
)
2025-02-11 05:47:15 +03:00
notifications : NotificationConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = NotificationConfig ,
title = " Notifications " ,
description = " Settings to enable and control notifications for this camera. " ,
2025-02-11 05:47:15 +03:00
)
2024-09-28 22:21:42 +03:00
onvif : OnvifConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = OnvifConfig ,
title = " ONVIF " ,
description = " ONVIF connection and PTZ autotracking settings for this camera. " ,
)
type : CameraTypeEnum = Field (
default = CameraTypeEnum . generic ,
title = " Camera type " ,
description = " Camera Type " ,
2024-09-28 22:21:42 +03:00
)
ui : CameraUiConfig = Field (
2026-02-27 18:55:36 +03:00
default_factory = CameraUiConfig ,
title = " Camera UI " ,
description = " Display ordering and visibility for this camera in the UI. Ordering affects the default dashboard. For more granular control, use camera groups. " ,
2024-09-28 22:21:42 +03:00
)
webui_url : Optional [ str ] = Field (
None ,
2026-02-27 18:55:36 +03:00
title = " Camera URL " ,
description = " URL to visit the camera directly from system page " ,
2024-09-28 22:21:42 +03:00
)
Camera profile support (#22482)
* add CameraProfileConfig model for named config overrides
* add profiles field to CameraConfig
* add active_profile field to FrigateConfig
Runtime-only field excluded from YAML serialization, tracks which
profile is currently active.
* add ProfileManager for profile activation and persistence
Handles snapshotting base configs, applying profile overrides via
deep_merge + apply_section_update, publishing ZMQ updates, and
persisting active profile to /config/.active_profile.
* add profile API endpoints (GET /profiles, GET/PUT /profile)
* add MQTT and dispatcher integration for profiles
- Subscribe to frigate/profile/set MQTT topic
- Publish profile/state and profiles/available on connect
- Add _on_profile_command handler to dispatcher
- Broadcast active profile state on WebSocket connect
* wire ProfileManager into app startup and FastAPI
- Create ProfileManager after dispatcher init
- Restore persisted profile on startup
- Pass dispatcher and profile_manager to FastAPI app
* add tests for invalid profile values and keys
Tests that Pydantic rejects: invalid field values (fps: "not_a_number"),
unknown section keys (ffmpeg in profile), invalid nested values, and
invalid profiles in full config parsing.
* formatting
* fix CameraLiveConfig JSON serialization error on profile activation
refactor _publish_updates to only publish ZMQ updates for
sections that actually changed, not all sections on affected cameras.
* consolidate
* add enabled field to camera profiles for enabling/disabling cameras
* add zones support to camera profiles
* add frontend profile types, color utility, and config save support
* add profile state management and save preview support
* add profileName prop to BaseSection for profile-aware config editing
* add profile section dropdown and wire into camera settings pages
* add per-profile camera enable/disable to Camera Management view
* add profiles summary page with card-based layout and fix backend zone comparison bug
* add active profile badge to settings toolbar
* i18n
* add red dot for any pending changes including profiles
* profile support for mask and zone editor
* fix hidden field validation errors caused by lodash wildcard and schema gaps
lodash unset does not support wildcard (*) segments, so hidden fields like
filters.*.mask were never stripped from form data, leaving null raw_coordinates
that fail RJSF anyOf validation. Add unsetWithWildcard helper and also strip
hidden fields from the JSON schema itself as defense-in-depth.
* add face_recognition and lpr to profile-eligible sections
* move profile dropdown from section panes to settings header
* add profiles enable toggle and improve empty state
* formatting
* tweaks
* tweak colors and switch
* fix profile save diff, masksAndZones delete, and config sync
* ui tweaks
* ensure profile manager gets updated config
* rename profile settings to ui settings
* refactor profilesview and add dots/border colors when overridden
* implement an update_config method for profile manager
* fix mask deletion
* more unique colors
* add top-level profiles config section with friendly names
* implement profile friendly names and improve profile UI
- Add ProfileDefinitionConfig type and profiles field to FrigateConfig
- Use ProfilesApiResponse type with friendly_name support throughout
- Replace Record<string, unknown> with proper JsonObject/JsonValue types
- Add profile creation form matching zone pattern (Zod + NameAndIdFields)
- Add pencil icon for renaming profile friendly names in ProfilesView
- Move Profiles menu item to first under Camera Configuration
- Add activity indicators on save/rename/delete buttons
- Display friendly names in CameraManagementView profile selector
- Fix duplicate colored dots in management profile dropdown
- Fix i18n namespace for overridden base config tooltips
- Move profile override deletion from dropdown trash icon to footer
button with confirmation dialog, matching Reset to Global pattern
- Remove Add Profile from section header dropdown to prevent saving
camera overrides before top-level profile definition exists
- Clean up newProfiles state after API profile deletion
- Refresh profiles SWR cache after saving profile definitions
* remove profile badge in settings and add profiles to main menu
* use icon only on mobile
* change color order
* docs
* show activity indicator on trash icon while deleting a profile
* tweak language
* immediately create profiles on backend instead of deferring to Save All
* hide restart-required fields when editing a profile section
fields that require a restart cannot take effect via profile switching,
so they are merged into hiddenFields when profileName is set
* show active profile indicator in desktop status bar
* fix profile config inheritance bug where Pydantic defaults override base values
The /config API was dumping profile overrides with model_dump() which included
all Pydantic defaults. When the frontend merged these over
the camera's base config, explicitly-set base values were
lost. Now profile overrides are re-dumped with exclude_unset=True so only
user-specified fields are returned.
Also fixes the Save All path generating spurious deletion markers for
restart-required fields that are hidden during profile
editing but not excluded from the raw data sanitization in
prepareSectionSavePayload.
* docs tweaks
* docs tweak
* formatting
* formatting
* fix typing
* fix test pollution
test_maintainer was injecting MagicMock() into sys.modules["frigate.config.camera.updater"] at module load time and never restoring it. When the profile tests later imported CameraConfigUpdateEnum and CameraConfigUpdateTopic from that module, they got mock objects instead of the real dataclass/enum, so equality comparisons always failed
* remove
* fix settings showing profile-merged values when editing base config
When a profile is active, the in-memory config contains effective
(profile-merged) values. The settings UI was displaying these merged
values even when the "Base Config" view was selected.
Backend: snapshot pre-profile base configs in ProfileManager and expose
them via a `base_config` key in the /api/config camera response when a
profile is active. The top-level sections continue to reflect the
effective running config.
Frontend: read from `base_config` when available in BaseSection,
useConfigOverride, useAllCameraOverrides, and prepareSectionSavePayload.
Include formData labels in Object/Audio switches widgets so that labels
added only by a profile override remain visible when editing that profile.
* use rasterized_mask as field
makes it easier to exclude from the schema with exclude=True
prevents leaking of the field when using model_dump for profiles
* fix zones
- Fix zone colors not matching across profiles by falling back to base zone color when profile zone data lacks a color field
- Use base_config for base-layer values in masks/zones view so profile-merged values don't pollute the base config editing view
- Handle zones separately in profile manager snapshot/restore since ZoneConfig requires special serialization (color as private attr, contour generation)
- Inherit base zone color and generate contours for profile zone overrides in profile manager
* formatting
* don't require restart for camera enabled change for profiles
* publish camera state when changing profiles
* formatting
* remove available profiles from mqtt
* improve typing
2026-03-19 17:47:57 +03:00
profiles : dict [ str , CameraProfileConfig ] = Field (
default_factory = dict ,
title = " Profiles " ,
description = " Named config profiles with partial overrides that can be activated at runtime. " ,
)
2024-09-28 22:21:42 +03:00
zones : dict [ str , ZoneConfig ] = Field (
2026-02-27 18:55:36 +03:00
default_factory = dict ,
title = " Zones " ,
description = " Zones allow you to define a specific area of the frame so you can determine whether or not an object is within a particular area. " ,
2024-09-28 22:21:42 +03:00
)
2025-03-03 18:30:52 +03:00
enabled_in_config : Optional [ bool ] = Field (
2026-02-27 18:55:36 +03:00
default = None ,
title = " Original camera state " ,
description = " Keep track of original state of camera. " ,
2025-03-03 18:30:52 +03:00
)
2024-09-28 22:21:42 +03:00
_ffmpeg_cmds : list [ dict [ str , list [ str ] ] ] = PrivateAttr ( )
def __init__ ( self , * * config ) :
# Set zone colors
if " zones " in config :
colors = generate_color_palette ( len ( config [ " zones " ] ) )
config [ " zones " ] = {
name : { * * z , " color " : color }
for ( name , z ) , color in zip ( config [ " zones " ] . items ( ) , colors )
}
# add roles to the input if there is only one
if len ( config [ " ffmpeg " ] [ " inputs " ] ) == 1 :
has_audio = " audio " in config [ " ffmpeg " ] [ " inputs " ] [ 0 ] . get ( " roles " , [ ] )
config [ " ffmpeg " ] [ " inputs " ] [ 0 ] [ " roles " ] = [
" record " ,
" detect " ,
]
if has_audio :
config [ " ffmpeg " ] [ " inputs " ] [ 0 ] [ " roles " ] . append ( " audio " )
super ( ) . __init__ ( * * config )
@property
def frame_shape ( self ) - > tuple [ int , int ] :
return self . detect . height , self . detect . width
@property
def frame_shape_yuv ( self ) - > tuple [ int , int ] :
return self . detect . height * 3 / / 2 , self . detect . width
@property
def ffmpeg_cmds ( self ) - > list [ dict [ str , list [ str ] ] ] :
return self . _ffmpeg_cmds
2025-11-10 20:03:56 +03:00
def get_formatted_name ( self ) - > str :
""" Return the friendly name if set, otherwise return a formatted version of the camera name. """
if self . friendly_name :
return self . friendly_name
return self . name . replace ( " _ " , " " ) . title ( ) if self . name else " "
2024-09-28 22:21:42 +03:00
def create_ffmpeg_cmds ( self ) :
if " _ffmpeg_cmds " in self :
return
2026-03-06 23:45:39 +03:00
self . _build_ffmpeg_cmds ( )
def recreate_ffmpeg_cmds ( self ) :
""" Force regeneration of ffmpeg commands from current config. """
self . _build_ffmpeg_cmds ( )
def _build_ffmpeg_cmds ( self ) :
""" Build ffmpeg commands from the current ffmpeg config. """
2024-09-28 22:21:42 +03:00
ffmpeg_cmds = [ ]
for ffmpeg_input in self . ffmpeg . inputs :
ffmpeg_cmd = self . _get_ffmpeg_cmd ( ffmpeg_input )
if ffmpeg_cmd is None :
continue
ffmpeg_cmds . append ( { " roles " : ffmpeg_input . roles , " cmd " : ffmpeg_cmd } )
self . _ffmpeg_cmds = ffmpeg_cmds
def _get_ffmpeg_cmd ( self , ffmpeg_input : CameraInput ) :
ffmpeg_output_args = [ ]
if " detect " in ffmpeg_input . roles :
detect_args = get_ffmpeg_arg_list ( self . ffmpeg . output_args . detect )
scale_detect_args = parse_preset_hardware_acceleration_scale (
ffmpeg_input . hwaccel_args or self . ffmpeg . hwaccel_args ,
detect_args ,
self . detect . fps ,
self . detect . width ,
self . detect . height ,
)
ffmpeg_output_args = scale_detect_args + ffmpeg_output_args + [ " pipe: " ]
if " record " in ffmpeg_input . roles and self . record . enabled :
record_args = get_ffmpeg_arg_list (
parse_preset_output_record (
self . ffmpeg . output_args . record ,
2025-01-03 17:11:18 +03:00
self . ffmpeg . apple_compatibility ,
2024-09-28 22:21:42 +03:00
)
or self . ffmpeg . output_args . record
)
ffmpeg_output_args = (
record_args
+ [ f " { os . path . join ( CACHE_DIR , self . name ) } @ { CACHE_SEGMENT_FORMAT } .mp4 " ]
+ ffmpeg_output_args
)
# if there aren't any outputs enabled for this input
if len ( ffmpeg_output_args ) == 0 :
return None
global_args = get_ffmpeg_arg_list (
ffmpeg_input . global_args or self . ffmpeg . global_args
)
camera_arg = (
self . ffmpeg . hwaccel_args if self . ffmpeg . hwaccel_args != " auto " else None
)
hwaccel_args = get_ffmpeg_arg_list (
parse_preset_hardware_acceleration_decode (
ffmpeg_input . hwaccel_args ,
self . detect . fps ,
self . detect . width ,
self . detect . height ,
2025-10-13 18:59:38 +03:00
self . ffmpeg . gpu ,
2024-09-28 22:21:42 +03:00
)
or ffmpeg_input . hwaccel_args
or parse_preset_hardware_acceleration_decode (
camera_arg ,
self . detect . fps ,
self . detect . width ,
self . detect . height ,
2025-10-13 18:59:38 +03:00
self . ffmpeg . gpu ,
2024-09-28 22:21:42 +03:00
)
or camera_arg
or [ ]
)
input_args = get_ffmpeg_arg_list (
parse_preset_input ( ffmpeg_input . input_args , self . detect . fps )
or ffmpeg_input . input_args
or parse_preset_input ( self . ffmpeg . input_args , self . detect . fps )
or self . ffmpeg . input_args
)
cmd = (
[ self . ffmpeg . ffmpeg_path ]
+ global_args
+ ( hwaccel_args if " detect " in ffmpeg_input . roles else [ ] )
+ input_args
+ [ " -i " , escape_special_characters ( ffmpeg_input . path ) ]
+ ffmpeg_output_args
)
return [ part for part in cmd if part != " " ]