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}