Skip to content

feat(player): SABR playback (chunk-based, seekable)#47

Open
Priveetee wants to merge 29 commits into
InfinityLoop1308:devfrom
Priveetee:feat/sabr-client
Open

feat(player): SABR playback (chunk-based, seekable)#47
Priveetee wants to merge 29 commits into
InfinityLoop1308:devfrom
Priveetee:feat/sabr-client

Conversation

@Priveetee
Copy link
Copy Markdown
Contributor

@Priveetee Priveetee commented Jun 5, 2026

First real integration of SABR playback (supersedes the PoC #43). Built on the media3 migration #45 and the extractor PR InfinityLoop1308/PipePipeExtractor#69. Tracking: #42.

Docs (how SABR works end to end): https://priveetee.github.io/Docs-PipePipe/developer-guide/introduction

Related:

Summary

Plays YouTube SABR streams on media3 through a proper chunk-based MediaSource (like DASH/HLS), so seeking is real. One source carries both audio and video; a background pump fills a shared segment cache and the chunks read it, so neither track starves the other on a round-trip. The PO token is minted in a headless WebView (BotGuard), cached per videoId.

Changes

  • SabrMediaSource / SabrMediaPeriod / SabrChunkSource / SabrSegmentDataSource: SABR exposed to media3 via the chunk framework. Loading is driven by chunk index (mapped from time), so seek is time-based and lands. Each chunk is a self-contained init + fragment; the extractor is picked by container (VP9/Opus = WebM, AVC/AAC = fragmented mp4).
  • SabrStreamPump / SabrSessionStore: background pump fills the shared segment cache; pacing + eviction follow what each track has actually read.
  • WebViewPoTokenProvider + the WebView script: headless BotGuard PO token, cached per videoId.
  • wire DeliveryMethod.SABR into PlaybackResolver (one SabrMediaSource per video, audio + video).
  • LoadController: cap the player buffer (time over size); largeHeap for headroom.
  • SabrSessionStore format pick: hardware-friendly, and honours the chosen resolution. When the preferred itag's codec isn't HW-decodable (e.g. AV1 1080p on a phone with no HW AV1 like the Pixel 8), it falls back to a decodable codec at the same resolution instead of the highest, which was landing on VP9 4K and hitting the decoder wall.
  • backward seek: a back-buffer keeps short rewinds in cache; bigger rewinds re-request the target from the server (the session's buffered head was one-way before); the back-buffer shrinks when the cache goes over budget so a high-bitrate stream can't throttle-deadlock.

Why

The PoC #43 and the first byte-stream version played but could not seek: media3 seeks a progressive source by byte offset and the byte-skip never landed, so any seek hung on an endless buffer. A chunk MediaSource loads by chunk index from the seek time, so it actually lands.

Impact / Compatibility

Additive on the player side: a new SABR datasource/ set + a DeliveryMethod.SABR branch in the resolver. Existing HLS/DASH/progressive playback is untouched (the SABR path only runs for streams the extractor marks SABR).

Validation

  • JAVA_HOME=<jdk25> ./gradlew :app:assembleDebug
  • Pixel 8 + Galaxy S25 + emulator (Android 14 and 16): SABR plays end to end, forward and backward seek both land (including big rewinds well past the buffer), mid-playback quality/codec switch, and 60s network-drop recovery. 1080p is solid; >=1440p is the device decoder (S25 does 4K, Pixel 8 doesn't).

Notes

  • First real integration, not a PoC, but WIP, not for merge yet.
  • seek works fully now: forward, backward, repeated, and big rewinds beyond the back-buffer.
  • quality: now honours the chosen resolution instead of forcing the max (the earlier 4K-wall note is fixed). Audio is AAC; Opus/webm through the chunk pipeline is the one known gap.
  • SABR is currently force-routed for every video by the extractor's test flag (feat(youtube): SABR extractor support PipePipeExtractor#69), off for production.
  • the WebView script keeps its carryover name sabr_potoken_poc.js, it's the real minting script.

@Priveetee
Copy link
Copy Markdown
Contributor Author

bit of context: the PoC #43 (and the extractor PoC InfinityLoop1308/PipePipeExtractor#68) were throwaway PoCs to prove SABR actually plays end to end. they did their job, so i closed #43 rather than keep pushing onto a messy branch.

this is the real integration, rebuilt clean on top of the media3 PR #45 (so no media3 noise here, just SABR). the buffering is reworked to be reader-driven (pacing + cache eviction follow what the player has actually read, not the play head, so it doesn't deadlock or blow up memory anymore). the extractor side is InfinityLoop1308/PipePipeExtractor#69.

still WIP, not for merge yet (4K hits a device VP9 decoder wall and reload-resume restarts at 0, both noted above), but this is where it continues from now :)

@Priveetee Priveetee force-pushed the feat/sabr-client branch 2 times, most recently from 7f8f3f9 to 22e0422 Compare June 5, 2026 14:53
@Priveetee Priveetee changed the title feat(player): SABR playback (reader-driven) feat(player): SABR playback (chunk-based, seekable) Jun 5, 2026
@Priveetee
Copy link
Copy Markdown
Contributor Author

yes it mean that im gonna drop my beloved pickHardwareFriendlyVideo and actually respect the quality that the user choose 😢

Comment thread app/src/main/java/org/schabi/newpipe/player/datasource/SabrSessionStore.java Outdated
@Priveetee
Copy link
Copy Markdown
Contributor Author

man im more fighting with this freaking decoder than sabr, honestly as much as I love my pixel 8 next time I buy a phone i will be choosing a more freaking reliable decoder

@InfinityLoop1308
Copy link
Copy Markdown
Owner

InfinityLoop1308 commented Jun 5, 2026

some devices even claims for codecs that they doesn't support at all xD

so yeah I think it would be better to let user pick instead of detecting automatically.

@Priveetee
Copy link
Copy Markdown
Contributor Author

yeah 100%, i ran into exactly that on my side 😂 the device happily advertised hw vp9/av1 then choked initializing the decoder anyway, so the auto-detect was basically trusting a codec list that lies. dropping my beloved hardware-friendly pick and just respecting whatever quality the user actually selects, way more predictable.

honestly kinda a shame, auto-picking the best codec for the user would've been a sweet lil UX win, but not worth fighting these freaking decoders over. if their device can't keep up that's on the device now, not me guessing wrong for them

Priveetee added 20 commits June 6, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants