Initially, this project was created to showcase how Shaka Player can be adapted to play videos streamed via YouTube’s SABR protocol. It now serves as a general example for the YouTube.js and googlevideo libraries.
- Play videos using SABR streaming.
- Nearly instant playback load times.
- Support for Live, Post-Live, and VOD content (Live content still uses standard HLS/DASH manifests).
- Recommendation system using persistent InnerTube sessions.
- Responsive on both desktop and mobile browsers (NOTE: Most mobile browsers do not support extensions; you'll need a proxy).
- SABR-based downloader.
- Video search.
- Install dependencies and run the application:
npm install
npm run dev
# To build for production:
npm run build
- Open your browser and navigate to
http://localhost:5173
and follow the instructions on the page.
About a year or two ago, YouTube started experimenting with SABR (Server-side Adaptive Bitrate) streaming. It allows the server to dynamically adjust the stream based on the user's network conditions and device capabilities. While this is good for YouTube, implementing SABR properly in third-party apps (for example FreeTube, NewPipe, GrayJay) is quite difficult.
Unlike standard DASH or HLS streams, SABR streams use a custom response format (UMP) that is incompatible with existing video players. And on top of that, SABR delivers both audio and video segments in a single request, rather than separately, and uses player time in combination with buffered range metadata instead of byte ranges when requesting specific segments.
Trying to get around the aforementioned issues, I implemented a few layers of abstraction to make things easier to work with. You can find the actual code for these modules in the luanrt/googlevideo repository, but here's a small overview for each one:
SabrStreamingAdapter
- A bridge between the SABR protocol and media players. It manages the streaming session, creates request payloads, and handles server signals. Players must implement theSabrPlayerAdapter
interface to use it.SabrUmpProcessor
- A UMP processor that extracts audio/video segments and metadata from the UMP response, allowing the underlying player to consume them as standard segments.
Other important modules used internally:
CompositeBuffer
- A buffer that manages discontinuous chunks as a single logical stream.UmpReader
- A parser that efficiently processes chunked UMP binary data.
This project's implementation of the SabrPlayerAdapter
interface for Shaka Player can be found in src/streaming/ShakaPlayerAdapter.ts
.
The core of the integration is the SabrStreamingAdapter
, which is initialized with our custom ShakaPlayerAdapter
class.
Shaka Player is loaded with a dynamically generated DASH manifest for VOD content or a standard HLS/DASH manifest for live and post-live streams. The ShakaPlayerAdapter
registers a custom networking scheme to intercept all segment requests.
When the player requests a media segment, it is modified and a proper payload is created. The response for these requests has a content-type
of SabrUmpProcessor
.
The processor extracts the specific media data the player requested, along with metadata needed to maintain the streaming session, and then aborts the request to save bandwidth.
For those who want a barebones example of how to integrate SABR with Shaka Player, a minimal project is available. It strips away the UI and advanced features of Kira to focus solely on the player integration logic.
You can find it here: sabr-shaka-example
Special thanks to @absidue for helping debug Shaka Player issues and investigating different implementation approaches.
Distributed under the MIT License.