/src/symphonia/symphonia-format-isomp4/src/atoms/sidx.rs
Line | Count | Source |
1 | | // Symphonia |
2 | | // Copyright (c) 2019-2026 The Project Symphonia Developers. |
3 | | // |
4 | | // This Source Code Form is subject to the terms of the Mozilla Public |
5 | | // License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | // file, You can obtain one at https://mozilla.org/MPL/2.0/. |
7 | | |
8 | | use std::num::NonZero; |
9 | | |
10 | | use symphonia_core::errors::Error; |
11 | | |
12 | | use crate::atoms::{Atom, AtomHeader, AtomIterator, ReadAtom, Result, decode_error}; |
13 | | |
14 | | #[derive(Debug)] |
15 | | pub enum ReferenceType { |
16 | | Segment, |
17 | | Media, |
18 | | } |
19 | | |
20 | | #[allow(dead_code)] |
21 | | #[derive(Debug)] |
22 | | pub struct SidxReference { |
23 | | pub reference_type: ReferenceType, |
24 | | pub reference_size: u32, |
25 | | pub subsegment_duration: u32, |
26 | | // pub starts_with_sap: bool, |
27 | | // pub sap_type: u8, |
28 | | // pub sap_delta_time: u32, |
29 | | } |
30 | | |
31 | | /// Segment index atom. |
32 | | #[allow(dead_code)] |
33 | | #[derive(Debug)] |
34 | | pub struct SidxAtom { |
35 | | pub reference_id: u32, |
36 | | pub timescale: NonZero<u32>, |
37 | | pub earliest_pts: u64, |
38 | | pub first_offset: u64, |
39 | | pub references: Vec<SidxReference>, |
40 | | pub total_duration: u64, |
41 | | } |
42 | | |
43 | | impl Atom for SidxAtom { |
44 | 4.33k | fn read<R: ReadAtom>(it: &mut AtomIterator<R>, header: &AtomHeader) -> Result<Self> { |
45 | 4.33k | let (version, _) = it.read_extended_header()?; |
46 | | |
47 | 4.32k | let reference_id = it.read_u32()?; |
48 | 4.32k | let timescale = NonZero::new(it.read_u32()?) |
49 | 4.31k | .ok_or(Error::DecodeError("isomp4 (sidx): timescale is zero"))?; |
50 | | |
51 | | // The anchor point for segment offsets is the first byte after this atom. |
52 | 4.31k | let anchor = header |
53 | 4.31k | .size() |
54 | 4.31k | .map(|atom_len| header.pos() + atom_len.get()) |
55 | 4.31k | .ok_or(Error::DecodeError("isomp4 (sidx): expected atom size to be known"))?; |
56 | | |
57 | 4.28k | let (earliest_pts, first_offset) = match version { |
58 | 4.10k | 0 => (u64::from(it.read_u32()?), anchor + u64::from(it.read_u32()?)), |
59 | 170 | 1 => (it.read_u64()?, anchor + it.read_u64()?), |
60 | 10 | _ => return decode_error("isomp4 (sidx): invalid version"), |
61 | | }; |
62 | | |
63 | 4.22k | let _reserved = it.read_u16()?; |
64 | 4.21k | let reference_count = it.read_u16()?; |
65 | | |
66 | 4.21k | let mut references = Vec::new(); |
67 | 4.21k | let mut total_duration = 0u64; |
68 | | |
69 | 4.21k | for _ in 0..reference_count { |
70 | 19.7k | let reference = it.read_u32()?; |
71 | 19.6k | let subsegment_duration = it.read_u32()?; |
72 | | |
73 | 19.6k | total_duration = total_duration |
74 | 19.6k | .checked_add(u64::from(subsegment_duration)) |
75 | 19.6k | .ok_or(Error::DecodeError("isomp4 (sidx): total duration overflow"))?; |
76 | | |
77 | 19.6k | let reference_type = match (reference & 0x8000_0000) != 0 { |
78 | 11.2k | false => ReferenceType::Media, |
79 | 8.39k | true => ReferenceType::Segment, |
80 | | }; |
81 | | |
82 | 19.6k | let reference_size = reference & !0x8000_0000; |
83 | | |
84 | | // Ignore SAP |
85 | 19.6k | let _ = it.read_u32()?; |
86 | | |
87 | 19.5k | references.push(SidxReference { reference_type, reference_size, subsegment_duration }); |
88 | | } |
89 | | |
90 | 4.07k | Ok(SidxAtom { |
91 | 4.07k | reference_id, |
92 | 4.07k | timescale, |
93 | 4.07k | earliest_pts, |
94 | 4.07k | first_offset, |
95 | 4.07k | references, |
96 | 4.07k | total_duration, |
97 | 4.07k | }) |
98 | 4.33k | } |
99 | | } |