toposync-ext-streaming 0.1.22__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/PKG-INFO +382 -21
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/README.md +380 -20
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/pyproject.toml +2 -2
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/api/models.py +225 -17
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/api/routes.py +2387 -356
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/pipelines/operators.py +144 -12
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/plugin.py +41 -1
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/static/4.js +2 -0
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/static/623.js +2 -0
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/static/703.js +2 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/main.js +1 -1
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/static/remoteEntry.js +1 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/__init__.py +1 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/camera_ingest.py +0 -18
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/streaming/go2rtc_binary.py +163 -0
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/streaming/go2rtc_config.py +55 -0
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/streaming/go2rtc_manager.py +268 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/ingest_resolver.py +3 -18
- toposync_ext_streaming-0.2.0/src/toposync_ext_streaming/streaming/jsmpeg_manager.py +472 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/platform.py +7 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/writer_bridge.py +90 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/wizard/pipeline_builder.py +58 -2
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/api/streamingApi.ts +3 -1
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/settings/StreamingSettingsPanel.tsx +692 -80
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/settings/WizardCreatePipelineFromTransmission.tsx +0 -11
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/translations.ts +166 -14
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/types.ts +38 -5
- toposync_ext_streaming-0.1.22/src/toposync_ext_streaming/static/4.js +0 -2
- toposync_ext_streaming-0.1.22/src/toposync_ext_streaming/static/623.js +0 -2
- toposync_ext_streaming-0.1.22/src/toposync_ext_streaming/static/703.js +0 -2
- toposync_ext_streaming-0.1.22/src/toposync_ext_streaming/static/remoteEntry.js +0 -1
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/.gitignore +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/LICENSE +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/LICENSE.ffmpeg +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/LICENSE.mediamtx +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/__init__.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/api/__init__.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/bin/ffmpeg/LICENSE +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/bin/mediamtx/LICENSE +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/extension.json +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/pipelines/__init__.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/326.js +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/326.js.LICENSE.txt +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/4.js.LICENSE.txt +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/623.js.LICENSE.txt +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/703.js.LICENSE.txt +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/static/main.js.LICENSE.txt +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/arbitration.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/distributed_sync.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/encoder_state.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/engine_manager.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/ffmpeg_binary.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/ingest_auth.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/mediamtx_api_client.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/mediamtx_binary.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/mediamtx_config.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/mediamtx_processes.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/placeholder.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/playback_events.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/publisher_manager.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/resize.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/streaming/runtime_state.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/src/toposync_ext_streaming/wizard/__init__.py +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/package.json +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/activate.tsx +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/constants.ts +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/entry.ts +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/src/settings/SubModal.tsx +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/tsconfig.json +0 -0
- {toposync_ext_streaming-0.1.22 → toposync_ext_streaming-0.2.0}/ui/webpack.config.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toposync-ext-streaming
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Toposync first-party extension: streaming settings, API surface, and pipeline sink bootstrap.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,39 +8,58 @@ Requires-Python: >=3.11
|
|
|
8
8
|
Requires-Dist: numpy>=1.26
|
|
9
9
|
Requires-Dist: opencv-python-headless>=4.10
|
|
10
10
|
Requires-Dist: toposync-core>=0.3.3
|
|
11
|
+
Requires-Dist: websockets>=12.0
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
|
|
13
14
|
# Toposync Streaming Extension
|
|
14
15
|
|
|
15
16
|
Extension ID: `com.toposync.streaming`
|
|
16
17
|
|
|
17
|
-
This extension provides
|
|
18
|
+
This extension provides camera and pipeline video publication in Toposync:
|
|
18
19
|
|
|
19
|
-
- Users
|
|
20
|
-
-
|
|
20
|
+
- Users normally publish **camera sources** with a `Transmitir esta fonte` intent.
|
|
21
|
+
- The extension reconciles generated **CameraLiveView**, **Transmission**, **Outputs**, and implicit continuous pipelines.
|
|
22
|
+
- Advanced pipelines can publish a rendered variant through **`stream.publish_video`**.
|
|
21
23
|
- A local **MediaMTX** engine serves RTSP/HLS/WebRTC (WHEP) URLs.
|
|
22
24
|
- FFmpeg publishers (one per output) push encoded video into MediaMTX paths.
|
|
23
25
|
|
|
24
26
|
The core design goal is reliability in local-first setups with highly dynamic pipelines:
|
|
25
27
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
28
|
+
- Regular camera playback should work after adding a camera, without manually creating transmissions or pipelines.
|
|
29
|
+
- Generated camera pipelines must be continuous, so a video stream is not hidden behind motion/event gates.
|
|
30
|
+
- Advanced pipelines can still be intermittent (open/update/close based on detection/tracking).
|
|
31
|
+
- Multiple writers can write to the same Transmission when using advanced/manual flows.
|
|
32
|
+
- Encoding should happen only when there is actual playback demand.
|
|
33
|
+
|
|
34
|
+
The canonical product and engineering principles for streaming are documented in
|
|
35
|
+
[`docs/toposync-streaming-dossier-solid-priorities.md`](../../docs/toposync-streaming-dossier-solid-priorities.md#00-principios-permanentes-de-streaming).
|
|
36
|
+
In short:
|
|
37
|
+
|
|
38
|
+
- User-facing flows deal with publishable sources and variants; `Transmission`, outputs, engine paths, and quality profile IDs are advanced artifacts.
|
|
39
|
+
- Stability wins over latency and quality: live requires fresh selected frames, an active writer, and a healthy selected output.
|
|
40
|
+
- Transport is contextual: HLS is the stable baseline, MSE is preferred for passive web when the sidecar is healthy, WebRTC is explicit low latency/PTZ, and JSMpeg is the last visual fallback.
|
|
41
|
+
- Home Assistant Cloud support goes through native HA `camera` entities, not direct WebRTC inside the Toposync ingress player.
|
|
42
|
+
- Expensive work must be demand driven and scoped to the active stream/output/session.
|
|
43
|
+
- The core remains generic; streaming-specific reconciliation and policy live in this extension.
|
|
29
44
|
|
|
30
45
|
## Implemented features (high level)
|
|
31
46
|
|
|
32
47
|
- MediaMTX engine lifecycle management (start/stop/restart/status) with on-demand binary install (download + SHA256 verification) and dynamic port resolution.
|
|
48
|
+
- Stream publication specs for camera sources and pipeline output variants.
|
|
49
|
+
- Reconciliation from publication intent to generated live views, transmissions, outputs, and implicit pipelines.
|
|
33
50
|
- Transmission and output CRUD stored in extension settings.
|
|
34
51
|
- Per-output URLs for RTSP, HLS, and WebRTC/WHEP.
|
|
35
52
|
- Pipeline sink operator `stream.publish_video` that publishes frames into a transmission (multi-writer capable).
|
|
53
|
+
- Pipeline sink operator publication mode for generated variants.
|
|
36
54
|
- Multi-writer arbitration using lifecycle (`open/update/close`), priority, and a sticky window.
|
|
37
55
|
- Output-level placeholder frames when no writer is active.
|
|
38
56
|
- Output-level resolution and FPS enforcement, including contain resizing with black padding.
|
|
39
57
|
- FFmpeg publishers (one per output) that publish RTSP into MediaMTX.
|
|
40
58
|
- On-demand encoding based on MediaMTX viewer count, with debounce stop.
|
|
41
59
|
- Demand priming to reduce "first connect" 404/no-stream failures.
|
|
60
|
+
- Demand heartbeat for web, app, PiP, PTZ, and Home Assistant entity playback.
|
|
42
61
|
- Distributed hosting via `Transmission.host_server_id`, plus URL proxying and processing-side settings sync.
|
|
43
|
-
- Dashboard playback
|
|
62
|
+
- Dashboard playback using a backend Playback Plan with HLS/WebRTC, MSE through the optional go2rtc sidecar, and JSMpeg as an on-demand emergency visual fallback.
|
|
44
63
|
|
|
45
64
|
## Supported protocols (as implemented)
|
|
46
65
|
|
|
@@ -59,14 +78,43 @@ The core design goal is reliability in local-first setups with highly dynamic pi
|
|
|
59
78
|
|
|
60
79
|
### WebRTC (WHEP)
|
|
61
80
|
- URL format: `http://<host>:<webrtc_port>/<path>/whep`
|
|
62
|
-
- Used by the Toposync dashboard
|
|
81
|
+
- Used by the Toposync dashboard when low latency, PTZ, or another explicit interactive context requests it.
|
|
63
82
|
- Current implementation is LAN-first (HTTP, no TLS termination built in). If you expose streaming beyond LAN, plan to terminate TLS.
|
|
64
83
|
|
|
84
|
+
### MSE
|
|
85
|
+
- URL format: `ws://<toposync-host>/api/streams/media/mse/<path>/ws?media_token=...`
|
|
86
|
+
- go2rtc consumes `rtsp://127.0.0.1:<mediamtx_rtsp_port>/<path>` from MediaMTX.
|
|
87
|
+
- The browser never talks to go2rtc directly. Toposync verifies the signed media token and proxies text control messages plus binary fMP4 fragments.
|
|
88
|
+
- Dashboard Auto can prefer MSE for passive web/grid/fullscreen playback when the sidecar is running and the backing output is browser-compatible.
|
|
89
|
+
|
|
90
|
+
### JSMpeg
|
|
91
|
+
- URL format: `ws://<toposync-host>/api/streams/media/jsmpeg/<path>/ws?media_token=...`
|
|
92
|
+
- Intended only as an emergency visual fallback. It is video-only, low resolution/FPS, and does not carry audio.
|
|
93
|
+
- Each browser WebSocket creates one isolated FFmpeg process that converts the selected runtime frame stream to MPEG-TS/MPEG-1. The process is stopped when the WebSocket closes.
|
|
94
|
+
- The source is the selected Toposync Transmission frame, or an explicit placeholder while warming up/offline. It never pulls camera RTSP directly.
|
|
95
|
+
|
|
96
|
+
### Playback Plan candidates
|
|
97
|
+
|
|
98
|
+
The Playback Plan API can return these transport candidates:
|
|
99
|
+
|
|
100
|
+
- `hls`: stable baseline, active today.
|
|
101
|
+
- `webrtc`: low-latency path, active today when context allows it.
|
|
102
|
+
- `mse`: browser-first path through an optional go2rtc sidecar. go2rtc consumes the internal MediaMTX RTSP path, and browsers only connect through a signed Toposync WebSocket proxy.
|
|
103
|
+
- `jsmpeg`: emergency visual fallback through a signed Toposync WebSocket. It is selected only after better browser transports are unavailable or fail.
|
|
104
|
+
|
|
105
|
+
RTSP is not a browser transport. It remains the internal/ecosystem contract for HA Core, VLC/ffplay, Frigate/dev, go2rtc sidecars, and diagnostics.
|
|
106
|
+
|
|
65
107
|
## Architecture overview
|
|
66
108
|
|
|
67
109
|
### Data flow
|
|
68
110
|
|
|
69
|
-
|
|
111
|
+
Camera source publication:
|
|
112
|
+
|
|
113
|
+
`camera source` -> `StreamPublicationSpec` -> reconciler -> implicit pipeline -> `stream.publish_video` -> `TransmissionRuntimeState` -> `StreamWriterBridge` -> `FFmpeg publisher` -> `MediaMTX path` -> viewers (RTSP/HLS/WHEP)
|
|
114
|
+
|
|
115
|
+
Advanced pipeline publication:
|
|
116
|
+
|
|
117
|
+
`pipeline frames` -> `stream.publish_video` -> generated/manual `Transmission` -> `TransmissionRuntimeState` -> `StreamWriterBridge` -> `FFmpeg publisher` -> `MediaMTX path` -> viewers (RTSP/HLS/WHEP)
|
|
70
118
|
|
|
71
119
|
### Components
|
|
72
120
|
|
|
@@ -74,6 +122,15 @@ The core design goal is reliability in local-first setups with highly dynamic pi
|
|
|
74
122
|
- Ensures the correct MediaMTX binary is available for the current OS/arch (downloads on demand when missing).
|
|
75
123
|
- Renders a YAML config and starts/stops/restarts the MediaMTX process.
|
|
76
124
|
- Resolves ports (preferred vs actual) and exposes engine status and test URLs.
|
|
125
|
+
- `Go2RtcSidecarManager`
|
|
126
|
+
- Optionally downloads and starts go2rtc `v1.9.14` for browser MSE playback.
|
|
127
|
+
- Renders `runtime/streaming/go2rtc/go2rtc.yaml` from generated streaming outputs.
|
|
128
|
+
- Exposes no direct browser API; the dashboard uses the signed Toposync MSE proxy.
|
|
129
|
+
- Uses internal MediaMTX RTSP URLs only, never direct camera credentials or camera URLs.
|
|
130
|
+
- `JsmpegSessionManager`
|
|
131
|
+
- Starts FFmpeg only while a signed JSMpeg WebSocket session is connected.
|
|
132
|
+
- Reads frames from `TransmissionRuntimeState`, resizes/contains them to the configured fallback profile, and writes MPEG-TS/MPEG-1 bytes to the browser.
|
|
133
|
+
- Enforces global and per-transmission session limits so the fallback cannot silently become the primary load path.
|
|
77
134
|
- `TransmissionRuntimeState`
|
|
78
135
|
- Stores latest frame per writer and per transmission.
|
|
79
136
|
- Applies lifecycle and multi-writer arbitration to select the active writer.
|
|
@@ -82,6 +139,10 @@ The core design goal is reliability in local-first setups with highly dynamic pi
|
|
|
82
139
|
- Periodic "tick loop" that loads streaming settings, ensures engine is running, refreshes viewer counts, starts/stops publishers on-demand, and pushes frames (or placeholders) into publishers.
|
|
83
140
|
- Implements best-effort demand priming and a fallback "synthetic demand" hint.
|
|
84
141
|
- Implements a bypass mode for simple pipelines (publisher pulls camera RTSP directly).
|
|
142
|
+
- Publication reconciler
|
|
143
|
+
- Converts user intent (`StreamPublicationSpec`) into generated `CameraLiveView`, `Transmission`, outputs, and implicit camera pipelines.
|
|
144
|
+
- Preserves generated artifact metadata (`generated_by`, `publication_id`, owner/camera/source/role) for diagnostics and read-only UI display.
|
|
145
|
+
- Runs after camera/source changes, publication updates, pipeline saves, and explicit `POST /api/streams/reconcile`.
|
|
85
146
|
- `PublisherManager`
|
|
86
147
|
- Spawns and supervises FFmpeg processes.
|
|
87
148
|
- Supports rawvideo frames over stdin (`rawvideo_pipe`) or RTSP pull (`rtsp_pull`).
|
|
@@ -89,9 +150,87 @@ The core design goal is reliability in local-first setups with highly dynamic pi
|
|
|
89
150
|
|
|
90
151
|
## Domain model and settings
|
|
91
152
|
|
|
153
|
+
### StreamPublicationSpec
|
|
154
|
+
|
|
155
|
+
`StreamPublicationSpec` is the user-facing intent model for publishing video.
|
|
156
|
+
|
|
157
|
+
For normal camera playback, the user should not create a Transmission manually. The camera source owns a publication spec, and the streaming extension reconciles the generated artifacts.
|
|
158
|
+
|
|
159
|
+
Fields:
|
|
160
|
+
|
|
161
|
+
- `id`: deterministic publication id.
|
|
162
|
+
- `owner_kind`: `"camera_source"` or `"pipeline_output"`.
|
|
163
|
+
- `camera_id`: camera/live-view group id.
|
|
164
|
+
- `camera_source_id`: concrete camera source id when publishing a camera source.
|
|
165
|
+
- `pipeline_name` and `publish_node_id`: source pipeline/node when publishing a manual rendered variant.
|
|
166
|
+
- `enabled`: turns the publication and generated artifacts on/off.
|
|
167
|
+
- `role`: `"main" | "sub" | "zoom" | "custom"`.
|
|
168
|
+
- `label`: user-facing label shown in source selectors.
|
|
169
|
+
- `live_view_id`: optional live-view group override.
|
|
170
|
+
- `host_server_id`: effective stream host.
|
|
171
|
+
- `quality_policy`: output/profile hints for generated artifacts.
|
|
172
|
+
- `transport_policy`: playback/transport hints for generated artifacts.
|
|
173
|
+
|
|
174
|
+
Deterministic ids:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
camera:{camera_id}:{source_id}
|
|
178
|
+
pipeline:{pipeline_name}:{node_id}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Generated Transmissions, CameraLiveViews, variants, and implicit pipelines include metadata such as:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"generated_by": "stream_publication",
|
|
186
|
+
"publication_id": "camera:front:sub",
|
|
187
|
+
"owner_kind": "camera_source",
|
|
188
|
+
"camera_id": "front",
|
|
189
|
+
"camera_source_id": "sub",
|
|
190
|
+
"role": "sub"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Generated artifacts are normal runtime artifacts, but the regular UI treats them as read-only and points the user back to the owning camera source or pipeline operator.
|
|
195
|
+
|
|
196
|
+
### CameraLiveView and variants
|
|
197
|
+
|
|
198
|
+
`CameraLiveView` groups the public variants for one camera or logical video group. A variant maps a camera role to a generated Transmission/output.
|
|
199
|
+
|
|
200
|
+
Context defaults:
|
|
201
|
+
|
|
202
|
+
- `thumbnail` and `pip`: prefer `sub`.
|
|
203
|
+
- `large` and `fullscreen`: prefer `main`.
|
|
204
|
+
- `ptz`: prefer `zoom`, then `main`, then `sub`.
|
|
205
|
+
|
|
206
|
+
This is intentionally separate from technical quality labels. The dashboard source selector should expose labels such as "Principal", "Baixa resolução", "Zoom", or custom names, not internal output ids.
|
|
207
|
+
|
|
208
|
+
### Reconciliation rules
|
|
209
|
+
|
|
210
|
+
The reconciler is the owner of generated streaming artifacts.
|
|
211
|
+
|
|
212
|
+
It runs when:
|
|
213
|
+
|
|
214
|
+
- camera/source settings are saved;
|
|
215
|
+
- ONVIF discovery creates or updates video sources;
|
|
216
|
+
- `GET /api/streams/publications` normalizes publication specs for display;
|
|
217
|
+
- `PUT /api/streams/publications/camera-sources/{camera_id}/{source_id}` updates a source publication;
|
|
218
|
+
- `POST /api/streams/reconcile` is called;
|
|
219
|
+
- pipelines are saved, enabled, disabled, or removed.
|
|
220
|
+
|
|
221
|
+
For `owner_kind="camera_source"`, it creates one generated Transmission per published source and an implicit continuous pipeline named from the generated transmission. That pipeline feeds `camera.source` directly into `stream.publish_video`.
|
|
222
|
+
|
|
223
|
+
For `owner_kind="pipeline_output"`, it reads publication fields from the `stream.publish_video` node, creates a publication for that rendered variant, creates the generated Transmission, and writes the generated `transmission_id` back into the node when needed.
|
|
224
|
+
|
|
225
|
+
Generated camera pipelines must be continuous. A stream sink behind a motion gate, event-only detector, or event-only tracker is a manual/diagnostic case and should surface a warning rather than pretending to be a stable live camera stream.
|
|
226
|
+
|
|
92
227
|
### Transmission
|
|
93
228
|
|
|
94
|
-
A Transmission is the
|
|
229
|
+
A Transmission is the technical stream entity consumed by MediaMTX/FFmpeg.
|
|
230
|
+
|
|
231
|
+
For regular camera sources, Transmissions are generated from `StreamPublicationSpec`. Manual CRUD remains available for advanced diagnostics and integration work.
|
|
232
|
+
|
|
233
|
+
Fields (as implemented by the API model):
|
|
95
234
|
|
|
96
235
|
- `id`: UUID (generated server-side if omitted).
|
|
97
236
|
- `name`: display name.
|
|
@@ -334,11 +473,22 @@ Config (as implemented):
|
|
|
334
473
|
"input_artifact_name": "",
|
|
335
474
|
"resize_mode": "contain",
|
|
336
475
|
"writer_priority": 0,
|
|
337
|
-
"bypass_mode": "auto"
|
|
476
|
+
"bypass_mode": "auto",
|
|
477
|
+
"publication_enabled": false,
|
|
478
|
+
"publication_camera_id": "",
|
|
479
|
+
"publication_camera_source_id": "",
|
|
480
|
+
"publication_live_view_id": "",
|
|
481
|
+
"publication_role": "custom",
|
|
482
|
+
"publication_label": "",
|
|
483
|
+
"publication_show_in_dashboard": true,
|
|
484
|
+
"publication_show_in_home_assistant": false,
|
|
485
|
+
"publication_quality_profile_id": ""
|
|
338
486
|
}
|
|
339
487
|
```
|
|
340
488
|
|
|
341
489
|
Notes:
|
|
490
|
+
- `transmission_id` is still the runtime target.
|
|
491
|
+
- For generated variants, the UI can leave `transmission_id` empty and set `publication_enabled=true`; the reconciler generates the Transmission and later fills the target id.
|
|
342
492
|
- `resize_mode` exists in the operator config, but resizing is currently applied by the writer bridge based on output settings.
|
|
343
493
|
- Artifact selection:
|
|
344
494
|
- Reads `input_artifact_name` exactly, or `main` when it is empty.
|
|
@@ -346,8 +496,31 @@ Notes:
|
|
|
346
496
|
- Normalizes frames to `uint8` BGR and contiguous memory.
|
|
347
497
|
- Lifecycle handling:
|
|
348
498
|
- On `close`, the writer is marked closed and becomes ineligible for arbitration.
|
|
499
|
+
- Diagnostics:
|
|
500
|
+
- The operator warns when it is downstream of motion gates or event-only detection/tracking, because those graphs do not produce continuous live video.
|
|
501
|
+
|
|
502
|
+
### Manual publication mode
|
|
503
|
+
|
|
504
|
+
Advanced pipelines should publish rendered video as a variant instead of asking the user to pick an existing Transmission id.
|
|
349
505
|
|
|
350
|
-
|
|
506
|
+
User-facing fields:
|
|
507
|
+
|
|
508
|
+
- destination camera/group;
|
|
509
|
+
- source role: `main`, `sub`, `zoom`, or `custom`;
|
|
510
|
+
- visible label;
|
|
511
|
+
- whether the variant appears in the dashboard;
|
|
512
|
+
- whether the variant is exported to Home Assistant;
|
|
513
|
+
- quality profile override when needed.
|
|
514
|
+
|
|
515
|
+
Pipeline-owned publications use deterministic ids:
|
|
516
|
+
|
|
517
|
+
```text
|
|
518
|
+
pipeline:{pipeline_name}:{node_id}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
If the pipeline is disabled or removed, the publication and generated stream artifacts are disabled/removed by reconciliation.
|
|
522
|
+
|
|
523
|
+
## Advanced wizard: create pipeline from a Transmission
|
|
351
524
|
|
|
352
525
|
Endpoint:
|
|
353
526
|
- `POST /api/streams/wizard/create-pipeline`
|
|
@@ -368,6 +541,8 @@ Generated topology (high level):
|
|
|
368
541
|
Critical validation:
|
|
369
542
|
- `Transmission.host_server_id` must match the pipeline `processing_server_id` (wizard enforces this).
|
|
370
543
|
|
|
544
|
+
This wizard is an advanced/diagnostic shortcut. The normal camera flow is now camera source publication plus reconciliation.
|
|
545
|
+
|
|
371
546
|
## Bypass mode (publisher input optimization)
|
|
372
547
|
|
|
373
548
|
When a pipeline matches a "simple stream" shape, the writer bridge can switch publishers to `rtsp_pull`.
|
|
@@ -433,14 +608,29 @@ Core auth (enforced mode):
|
|
|
433
608
|
|
|
434
609
|
## UI behavior (Settings and Dashboard)
|
|
435
610
|
|
|
611
|
+
### Camera settings
|
|
612
|
+
|
|
613
|
+
For regular cameras, streaming is configured from the camera source itself:
|
|
614
|
+
|
|
615
|
+
- each video source can show a `Transmitir esta fonte` checkbox;
|
|
616
|
+
- the source role is used as the publication role (`main`, `sub`, `zoom`, `custom`);
|
|
617
|
+
- the visible source label becomes the publication label;
|
|
618
|
+
- ONVIF-discovered video sources can be published by default;
|
|
619
|
+
- saving the source triggers streaming reconciliation.
|
|
620
|
+
|
|
621
|
+
If the streaming extension is not active, camera settings should not expose streaming controls.
|
|
622
|
+
|
|
436
623
|
### Settings panel
|
|
437
624
|
|
|
438
|
-
The extension adds a Streaming panel in Settings where users can:
|
|
625
|
+
The extension adds a Streaming/advanced panel in Settings where users can:
|
|
439
626
|
|
|
440
|
-
-
|
|
627
|
+
- Inspect generated transmissions, outputs, live views, and runtime health.
|
|
628
|
+
- Create/edit manual transmissions and outputs for advanced diagnostics.
|
|
441
629
|
- Start/stop the engine.
|
|
442
630
|
- Resolve URLs (and best-effort prime demand).
|
|
443
|
-
- Create a pipeline from a transmission using the wizard.
|
|
631
|
+
- Create a pipeline from a transmission using the advanced wizard.
|
|
632
|
+
|
|
633
|
+
Generated artifacts are read-only in the normal UI. To change a generated camera stream, edit the camera source publication. To change a generated pipeline variant, edit the owning `stream.publish_video` node.
|
|
444
634
|
|
|
445
635
|
### Dashboard (Rendering -> Streams)
|
|
446
636
|
|
|
@@ -448,10 +638,27 @@ The main UI includes a "Streams" rendering mode with:
|
|
|
448
638
|
|
|
449
639
|
- Grid modes `1x1` and `2x2` with pagination.
|
|
450
640
|
- Auto-hide overlay.
|
|
641
|
+
- Source/role selector using camera variants, for example Principal, Baixa resolução, Zoom, or custom names.
|
|
451
642
|
- Playback strategy:
|
|
452
|
-
1.
|
|
453
|
-
2.
|
|
454
|
-
3.
|
|
643
|
+
1. Pick the best variant for the visual context.
|
|
644
|
+
2. Request the backend Playback Plan for that transmission/output/context.
|
|
645
|
+
3. Prime/heartbeat demand for the selected output.
|
|
646
|
+
4. Use the first available transport from the plan.
|
|
647
|
+
5. Monitor playback and fallback without surfacing non-blocking transport warnings as primary errors.
|
|
648
|
+
|
|
649
|
+
Default variant selection:
|
|
650
|
+
|
|
651
|
+
- grid/thumbnail/PiP: prefer `sub`;
|
|
652
|
+
- fullscreen/large: prefer `main`;
|
|
653
|
+
- PTZ/low latency: prefer `zoom`, then `main`;
|
|
654
|
+
- diagnostics/poor network: prefer the smallest available public variant.
|
|
655
|
+
|
|
656
|
+
Default transport policy:
|
|
657
|
+
|
|
658
|
+
- web grid/passive: `MSE -> HLS -> JSMpeg`; WebRTC is blocked unless low latency/PTZ is explicit;
|
|
659
|
+
- web PTZ/low latency: `WebRTC -> MSE -> HLS -> JSMpeg`;
|
|
660
|
+
- app and Home Assistant ingress: HLS-first;
|
|
661
|
+
- Home Assistant entity: no web player decision, use the HA camera contract.
|
|
455
662
|
|
|
456
663
|
Authentication in browser playback:
|
|
457
664
|
|
|
@@ -492,12 +699,24 @@ All endpoints are under `/api/streams`.
|
|
|
492
699
|
- `GET /api/streams/settings`
|
|
493
700
|
- `PATCH /api/streams/settings`
|
|
494
701
|
|
|
702
|
+
### Publications and reconciliation
|
|
703
|
+
- `GET /api/streams/publications?camera_id=...`
|
|
704
|
+
- `PUT /api/streams/publications/camera-sources/{camera_id}/{source_id}`
|
|
705
|
+
- `POST /api/streams/reconcile`
|
|
706
|
+
|
|
495
707
|
### Engine
|
|
496
708
|
- `GET /api/streams/engine/status`
|
|
497
709
|
- `POST /api/streams/engine/start`
|
|
498
710
|
- `POST /api/streams/engine/stop`
|
|
499
711
|
- `POST /api/streams/engine/restart`
|
|
500
712
|
|
|
713
|
+
### MSE sidecar
|
|
714
|
+
- `GET /api/streams/mse/status`
|
|
715
|
+
- `POST /api/streams/mse/download`
|
|
716
|
+
- `POST /api/streams/mse/start`
|
|
717
|
+
- `POST /api/streams/mse/stop`
|
|
718
|
+
- `POST /api/streams/mse/restart`
|
|
719
|
+
|
|
501
720
|
### Transmissions CRUD
|
|
502
721
|
- `GET /api/streams/transmissions`
|
|
503
722
|
- `POST /api/streams/transmissions`
|
|
@@ -506,18 +725,31 @@ All endpoints are under `/api/streams`.
|
|
|
506
725
|
|
|
507
726
|
### URL resolution
|
|
508
727
|
- `GET /api/streams/transmissions/{transmission_id}/urls` (local or proxy)
|
|
728
|
+
- `GET /api/streams/transmissions/{transmission_id}/playback-plan`
|
|
729
|
+
- `GET /api/streams/transmissions/{transmission_id}/hls/probe`
|
|
730
|
+
- `GET /api/streams/transmissions/{transmission_id}/still.jpg`
|
|
731
|
+
- `POST /api/streams/transmissions/{transmission_id}/webrtc/offer` (Home Assistant native WebRTC opt-in)
|
|
509
732
|
- `GET /api/streams/internal/transmissions/{transmission_id}/urls` (only on host server)
|
|
510
733
|
|
|
734
|
+
### Home Assistant
|
|
735
|
+
- `GET /api/streams/home-assistant/cameras`
|
|
736
|
+
|
|
511
737
|
### Distributed settings
|
|
512
738
|
- `GET /api/streams/distributed/settings/{server_id}`
|
|
513
739
|
|
|
514
740
|
### Runtime
|
|
515
741
|
- `GET /api/streams/runtime/outputs`
|
|
742
|
+
- `GET /api/streams/runtime/health`
|
|
743
|
+
- `GET /api/streams/runtime/pipelines`
|
|
744
|
+
- `GET /api/streams/runtime/observability`
|
|
745
|
+
- `GET /api/streams/runtime/diagnostic-snapshot`
|
|
516
746
|
- `GET /api/streams/runtime/diagnostics`
|
|
747
|
+
- `POST /api/streams/runtime/playback-events`
|
|
517
748
|
|
|
518
749
|
### Demand
|
|
519
750
|
- `GET /api/streams/transmissions/{transmission_id}/demand`
|
|
520
751
|
- `POST /api/streams/transmissions/{transmission_id}/demand/prime`
|
|
752
|
+
- `POST /api/streams/transmissions/{transmission_id}/demand/heartbeat`
|
|
521
753
|
|
|
522
754
|
### Wizard
|
|
523
755
|
- `POST /api/streams/wizard/create-pipeline`
|
|
@@ -559,12 +791,82 @@ Transmission URLs (`GET /api/streams/transmissions/{id}/urls`):
|
|
|
559
791
|
"url": "http://127.0.0.1:8888/front-door/index.m3u8",
|
|
560
792
|
"requires_auth": false,
|
|
561
793
|
"auth_username": null
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
"output_id": "hls_main",
|
|
797
|
+
"protocol": "mse",
|
|
798
|
+
"resolved_engine_path": "front-door",
|
|
799
|
+
"url": "ws://127.0.0.1:8100/api/streams/media/mse/front-door/ws?media_token=...",
|
|
800
|
+
"requires_auth": false,
|
|
801
|
+
"auth_username": null
|
|
562
802
|
}
|
|
563
803
|
],
|
|
564
804
|
"warnings": []
|
|
565
805
|
}
|
|
566
806
|
```
|
|
567
807
|
|
|
808
|
+
Playback plan (`GET /api/streams/transmissions/{id}/playback-plan?client=web&context=fullscreen`):
|
|
809
|
+
|
|
810
|
+
```json
|
|
811
|
+
{
|
|
812
|
+
"transmission_id": "uuid",
|
|
813
|
+
"client": "web",
|
|
814
|
+
"selected_transport": "mse",
|
|
815
|
+
"transports": [
|
|
816
|
+
{
|
|
817
|
+
"transport": "mse",
|
|
818
|
+
"rank": 0,
|
|
819
|
+
"available": true,
|
|
820
|
+
"output_id": "hls_fullscreen_quality",
|
|
821
|
+
"url": "ws://127.0.0.1:8100/api/streams/media/mse/front-door/ws?media_token=...",
|
|
822
|
+
"fallback_rank": 0
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"transport": "hls",
|
|
826
|
+
"rank": 1,
|
|
827
|
+
"available": true,
|
|
828
|
+
"output_id": "hls_fullscreen_quality",
|
|
829
|
+
"url": "http://127.0.0.1:8100/api/streams/media/hls/...",
|
|
830
|
+
"fallback_rank": 1
|
|
831
|
+
}
|
|
832
|
+
],
|
|
833
|
+
"hls_warnings": [],
|
|
834
|
+
"webrtc_warnings": []
|
|
835
|
+
}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Transport policy:
|
|
839
|
+
|
|
840
|
+
- HLS is the stable browser/app/Home Assistant ingress baseline.
|
|
841
|
+
- WebRTC/WHEP is generated for `zoom`/PTZ publications and for publications with `transport_policy.enable_webrtc=true`; regular `main`/`sub` streams stay HLS-only by default.
|
|
842
|
+
- MSE is available when MediaMTX is running, the go2rtc sidecar is enabled/running, a backing HLS/RTSP output exists, and the browser codec path is compatible. Otherwise it is blocked with a specific reason.
|
|
843
|
+
- JSMpeg is available when FFmpeg is available, the fallback is enabled, a backing HLS output exists, and session limits allow it. The fixed transport debug page does not silently fall back.
|
|
844
|
+
|
|
845
|
+
Transport frame checks can be run with:
|
|
846
|
+
|
|
847
|
+
```bash
|
|
848
|
+
node scripts/check_stream_transport_frames.mjs --base-url http://127.0.0.1:8100 --matrix --transports hls,webrtc,mse,jsmpeg
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
Camera source publication (`GET /api/streams/publications?camera_id=front`):
|
|
852
|
+
|
|
853
|
+
```json
|
|
854
|
+
[
|
|
855
|
+
{
|
|
856
|
+
"id": "camera:front:sub",
|
|
857
|
+
"owner_kind": "camera_source",
|
|
858
|
+
"camera_id": "front",
|
|
859
|
+
"camera_source_id": "sub",
|
|
860
|
+
"enabled": true,
|
|
861
|
+
"role": "sub",
|
|
862
|
+
"label": "Baixa resolução",
|
|
863
|
+
"host_server_id": "local",
|
|
864
|
+
"quality_policy": {},
|
|
865
|
+
"transport_policy": {}
|
|
866
|
+
}
|
|
867
|
+
]
|
|
868
|
+
```
|
|
869
|
+
|
|
568
870
|
Demand (`GET /api/streams/transmissions/{id}/demand`):
|
|
569
871
|
|
|
570
872
|
```json
|
|
@@ -578,7 +880,31 @@ Demand (`GET /api/streams/transmissions/{id}/demand`):
|
|
|
578
880
|
}
|
|
579
881
|
```
|
|
580
882
|
|
|
581
|
-
## Practical quickstart
|
|
883
|
+
## Practical quickstart
|
|
884
|
+
|
|
885
|
+
### Camera-source flow
|
|
886
|
+
|
|
887
|
+
For normal use:
|
|
888
|
+
|
|
889
|
+
1. Add/discover a camera in the Cameras extension.
|
|
890
|
+
2. Keep `Transmitir esta fonte` enabled on the desired video sources.
|
|
891
|
+
3. Save the camera/source.
|
|
892
|
+
4. The streaming reconciler creates the live view, generated transmissions, outputs, and implicit pipelines.
|
|
893
|
+
5. Open the dashboard and select the camera/source role.
|
|
894
|
+
|
|
895
|
+
The direct streaming API for that intent is:
|
|
896
|
+
|
|
897
|
+
```bash
|
|
898
|
+
curl http://127.0.0.1:8100/api/streams/publications?camera_id=<camera_id>
|
|
899
|
+
|
|
900
|
+
curl -X PUT http://127.0.0.1:8100/api/streams/publications/camera-sources/<camera_id>/<source_id> \
|
|
901
|
+
-H 'content-type: application/json' \
|
|
902
|
+
-d '{"enabled": true, "role": "sub", "label": "Baixa resolução"}'
|
|
903
|
+
|
|
904
|
+
curl -X POST http://127.0.0.1:8100/api/streams/reconcile
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
### Advanced manual flow (curl + ffplay)
|
|
582
908
|
|
|
583
909
|
Start the engine:
|
|
584
910
|
|
|
@@ -664,6 +990,38 @@ Fix:
|
|
|
664
990
|
- Check `GET /api/streams/engine/status`.
|
|
665
991
|
- Use `GET /api/streams/runtime/diagnostics` and inspect `engine`, `publisher`, and `runtime_state`.
|
|
666
992
|
|
|
993
|
+
### Dashboard says no pipeline is feeding the stream
|
|
994
|
+
Likely causes:
|
|
995
|
+
- The camera source publication is disabled.
|
|
996
|
+
- Generated implicit pipeline was removed or disabled.
|
|
997
|
+
- The manual pipeline that owns a variant is disabled.
|
|
998
|
+
- `stream.publish_video` has not received a frame yet.
|
|
999
|
+
|
|
1000
|
+
Fix:
|
|
1001
|
+
- For camera streams, check the camera source and keep `Transmitir esta fonte` enabled.
|
|
1002
|
+
- Call `POST /api/streams/reconcile`.
|
|
1003
|
+
- Check `GET /api/streams/runtime/pipelines` to see which pipeline owns the generated transmission.
|
|
1004
|
+
- Check `GET /api/streams/runtime/health` for `active_writer_id`, `selected_writer_id`, `fallback_reason`, and frame age.
|
|
1005
|
+
|
|
1006
|
+
The primary user-facing message for this class is:
|
|
1007
|
+
|
|
1008
|
+
```text
|
|
1009
|
+
Nenhuma pipeline está alimentando esta transmissão.
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### HLS plays but WebRTC warning appears
|
|
1013
|
+
If the effective transport is HLS and the HLS probe is healthy, WebRTC network warnings are technical diagnostics only.
|
|
1014
|
+
|
|
1015
|
+
Common causes:
|
|
1016
|
+
- Home Assistant add-on did not publish the UDP WebRTC port.
|
|
1017
|
+
- The browser is remote or behind NAT without TURN/ICE reachability.
|
|
1018
|
+
- The context is HA ingress, where direct Toposync WebRTC is blocked by default.
|
|
1019
|
+
|
|
1020
|
+
Fix:
|
|
1021
|
+
- Keep HLS as the stable path for HA/app/passive views.
|
|
1022
|
+
- Use WebRTC only for explicit low-latency/PTZ contexts.
|
|
1023
|
+
- For HA Cloud, use the native Home Assistant camera entity path.
|
|
1024
|
+
|
|
667
1025
|
### RTSP returns 401 Unauthorized
|
|
668
1026
|
The output requires authentication.
|
|
669
1027
|
|
|
@@ -725,6 +1083,7 @@ Then run Toposync as usual (see repo `docs/DEVELOPMENT.md`).
|
|
|
725
1083
|
|
|
726
1084
|
- Public wheels do not ship MediaMTX binaries. The extension downloads the correct release asset on demand and caches it under `runtime/streaming/mediamtx/<version>/<platform>/`.
|
|
727
1085
|
- License notice: [LICENSE.mediamtx](LICENSE.mediamtx)
|
|
1086
|
+
- Public wheels do not ship go2rtc binaries. The MSE sidecar downloads go2rtc `v1.9.14` on demand and caches it under `runtime/streaming/go2rtc-bin/<version>/<platform>/`, unless `TOPOSYNC_STREAMING_GO2RTC_PATH` points to an explicit binary.
|
|
728
1087
|
- FFmpeg integration expects an external binary by default (`PATH` or `TOPOSYNC_STREAMING_FFMPEG_PATH`). Bundling FFmpeg binaries is optional and must be handled carefully for redistribution.
|
|
729
1088
|
- License placeholder: [LICENSE.ffmpeg](LICENSE.ffmpeg)
|
|
730
1089
|
|
|
@@ -735,5 +1094,7 @@ If you plan to ship FFmpeg binaries, pay attention to LGPL/GPL build flags and c
|
|
|
735
1094
|
- Video-only: audio is not published (`-an` in FFmpeg).
|
|
736
1095
|
- No built-in TLS for MediaMTX endpoints (LAN-first).
|
|
737
1096
|
- No Low-Latency HLS by default (to avoid TLS requirements and keep the default simpler).
|
|
1097
|
+
- MSE requires a running go2rtc sidecar and browser-compatible codec output. HEVC/H.265 paths must be transcoded to H.264/AAC-compatible browser output before MSE can be selected.
|
|
1098
|
+
- JSMpeg is video-only and intentionally low quality. It is a last-resort visual fallback, not a replacement for HLS/MSE/WebRTC and not an audio path.
|
|
738
1099
|
- Hardware encoding selection exists in code paths but is not exposed as a stable user-facing setting yet.
|
|
739
|
-
- On-demand stops publishers, but does not stop pipeline execution; pipeline compute is controlled by pipeline configuration and lifecycle semantics.
|
|
1100
|
+
- On-demand stops publishers, but does not stop arbitrary manual pipeline execution; pipeline compute is controlled by pipeline configuration and lifecycle semantics.
|