Skip to content

Latest commit

 

History

History
78 lines (65 loc) · 4.56 KB

File metadata and controls

78 lines (65 loc) · 4.56 KB

Architecture

dashpipe is one data plane with three stages under a single context.Context, wired by pipeline.Run:

              ┌──────────────────────┐   Fragment    ┌──────────────┐  decrypted   ┌──────────────┐
live MPD/HLS ─► │ dash.Reader / hls.Reader │ ─(chan)─► │ cenc.Decrypt │ ───samples──►│ output.TSMux │ ──► io.Writer
              └──────────────────────┘               └──────────────┘              └──────────────┘
                live edge,                            AES-CTR/CBC in-proc,          fMP4 → MPEG-TS,
                refresh, retry,                       key supplied                 rebase + splice
                drop ad Periods                                                    discontinuity

The reader is selected by pipeline.Config.Engine ("dash" default, or "hls"). Both readers satisfy the same fragmentReader interface (Run(ctx, chan<- Fragment)), so the decrypt and mux stages are identical regardless of input protocol.

Stages

dash — the live reader

  • Parses the MPD subset live DAI streams use (mpd.go), expands SegmentTimeline runs into concrete segments (timeline.go), selects the video Representation by WxH and an audio track (select.go).
  • Holds a cursor ~LiveEdgeTarget behind the newest segment so it never requests an unpublished segment, and refreshes at minimumUpdatePeriod (reader.go).
  • Emits an ordered Fragment stream (init + media, per kind, tagged with Period/Rep, timescale, PTO). Failed inits/segments are non-fatal — it logs and advances so an ad-break splice can't kill the stream.
  • Content-only: clear DAI ad Periods are dropped (DropAds); InAdBreak() lets the consumer tell when the live edge currently sits in a break.

hls — the live HLS reader

  • Parses the master playlist (variants + default audio rendition) and per-rendition media playlists (playlist.go), selecting the video variant by WxH.
  • fMP4 segments only: reads the #EXT-X-MAP init, extracts the media timescale via mp4.MediaTimescale, and emits the same Fragment stream as dash (reader.go).
  • Holds audio and video in lockstep at a shared live-edge boundary and emits in sequence order, so a progressive player isn't starved of audio behind a video preroll.
  • No ad Periods (single synthetic Period "hls"), so there is no DropAds/slate path.

cenc — in-process decrypt

  • Minimal ISO-BMFF box walk (moof/traf/senc/saio/saiz/trun/tenc/schm) over the encrypted subsample ranges, using only crypto/aes + crypto/cipher.
  • Both CENC schemes: cenc (AES-CTR) and cbcs (AES-CBC with the crypt:skip pattern and a constant IV — Apple SAMPLE-AES, used by HLS fMP4).
  • DecryptFragment(media, key, Init) mutates the fragment's mdat in place.
  • ParseInit reads the schm/tenc boxes (scheme, KID, IV size, cbcs pattern + constant IV) from an init segment.
  • It decrypts with a supplied key. It never contacts a license server.

output — the mux

  • TSMuxer converts decrypted samples to MPEG-TS via go-astits, doing H.264 AVCC→Annex B (re-inserting SPS/PPS at IDRs), AAC→ADTS, and PTS/DTS/PCR.
  • Both tracks are rebased onto one monotonic 90 kHz timeline (a single shared offset preserves A/V sync). At a Period change it continues the timeline, marks a TS discontinuity, and lets the next IDR carry fresh SPS/PPS — this is what makes an ad-break splice resume cleanly.
  • KeepAlive implements the hold/slate gap strategies; Serve is the single-client HTTP TS sink.

pipeline — orchestration

  • Owns the goroutine running the reader, the decrypt step, the muxer, the keep-alive ticker, and clean teardown on context cancel.
  • Resolves keys: a static Key, or a KeyProvider callback for in-process rotation.
  • Surfaces terminal conditions (ErrKeyRotation, ErrDecrypt) for the caller to map.

Key seams (for integrators)

  • pipeline.KeyProvider — inject your DRM key source. The library stays free of any DRM client; this is where Widevine/PlayReady/etc. would live in your code.
  • pipeline.GapStrategy — choose GapDrop / GapHoldLastFrame / GapSlate.
  • output.Serve / a plain io.Writer — choose the sink.

Non-goals

Ad muxing, DRM license acquisition, HEVC, and a fMP4 output mux are deliberately out of scope. See the README support matrix.