dash_runtime/address/
list.rs1use super::AddressError;
4use super::timeline::TimelineIndex;
5use broadcast_dash::inherit::ListInfo;
6use broadcast_dash::{ByteRange, SegmentUrl};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[non_exhaustive]
11pub struct ListSegment {
12 pub number: u64,
14 pub time: u64,
16 pub duration: u64,
18 pub reference: String,
20 pub range: Option<ByteRange>,
22 pub entry: SegmentUrl,
24}
25
26pub fn expand(
32 info: &ListInfo,
33 timeline: Option<&TimelineIndex>,
34 period_duration_ticks: Option<u64>,
35) -> Result<Vec<ListSegment>, AddressError> {
36 let urls = &info.urls;
37 let multi = &info.multi;
38 let mut out = Vec::with_capacity(urls.len());
39 if let Some(t) = timeline {
40 if t.len() != urls.len() as u64 {
41 return Err(AddressError::ListTimelineMismatch {
42 urls: urls.len(),
43 segments: t.len(),
44 });
45 }
46 } else if multi.duration.is_none() && urls.len() > 1 {
47 return Err(AddressError::MissingDuration);
48 }
49 for (i, entry) in urls.iter().enumerate() {
50 if entry.media.is_none() && entry.media_range.is_none() {
51 return Err(AddressError::EmptySegmentUrl);
52 }
53 let idx = i as u64;
54 let (number, time, duration) = match timeline.and_then(|t| t.segment(idx)) {
55 Some(seg) => (seg.number, seg.time, seg.duration),
56 None => {
57 let d = multi.duration.unwrap_or(period_duration_ticks.unwrap_or(0));
58 let start = idx.checked_mul(d).ok_or(AddressError::Overflow)?;
59 let last = i + 1 == urls.len();
60 let dur = match (last, multi.duration, period_duration_ticks) {
61 (true, Some(nominal), Some(total)) => total.saturating_sub(start).min(nominal),
62 _ => d,
63 };
64 (multi.start_number.saturating_add(idx), start, dur)
65 }
66 };
67 out.push(ListSegment {
68 number,
69 time,
70 duration,
71 reference: entry.media.clone().unwrap_or_default(),
72 range: entry.media_range,
73 entry: entry.clone(),
74 });
75 }
76 Ok(out)
77}