feat: encode on the GPU and restart individual renditions
Hardware encoding
- Detect the best usable encoder at startup by encoding a test frame with each
candidate in turn (nvenc, qsv, amf, then libx264). Being compiled into ffmpeg
is not enough: h264_amf fails without amfrt64.dll and h264_qsv fails without an
Intel iGPU, so the probe is the only reliable answer.
- Translate the quality target into the chosen encoder's own vocabulary. libx264's
-crf and "ultrafast" mean nothing to h264_nvenc, which takes -cq and p1..p7, so
passing the configured values straight through would have been silently wrong.
- On the reference GTX 1060 a 1080p->720p rendition costs ~62% of a core on NVENC
versus ~109% on libx264 ultrafast.
Per-rendition supervision
- Track encoder processes per rendition, not per stream. is_running answered
"any alive", so when the source ("原画") encoder died while 1080p and 720p kept
running, the supervisor saw a healthy stream and never restarted it — the
source URL then 404'd permanently. It now requires every rendition to be alive
and reports which ones are down.
- Restart only the dead renditions, so a single failure no longer interrupts
viewers on the renditions that were fine.
Production serving
- Serve the built frontend from FastAPI with SPA fallback, so production is one
process and one port with no Node runtime. Node becomes a build-time dependency.
- start.ps1/start.sh build the frontend on first run instead of failing to a 503.
Cleanup
- Drop the duplicated top-left LIVE badge; the control strip already carries it.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
1 parent
996e3fea39
commit
4ee945ca0d
7 files changed
+394
-111
No files matched your search
+43
-6
@@ -22,27 +22,64 @@ Required on PATH: Python 3.11+, FFmpeg, and MediaMTX. MediaMTX may instead be le
|
||||
powershell -ExecutionPolicy Bypass -File .\start.ps1 -InstallDeps
|
||||
```
|
||||
|
||||
### 3. Start the stack
|
||||
### 3. Build the frontend
|
||||
|
||||
Once per deployment, and again whenever the frontend changes. The build output is
|
||||
committed to the server by the build step and then served by the backend itself,
|
||||
so **Node.js is a build-time dependency only** — production runs without it and
|
||||
without a Vite dev server.
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build
|
||||
cd ..
|
||||
```
|
||||
|
||||
Skipping this is not silent: the backend answers every page with HTTP 503 and
|
||||
`s Frontend not built` until `frontend\dist` exists.
|
||||
|
||||
### 4. Start the stack
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\start.ps1
|
||||
```
|
||||
|
||||
This starts the FastAPI backend on 0.0.0.0:8080. The backend owns everything else:
|
||||
This starts one process on 0.0.0.0:8080 that owns everything:
|
||||
|
||||
- **The frontend** is served from `frontend\dist` on the same port. Unknown paths
|
||||
return the app shell so client-side routes survive a refresh.
|
||||
- **MediaMTX** is started at boot if nothing is already answering its API on :9997, and restarted by the supervisor if it dies. Set `LS_MEDIA_ORIGIN_AUTOSTART=false` to manage it externally; the backend then only supervises transcoders.
|
||||
- **Transcoders** are started for every live stream whose MediaMTX path is publishing, and restarted within ~10s of an ffmpeg process exiting.
|
||||
- **Transcoders** are started for every live stream whose MediaMTX path is publishing, and restarted within ~10s of an ffmpeg process exiting. They encode on the GPU when one is available (see below).
|
||||
- **HLS** is written under `runtime\hls` and served through `GET /hls/...`, which falls back to proxying MediaMTX's own HLS when the local files are absent.
|
||||
|
||||
Publish RTMP to rtmp://127.0.0.1:1935/live/<stream_key>. Backend docs are at http://127.0.0.1:8080/docs.
|
||||
Open http://127.0.0.1:8080/ for the site and /docs for the API. Publish RTMP to
|
||||
rtmp://127.0.0.1:1935/live/<stream_key>.
|
||||
|
||||
### 4. Useful variants
|
||||
### Hardware encoding
|
||||
|
||||
The transcoders detect the best encoder the host actually has, at startup, by
|
||||
encoding a test frame with each candidate in turn:
|
||||
|
||||
1. `h264_nvenc` / `hevc_nvenc` (NVIDIA)
|
||||
2. `h264_qsv` (Intel iGPU)
|
||||
3. `h264_amf` (AMD)
|
||||
4. `libx264` (CPU fallback)
|
||||
|
||||
Only encoders that really work are used — being compiled into ffmpeg is not
|
||||
enough, since `h264_amf` fails without `amfrt64.dll` and `h264_qsv` fails without
|
||||
an Intel iGPU. The choice is logged at startup as `[transcoder] hardware encoder:
|
||||
…`, or `[transcoder] no working hardware encoder; falling back to libx264` with
|
||||
the probed candidates listed. On the reference GTX 1060, one 1080p→720p
|
||||
rendition costs ~62% of a core on NVENC versus ~109% on libx264 ultrafast.
|
||||
|
||||
### 5. Useful variants
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\start.ps1 -HostAddress 0.0.0.0 -BackendPort 8080
|
||||
```
|
||||
|
||||
### 5. Smoke test commands
|
||||
### 6. Smoke test commands
|
||||
|
||||
```powershell
|
||||
curl.exe http://127.0.0.1:8080/api/health
|
||||
|
||||
Reference in new issue
Block a user