Skip to main content

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}