diff --git a/TASKS/task-04-rtmp-ingest.md b/TASKS/task-04-rtmp-ingest.md index a1a3be2..c83f280 100644 --- a/TASKS/task-04-rtmp-ingest.md +++ b/TASKS/task-04-rtmp-ingest.md @@ -26,6 +26,9 @@ until a frame source exists, so the compositor is ship step 1. The pipeline is 1. **Encoding** — H.264 (hardware via NVENC/AMD, fallback x264) + AAC audio; **must comply**: keyframes ≤ 4s (gopSizeLong), closed GOP, AAC/MP3 @ 44.1/48kHz, mono/stereo only. **License posture (decided): GPL-free build** — NVENC (NVIDIA) / QSV (Intel) / AMF (AMD) + OpenH264 software fallback + built-in AAC; no libx264 (GPL contaminates a paid product). Output containers are identical either way (H.264+AAC in `.flv` for RTMP, `.mp4`/`.ts` for VOD) — the format is NOT the differentiator, the license and per-GPU quality are. **License guardrails (never violate — see `ai.md` → "Licensing — do not violate"):** only BtbN `lgpl`/`lgpl-shared` builds; never GPL (gyan.dev) or `nonfree` (fdk-aac); never static for distribution (LGPL §6 relink material); never link FFmpeg into the app; never drop `THIRD-PARTY-NOTICES.txt` from the app/About screen. 2. **RTMP push** — **FFmpeg subprocess (decided)**: app feeds raw frames via stdin, parses stderr for health; one battle-tested binary does encode + FLV mux + push. **No self-heal (claim-check 2026-09-01): ffmpeg's reconnect flags are input-side; an RTMP *output* push does not reconnect itself — retry is app-side, owned by TASK 32.** **Binary distribution (decided): check-then-pull** — probe `where ffmpeg`/PATH at first go-live; if absent, download a **pinned** build (**BtbN LGPL-shared win64** zip, ~75 MB — gyan.dev's builds are GPLv3 and ship libx264, which violates the license posture; BtbN's LGPL variant drops x264/x265 while keeping NVENC/QSV/AMF + libopenh264 + native AAC) to `%APPDATA%\ytLlive\tools\ffmpeg.exe` (extract `ffmpeg.exe` **plus the `libav*.dll` family**) and cache it, offline-friendly. Behind an `IFfmpegLocator` seam so tests fake it (ship step 2, below). Push goes to the cached reusable stream's ingestion URL 3. **Quality ladder** — the offered tiers, with **1080p60 @ 8 Mbps as the standard/default**: + > **Superseded 2026-11-12:** the shipped ladder is 1080p60@12, 1080p30@10, 720p@6, vertical mirroring + > its landscape pair, and the rate is CBR (`docs/ai/ui-surface.md`, `docs/ai/output.md`). The numbers + > below are the original decision, recorded as history — the flat 8 was never derived from anything. 1. 720p30 @ 6 Mbps 2. 720p60 @ 6 Mbps 3. 1080p30 @ 8 Mbps diff --git a/TASKS/task-33-bandwidth-step-down.md b/TASKS/task-33-bandwidth-step-down.md index 433d4bc..2bafd2a 100644 --- a/TASKS/task-33-bandwidth-step-down.md +++ b/TASKS/task-33-bandwidth-step-down.md @@ -37,6 +37,9 @@ that step relieves nothing. Fps is **not** a congestion lever: same bitrate, sam | 720p60 | **1** | 720p30 @ 4.8 Mbps | | Vertical 1080p60 | **1** | Vertical 1080p30 @ 6.4 Mbps | +> **Superseded 2026-11-12:** the bitrate floor is the tier's YouTube minimum — 6 Mbps at 1080p60, 5 at +> 1080p30, 3 at 720p (`Models/RateLadder`, passed into `StepDownPolicy`) — and the ladder's defaults are +> 12/10/6. The table above records the 8-Mbps-era examples, not current output. - Floors: 16:9 never below **720p30**; vertical never below **Vertical 1080p30**. - Budget exhausted → **hold**, keep streaming, one persistent warning naming the cause, manual step-up stays available. Never disconnect, never nag repeatedly.