Skip to main content

broadcast_dash/
inherit.rs

1//! Attribute inheritance down Period > AdaptationSet > Representation.
2//!
3//! ISO/IEC 23009-1 5.3.9.1: Segment information may be declared at any of the
4//! three levels; an element inherits the attributes and children of the same
5//! element above it, and the lower level wins attribute by attribute.
6//! `@duration` and `SegmentTimeline` are exclusive (5.3.9.2.1,
7//! `private/specs-verified/dash/23009-1/05-3-9-segment-information.md`) in the
8//! Representation's *effective* Segment information, so a child timeline and a
9//! parent `@duration` conflict exactly as two attributes on one level do. A
10//! SegmentTemplate and a SegmentList may not both appear along one chain.
11//! The `RepresentationBase` attributes (5.3.7.2) of a Representation fall back
12//! to its AdaptationSet's.
13
14use thiserror::Error;
15
16use super::model::{
17    AdaptationSet, BaseInfo, CommonAttributes, MultiInfo, Period, Representation, SegmentLayer,
18    SegmentTemplate, SegmentTimeline, SegmentUrl,
19};
20
21/// `@timescale` default (5.3.9.2.2).
22pub const DEFAULT_TIMESCALE: u64 = 1;
23/// `@startNumber` default (5.3.9.5.3).
24pub const DEFAULT_START_NUMBER: u64 = 1;
25/// `@presentationTimeOffset` default (5.3.9.2.2).
26pub const DEFAULT_PRESENTATION_TIME_OFFSET: u64 = 0;
27
28/// Why a Representation's Segment information could not be resolved.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
30#[non_exhaustive]
31pub enum InheritError {
32    /// A SegmentTemplate and a SegmentList along one chain (5.3.9.1).
33    #[error(
34        "SegmentTemplate and SegmentList both appear along one Period/AdaptationSet/Representation chain"
35    )]
36    TemplateAndList,
37    /// `@duration` and `SegmentTimeline` in one Representation's effective
38    /// Segment information, on one level or across inherited levels
39    /// (5.3.9.2.1, `private/specs-verified/dash/23009-1/05-3-9-segment-information.md`).
40    #[error("both @duration and SegmentTimeline are present (on one level or across inheritance)")]
41    DurationAndTimeline,
42}
43
44/// The inherited multiple-Segment fields with defaults applied.
45#[derive(Debug, Clone, PartialEq)]
46#[non_exhaustive]
47pub struct ResolvedMulti {
48    /// Merged Table 16 fields (raw, defaults not applied).
49    pub base: BaseInfo,
50    /// `@timescale`, default 1.
51    pub timescale: u64,
52    /// `@presentationTimeOffset`, default 0.
53    pub presentation_time_offset: u64,
54    /// `@duration`.
55    pub duration: Option<u64>,
56    /// `@startNumber`, default 1.
57    pub start_number: u64,
58    /// `@endNumber`.
59    pub end_number: Option<u64>,
60    /// The effective `SegmentTimeline`.
61    pub timeline: Option<SegmentTimeline>,
62}
63
64/// A resolved `SegmentTemplate`.
65#[derive(Debug, Clone, PartialEq)]
66#[non_exhaustive]
67pub struct TemplateInfo {
68    /// Merged numeric fields.
69    pub multi: ResolvedMulti,
70    /// `@media`.
71    pub media: Option<String>,
72    /// `@index`.
73    pub index: Option<String>,
74    /// `@initialization`.
75    pub initialization: Option<String>,
76    /// `@bitstreamSwitching`.
77    pub bitstream_switching: Option<String>,
78}
79
80/// A resolved `SegmentList`.
81#[derive(Debug, Clone, PartialEq)]
82#[non_exhaustive]
83pub struct ListInfo {
84    /// Merged numeric fields.
85    pub multi: ResolvedMulti,
86    /// The `SegmentURL` entries (from the lowest level that lists any).
87    pub urls: Vec<SegmentUrl>,
88}
89
90/// A Representation's effective Segment information (5.3.9.1): exactly one of
91/// the three kinds.
92#[derive(Debug, Clone, PartialEq)]
93#[non_exhaustive]
94pub enum SegmentInfo {
95    /// `SegmentTemplate`.
96    Template(TemplateInfo),
97    /// `SegmentList`.
98    List(ListInfo),
99    /// `SegmentBase` or none: one Media Segment at the `BaseURL`, optionally
100    /// indexed by a `sidx` at `@indexRange`.
101    Base(BaseInfo),
102}
103
104/// `level` with its `SegmentTemplate` taking the `SegmentTimeline` it does not
105/// declare from the enclosing levels' templates (5.3.9.2.1: the lowest level
106/// that declares one wins).
107fn with_inherited_timeline<'a>(
108    enclosing: impl Iterator<Item = &'a SegmentLayer>,
109    level: &'a SegmentLayer,
110) -> Result<SegmentLayer, InheritError> {
111    let Some(template) = &level.template else {
112        return Ok(level.clone());
113    };
114    let inherited = enclosing
115        .filter_map(|l| l.template.as_ref())
116        .map(|t| &t.multi)
117        .try_fold(MultiInfo::default(), |merged, multi| {
118            merge_multi(&merged, multi)
119        })?;
120    let mut layer = level.clone();
121    layer.template = Some(SegmentTemplate {
122        multi: merge_multi(&inherited, &template.multi)?,
123        media: template.media.clone(),
124        index: template.index.clone(),
125        initialization: template.initialization.clone(),
126        bitstream_switching: template.bitstream_switching.clone(),
127    });
128    Ok(layer)
129}
130
131fn merge_base(parent: &BaseInfo, child: &BaseInfo) -> BaseInfo {
132    BaseInfo {
133        timescale: child.timescale.or(parent.timescale),
134        presentation_time_offset: child
135            .presentation_time_offset
136            .or(parent.presentation_time_offset),
137        ept_delta: child.ept_delta.or(parent.ept_delta),
138        pd_delta: child.pd_delta.or(parent.pd_delta),
139        presentation_duration: child.presentation_duration.or(parent.presentation_duration),
140        time_shift_buffer_depth: child
141            .time_shift_buffer_depth
142            .or(parent.time_shift_buffer_depth),
143        index_range: child.index_range.or(parent.index_range),
144        index_range_exact: child.index_range_exact.or(parent.index_range_exact),
145        availability_time_offset: child
146            .availability_time_offset
147            .or(parent.availability_time_offset),
148        availability_time_complete: child
149            .availability_time_complete
150            .or(parent.availability_time_complete),
151        initialization: child
152            .initialization
153            .clone()
154            .or_else(|| parent.initialization.clone()),
155        representation_index: child
156            .representation_index
157            .clone()
158            .or_else(|| parent.representation_index.clone()),
159    }
160}
161
162fn merge_multi(parent: &MultiInfo, child: &MultiInfo) -> Result<MultiInfo, InheritError> {
163    let (duration, timeline) = (
164        child.duration.or(parent.duration),
165        child.timeline.clone().or_else(|| parent.timeline.clone()),
166    );
167    Ok(MultiInfo {
168        base: merge_base(&parent.base, &child.base),
169        duration,
170        start_number: child.start_number.or(parent.start_number),
171        end_number: child.end_number.or(parent.end_number),
172        timeline,
173        bitstream_switching: child
174            .bitstream_switching
175            .clone()
176            .or_else(|| parent.bitstream_switching.clone()),
177    })
178}
179
180fn finish_multi(m: MultiInfo) -> Result<ResolvedMulti, InheritError> {
181    if m.duration.is_some() && m.timeline.is_some() {
182        return Err(InheritError::DurationAndTimeline);
183    }
184    Ok(ResolvedMulti {
185        timescale: m.base.timescale.unwrap_or(DEFAULT_TIMESCALE),
186        presentation_time_offset: m
187            .base
188            .presentation_time_offset
189            .unwrap_or(DEFAULT_PRESENTATION_TIME_OFFSET),
190        base: m.base,
191        duration: m.duration,
192        start_number: m.start_number.unwrap_or(DEFAULT_START_NUMBER),
193        end_number: m.end_number,
194        timeline: m.timeline,
195    })
196}
197
198/// Resolve the effective Segment information of `rep`.
199///
200/// # Errors
201/// [`InheritError`] when the chain violates 5.3.9.1 / 5.3.9.2.1; the caller
202/// drops the Representation.
203pub fn resolve_segment_info(
204    period: &Period,
205    set: &AdaptationSet,
206    rep: &Representation,
207) -> Result<SegmentInfo, InheritError> {
208    let segments = [&period.segment, &set.segment, &rep.segment];
209    let resolved: Vec<SegmentLayer> = segments
210        .iter()
211        .copied()
212        .enumerate()
213        .map(|(i, l)| with_inherited_timeline(segments[..i].iter().copied(), l))
214        .collect::<Result<_, _>>()?;
215    let layers = [&resolved[0], &resolved[1], &resolved[2]];
216    let has_template = layers.iter().any(|l| l.template.is_some());
217    let has_list = layers.iter().any(|l| l.list.is_some());
218    if has_template && has_list {
219        return Err(InheritError::TemplateAndList);
220    }
221    if has_template {
222        let mut merged = crate::model::SegmentTemplate::default();
223        for t in layers.iter().filter_map(|l| l.template.as_ref()) {
224            merged = crate::model::SegmentTemplate {
225                multi: merge_multi(&merged.multi, &t.multi)?,
226                media: t.media.clone().or(merged.media),
227                index: t.index.clone().or(merged.index),
228                initialization: t.initialization.clone().or(merged.initialization),
229                bitstream_switching: t.bitstream_switching.clone().or(merged.bitstream_switching),
230            };
231        }
232        return Ok(SegmentInfo::Template(TemplateInfo {
233            multi: finish_multi(merged.multi)?,
234            media: merged.media,
235            index: merged.index,
236            initialization: merged.initialization,
237            bitstream_switching: merged.bitstream_switching,
238        }));
239    }
240    if has_list {
241        let mut multi = MultiInfo::default();
242        let mut urls: Vec<SegmentUrl> = Vec::new();
243        for l in layers.iter().filter_map(|l| l.list.as_ref()) {
244            multi = merge_multi(&multi, &l.multi)?;
245            if !l.urls.is_empty() {
246                urls.clone_from(&l.urls);
247            }
248        }
249        return Ok(SegmentInfo::List(ListInfo {
250            multi: finish_multi(multi)?,
251            urls,
252        }));
253    }
254    let mut base = BaseInfo::default();
255    for b in layers.iter().filter_map(|l| l.base.as_ref()) {
256        base = merge_base(&base, &b.info);
257    }
258    Ok(SegmentInfo::Base(base))
259}
260
261/// The `RepresentationBase` attributes of `rep`, each falling back to `set`.
262#[must_use]
263pub fn effective_common(set: &AdaptationSet, rep: &Representation) -> CommonAttributes {
264    let (s, r) = (&set.common, &rep.common);
265    CommonAttributes {
266        profiles: r.profiles.clone().or_else(|| s.profiles.clone()),
267        width: r.width.or(s.width),
268        height: r.height.or(s.height),
269        sar: r.sar.clone().or_else(|| s.sar.clone()),
270        frame_rate: r.frame_rate.clone().or_else(|| s.frame_rate.clone()),
271        audio_sampling_rate: r
272            .audio_sampling_rate
273            .clone()
274            .or_else(|| s.audio_sampling_rate.clone()),
275        mime_type: r.mime_type.clone().or_else(|| s.mime_type.clone()),
276        codecs: r.codecs.clone().or_else(|| s.codecs.clone()),
277        max_playout_rate: r.max_playout_rate.or(s.max_playout_rate),
278        coding_dependency: r.coding_dependency.or(s.coding_dependency),
279    }
280}