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