Multi-Camera
One airframe can carry several cameras: an EO, a wide EO, a thermal, a down-facing landing cam. Each one is a leg, and each leg is served as its own mediamtx path. Exactly one leg is the primary. It is the leg that rides the radio and the cloud relay. Every other leg is served over the LAN only.One camera, or legs
The legacy single-camera shape is still the whole config for a one-camera node:video.cameras replaces it. When video.cameras is absent the
agent resolves the single video.camera block verbatim as one primary leg with
the id main, so an existing config is byte-identical after the multi-leg
support landed.
Per-leg fields
Identity and transport
A
source starting rtsp://, rtsps://, http:// or https:// is a network
capture URL. Everything else is a local device.
Encode
These are read by the encode pipeline and reach the encoder command builder.Roster metadata
These are surfaced through the camera roster and consumed by extensions. The encode and radio pipeline reads none of them.role and purpose are complementary, not alternatives. role is the
transport plane (which leg rides the radio). purpose is the consumer
plane (what an extension binds to). A leg can be the primary transport and also
be the detect source.
What primary means
Selection rules, in order:
- The first leg whose
roleis exactlyprimarywins, wherever it sits in the list. - If no leg declares
role: primary, the first leg in the list is the primary.
main so the radio, the cloud relay and
every downstream consumer keep one fixed path name. Its declared role string is
preserved for the Mission Control label map, so a primary declared as role: eo
still renders as an EO leg while being served at main.
A secondary with a network source becomes a mediamtx sourceOnDemand pull: no
agent-owned encoder process, and mediamtx only connects upstream when a viewer
asks. A secondary on a local device does get its own agent-owned encoder, using
the same command builder as the primary.
Airtime and the thumbnail profile
One fleet shares one 20 MHz channel, so exactly one aircraft streams full video at a time. The primary leg’s top-levelwidth / height / fps /
bitrate_kbps are the hero profile. The thumbnail sub-block is the
non-hero profile the drone falls back to while the operator’s attention is on a
different aircraft:
thumbnail block is
unread on a secondary leg. Mission Control drives the switch through
POST /api/video/profile.
The camera roster
GET /api/video/roster is the one place an operator sees every camera the node
knows about. It reconciles three sources into one list:
- the legs declared in
video.cameras(or the legacyvideo.camerablock, synthesised asmain), - the devices the hardware enumeration discovered
(
/run/ados/cameras-discovered.json), - the live stream state (
/run/ados/video-streams.json).
state:
The read is guaranteed
200 and degrades to {"cameras": []} when the sidecars
are absent. A ground station carries no onboard camera, so it serves an empty
roster rather than a phantom main.
/api/video/roster is not /api/video/cameras. The latter is the ground
station’s switchable-camera enumeration ({cameras, assignments}) that the
camera-switch control uses, and it is a different surface.Writing the roster
PUT /api/video/roster persists the operator’s leg list. It validates before it
writes:
- ids must be unique and path-safe,
orientationandpurposemust be known values,- no non-primary leg may claim the reserved id
main.
400. The write then forwards a video.cameras.set
op to the supervisor’s video command socket (/run/ados/video-cmd.sock), which
is the config-write and restart authority. An unreachable supervisor is a 503;
a saved-but-not-restarted result is a 502.
The persist is a merge by owner. An operator write preserves the legs an
extension declared and an extension write preserves the operator’s, so a driver
extension that declares a pod’s legs does not lose them the next time you edit
the roster in Mission Control. A client-supplied owner on a leg is ignored;
the supervisor stamps operator on an operator write.
A ground station returns 404 for the write: there is no onboard camera to
manage there.