Skip to main content

dash_runtime/mpd/
descriptors.rs

1//! Descriptor scheme URIs and the typed readers over [`Descriptor`] lists.
2//!
3//! Role values: ISO/IEC 23009-1 5.8.5.5 Table 34. Continuity / connectivity /
4//! reset: 5.3.2.4, 5.4.2. URL parameters: Annex I.2. The last-segment-number
5//! property is DASH-IF IOP v4.3.
6
7use broadcast_common::impl_spec_display;
8
9use super::model::{Descriptor, UrlQueryInfo};
10
11/// 5.8.5.5: the role scheme.
12pub const SCHEME_ROLE: &str = "urn:mpeg:dash:role:2011";
13/// 5.3.2.4: Period-continuity signalling.
14pub const SCHEME_PERIOD_CONTINUITY: &str = "urn:mpeg:dash:period-continuity:2015";
15/// 5.3.2.4: Period-connectivity signalling.
16pub const SCHEME_PERIOD_CONNECTIVITY: &str = "urn:mpeg:dash:period-connectivity:2015";
17/// 5.4.2: MPD reset.
18pub const SCHEME_RESET: &str = "urn:mpeg:dash:reset:2016";
19/// Annex I.2: URL parameter signalling (media Segment requests).
20pub const SCHEME_URLPARAM: &str = "urn:mpeg:dash:urlparam:2014";
21/// Annex I.3: the 2016 superset scheme (not understood).
22pub const SCHEME_URLPARAM_2016: &str = "urn:mpeg:dash:urlparam:2016";
23/// DASH-IF IOP v4.3: the last Segment number of a live Period.
24pub const SCHEME_LAST_SEGMENT_NUMBER: &str = "http://dashif.org/guidelines/last-segment-number";
25/// 5.5.3 rule 4: an xlink that removes its element.
26pub const XLINK_RESOLVE_TO_ZERO: &str = "urn:mpeg:dash:resolve-to-zero:2013";
27/// 5.8.5.2: the MP4 protection scheme descriptor.
28pub const SCHEME_MP4_PROTECTION: &str = "urn:mpeg:dash:mp4protection:2011";
29
30/// A 5.8.5.5 role value.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum Role {
34    /// `caption`.
35    Caption,
36    /// `subtitle`.
37    Subtitle,
38    /// `main`.
39    Main,
40    /// `alternate`.
41    Alternate,
42    /// `supplementary`.
43    Supplementary,
44    /// `commentary`.
45    Commentary,
46    /// `dub`.
47    Dub,
48    /// `description`.
49    Description,
50    /// `sign`.
51    Sign,
52    /// `metadata`.
53    Metadata,
54    /// `enhanced-audio-intelligibility`.
55    EnhancedAudioIntelligibility,
56    /// `emergency`.
57    Emergency,
58    /// `forced-subtitle`.
59    ForcedSubtitle,
60    /// `easyreader`.
61    EasyReader,
62    /// `karaoke`.
63    Karaoke,
64    /// Any other token.
65    Other,
66}
67
68impl Role {
69    /// Classify a `Role@value` of the DASH role scheme.
70    #[must_use]
71    pub fn from_value(value: &str) -> Self {
72        match value {
73            "caption" => Self::Caption,
74            "subtitle" => Self::Subtitle,
75            "main" => Self::Main,
76            "alternate" => Self::Alternate,
77            "supplementary" => Self::Supplementary,
78            "commentary" => Self::Commentary,
79            "dub" => Self::Dub,
80            "description" => Self::Description,
81            "sign" => Self::Sign,
82            "metadata" => Self::Metadata,
83            "enhanced-audio-intelligibility" => Self::EnhancedAudioIntelligibility,
84            "emergency" => Self::Emergency,
85            "forced-subtitle" => Self::ForcedSubtitle,
86            "easyreader" => Self::EasyReader,
87            "karaoke" => Self::Karaoke,
88            _ => Self::Other,
89        }
90    }
91
92    /// The Table 34 token, or `"other"`.
93    #[must_use]
94    pub fn name(&self) -> &'static str {
95        match self {
96            Self::Caption => "caption",
97            Self::Subtitle => "subtitle",
98            Self::Main => "main",
99            Self::Alternate => "alternate",
100            Self::Supplementary => "supplementary",
101            Self::Commentary => "commentary",
102            Self::Dub => "dub",
103            Self::Description => "description",
104            Self::Sign => "sign",
105            Self::Metadata => "metadata",
106            Self::EnhancedAudioIntelligibility => "enhanced-audio-intelligibility",
107            Self::Emergency => "emergency",
108            Self::ForcedSubtitle => "forced-subtitle",
109            Self::EasyReader => "easyreader",
110            Self::Karaoke => "karaoke",
111            Self::Other => "other",
112        }
113    }
114}
115impl_spec_display!(Role);
116
117/// The roles declared by `Role` descriptors of the DASH role scheme.
118pub fn roles(descriptors: &[Descriptor]) -> impl Iterator<Item = Role> + '_ {
119    descriptors
120        .iter()
121        .filter(|d| d.scheme_id_uri == SCHEME_ROLE)
122        .filter_map(|d| d.value.as_deref())
123        .map(Role::from_value)
124}
125
126/// The first descriptor with `scheme`.
127#[must_use]
128pub fn find<'a>(descriptors: &'a [Descriptor], scheme: &str) -> Option<&'a Descriptor> {
129    descriptors.iter().find(|d| d.scheme_id_uri == scheme)
130}
131
132/// The `urn:mpeg:dash:urlparam:2014` information among `descriptors`.
133#[must_use]
134pub fn url_query_info(descriptors: &[Descriptor]) -> Option<&UrlQueryInfo> {
135    descriptors
136        .iter()
137        .filter(|d| d.scheme_id_uri == SCHEME_URLPARAM)
138        .find_map(|d| d.url_query.as_ref())
139}
140
141/// Schemes an `EssentialProperty` may name without making the parent element
142/// unprocessable (5.8.4.8: a client that does not understand an essential
143/// scheme drops the parent).
144pub const UNDERSTOOD_ESSENTIAL: &[&str] = &[
145    SCHEME_PERIOD_CONTINUITY,
146    SCHEME_PERIOD_CONNECTIVITY,
147    SCHEME_RESET,
148    SCHEME_URLPARAM,
149    SCHEME_LAST_SEGMENT_NUMBER,
150];
151
152/// Whether this core understands an `EssentialProperty` scheme.
153#[must_use]
154pub fn essential_understood(descriptor: &Descriptor) -> bool {
155    UNDERSTOOD_ESSENTIAL.contains(&descriptor.scheme_id_uri.as_str())
156}