1use thiserror::Error;
13
14use super::model::{
15 AdaptationSet, BaseInfo, CommonAttributes, MultiInfo, Period, Representation, SegmentTimeline,
16 SegmentUrl,
17};
18
19pub const DEFAULT_TIMESCALE: u64 = 1;
21pub const DEFAULT_START_NUMBER: u64 = 1;
23pub const DEFAULT_PRESENTATION_TIME_OFFSET: u64 = 0;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
28#[non_exhaustive]
29pub enum InheritError {
30 #[error(
32 "SegmentTemplate and SegmentList both appear along one Period/AdaptationSet/Representation chain"
33 )]
34 TemplateAndList,
35 #[error("both @duration and SegmentTimeline are present on one level")]
37 DurationAndTimeline,
38}
39
40#[derive(Debug, Clone, PartialEq)]
42#[non_exhaustive]
43pub struct ResolvedMulti {
44 pub base: BaseInfo,
46 pub timescale: u64,
48 pub presentation_time_offset: u64,
50 pub duration: Option<u64>,
52 pub start_number: u64,
54 pub end_number: Option<u64>,
56 pub timeline: Option<SegmentTimeline>,
58}
59
60#[derive(Debug, Clone, PartialEq)]
62#[non_exhaustive]
63pub struct TemplateInfo {
64 pub multi: ResolvedMulti,
66 pub media: Option<String>,
68 pub index: Option<String>,
70 pub initialization: Option<String>,
72 pub bitstream_switching: Option<String>,
74}
75
76#[derive(Debug, Clone, PartialEq)]
78#[non_exhaustive]
79pub struct ListInfo {
80 pub multi: ResolvedMulti,
82 pub urls: Vec<SegmentUrl>,
84}
85
86#[derive(Debug, Clone, PartialEq)]
89#[non_exhaustive]
90pub enum SegmentInfo {
91 Template(TemplateInfo),
93 List(ListInfo),
95 Base(BaseInfo),
98}
99
100fn merge_base(parent: &BaseInfo, child: &BaseInfo) -> BaseInfo {
101 BaseInfo {
102 timescale: child.timescale.or(parent.timescale),
103 presentation_time_offset: child
104 .presentation_time_offset
105 .or(parent.presentation_time_offset),
106 ept_delta: child.ept_delta.or(parent.ept_delta),
107 pd_delta: child.pd_delta.or(parent.pd_delta),
108 presentation_duration: child.presentation_duration.or(parent.presentation_duration),
109 time_shift_buffer_depth: child
110 .time_shift_buffer_depth
111 .or(parent.time_shift_buffer_depth),
112 index_range: child.index_range.or(parent.index_range),
113 index_range_exact: child.index_range_exact.or(parent.index_range_exact),
114 availability_time_offset: child
115 .availability_time_offset
116 .or(parent.availability_time_offset),
117 availability_time_complete: child
118 .availability_time_complete
119 .or(parent.availability_time_complete),
120 initialization: child
121 .initialization
122 .clone()
123 .or_else(|| parent.initialization.clone()),
124 representation_index: child
125 .representation_index
126 .clone()
127 .or_else(|| parent.representation_index.clone()),
128 }
129}
130
131fn merge_multi(parent: &MultiInfo, child: &MultiInfo) -> Result<MultiInfo, InheritError> {
132 if child.duration.is_some() && child.timeline.is_some() {
133 return Err(InheritError::DurationAndTimeline);
134 }
135 let (duration, timeline) = if child.timeline.is_some() {
136 (None, child.timeline.clone())
137 } else if child.duration.is_some() {
138 (child.duration, None)
139 } else {
140 (parent.duration, parent.timeline.clone())
141 };
142 Ok(MultiInfo {
143 base: merge_base(&parent.base, &child.base),
144 duration,
145 start_number: child.start_number.or(parent.start_number),
146 end_number: child.end_number.or(parent.end_number),
147 timeline,
148 bitstream_switching: child
149 .bitstream_switching
150 .clone()
151 .or_else(|| parent.bitstream_switching.clone()),
152 })
153}
154
155fn finish_multi(m: MultiInfo) -> Result<ResolvedMulti, InheritError> {
156 if m.duration.is_some() && m.timeline.is_some() {
157 return Err(InheritError::DurationAndTimeline);
158 }
159 Ok(ResolvedMulti {
160 timescale: m.base.timescale.unwrap_or(DEFAULT_TIMESCALE),
161 presentation_time_offset: m
162 .base
163 .presentation_time_offset
164 .unwrap_or(DEFAULT_PRESENTATION_TIME_OFFSET),
165 base: m.base,
166 duration: m.duration,
167 start_number: m.start_number.unwrap_or(DEFAULT_START_NUMBER),
168 end_number: m.end_number,
169 timeline: m.timeline,
170 })
171}
172
173pub fn resolve_segment_info(
179 period: &Period,
180 set: &AdaptationSet,
181 rep: &Representation,
182) -> Result<SegmentInfo, InheritError> {
183 let layers = [&period.segment, &set.segment, &rep.segment];
184 let has_template = layers.iter().any(|l| l.template.is_some());
185 let has_list = layers.iter().any(|l| l.list.is_some());
186 if has_template && has_list {
187 return Err(InheritError::TemplateAndList);
188 }
189 if has_template {
190 let mut merged = crate::mpd::model::SegmentTemplate::default();
191 for t in layers.iter().filter_map(|l| l.template.as_ref()) {
192 merged = crate::mpd::model::SegmentTemplate {
193 multi: merge_multi(&merged.multi, &t.multi)?,
194 media: t.media.clone().or(merged.media),
195 index: t.index.clone().or(merged.index),
196 initialization: t.initialization.clone().or(merged.initialization),
197 bitstream_switching: t.bitstream_switching.clone().or(merged.bitstream_switching),
198 };
199 }
200 return Ok(SegmentInfo::Template(TemplateInfo {
201 multi: finish_multi(merged.multi)?,
202 media: merged.media,
203 index: merged.index,
204 initialization: merged.initialization,
205 bitstream_switching: merged.bitstream_switching,
206 }));
207 }
208 if has_list {
209 let mut multi = MultiInfo::default();
210 let mut urls: Vec<SegmentUrl> = Vec::new();
211 for l in layers.iter().filter_map(|l| l.list.as_ref()) {
212 multi = merge_multi(&multi, &l.multi)?;
213 if !l.urls.is_empty() {
214 urls.clone_from(&l.urls);
215 }
216 }
217 return Ok(SegmentInfo::List(ListInfo {
218 multi: finish_multi(multi)?,
219 urls,
220 }));
221 }
222 let mut base = BaseInfo::default();
223 for b in layers.iter().filter_map(|l| l.base.as_ref()) {
224 base = merge_base(&base, &b.info);
225 }
226 Ok(SegmentInfo::Base(base))
227}
228
229#[must_use]
231pub fn effective_common(set: &AdaptationSet, rep: &Representation) -> CommonAttributes {
232 let (s, r) = (&set.common, &rep.common);
233 CommonAttributes {
234 profiles: r.profiles.clone().or_else(|| s.profiles.clone()),
235 width: r.width.or(s.width),
236 height: r.height.or(s.height),
237 sar: r.sar.clone().or_else(|| s.sar.clone()),
238 frame_rate: r.frame_rate.clone().or_else(|| s.frame_rate.clone()),
239 audio_sampling_rate: r
240 .audio_sampling_rate
241 .clone()
242 .or_else(|| s.audio_sampling_rate.clone()),
243 mime_type: r.mime_type.clone().or_else(|| s.mime_type.clone()),
244 codecs: r.codecs.clone().or_else(|| s.codecs.clone()),
245 max_playout_rate: r.max_playout_rate.or(s.max_playout_rate),
246 }
247}