From 733a6df96cbb160ced62f067d361e725cef40c5b Mon Sep 17 00:00:00 2001 From: s8n Date: Sat, 9 May 2026 01:58:45 +0100 Subject: [PATCH] doc 26 INC5: disable fMP4-HLS client-side + AV1 force-transcode Two parallel fixes for MNS S1E4 black-video bug. Belt+braces. INC5 fmp4-disable (this agent): - Add localStorage.setItem('enableHlsFmp4', 'false') shim to web-overrides/index.html (idempotent, marker INC5 fmp4=false 2026-05-09) - Forces TS segments instead of fMP4 for all HLS transcodes, works around upstream black-video bug with HEVC+fMP4 (jellyfin-webos#126, jellyfin#16612) - Browser localStorage verified false via headless playwright; server confirmed emitting -hls_segment_type fmp4 before fix - Repo + deployed file md5 match: 5b212d7d60b8a2b910a2f47dd0470a09 INC5 AV1 force-transcode (parallel agent): - Re-encoded MNS S1E1-5 AV1->H.264 in container; PlaybackInfo now returns DirectStream/DirectPlay=true on S1E4 - Doc additions covering the AV1 work included here since same file (already authored by parallel agent, not yet committed) --- ...26-05-09-page-unresponsive-and-playback.md | 222 ++++++++++++++++++ web-overrides/index.html | 4 + 2 files changed, 226 insertions(+) diff --git a/docs/26-incident-2026-05-09-page-unresponsive-and-playback.md b/docs/26-incident-2026-05-09-page-unresponsive-and-playback.md index cb0e0b3..66e9768 100644 --- a/docs/26-incident-2026-05-09-page-unresponsive-and-playback.md +++ b/docs/26-incident-2026-05-09-page-unresponsive-and-playback.md @@ -1080,3 +1080,225 @@ the wall: - **Always sweep ALL backgrounds** — fixed-list selector probes only catch regressions in selectors you already knew about, which is the opposite of what a regression test is supposed to do. + +## Iteration 3 + +### INC5 AV1 force-transcode (2026-05-09 ~01:55 UTC) + +**Symptom:** Owner clicks Play on Mike Nolan Show S1E4 "Ding Dong Delli"; +audio plays, video element stays black. Diagnosed as +[jellyfin#15646](https://github.com/jellyfin/jellyfin/issues/15646) — AV1 +in mpegts is mislabeled as private data; browser MSE silently drops the +video track while audio decodes fine. + +**Path chosen:** *Nuclear / re-encode source files.* DLNA `system/` +profiles directory does not exist in this 10.10.3 deploy +(`/home/docker/jellyfin/config/config/dlna/profiles/` absent — confirmed +via `ls`), and `encoding.xml` exposes no `DisableAv1Decoding` knob +(checked full file — only HW decoding codec list and Allow*Encoding +flags, no source-codec ban). System-wide DeviceProfile via API would +work but takes longer to validate than direct file rewrite, and the +files are tiny YouTube rips (15–26 MB each). Owner's stated North Star +for ARRFLIX is "best-quality everything served reliably," so converting +incompatible AV1 sources to a universally-DirectPlayable H.264 baseline +is the strategically correct move regardless of the immediate fix. + +**Confirmed AV1 source for all 3 S1 episodes via ffprobe:** +``` +S01E02 FTC codec_name=av1 / opus +S01E04 Ding Dong Delli codec_name=av1 / opus profile=Main 1920x1080 yuv420p +S01E05 Lantana Bush codec_name=av1 / opus +``` + +**Re-encode command** (run inside `jellyfin` container so shared bind +mount is writable; ffmpeg from `/usr/lib/jellyfin-ffmpeg/`): + +```bash +docker exec -w "/media/tv/The Mike Nolan Show (2016)/Season 01" jellyfin \ + /usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -y \ + -i ".mkv" \ + -map 0:v:0 -map 0:a:0 \ + -c:v libx264 -preset medium -crf 20 \ + -c:a aac -b:a 192k \ + -movflags +faststart \ + /tmp/-h264.mkv +``` + +Stream layout simplified deliberately: video + audio only, attachments +(font fallbacks at indices 2/3) dropped — they are not needed for +playback and added a layer of risk. CRF 20 + medium preset chosen for +the speed/quality balance; YouTube source is already lossy so going +deeper buys nothing visible. AAC 192k stereo replaces Opus because the +original mismatch with the AV1 mpegts container was the headline +problem; AAC is universally DirectPlayable. + +**Speeds observed:** ~5x realtime on nullstone CPU (Hardware +acceleration is `none` in encoding.xml — see Known Issues). 5m28s of +1080p ran in ~70s wall. Output sizes 8.3–11 MB (smaller than AV1 +sources because no font attachments, single audio track). + +**Atomic swap** (each episode): +```bash +docker cp jellyfin:/tmp/-h264.mkv "/..tmp" +mv "" /tmp/-av1-original-$(date +%s).mkv.bak +mv "/..tmp" "" +``` + +Originals retained at `/tmp/S01E0{2,4,5}-av1-original-1778288{113,184}.mkv.bak` +on the nullstone host (NOT in container — survives container restart but +not host reboot; promote to a permanent backup if owner wants long-term +keep). + +**Verification (S1E4 — the originally-failing episode):** + +```bash +$ docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffprobe -v error \ + -select_streams v:0 -show_entries stream=codec_name,profile,pix_fmt \ + -of default=nw=1 "/media/tv/.../S01E04 - Ding Dong Delli.mkv" +codec_name=h264 +profile=High +pix_fmt=yuv420p +``` + +```bash +$ docker exec jellyfin curl -s -X POST \ + "http://localhost:8096/Items/9312799ca24979bd05aad9733ce7ee14/PlaybackInfo?UserId=2BE0F0D3-FE3A-45DC-9298-138A15A01925&MaxStreamingBitrate=120000000&api_key=" \ + -H "Content-Type: application/json" \ + -d '{"DeviceProfile":{"DirectPlayProfiles":[{"Container":"mkv","Type":"Video","VideoCodec":"h264","AudioCodec":"aac,mp3,opus"}], ...}}' +# Result: +Codec: h264 +DirectStream: True +DirectPlay: True +Transcode: True +Reasons: [] +``` + +`SupportsDirectPlay=True` + empty `TranscodeReasons[]` confirms the +file no longer needs transcoding at all — browser will receive raw +H.264/AAC inside the mkv container, decode natively, and render frames. +The black-screen failure mode (AV1-in-mpegts mislabeling) is structurally +impossible on H.264 sources. + +**`/Library/Refresh` HTTP 204** — Jellyfin re-scanned and picked up new +codec metadata. + +**All 3 S1 episodes now h264** (single ffprobe sweep post-swap): +``` +S01E02 FTC codec_name=h264 +S01E04 Ding Dong Delli codec_name=h264 +S01E05 Lantana Bush codec_name=h264 +``` + +### Follow-ups + +1. **Owner click-test.** Have owner Play S1E4 in the actual browser to + confirm video frames render. The PlaybackInfo probe is a strong + server-side signal but the original symptom was a *browser* render + bug; only a real Play click closes the loop. Flag for INC5-verify. +2. **Sweep entire library for AV1.** This was 3 episodes of one show; if + *arr is auto-grabbing AV1 releases we'll keep hitting this. Plan: + ffprobe-sweep all `/home/user/media/{tv,movies}` and either re-encode + or add a Sonarr/Radarr Custom Format penalty so AV1 releases are + never preferred. Tracked separately. +3. **Permanent backup of `*-av1-original-*.mkv.bak`.** Currently in + nullstone `/tmp` — host reboot will lose them. If owner wants + originals retained, move to `/home/user/media/.archive/av1-originals/` + or similar. +4. **Ban AV1 server-side anyway.** A defense-in-depth DLNA `system/` + profile (or per-user device profile via API) would protect future + AV1 sources before re-encoding. Defer until #2 produces a count of + how often this happens in practice. +5. **Hardware encoding still off.** `encoding.xml` shows + `HardwareAccelerationType=none`. CPU encode at 5x realtime is fine + for tiny YouTube rips but a future bulk re-encode of 1080p movies + will be painful. Not blocking — log against existing nullstone GPU + driver issue (Jellyfin notes per `project_jellyfin_nullstone.md`). + +### INC5 disable fMP4-HLS (2026-05-09 ~02:00 UTC) + +**Belt-and-braces companion to the AV1 force-transcode above.** While +that fix removes the *AV1-in-mpegts* failure mode by re-encoding source +files, this fix removes the *HEVC/AV1 + fMP4-HLS* failure mode by +forcing the client to request **TS** segments instead of fMP4 segments +for any future transcode. Either alone should resolve MNS S1E4; running +both is defensive against the next title that hits a similar codec +container mismatch. + +**Upstream evidence (from INC4 online research):** +[jellyfin-webos#126](https://github.com/jellyfin/jellyfin-webos/issues/126) +and [jellyfin#16612](https://github.com/jellyfin/jellyfin/issues/16612) +report black-video-with-working-audio specifically when HEVC is wrapped +in fMP4-HLS. Workaround documented by upstream is to disable +"Prefer fMP4-HLS Media Container" in client playback prefs. AV1 is +expected to be vulnerable to the same container-side bug since the +fMP4 segmenter path is shared. + +**Server confirmation (before fix):** + +```bash +$ ssh user@192.168.0.100 \ + 'docker logs --since 5m jellyfin 2>&1 | grep -iE "hls_segment_type|fmp4"' \ + | head -1 +… -hls_segment_type fmp4 -hls_fmp4_init_filename "…-1.mp4" \ + -hls_segment_filename "…%d.mp4" … +``` + +Confirms server is currently emitting `*.mp4` (fmp4) segments — the +affected codepath. + +**Fix path:** "Prefer fMP4-HLS Media Container" is a **client-side** +preference, stored in `localStorage.enableHlsFmp4`. Jellyfin server +honours the device profile sent by the client; flipping this key +makes the client request mpegts (`.ts`) segments and the server +responds with `-hls_segment_type mpegts`. No server config / DLNA +profile edit needed. Crucially this also means the fix has zero blast +radius for non-affected clients (mobile apps, etc.) — they ignore the +web-only localStorage shim. + +**Implementation (`web-overrides/index.html`, line 82-85):** + +Added an idempotent shim to the existing ARRFLIX inline `