vsd_mp4/boxes/sidx.rs
1use crate::{Mp4Parser, ParsedBox, Result, bail, data};
2
3/// A byte range for a subsegment or media fragment indexed by the `sidx` box.
4#[derive(Debug, Clone)]
5pub struct SidxRange {
6 /// The ending byte offset (inclusive) of the subsegment.
7 pub end: u64,
8 /// The starting byte offset of the subsegment.
9 pub start: u64,
10}
11
12/// Segment Index Box (sidx) - provides index information for media subsegments.
13///
14/// This box defines the subsegment structure, mapping them to specific byte ranges
15/// inside the media container.
16#[derive(Debug, Clone)]
17pub struct SidxBox {
18 /// The list of byte ranges for the indexed subsegments.
19 pub ranges: Vec<SidxRange>,
20}
21
22impl SidxBox {
23 /// Helper method to find and parse a `sidx` box from initialization or segment data.
24 ///
25 /// # Arguments
26 /// * `data` - The byte slice containing the box hierarchy.
27 /// * `offset` - The absolute starting byte offset of the `sidx` box.
28 pub fn from_init(data: &[u8], offset: u64) -> Result<Option<Self>> {
29 let sidx_box = data!();
30 let sidx_box_c = sidx_box.clone();
31
32 Mp4Parser::new()
33 .full_box("sidx", move |mut box_| {
34 *sidx_box_c.borrow_mut() = Some(Self::new(&mut box_, offset)?);
35 Ok(())
36 })
37 .parse(data, false, false)?;
38
39 Ok(sidx_box.take())
40 }
41
42 /// Parses a `sidx` box from a `ParsedBox`.
43 ///
44 /// # Arguments
45 /// * `box_` - The parsed box to read from.
46 /// * `offset` - The absolute starting byte offset of the `sidx` box.
47 pub fn new(box_: &mut ParsedBox, offset: u64) -> Result<Self> {
48 if box_.version.is_none() {
49 bail!("SIDX is a full box and should have a valid version.");
50 }
51
52 let reader = &mut box_.reader;
53 let version = box_.version.unwrap();
54
55 let mut references = Vec::new();
56
57 reader.skip(4)?;
58
59 let timescale = reader.read_u32()?;
60
61 if timescale == 0 {
62 bail!("SIDX box has invalid timescale.");
63 }
64
65 let _earliest_presentation_time;
66 let first_offset;
67
68 if version == 0 {
69 _earliest_presentation_time = reader.read_u32()? as u64;
70 first_offset = reader.read_u32()? as u64;
71 } else {
72 _earliest_presentation_time = reader.read_u64()?;
73 first_offset = reader.read_u64()?;
74 }
75
76 reader.skip(2)?;
77
78 let reference_count = reader.read_u16()?;
79
80 // Subtract the presentation time offset
81 // let mut unscaled_start_time = earliest_presentation_time;
82 let mut start_byte = offset + box_.size as u64 + first_offset;
83
84 for _ in 0..reference_count {
85 // |chunk| is 1 bit for |referenceType|, and 31 bits for |referenceSize|.
86 let chunk = reader.read_u32()?;
87 let reference_type = (chunk & 0x80000000) >> 31;
88 let reference_size = chunk & 0x7FFFFFFF;
89
90 let _subsegment_duration = reader.read_u32()?;
91
92 // Skipping 1 bit for |startsWithSap|, 3 bits for |sapType|, and 28 bits
93 // for |sapDelta|.
94 reader.skip(4)?;
95
96 // If |referenceType| is 1 then the reference is to another SIDX.
97 // We do not support this.
98 if reference_type == 1 {
99 bail!("Hierarchical SIDXs are not supported.");
100 }
101
102 // The media timestamps inside the container.
103 // let native_start_Time = unscaled_start_time as f64 / timescale as f64;
104 // let native_end_Time = (unscaled_start_time as f64 + subsegment_duration as f64) / timescale as f64;
105
106 references.push(SidxRange {
107 end: start_byte + reference_size as u64 - 1,
108 start: start_byte,
109 });
110
111 // unscaled_start_time += subsegment_duration as u64;
112 start_byte += reference_size as u64;
113 }
114
115 box_.parser.stop();
116 Ok(Self { ranges: references })
117 }
118}