Skip to main content

broadcast_dash/
model.rs

1//! The consume-only MPD model (ISO/IEC 23009-1 clause 5.3, Annex B schema).
2//!
3//! Every field is typed; nothing keeps source text for a later passthrough.
4//! Times are Unix microseconds (`*_us`, `i64`) or [`Duration`]. Elements the
5//! core does not act on (`EventStream`, `Preselection`, ...) are still modelled
6//! so [`Mpd::to_xml`] writes back what [`Mpd::parse`] read.
7
8use std::time::Duration;
9
10use broadcast_common::impl_spec_display;
11
12use crate::error::Unsupported;
13use crate::utc_timing::UtcScheme;
14
15/// `MPD@type` (Table 3).
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17#[non_exhaustive]
18pub enum PresentationType {
19    /// `static` (the default): the whole presentation is available.
20    #[default]
21    Static,
22    /// `dynamic`: segments become available over wall-clock time.
23    Dynamic,
24    /// `list` (ISO/IEC 23009-1 ed.6): the presentation is an ordered list of
25    /// Periods, each naming an imported MPD.
26    List,
27}
28
29impl PresentationType {
30    /// Stable label (the attribute token).
31    #[must_use]
32    pub fn name(&self) -> &'static str {
33        match self {
34            Self::Static => "static",
35            Self::Dynamic => "dynamic",
36            Self::List => "list",
37        }
38    }
39}
40impl_spec_display!(PresentationType);
41
42/// `@xlink:actuate` (5.5.3).
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44#[non_exhaustive]
45pub enum Actuate {
46    /// Resolve when the MPD is processed.
47    OnLoad,
48    /// Resolve when needed (the default).
49    #[default]
50    OnRequest,
51}
52
53impl Actuate {
54    /// Stable label (the attribute token).
55    #[must_use]
56    pub fn name(&self) -> &'static str {
57        match self {
58            Self::OnLoad => "onLoad",
59            Self::OnRequest => "onRequest",
60        }
61    }
62}
63impl_spec_display!(Actuate);
64
65/// An `xlink` reference on a Period, AdaptationSet or SegmentList.
66#[derive(Debug, Clone, PartialEq, Eq, Default)]
67#[non_exhaustive]
68pub struct Xlink {
69    /// `@xlink:href`.
70    pub href: String,
71    /// `@xlink:actuate`.
72    pub actuate: Actuate,
73}
74
75/// A single byte range `first-last` (RFC 7233 2.1), inclusive.
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
77#[non_exhaustive]
78pub struct ByteRange {
79    /// First byte.
80    pub first: u64,
81    /// Last byte; `None` for the open-ended form `first-`.
82    pub last: Option<u64>,
83}
84
85impl core::fmt::Display for ByteRange {
86    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
87        match self.last {
88            Some(last) => write!(f, "{}-{}", self.first, last),
89            None => write!(f, "{}-", self.first),
90        }
91    }
92}
93
94impl ByteRange {
95    /// A closed range.
96    #[must_use]
97    pub fn new(first: u64, last: u64) -> Self {
98        Self {
99            first,
100            last: Some(last),
101        }
102    }
103
104    /// Number of bytes; `None` when open-ended or `last < first`.
105    #[must_use]
106    pub fn len(&self) -> Option<u64> {
107        let last = self.last?;
108        last.checked_sub(self.first)?.checked_add(1)
109    }
110
111    /// Whether the range is empty or open-ended (no byte count).
112    #[must_use]
113    pub fn is_empty(&self) -> bool {
114        self.len().is_none()
115    }
116
117    /// The closed `(offset, length)` form, or the typed unsupported error for
118    /// an open-ended range.
119    ///
120    /// # Errors
121    /// [`Unsupported::OpenEndedRange`].
122    pub fn offset_len(&self) -> Result<(u64, u64), Unsupported> {
123        self.len()
124            .map(|n| (self.first, n))
125            .ok_or(Unsupported::OpenEndedRange)
126    }
127}
128
129/// `URLType` (Table 18): an `Initialization`/`RepresentationIndex` address.
130#[derive(Debug, Clone, PartialEq, Eq, Default)]
131#[non_exhaustive]
132pub struct UrlType {
133    /// `@sourceURL`; absent means the BaseURL itself.
134    pub source_url: Option<String>,
135    /// `@range`.
136    pub range: Option<ByteRange>,
137}
138
139/// A `BaseURL` (Table 30) with the DVB extension attributes.
140#[derive(Debug, Clone, PartialEq, Default)]
141#[non_exhaustive]
142pub struct BaseUrl {
143    /// Element text.
144    pub url: String,
145    /// `@serviceLocation`.
146    pub service_location: Option<String>,
147    /// `@dvb:priority` (ETSI TS 103 285 10.8.2.1).
148    pub priority: Option<u32>,
149    /// `@dvb:weight`; parsed, never used (the core is deterministic).
150    pub weight: Option<u32>,
151    /// `@availabilityTimeOffset`, seconds.
152    pub availability_time_offset: Option<f64>,
153    /// `@availabilityTimeComplete`.
154    pub availability_time_complete: Option<bool>,
155    /// `@timeShiftBufferDepth`.
156    pub time_shift_buffer_depth: Option<Duration>,
157}
158
159/// A generic descriptor (5.8.2): `Role`, `Accessibility`,
160/// `EssentialProperty`, `SupplementalProperty`, `ContentProtection`, ...
161#[derive(Debug, Clone, PartialEq, Eq, Default)]
162#[non_exhaustive]
163pub struct Descriptor {
164    /// `@schemeIdUri`.
165    pub scheme_id_uri: String,
166    /// `@value`.
167    pub value: Option<String>,
168    /// `@id`.
169    pub id: Option<String>,
170    /// `@cenc:default_KID` on `ContentProtection`.
171    pub default_kid: Option<String>,
172    /// `cenc:pssh` child text on `ContentProtection`.
173    pub pssh: Option<String>,
174    /// The `UrlQueryInfo` child of an `urn:mpeg:dash:urlparam:2014` property.
175    pub url_query: Option<UrlQueryInfo>,
176}
177
178/// `up:UrlQueryInfo` (Annex I.2).
179#[derive(Debug, Clone, PartialEq, Eq, Default)]
180#[non_exhaustive]
181pub struct UrlQueryInfo {
182    /// `@useMPDUrlQuery`.
183    pub use_mpd_url_query: bool,
184    /// `@queryString`, literal.
185    pub query_string: Option<String>,
186    /// `@queryTemplate`; present means placeholders this core does not
187    /// understand.
188    pub query_template: Option<String>,
189}
190
191/// A `UTCTiming` element (5.8.4.11).
192#[derive(Debug, Clone, PartialEq, Eq, Default)]
193#[non_exhaustive]
194pub struct UtcTiming {
195    /// Classified `@schemeIdUri`.
196    pub scheme: UtcScheme,
197    /// `@schemeIdUri`.
198    pub scheme_id_uri: String,
199    /// `@value`: the time itself for `direct`, else whitespace-separated URLs.
200    pub value: String,
201    /// `@id`.
202    pub id: Option<String>,
203}
204
205impl UtcTiming {
206    /// The whitespace-separated entries of `@value`.
207    pub fn values(&self) -> impl Iterator<Item = &str> {
208        self.value.split_ascii_whitespace()
209    }
210}
211
212/// Which constructs the MPD contained that the core reports rather than
213/// models element by element.
214///
215/// Every flag is derived from content the writer emits, so it survives a parse
216/// -> [`Mpd::to_xml`] -> parse round trip.
217#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
218#[non_exhaustive]
219pub struct MpdFeatures {
220    /// `InbandEventStream` (5.10.3).
221    pub inband_event_stream: bool,
222    /// `ServiceDescription` (Annex K).
223    pub service_description: bool,
224    /// An `availabilityTimeOffset`, or `availabilityTimeComplete="false"`,
225    /// anywhere: a low-latency presentation.
226    pub low_latency: bool,
227    /// A Period or AdaptationSet removed because its xlink was
228    /// `urn:mpeg:dash:resolve-to-zero:2013`.
229    pub xlink_resolve_to_zero: bool,
230}
231
232/// The `RepresentationBase` attributes (5.3.7.2) that AdaptationSet and
233/// Representation both carry and Representation inherits.
234#[derive(Debug, Clone, PartialEq, Default)]
235#[non_exhaustive]
236pub struct CommonAttributes {
237    /// `@profiles`.
238    pub profiles: Option<String>,
239    /// `@width`.
240    pub width: Option<u32>,
241    /// `@height`.
242    pub height: Option<u32>,
243    /// `@sar`.
244    pub sar: Option<String>,
245    /// `@frameRate` (`n` or `n/d`).
246    pub frame_rate: Option<String>,
247    /// `@audioSamplingRate` (`n` or `n n`).
248    pub audio_sampling_rate: Option<String>,
249    /// `@mimeType`.
250    pub mime_type: Option<String>,
251    /// `@codecs`.
252    pub codecs: Option<String>,
253    /// `@maxPlayoutRate`.
254    pub max_playout_rate: Option<f64>,
255    /// `@codingDependency`.
256    pub coding_dependency: Option<bool>,
257}
258
259/// `SegmentBase` / the Segment Base Information fields (Table 16).
260#[derive(Debug, Clone, PartialEq, Default)]
261#[non_exhaustive]
262pub struct BaseInfo {
263    /// `@timescale`.
264    pub timescale: Option<u64>,
265    /// `@presentationTimeOffset`.
266    pub presentation_time_offset: Option<u64>,
267    /// `@eptDelta`.
268    pub ept_delta: Option<i64>,
269    /// `@pdDelta`.
270    pub pd_delta: Option<i64>,
271    /// `@presentationDuration`.
272    pub presentation_duration: Option<u64>,
273    /// `@timeShiftBufferDepth`.
274    pub time_shift_buffer_depth: Option<Duration>,
275    /// `@indexRange`.
276    pub index_range: Option<ByteRange>,
277    /// `@indexRangeExact`.
278    pub index_range_exact: Option<bool>,
279    /// `@availabilityTimeOffset`, seconds (may be `INF`).
280    pub availability_time_offset: Option<f64>,
281    /// `@availabilityTimeComplete`.
282    pub availability_time_complete: Option<bool>,
283    /// `Initialization`.
284    pub initialization: Option<UrlType>,
285    /// `RepresentationIndex`.
286    pub representation_index: Option<UrlType>,
287}
288
289/// `SegmentBase` element.
290#[derive(Debug, Clone, PartialEq, Default)]
291#[non_exhaustive]
292pub struct SegmentBase {
293    /// The Table 16 fields.
294    pub info: BaseInfo,
295}
296
297/// One `S` of a `SegmentTimeline` (Table 22).
298#[derive(Debug, Clone, Copy, PartialEq, Eq)]
299#[non_exhaustive]
300pub struct TimelineEntry {
301    /// `@t`.
302    pub t: Option<u64>,
303    /// `@n`.
304    pub n: Option<u64>,
305    /// `@d`.
306    pub d: u64,
307    /// `@r` (negative: until the next `S@t` or the Period end).
308    pub r: i64,
309    /// `@k`.
310    pub k: Option<u64>,
311}
312
313impl TimelineEntry {
314    /// An entry with only `d` set (`t`, `n`, `k` absent, `r` 0).
315    #[must_use]
316    pub fn new(d: u64) -> Self {
317        Self {
318            t: None,
319            n: None,
320            d,
321            r: 0,
322            k: None,
323        }
324    }
325}
326
327/// `SegmentTimeline` (5.3.9.6).
328#[derive(Debug, Clone, PartialEq, Eq, Default)]
329#[non_exhaustive]
330pub struct SegmentTimeline {
331    /// The `S` entries in document order.
332    pub entries: Vec<TimelineEntry>,
333    /// Set when the timeline uses a feature outside 0.1 (`S@k` above 1, an
334    /// Ed.6 `Pattern`); addressing then fails with that typed error.
335    pub unsupported: Option<Unsupported>,
336}
337
338/// The Multiple Segment Base Information fields (Table 17) over [`BaseInfo`].
339#[derive(Debug, Clone, PartialEq, Default)]
340#[non_exhaustive]
341pub struct MultiInfo {
342    /// The Table 16 fields.
343    pub base: BaseInfo,
344    /// `@duration`.
345    pub duration: Option<u64>,
346    /// `@startNumber`.
347    pub start_number: Option<u64>,
348    /// `@endNumber`.
349    pub end_number: Option<u64>,
350    /// `SegmentTimeline`.
351    pub timeline: Option<SegmentTimeline>,
352    /// `BitstreamSwitching`.
353    pub bitstream_switching: Option<UrlType>,
354}
355
356/// `SegmentTemplate` (5.3.9.4).
357#[derive(Debug, Clone, PartialEq, Default)]
358#[non_exhaustive]
359pub struct SegmentTemplate {
360    /// Table 16/17 fields.
361    pub multi: MultiInfo,
362    /// `@media` template.
363    pub media: Option<String>,
364    /// `@index` template.
365    pub index: Option<String>,
366    /// `@initialization` template.
367    pub initialization: Option<String>,
368    /// `@bitstreamSwitching` template.
369    pub bitstream_switching: Option<String>,
370}
371
372/// One `SegmentURL` (Table 19).
373#[derive(Debug, Clone, PartialEq, Eq, Default)]
374#[non_exhaustive]
375pub struct SegmentUrl {
376    /// `@media`.
377    pub media: Option<String>,
378    /// `@mediaRange`.
379    pub media_range: Option<ByteRange>,
380    /// `@index`.
381    pub index: Option<String>,
382    /// `@indexRange`.
383    pub index_range: Option<ByteRange>,
384}
385
386/// `SegmentList` (5.3.9.3).
387#[derive(Debug, Clone, PartialEq, Default)]
388#[non_exhaustive]
389pub struct SegmentList {
390    /// Table 16/17 fields.
391    pub multi: MultiInfo,
392    /// `@xlink:href`.
393    pub xlink: Option<Xlink>,
394    /// The `SegmentURL` entries.
395    pub urls: Vec<SegmentUrl>,
396}
397
398/// The Segment information declared at one hierarchy level: at most one of
399/// the three kinds (5.3.9.1).
400#[derive(Debug, Clone, PartialEq, Default)]
401#[non_exhaustive]
402pub struct SegmentLayer {
403    /// `SegmentBase`.
404    pub base: Option<SegmentBase>,
405    /// `SegmentList`.
406    pub list: Option<SegmentList>,
407    /// `SegmentTemplate`.
408    pub template: Option<SegmentTemplate>,
409}
410
411/// `Event@status` (ISO/IEC 23009-1 Annex B `EventStatusType`).
412#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
413#[non_exhaustive]
414pub enum EventStatus {
415    /// `none`.
416    None,
417    /// `update`.
418    Update,
419    /// `repeat` (the schema default).
420    #[default]
421    Repeat,
422}
423
424impl EventStatus {
425    /// Stable label (the attribute token).
426    #[must_use]
427    pub fn name(&self) -> &'static str {
428        match self {
429            Self::None => "none",
430            Self::Update => "update",
431            Self::Repeat => "repeat",
432        }
433    }
434}
435impl_spec_display!(EventStatus);
436
437/// One `Event` of an `EventStream` (ISO/IEC 23009-1 clause 5.10.2, Table 28;
438/// Annex B `EventType`).
439///
440/// An Event whose content is an XML payload (`SelectionInfo`,
441/// `InsertPresentation`, `ReplacePresentation` or a foreign-namespace
442/// element, e.g. an SCTE 35 `Signal`) is parsed with [`StreamEvent::unsupported`]
443/// set and its payload dropped; [`Mpd::to_xml`] then refuses to write the MPD
444/// with [`Unsupported::EventXmlPayload`] instead of silently losing it.
445#[derive(Debug, Clone, PartialEq, Eq, Default)]
446#[non_exhaustive]
447pub struct StreamEvent {
448    /// `@presentationTime`, in the EventStream timescale (default 0).
449    pub presentation_time: u64,
450    /// `@duration`, in the EventStream timescale.
451    pub duration: Option<u64>,
452    /// `@id`.
453    pub id: Option<u64>,
454    /// `@status`; `None` when absent (the schema default is `repeat`).
455    pub status: Option<EventStatus>,
456    /// `@messageData` (deprecated since ed.4, prohibited by the ed.6 schema).
457    pub message_data: Option<String>,
458    /// The element's character data, trimmed: a text or base64 message body.
459    pub text: String,
460    /// `SupplementalProperty` children.
461    pub supplemental_properties: Vec<Descriptor>,
462    /// `EssentialProperty` children.
463    pub essential_properties: Vec<Descriptor>,
464    /// `ServiceDescription` children (ed.6 service-description events).
465    pub service_descriptions: Vec<ServiceDescription>,
466    /// Set when the Event carries an XML payload this model cannot hold.
467    pub unsupported: Option<Unsupported>,
468}
469
470/// An `EventStream` (ISO/IEC 23009-1 clause 5.10.2, Table 27; Annex B
471/// `EventStreamType`) of a Period.
472#[derive(Debug, Clone, PartialEq, Default)]
473#[non_exhaustive]
474pub struct EventStream {
475    /// `xlink` reference; the stream is then unresolved.
476    pub xlink: Option<Xlink>,
477    /// `@schemeIdUri`.
478    pub scheme_id_uri: String,
479    /// `@value`.
480    pub value: Option<String>,
481    /// `@timescale`, ticks per second.
482    pub timescale: Option<u32>,
483    /// `@presentationTimeOffset`, in the timescale.
484    pub presentation_time_offset: Option<u64>,
485    /// The `Event` children in document order.
486    pub events: Vec<StreamEvent>,
487    /// `BaseURL` alternates.
488    pub base_urls: Vec<BaseUrl>,
489    /// `RequestParam` children (`up:ExtendedUrlInfoType`).
490    pub request_params: Vec<RequestParam>,
491    /// `EssentialProperty`.
492    pub essential_properties: Vec<Descriptor>,
493    /// `SupplementalProperty`.
494    pub supplemental_properties: Vec<Descriptor>,
495}
496
497/// `RequestParam` (`up:ExtendedUrlInfoType`, ISO/IEC 23009-1 Annex I).
498#[derive(Debug, Clone, PartialEq, Eq, Default)]
499#[non_exhaustive]
500pub struct RequestParam {
501    /// The `UrlQueryInfoType` attributes.
502    pub query: UrlQueryInfo,
503    /// `xlink` reference.
504    pub xlink: Option<Xlink>,
505    /// `@includeInRequests`; `None` when absent (the schema default is `segment`).
506    pub include_in_requests: Option<String>,
507    /// `@headerParamSource`; `None` when absent (the schema default is `segment`).
508    pub header_param_source: Option<String>,
509    /// `@sameOriginOnly`; `None` when absent (the schema default is false).
510    pub same_origin_only: Option<bool>,
511    /// `@header`.
512    pub header: Option<String>,
513}
514
515/// `ProducerReferenceTime@type` (ISO/IEC 23009-1 clause 5.12, Table 33).
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
517#[non_exhaustive]
518pub enum ProducerReferenceKind {
519    /// `encoder` (the default): the time the encoder produced the sample.
520    #[default]
521    Encoder,
522    /// `captured`: the capture time of the content.
523    Captured,
524    /// `application`: defined by `@applicationScheme`.
525    Application,
526}
527
528impl ProducerReferenceKind {
529    /// Stable label (the attribute token).
530    #[must_use]
531    pub fn name(&self) -> &'static str {
532        match self {
533            Self::Encoder => "encoder",
534            Self::Captured => "captured",
535            Self::Application => "application",
536        }
537    }
538}
539impl_spec_display!(ProducerReferenceKind);
540
541/// A `ProducerReferenceTime` (ISO/IEC 23009-1 clause 5.12, Table 33) of an
542/// AdaptationSet or Representation.
543#[derive(Debug, Clone, PartialEq, Eq, Default)]
544#[non_exhaustive]
545pub struct ProducerReferenceTime {
546    /// `@id`.
547    pub id: u32,
548    /// `@inband` (default false).
549    pub inband: bool,
550    /// `@type`.
551    pub kind: ProducerReferenceKind,
552    /// `@applicationScheme`.
553    pub application_scheme: Option<String>,
554    /// `@wallClockTime`, the lexical form (NTP-style date-time).
555    pub wall_clock_time: String,
556    /// `@presentationTime`, in the Representation timescale.
557    pub presentation_time: u64,
558    /// The `UTCTiming` child naming the wall-clock source.
559    pub utc_timing: Option<UtcTiming>,
560}
561
562/// A `PatchLocation` (ISO/IEC 23009-1 clause 5.15, Table 41): where an MPD
563/// patch is fetched.
564#[derive(Debug, Clone, PartialEq, Default)]
565#[non_exhaustive]
566pub struct PatchLocation {
567    /// The element text (the patch URL).
568    pub url: String,
569    /// `@serviceLocation`.
570    pub service_location: Option<String>,
571    /// `@ttl`, seconds the patch location stays valid.
572    pub ttl: Option<f64>,
573}
574
575/// A `Label` or `GroupLabel` (`LabelType`): its text with `@id` (default 0)
576/// and `@lang`.
577#[derive(Debug, Clone, PartialEq, Default)]
578#[non_exhaustive]
579pub struct Label {
580    /// `@id`; `0` is the schema default and is omitted on write, so an explicit
581    /// `id="0"` parses equal but is not written back.
582    pub id: u32,
583    /// `@lang`.
584    pub lang: Option<String>,
585    /// Element text.
586    pub text: String,
587}
588
589/// A `Resync` (ISO/IEC 23009-1 clause 5.3.13, Table 15) resynchronisation
590/// point of an AdaptationSet or Representation.
591#[derive(Debug, Clone, PartialEq, Default)]
592#[non_exhaustive]
593pub struct Resync {
594    /// `@type`, the SAP type 0 to 6 (default 0).
595    pub kind: u8,
596    /// `@dT`, the maximum time offset.
597    pub dt: Option<u32>,
598    /// `@dImax`, the maximum Resync interval.
599    pub d_imax: Option<f64>,
600    /// `@dImin`, the minimum Resync interval.
601    pub d_imin: Option<f64>,
602    /// `@marker`.
603    pub marker: bool,
604}
605
606/// `Preselection@order` (ISO/IEC 23009-1 clause 5.3.11, Table 14).
607#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
608#[non_exhaustive]
609pub enum PreselectionOrder {
610    /// `undefined` (the default).
611    #[default]
612    Undefined,
613    /// `time-ordered`.
614    TimeOrdered,
615    /// `fully-ordered`.
616    FullyOrdered,
617}
618
619impl PreselectionOrder {
620    /// Stable label (the attribute token).
621    #[must_use]
622    pub fn name(&self) -> &'static str {
623        match self {
624            Self::Undefined => "undefined",
625            Self::TimeOrdered => "time-ordered",
626            Self::FullyOrdered => "fully-ordered",
627        }
628    }
629}
630impl_spec_display!(PreselectionOrder);
631
632/// A `Preselection` (ISO/IEC 23009-1 clause 5.3.11, Table 14) of a Period.
633///
634/// Carries the `RepresentationBase` attributes and children the model has a
635/// type for; `Switching`, `RandomAccess`, `ContentPopularityRate` and
636/// `SegmentSequenceProperties` set `unsupported` instead of being dropped.
637#[derive(Debug, Clone, PartialEq, Default)]
638#[non_exhaustive]
639pub struct Preselection {
640    /// `@id`; `None` when absent (the schema default is `1`).
641    pub id: Option<String>,
642    /// `@preselectionComponents`, whitespace-separated AdaptationSet ids.
643    pub preselection_components: Vec<String>,
644    /// `@lang`.
645    pub lang: Option<String>,
646    /// `@order`; `None` when absent (the schema default is `undefined`).
647    pub order: Option<PreselectionOrder>,
648    /// The `RepresentationBase` attributes.
649    pub common: CommonAttributes,
650    /// `AudioChannelConfiguration`.
651    pub audio_channel_configurations: Vec<Descriptor>,
652    /// `EssentialProperty`.
653    pub essential_properties: Vec<Descriptor>,
654    /// `SupplementalProperty`.
655    pub supplemental_properties: Vec<Descriptor>,
656    /// `Accessibility` descriptors.
657    pub accessibilities: Vec<Descriptor>,
658    /// `Role` descriptors.
659    pub roles: Vec<Descriptor>,
660    /// `Rating` descriptors.
661    pub ratings: Vec<Descriptor>,
662    /// `Viewpoint` descriptors.
663    pub viewpoints: Vec<Descriptor>,
664    /// `@tag`.
665    pub tag: Option<String>,
666    /// `@selectionPriority`; `None` when absent (the schema default is `1`).
667    pub selection_priority: Option<u32>,
668    /// `@startWithSAP`.
669    pub start_with_sap: Option<u8>,
670    /// `@scanType`.
671    pub scan_type: Option<String>,
672    /// `@segmentProfiles`.
673    pub segment_profiles: Option<String>,
674    /// `@containerProfiles`.
675    pub container_profiles: Option<String>,
676    /// `@maximumSAPPeriod`, seconds.
677    pub maximum_sap_period: Option<f64>,
678    /// `FramePacking`.
679    pub frame_packings: Vec<Descriptor>,
680    /// `ContentProtection`.
681    pub content_protections: Vec<Descriptor>,
682    /// `OutputProtection`.
683    pub output_protection: Option<Descriptor>,
684    /// `InbandEventStream`.
685    pub inband_event_streams: Vec<Descriptor>,
686    /// `GroupLabel` elements.
687    pub group_labels: Vec<Label>,
688    /// `Label` elements.
689    pub labels: Vec<Label>,
690    /// `ProducerReferenceTime`.
691    pub producer_reference_times: Vec<ProducerReferenceTime>,
692    /// `Resync`.
693    pub resyncs: Vec<Resync>,
694    /// Set when a child the model cannot carry was present.
695    pub unsupported: Option<Unsupported>,
696}
697
698/// A `ContentSteering` (ISO/IEC 23009-1 clause 5.3.1, Table 3; Annex B
699/// `ContentSteeringType`) of the MPD.
700#[derive(Debug, Clone, PartialEq, Eq, Default)]
701#[non_exhaustive]
702pub struct ContentSteering {
703    /// The element text (the steering server URL).
704    pub url: String,
705    /// `@defaultServiceLocation`.
706    pub default_service_location: Option<String>,
707    /// `@queryBeforeStart` (default false).
708    pub query_before_start: bool,
709    /// `@clientRequirement`; `None` when absent (the schema default is true).
710    pub client_requirement: Option<bool>,
711}
712
713/// A `Representation` (5.3.5).
714#[derive(Debug, Clone, PartialEq, Default)]
715#[non_exhaustive]
716pub struct Representation {
717    /// `@id`.
718    pub id: String,
719    /// `@bandwidth`, bits per second.
720    pub bandwidth: u64,
721    /// `@qualityRanking`.
722    pub quality_ranking: Option<u32>,
723    /// `@dependencyId` (whitespace-separated Representation ids).
724    pub dependency_ids: Vec<String>,
725    /// Common attributes (not yet merged with the AdaptationSet's).
726    pub common: CommonAttributes,
727    /// `BaseURL` alternates.
728    pub base_urls: Vec<BaseUrl>,
729    /// Segment information declared here.
730    pub segment: SegmentLayer,
731    /// `ContentProtection`.
732    pub content_protections: Vec<Descriptor>,
733    /// `EssentialProperty`.
734    pub essential_properties: Vec<Descriptor>,
735    /// `SupplementalProperty`.
736    pub supplemental_properties: Vec<Descriptor>,
737    /// `AudioChannelConfiguration`.
738    pub audio_channel_configurations: Vec<Descriptor>,
739    /// `InbandEventStream`.
740    pub inband_event_streams: Vec<Descriptor>,
741    /// `ProducerReferenceTime`.
742    pub producer_reference_times: Vec<ProducerReferenceTime>,
743    /// `Resync`.
744    pub resyncs: Vec<Resync>,
745}
746
747/// An `AdaptationSet` (5.3.3).
748#[derive(Debug, Clone, PartialEq, Default)]
749#[non_exhaustive]
750pub struct AdaptationSet {
751    /// `@id`.
752    pub id: Option<u64>,
753    /// `@group`.
754    pub group: Option<u64>,
755    /// `@lang`.
756    pub lang: Option<String>,
757    /// `@contentType`.
758    pub content_type: Option<String>,
759    /// `@par`.
760    pub par: Option<String>,
761    /// `@segmentAlignment` (`true` or a non-zero count).
762    pub segment_alignment: bool,
763    /// `@startWithSAP`.
764    pub start_with_sap: Option<u8>,
765    /// `@bitstreamSwitching`.
766    pub bitstream_switching: Option<bool>,
767    /// Common attributes.
768    pub common: CommonAttributes,
769    /// `xlink` reference; the element is then unresolved.
770    pub xlink: Option<Xlink>,
771    /// `Role` descriptors.
772    pub roles: Vec<Descriptor>,
773    /// `Accessibility` descriptors.
774    pub accessibilities: Vec<Descriptor>,
775    /// `Label` elements.
776    pub labels: Vec<Label>,
777    /// `BaseURL` alternates.
778    pub base_urls: Vec<BaseUrl>,
779    /// Segment information declared here.
780    pub segment: SegmentLayer,
781    /// `ContentProtection`.
782    pub content_protections: Vec<Descriptor>,
783    /// `EssentialProperty`.
784    pub essential_properties: Vec<Descriptor>,
785    /// `SupplementalProperty`.
786    pub supplemental_properties: Vec<Descriptor>,
787    /// `AudioChannelConfiguration`.
788    pub audio_channel_configurations: Vec<Descriptor>,
789    /// `InbandEventStream`.
790    pub inband_event_streams: Vec<Descriptor>,
791    /// `ProducerReferenceTime`.
792    pub producer_reference_times: Vec<ProducerReferenceTime>,
793    /// `Resync`.
794    pub resyncs: Vec<Resync>,
795    /// The Representations.
796    pub representations: Vec<Representation>,
797}
798
799/// `ImportedMPD` (ISO/IEC 23009-1 ed.6 `ImportedMpdType`): an `xs:anyURI`
800/// element text plus `@earliestResolutionTimeOffset`.
801#[derive(Debug, Clone, PartialEq, Default)]
802#[non_exhaustive]
803pub struct ImportedMpd {
804    /// The imported MPD's location (the element text).
805    pub url: String,
806    /// `@earliestResolutionTimeOffset`, seconds; the schema default is 60.0.
807    pub earliest_resolution_time_offset: Option<f64>,
808}
809
810/// A `Period` (5.3.2).
811#[derive(Debug, Clone, PartialEq, Default)]
812#[non_exhaustive]
813pub struct Period {
814    /// `@id`.
815    pub id: Option<String>,
816    /// `@start`.
817    pub start: Option<Duration>,
818    /// `@duration`.
819    pub duration: Option<Duration>,
820    /// `@bitstreamSwitching`.
821    pub bitstream_switching: bool,
822    /// `xlink` reference.
823    pub xlink: Option<Xlink>,
824    /// `BaseURL` alternates.
825    pub base_urls: Vec<BaseUrl>,
826    /// Segment information declared here.
827    pub segment: SegmentLayer,
828    /// `AssetIdentifier`.
829    pub asset_identifier: Option<Descriptor>,
830    /// `EventStream`.
831    pub event_streams: Vec<EventStream>,
832    /// `ImportedMPD` (ISO/IEC 23009-1 ed.6 Table `ImportedMpdType`): the MPD a
833    /// `@type="list"` Period presents.
834    pub imported_mpd: Option<ImportedMpd>,
835    /// `EssentialProperty`.
836    pub essential_properties: Vec<Descriptor>,
837    /// `SupplementalProperty`.
838    pub supplemental_properties: Vec<Descriptor>,
839    /// The AdaptationSets.
840    pub adaptation_sets: Vec<AdaptationSet>,
841    /// `Preselection`.
842    pub preselections: Vec<Preselection>,
843    /// `ServiceDescription`.
844    pub service_descriptions: Vec<ServiceDescription>,
845}
846
847/// `Latency` child of `ServiceDescription` (Annex K).
848#[derive(Debug, Clone, PartialEq, Eq, Default)]
849#[non_exhaustive]
850pub struct Latency {
851    /// `@target`, milliseconds.
852    pub target: Option<u64>,
853    /// `@min`, milliseconds.
854    pub min: Option<u64>,
855    /// `@max`, milliseconds.
856    pub max: Option<u64>,
857    /// `@referenceId`.
858    pub reference_id: Option<u32>,
859}
860
861/// `PlaybackRate` child of `ServiceDescription` (Annex K).
862#[derive(Debug, Clone, PartialEq, Eq, Default)]
863#[non_exhaustive]
864pub struct PlaybackRate {
865    /// `@min`, lexical form.
866    pub min: Option<String>,
867    /// `@max`, lexical form.
868    pub max: Option<String>,
869}
870
871/// `ServiceDescription` (Annex K).
872#[derive(Debug, Clone, PartialEq, Eq, Default)]
873#[non_exhaustive]
874pub struct ServiceDescription {
875    /// `@id`.
876    pub id: Option<u64>,
877    /// `Latency`.
878    pub latency: Option<Latency>,
879    /// `PlaybackRate`.
880    pub playback_rate: Option<PlaybackRate>,
881}
882
883/// An `MPD` (5.3.1).
884#[derive(Debug, Clone, PartialEq, Default)]
885#[non_exhaustive]
886pub struct Mpd {
887    /// `@id`.
888    pub id: Option<String>,
889    /// `@profiles`, split on `,`.
890    pub profiles: Vec<String>,
891    /// `@type`.
892    pub kind: PresentationType,
893    /// `@availabilityStartTime`, Unix microseconds.
894    pub availability_start_time_us: Option<i64>,
895    /// `@availabilityEndTime`, Unix microseconds.
896    pub availability_end_time_us: Option<i64>,
897    /// `@publishTime`, Unix microseconds.
898    pub publish_time_us: Option<i64>,
899    /// `@mediaPresentationDuration`.
900    pub media_presentation_duration: Option<Duration>,
901    /// `@minimumUpdatePeriod`.
902    pub minimum_update_period: Option<Duration>,
903    /// `@minBufferTime`.
904    pub min_buffer_time: Option<Duration>,
905    /// `@timeShiftBufferDepth`.
906    pub time_shift_buffer_depth: Option<Duration>,
907    /// `@suggestedPresentationDelay`.
908    pub suggested_presentation_delay: Option<Duration>,
909    /// `@maxSegmentDuration`.
910    pub max_segment_duration: Option<Duration>,
911    /// `@maxSubsegmentDuration`.
912    pub max_subsegment_duration: Option<Duration>,
913    /// `BaseURL` alternates.
914    pub base_urls: Vec<BaseUrl>,
915    /// `Location` texts.
916    pub locations: Vec<String>,
917    /// `PatchLocation`.
918    pub patch_locations: Vec<PatchLocation>,
919    /// `ServiceDescription`.
920    pub service_descriptions: Vec<ServiceDescription>,
921    /// `UTCTiming` elements in document order (alternatives, in preference
922    /// order).
923    pub utc_timings: Vec<UtcTiming>,
924    /// `EssentialProperty`.
925    pub essential_properties: Vec<Descriptor>,
926    /// `SupplementalProperty`.
927    pub supplemental_properties: Vec<Descriptor>,
928    /// `ContentSteering`.
929    pub content_steering: Option<ContentSteering>,
930    /// The Periods.
931    pub periods: Vec<Period>,
932    /// Constructs seen but not acted on.
933    pub features: MpdFeatures,
934}
935
936impl Mpd {
937    /// Whether the MPD declares an `EventStream` in a Period or an
938    /// `InbandEventStream` anywhere.
939    #[must_use]
940    pub fn has_event_streams(&self) -> bool {
941        self.features.inband_event_stream
942            || self.periods.iter().any(|p| !p.event_streams.is_empty())
943    }
944
945    /// Whether any Period declares a `Preselection`.
946    #[must_use]
947    pub fn has_preselections(&self) -> bool {
948        self.periods.iter().any(|p| !p.preselections.is_empty())
949    }
950
951    /// Whether the MPD declares a `PatchLocation`.
952    #[must_use]
953    pub fn has_patch_location(&self) -> bool {
954        !self.patch_locations.is_empty()
955    }
956}