1use std::io::{Cursor, Read};
9use byteorder::{BigEndian, ReadBytesExt};
10use tracing::{warn, trace};
11
12
13#[derive(Debug, Clone, PartialEq)]
16pub struct SidxBox {
17 pub version: u8,
18 pub flags: u32, pub reference_id: u32,
20 pub timescale: u32,
21 pub earliest_presentation_time: u64,
22 pub first_offset: u64,
23 pub reference_count: u16,
24 pub references: Vec<SidxReference>,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct SidxReference {
29 pub reference_type: u8,
30 pub referenced_size: u32,
31 pub subsegment_duration: u32,
32 pub starts_with_sap: u8, pub sap_type: u8,
34 pub sap_delta_time: u32,
35}
36
37
38impl SidxBox {
39 pub fn parse(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
40 let mut rdr = Cursor::new(data);
41 let _box_size = rdr.read_u32::<BigEndian>()?;
42 let mut box_header = [0u8; 4];
43 if rdr.read_exact(&mut box_header).is_err() {
44 return Err("reading box header".into());
45 }
46 if !box_header.eq(b"sidx") {
47 return Err("expecting sidx BMFF header".into());
48 }
49 let version = rdr.read_u8()?;
50 let flags = rdr.read_u24::<BigEndian>()?;
51 let reference_id = rdr.read_u32::<BigEndian>()?;
52 let timescale = rdr.read_u32::<BigEndian>()?;
53 let earliest_presentation_time = if version == 0 {
54 u64::from(rdr.read_u32::<BigEndian>()?)
55 } else {
56 rdr.read_u64::<BigEndian>()?
57 };
58 let first_offset = if version == 0 {
59 u64::from(rdr.read_u32::<BigEndian>()?)
60 } else {
61 rdr.read_u64::<BigEndian>()?
62 };
63 let _reserved = rdr.read_u16::<BigEndian>()?;
64 let reference_count = rdr.read_u16::<BigEndian>()?;
65 let mut references = Vec::with_capacity(reference_count as usize);
66 for _ in 0..reference_count {
67 let chunk = rdr.read_u32::<BigEndian>()?;
69 let reference_type = ((chunk & 0x8000_0000) >> 31) as u8;
71 if reference_type != 0 {
72 warn!("Don't know how to handle hierarchical sidx");
73 }
74 let referenced_size = chunk & 0x7FFF_FFFF;
75 let subsegment_duration = rdr.read_u32::<BigEndian>()?;
76 let fields = rdr.read_u32::<BigEndian>()?;
77 let starts_with_sap = if (fields >> 31) == 1 { 1 } else { 0 };
78 let sap_type = ((fields >> 28) & 0b0111) as u8;
79 let sap_delta_time = fields & !(0b1111 << 28);
80
81 references.push(SidxReference {
82 reference_type,
83 referenced_size,
84 subsegment_duration,
85 starts_with_sap,
86 sap_type,
87 sap_delta_time,
88 });
89 }
90 Ok(SidxBox {
91 version,
92 flags,
93 reference_id,
94 timescale,
95 earliest_presentation_time,
96 first_offset,
97 reference_count,
98 references,
99 })
100 }
101}
102
103
104#[derive(Debug, Clone, PartialEq)]
105pub struct SegmentChunk {
106 pub start: u64,
107 pub end: u64
108}
109
110pub fn from_isobmff_sidx(data: &[u8], index_start: u64) -> Result<Vec<SegmentChunk>, Box<dyn std::error::Error>> {
111 let mut chunks = Vec::new();
112 let sidx = SidxBox::parse(data)?;
113 let mut current_pos = index_start;
114 for sref in sidx.references {
115 let start = current_pos;
116 let end = current_pos - 1 + u64::from(sref.referenced_size);
117 chunks.push(SegmentChunk{ start, end });
118 current_pos += u64::from(sref.referenced_size);
119 }
120 Ok(chunks)
121}
122
123
124pub fn from_webm_cue(data: &[u8]) -> Result<Vec<SegmentChunk>, Box<dyn std::error::Error>> {
133 use webm_iterable::WebmIterator;
134 use webm_iterable::matroska_spec::MatroskaSpec::{
135 CueClusterPosition,
136 CueRefCluster,
137 CueRefNumber,
138 CueRelativePosition
139 };
140
141 let mut chunks = Vec::new();
143 let mut current_pos: u64 = 0;
144 let mut copy = data;
145 for tag in WebmIterator::new(&mut copy, &[]) {
146 match tag {
147 Err(e) => warn!("Error decoding WebM cues: {e:#?}"),
148 Ok(CueRelativePosition(val)) => {
149 trace!("Saw CueRelativePosition {}", val);
150 },
151 Ok(CueRefCluster(val)) => {
152 trace!("Saw CueRefCluster {val}");
153 },
154 Ok(CueRefNumber(val)) => {
155 trace!("Saw CueRefNumber {val}");
156 },
157 Ok(CueClusterPosition(val)) => {
158 trace!("Saw CueClusterPosition {val}");
159 if current_pos != 0 {
160 chunks.push(SegmentChunk{ start: current_pos, end: val - 1});
161 }
162 current_pos = val;
163 },
164 _ => (),
165 }
166 }
167 Ok(chunks)
168}