Skip to main content

dash_runtime/
lib.rs

1//! Sans-IO MPEG-DASH: the MPD model and parser, segment addressing, the UTC
2//! clock and the live-edge arithmetic a DASH client is built on, and
3//! [`client::DashClient`], a client state machine for static (VOD) and
4//! dynamic (live) presentations.
5//!
6//! **Spec:** ISO/IEC 23009-1:2022 (clause 5.3 MPD, 5.3.9 Segment information,
7//! 5.6 BaseURL, 5.8.5.7 UTCTiming, Annex A client behaviour, Annex I URL
8//! parameters), DASH-IF IOP v4.3 (live timing) and ETSI TS 103 285 (BaseURL
9//! priority). The verified page references are in the private spec
10//! repository (`private/specs-verified/dash/docs-specs/`); decisions where
11//! the standard contradicts itself are in `docs/dash-runtime/DESIGN.md`
12//! section 11.
13//!
14//! Nothing here does I/O or reads a clock. Every instant is an argument; the
15//! caller fetches the MPD, the `sidx` and the segments, times its own
16//! requests, and asks this crate what to fetch and when it becomes available.
17//!
18//! | Module | What it gives |
19//! |---|---|
20//! | [`mpd`] | [`mpd::Mpd`]: the consume-only model, a bounded namespace-aware parser, attribute inheritance down Period > AdaptationSet > Representation, BaseURL alternates and URL resolution |
21//! | [`address`] | [`address::SegmentPlan`]: the lazy Segment list of a Representation (templates with width tags and `$$`, timelines with negative `@r` and `@n`, `SegmentList`, `SegmentBase` + `sidx`), with availability windows |
22//! | [`timing`] | [`timing::clock::UtcClock`], `UTCTiming` sampling, `xs:dateTime` / HTTP `Date` / NTP readers, PeriodStart, availability and live-edge arithmetic |
23//! | [`client`] | [`client::config::DashConfig`]: the DASH knobs of a client session (clock ladder, early-request cadence, refresh floor) |
24//! | [`selection`] | Pure choice of AdaptationSet and Representation by role, language, codec and bandwidth |
25//! | [`client`] | [`client::DashClient`]: plays static and dynamic MPDs to ordered `Fmp4Demux` samples, with typed failure classes, Period continuity and an origin pin |
26//!
27//! # Format policy
28//!
29//! The model is consume-only: there is no MPD serializer. The workspace
30//! round-trip invariant is met against `transmux`'s DASH generator by a
31//! differential test (`tests/differential.rs`): everything the generator
32//! writes is parsed, and the two parsers agree on every field both read, the
33//! expanded segment numbers and times, and the resolved URLs.
34//!
35//! # Scope of 0.1
36//!
37//! The client plays static and dynamic MPDs: a dynamic one gets a clock
38//! (`UTCTiming`, the host clock via `DashClient::set_wall_clock`, or the MPD
39//! response `Date`), a join near the live edge, availability gating and MPD
40//! refresh.
41//!
42//! The core handles: static and dynamic MPDs, `SegmentTemplate` (`$Number$`, `$Time$`,
43//! `$Bandwidth$`, `$RepresentationID$`), `SegmentTimeline`, `SegmentList`,
44//! `SegmentBase` with a `sidx`, BaseURL alternates, multiple Periods,
45//! `UTCTiming` (`direct`, `http-xsdate`, `http-iso`, `http-head`,
46//! `http-ntp`). Typed `Unsupported` (the Representation is dropped, never
47//! misread): segment sequences (`S@k`, `$SubNumber$`), `MPD@type="list"`,
48//! `data:` addresses, open-ended byte ranges, hierarchical `sidx`.
49//!
50//! # Examples
51//!
52//! * `cargo run -p dash-runtime --example list_segments` prints the segment
53//!   URLs of an MPD file.
54//! * `cargo run -p dash-runtime --example live_window` prints the live edge
55//!   of a dynamic MPD at a simulated clock.
56//! * `cargo run -p dash-runtime --example play_live` plays a dynamic MPD
57//!   against a loopback origin and a simulated clock.
58//! * `cargo run -p dash-runtime --example play_static` plays a static MPD from
59//!   the file system through `DashClient` and prints what a host receives.
60//!
61//! ```
62//! use dash_runtime::address::{PlanOptions, plan_representation};
63//! use dash_runtime::mpd::Mpd;
64//! use dash_runtime::selection::RepRef;
65//!
66//! let xml = r#"<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" type="static"
67//!                   mediaPresentationDuration="PT6S">
68//!   <Period><AdaptationSet mimeType="video/mp4">
69//!     <SegmentTemplate timescale="1000" duration="2000" startNumber="0"
70//!                      media="$RepresentationID$/$Number%03d$.m4s"/>
71//!     <Representation id="v1" bandwidth="500000"/>
72//!   </AdaptationSet></Period>
73//! </MPD>"#;
74//! let mpd = Mpd::parse(xml.as_bytes()).unwrap();
75//! let planned = plan_representation(&mpd, RepRef::at(0, 0, 0), &PlanOptions::default()).unwrap();
76//! let refs: Vec<_> = planned.plan.iter().map(|s| s.reference).collect();
77//! assert_eq!(refs, ["v1/000.m4s", "v1/001.m4s", "v1/002.m4s"]);
78//! ```
79#![forbid(unsafe_code)]
80#![cfg_attr(docsrs, feature(doc_cfg))]
81
82pub mod address;
83pub mod client;
84pub mod error;
85pub mod limits;
86pub mod mpd;
87pub mod selection;
88pub mod timing;