Coverage Report

Created: 2026-10-28 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}