Per-tile stream quality (high/low), fps cap, latency flags
Cameras carry multiple stream URLs (streams: high/medium/low); each tile picks one via Quality (auto/high/low). Small tiles can pull the low substream to cut Pi decode load. discover --enable-rtsp takes a comma list (high,low), enables each channel, records all enabled ones. TUI: q cycles a tile quality (shown in the tile); discover enables high+low. Player: --framedrop + low-delay demuxer flags; player.max_fps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,9 @@ type Player struct {
|
||||
Profile string `yaml:"profile"`
|
||||
// ExtraArgs are appended verbatim to every mpv invocation.
|
||||
ExtraArgs []string `yaml:"extra_args,omitempty"`
|
||||
// MaxFPS caps the rendered frame rate (mpv --vf=fps). 0 = uncapped. Trims
|
||||
// render/scale load; the bigger decode lever is using substreams.
|
||||
MaxFPS int `yaml:"max_fps,omitempty"`
|
||||
// RestartBackoffSeconds is how long to wait before relaunching a stream
|
||||
// that exited or stalled.
|
||||
RestartBackoffSeconds int `yaml:"restart_backoff_seconds,omitempty"`
|
||||
@@ -92,12 +95,62 @@ type Camera struct {
|
||||
ID string `yaml:"id,omitempty"`
|
||||
// Name is the human label and the key layouts reference. Must be unique.
|
||||
Name string `yaml:"name"`
|
||||
// RTSP is the fully-resolved stream URL.
|
||||
RTSP string `yaml:"rtsp"`
|
||||
// RTSP is a single fully-resolved stream URL. Kept for backward
|
||||
// compatibility and manual entries; Streams takes precedence when present.
|
||||
RTSP string `yaml:"rtsp,omitempty"`
|
||||
// Streams maps a quality ("high"|"medium"|"low") to its stream URL, so a
|
||||
// tile can choose per-tile which to pull. Populated by discovery.
|
||||
Streams map[string]string `yaml:"streams,omitempty"`
|
||||
// Disabled hides the camera from selection without deleting it.
|
||||
Disabled bool `yaml:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// Qualities in preference order, high to low.
|
||||
var Qualities = []string{"high", "medium", "low"}
|
||||
|
||||
// StreamURL returns the URL for the requested quality, falling back sensibly:
|
||||
// the exact quality, then any lower quality, then any stream at all, then the
|
||||
// legacy single RTSP field.
|
||||
func (c Camera) StreamURL(quality string) string {
|
||||
if len(c.Streams) > 0 {
|
||||
if quality != "" {
|
||||
if u := c.Streams[quality]; u != "" {
|
||||
return u
|
||||
}
|
||||
}
|
||||
// Fall back down the preference list from the requested quality.
|
||||
start := 0
|
||||
for i, q := range Qualities {
|
||||
if q == quality {
|
||||
start = i
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, q := range Qualities[start:] {
|
||||
if u := c.Streams[q]; u != "" {
|
||||
return u
|
||||
}
|
||||
}
|
||||
for _, q := range Qualities {
|
||||
if u := c.Streams[q]; u != "" {
|
||||
return u
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.RTSP
|
||||
}
|
||||
|
||||
// AvailableQualities lists the qualities this camera actually has, high to low.
|
||||
func (c Camera) AvailableQualities() []string {
|
||||
var out []string
|
||||
for _, q := range Qualities {
|
||||
if c.Streams[q] != "" {
|
||||
out = append(out, q)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// MaxTiles caps how many simultaneous streams a layout may show. Decoding
|
||||
// more than this on a Pi 4 is impractical even with substreams.
|
||||
const MaxTiles = 16
|
||||
@@ -125,6 +178,9 @@ type Tile struct {
|
||||
Row int `yaml:"row"`
|
||||
ColSpan int `yaml:"colspan,omitempty"` // defaults to 1
|
||||
RowSpan int `yaml:"rowspan,omitempty"` // defaults to 1
|
||||
// Quality selects which stream to pull for this tile: "high"|"medium"|
|
||||
// "low". Empty means the camera's best available (see Camera.StreamURL).
|
||||
Quality string `yaml:"quality,omitempty"`
|
||||
}
|
||||
|
||||
// Span returns the tile's spans with zero values normalized to 1.
|
||||
|
||||
Reference in New Issue
Block a user