1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::internal_utils::*;
16 use crate::parser::mp4box::ItemProperty;
17 use crate::parser::mp4box::MetaBox;
18 use crate::*;
19 
20 #[derive(Clone, Copy, Debug, PartialEq)]
21 pub enum RepetitionCount {
22     Unknown,
23     Infinite,
24     Finite(i32),
25 }
26 
27 impl Default for RepetitionCount {
default() -> Self28     fn default() -> Self {
29         Self::Finite(0)
30     }
31 }
32 
33 #[derive(Debug, Default)]
34 pub struct Track {
35     pub id: u32,
36     pub aux_for_id: Option<u32>,
37     pub prem_by_id: Option<u32>,
38     pub media_timescale: u32,
39     pub media_duration: u64,
40     pub track_duration: u64,
41     pub segment_duration: u64,
42     pub is_repeating: bool,
43     pub width: u32,
44     pub height: u32,
45     pub sample_table: Option<SampleTable>,
46     pub elst_seen: bool,
47     pub meta: Option<MetaBox>,
48 }
49 
50 impl Track {
check_limits(&self, size_limit: u32, dimension_limit: u32) -> bool51     pub fn check_limits(&self, size_limit: u32, dimension_limit: u32) -> bool {
52         check_limits(self.width, self.height, size_limit, dimension_limit)
53     }
54 
has_av1_samples(&self) -> bool55     fn has_av1_samples(&self) -> bool {
56         if let Some(sample_table) = &self.sample_table {
57             self.id != 0 && !sample_table.chunk_offsets.is_empty() && sample_table.has_av1_sample()
58         } else {
59             false
60         }
61     }
is_aux(&self, primary_track_id: u32) -> bool62     pub fn is_aux(&self, primary_track_id: u32) -> bool {
63         self.has_av1_samples() && self.aux_for_id == Some(primary_track_id)
64     }
is_color(&self) -> bool65     pub fn is_color(&self) -> bool {
66         self.has_av1_samples() && self.aux_for_id.is_none()
67     }
68 
get_properties(&self) -> Option<&Vec<ItemProperty>>69     pub fn get_properties(&self) -> Option<&Vec<ItemProperty>> {
70         self.sample_table.as_ref()?.get_properties()
71     }
72 
repetition_count(&self) -> AvifResult<RepetitionCount>73     pub fn repetition_count(&self) -> AvifResult<RepetitionCount> {
74         if !self.elst_seen {
75             return Ok(RepetitionCount::Unknown);
76         }
77         if self.is_repeating {
78             if self.track_duration == u64::MAX {
79                 // If isRepeating is true and the track duration is unknown/indefinite, then set the
80                 // repetition count to infinite(Section 9.6.1 of ISO/IEC 23008-12 Part 12).
81                 return Ok(RepetitionCount::Infinite);
82             } else {
83                 // Section 9.6.1. of ISO/IEC 23008-12 Part 12: 1, the entire edit list is repeated a
84                 // sufficient number of times to equal the track duration.
85                 //
86                 // Since libavif uses repetitionCount (which is 0-based), we subtract the value by 1
87                 // to derive the number of repetitions.
88                 assert!(self.segment_duration != 0);
89                 // We specifically check for trackDuration == 0 here and not when it is actually
90                 // read in order to accept files which inadvertently has a trackDuration of 0
91                 // without any edit lists.
92                 if self.track_duration == 0 {
93                     return Err(AvifError::BmffParseFailed(
94                         "invalid track duration 0".into(),
95                     ));
96                 }
97                 let repetition_count: u64 = self.track_duration.div_ceil(self.segment_duration) - 1;
98                 return match i32::try_from(repetition_count) {
99                     Ok(value) => Ok(RepetitionCount::Finite(value)),
100                     Err(_) => Ok(RepetitionCount::Infinite),
101                 };
102             }
103         }
104         Ok(RepetitionCount::Finite(0))
105     }
106 
image_timing(&self, image_index: u32) -> AvifResult<ImageTiming>107     pub fn image_timing(&self, image_index: u32) -> AvifResult<ImageTiming> {
108         let sample_table = self.sample_table.as_ref().ok_or(AvifError::NoContent)?;
109         let mut image_timing = ImageTiming {
110             timescale: self.media_timescale as u64,
111             pts_in_timescales: 0,
112             ..ImageTiming::default()
113         };
114         for i in 0..image_index as usize {
115             checked_incr!(
116                 image_timing.pts_in_timescales,
117                 sample_table.image_delta(i)? as u64
118             );
119         }
120         image_timing.duration_in_timescales =
121             sample_table.image_delta(image_index as usize)? as u64;
122         if image_timing.timescale > 0 {
123             image_timing.pts =
124                 image_timing.pts_in_timescales as f64 / image_timing.timescale as f64;
125             image_timing.duration =
126                 image_timing.duration_in_timescales as f64 / image_timing.timescale as f64;
127         } else {
128             image_timing.pts = 0.0;
129             image_timing.duration = 0.0;
130         }
131         Ok(image_timing)
132     }
133 }
134 
135 #[derive(Debug)]
136 pub struct TimeToSample {
137     pub sample_count: u32,
138     pub sample_delta: u32,
139 }
140 
141 // Section 8.7.4.3 of ISO/IEC 14496-12.
142 #[derive(Debug)]
143 pub struct SampleToChunk {
144     pub first_chunk: u32, // 1-based
145     pub samples_per_chunk: u32,
146     pub sample_description_index: u32, // 1-based
147 }
148 
149 #[derive(Debug, Default)]
150 pub struct SampleDescription {
151     pub format: String,
152     pub properties: Vec<ItemProperty>,
153 }
154 
155 #[derive(Debug)]
156 pub enum SampleSize {
157     FixedSize(u32),
158     Sizes(Vec<u32>),
159 }
160 
161 impl Default for SampleSize {
default() -> Self162     fn default() -> Self {
163         Self::FixedSize(0)
164     }
165 }
166 
167 #[derive(Debug, Default)]
168 pub struct SampleTable {
169     pub chunk_offsets: Vec<u64>,
170     pub sample_to_chunk: Vec<SampleToChunk>,
171     pub sample_size: SampleSize,
172     pub sync_samples: Vec<u32>,
173     pub time_to_sample: Vec<TimeToSample>,
174     pub sample_descriptions: Vec<SampleDescription>,
175 }
176 
177 impl SampleTable {
has_av1_sample(&self) -> bool178     pub fn has_av1_sample(&self) -> bool {
179         self.sample_descriptions.iter().any(|x| x.format == "av01")
180     }
181 
182     // returns the number of samples in the chunk.
get_sample_count_of_chunk(&self, chunk_index: u32) -> u32183     pub fn get_sample_count_of_chunk(&self, chunk_index: u32) -> u32 {
184         for entry in self.sample_to_chunk.iter().rev() {
185             if entry.first_chunk <= chunk_index + 1 {
186                 return entry.samples_per_chunk;
187             }
188         }
189         0
190     }
191 
get_properties(&self) -> Option<&Vec<ItemProperty>>192     pub fn get_properties(&self) -> Option<&Vec<ItemProperty>> {
193         Some(
194             &self
195                 .sample_descriptions
196                 .iter()
197                 .find(|x| x.format == "av01")?
198                 .properties,
199         )
200     }
201 
sample_size(&self, index: usize) -> AvifResult<usize>202     pub fn sample_size(&self, index: usize) -> AvifResult<usize> {
203         usize_from_u32(match &self.sample_size {
204             SampleSize::FixedSize(size) => *size,
205             SampleSize::Sizes(sizes) => {
206                 if index >= sizes.len() {
207                     return Err(AvifError::BmffParseFailed(
208                         "not enough sampel sizes in the table".into(),
209                     ));
210                 }
211                 sizes[index]
212             }
213         })
214     }
215 
image_delta(&self, index: usize) -> AvifResult<u32>216     pub fn image_delta(&self, index: usize) -> AvifResult<u32> {
217         let mut max_index: u32 = 0;
218         for (i, time_to_sample) in self.time_to_sample.iter().enumerate() {
219             checked_incr!(max_index, time_to_sample.sample_count);
220             if index < max_index as usize || i == self.time_to_sample.len() - 1 {
221                 return Ok(time_to_sample.sample_delta);
222             }
223         }
224         Ok(1)
225     }
226 }
227 
228 /// cbindgen:rename-all=CamelCase
229 #[repr(C)]
230 #[derive(Clone, Copy, Debug, Default)]
231 pub struct ImageTiming {
232     pub timescale: u64,
233     pub pts: f64,
234     pub pts_in_timescales: u64,
235     pub duration: f64,
236     pub duration_in_timescales: u64,
237 }
238