M7 — DASH partial: MPD serves OK, segment alignment still WIP

Big strides today:
- Sidecar resolve_dash op works (verified live on Pi)
- MPD builder generates valid MPEG-DASH on-demand manifest with
  H.264 720p/1080p video reps + best AAC audio rep
- ThreadingHTTPServer serves the MPD over the LAN IP (not 127.0.0.1
  — curl in Kodi 20's inputstream.adaptive can't open that)
- inputstream.adaptive PARSES our manifest cleanly: 'Successfully
  parsed manifest file (Periods: 1, Streams in first period: 2)'
- Segment GETs work once we set stream_headers with User-Agent
  + Origin + Referer (otherwise googlevideo 403s the audio segments)

Remaining issue:
- Audio drifts -25s → -44s behind video within seconds of playback
  start. inputstream.adaptive needs explicit SegmentTimeline timing
  derived from each rep's sidx box to stay aligned. Plugin.video.youtube
  does this; we'd need to fetch+parse sidx ourselves or fork their
  MPD-builder. Documented as M7-blocking + upstream PR candidate.

Default remains the stable yt-dlp progressive 360p path. DASH is
behind dash_enabled setting OR a dash.on marker file in addon_data.
Toggle on via:
  ssh <kodi> 'touch /storage/.kodi/userdata/addon_data/plugin.video.torttube/dash.on'
Toggle off:
  ssh <kodi> 'rm /storage/.kodi/userdata/addon_data/plugin.video.torttube/dash.on'

Addon v0.0.10. docs/upstream.md has the full segment-timing analysis.
This commit is contained in:
Kayos 2026-05-23 11:46:56 -07:00
parent a784321759
commit 0a289fea3a
4 changed files with 117 additions and 31 deletions

View file

@ -86,21 +86,34 @@
progressive) is deprecated by YouTube; higher quality needs DASH
manifest generation. Code path exists, gated behind `TORTTUBE_DASH=1`.
## M7 — DASH / HD playback [WIP]
## M7 — DASH / HD playback [WIP — close on segment timing]
- [x] sidecar `resolve_dash` op returns rustypipe's full
`video_only_streams` + `audio_streams` arrays (16+ representations)
- [x] addon `_build_dash_mpd` constructs valid on-demand MPD with H.264
video reps from 360p → 1080p + best AAC audio rep (XML-escaped URLs,
proper `SegmentBase indexRange` + `Initialization range`)
- [ ] **serve MPD over localhost HTTP** — inputstream.adaptive's libcurl
can't open `file://` URLs. ThreadingHTTPServer + Player monitor
lifecycle is sketched but caused Kodi's "two concurrent busydialogs"
fatal during rapid retries. Needs more work on lifecycle + retry
backoff before re-enabling.
- [ ] handle session-cookie / poToken inheritance — googlevideo URLs may
need the same client signature across MPD + segment fetches
- [ ] graceful fallback to progressive if MPD load fails mid-playback
video reps (filtered 720p-1080p so inputstream.adaptive's conservative
chooser doesn't land below HD) + best AAC audio rep, XML-escaped URLs,
proper `SegmentBase indexRange` + `Initialization range`
- [x] **serve MPD over localhost HTTP** — ThreadingHTTPServer binds to LAN IP
(not 127.0.0.1 — that fails curl auth in Kodi 20). Lifecycle: server
stays up until SponsorBlockMonitor exits, then `server.shutdown()` in
finally block. **Verified live: inputstream.adaptive parses the MPD
cleanly**.
- [x] `inputstream.adaptive.stream_headers` set with `User-Agent`, `Origin`,
and `Referer` matching what rustypipe / yt-dlp use when minting the
URL — fixes the 403 Forbidden from googlevideo on segment GETs
- [ ] **segment timing alignment** — audio drifts -25 → -44s behind video
within seconds. Need explicit `<SegmentTimeline>` per-segment timing
derived from each representation's sidx box, OR `presentationTimeOffset`.
Plugin.video.youtube derives these from sidx — we'd need to fetch + parse
that. See `docs/upstream.md` for the upstream PR target.
- [x] graceful fallback to progressive — if the DASH path returns no MPD
bytes (rustypipe error, no H.264 reps, etc.) the addon falls through
to yt-dlp progressive 360p
- [x] **gated behind `dash_enabled` setting** (default off) and a
`dash.on` marker file in addon_data (workaround for Kodi's settings
cache, useful for ad-hoc testing). Stable 360p path remains the
default until segment timing is solved.
## Upstream PR work (parallel lane — every bug evaluated for "fix it upstream?")