scuffle_mp4/boxes/types/
traf.rs1use std::io;
2
3use bytes::{Buf, Bytes};
4
5use super::sbgp::Sbgp;
6use super::subs::Subs;
7use super::tfdt::Tfdt;
8use super::tfhd::Tfhd;
9use super::trun::Trun;
10use crate::boxes::DynBox;
11use crate::boxes::header::BoxHeader;
12use crate::boxes::traits::BoxType;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Traf {
18 pub header: BoxHeader,
19 pub tfhd: Tfhd,
20 pub trun: Option<Trun>,
21 pub sbgp: Option<Sbgp>,
22 pub subs: Option<Subs>,
23 pub tfdt: Option<Tfdt>,
24 pub unknown: Vec<DynBox>,
25}
26
27impl Traf {
28 pub fn new(tfhd: Tfhd, trun: Option<Trun>, tfdt: Option<Tfdt>) -> Self {
29 Self {
30 header: BoxHeader::new(Self::NAME),
31 tfhd,
32 trun,
33 sbgp: None,
34 subs: None,
35 tfdt,
36 unknown: Vec::new(),
37 }
38 }
39
40 pub fn optimize(&mut self) {
43 let Some(trun) = &mut self.trun else {
44 return;
45 };
46
47 if trun.samples.is_empty() {
48 return;
49 }
50
51 let tfhd = &mut self.tfhd;
52
53 if tfhd.default_sample_flags.is_none()
54 && trun.samples.len() > 1
55 && trun.samples.iter().skip(2).all(|s| s.flags == trun.samples[1].flags)
56 {
57 tfhd.default_sample_flags = trun.samples[1].flags;
58
59 let first_sample = trun.samples.first().unwrap();
60 if first_sample.flags != tfhd.default_sample_flags {
61 trun.first_sample_flags = first_sample.flags;
62 }
63
64 trun.samples.iter_mut().for_each(|s| s.flags = None);
65 }
66
67 if trun.samples.iter().all(|s| s.composition_time_offset == Some(0)) {
68 trun.samples.iter_mut().for_each(|s| s.composition_time_offset = None);
69 }
70
71 if tfhd.default_sample_duration.is_none()
72 && trun.samples.iter().skip(1).all(|s| s.duration == trun.samples[0].duration)
73 {
74 tfhd.default_sample_duration = trun.samples[0].duration;
75 trun.samples.iter_mut().for_each(|s| s.duration = None);
76 }
77
78 if tfhd.default_sample_size.is_none() && trun.samples.iter().skip(1).all(|s| s.size == trun.samples[0].size) {
79 tfhd.default_sample_size = trun.samples[0].size;
80 trun.samples.iter_mut().for_each(|s| s.size = None);
81 }
82
83 trun.header.flags = if trun.data_offset.is_some() {
84 Trun::FLAG_DATA_OFFSET
85 } else {
86 0
87 } | if trun.first_sample_flags.is_some() {
88 Trun::FLAG_FIRST_SAMPLE_FLAGS
89 } else {
90 0
91 } | if trun.samples.first().and_then(|s| s.duration).is_some() {
92 Trun::FLAG_SAMPLE_DURATION
93 } else {
94 0
95 } | if trun.samples.first().and_then(|s| s.size).is_some() {
96 Trun::FLAG_SAMPLE_SIZE
97 } else {
98 0
99 } | if trun.samples.first().and_then(|s| s.flags).is_some() {
100 Trun::FLAG_SAMPLE_FLAGS
101 } else {
102 0
103 } | if trun.samples.first().and_then(|s| s.composition_time_offset).is_some() {
104 Trun::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET
105 } else {
106 0
107 };
108
109 tfhd.header.flags = if tfhd.base_data_offset.is_some() {
110 Tfhd::BASE_DATA_OFFSET_FLAG
111 } else {
112 0
113 } | if tfhd.default_sample_duration.is_some() {
114 Tfhd::DEFAULT_SAMPLE_DURATION_FLAG
115 } else {
116 0
117 } | if tfhd.default_sample_flags.is_some() {
118 Tfhd::DEFAULT_SAMPLE_FLAGS_FLAG
119 } else {
120 0
121 } | if tfhd.default_sample_size.is_some() {
122 Tfhd::DEFAULT_SAMPLE_SIZE_FLAG
123 } else {
124 0
125 } | tfhd.header.flags & Tfhd::DEFAULT_BASE_IS_MOOF_FLAG;
126 }
127
128 pub fn duration(&self) -> u32 {
129 let tfhd = &self.tfhd;
130 let trun = &self.trun;
131
132 if let Some(trun) = trun {
133 let mut duration = 0;
134 for sample in &trun.samples {
135 if let Some(d) = sample.duration {
136 duration += d;
137 } else if let Some(d) = tfhd.default_sample_duration {
138 duration += d;
139 }
140 }
141
142 return duration;
143 }
144
145 0
146 }
147
148 pub fn contains_keyframe(&self) -> bool {
149 let tfhd = &self.tfhd;
150 let trun = &self.trun;
151
152 if let Some(trun) = trun {
153 if let Some(flags) = trun.first_sample_flags {
154 if flags.sample_depends_on == 2 {
155 return true;
156 }
157 }
158
159 for sample in &trun.samples {
160 if let Some(flags) = sample.flags {
161 if flags.sample_depends_on == 2 {
162 return true;
163 }
164 } else if let Some(flags) = tfhd.default_sample_flags {
165 if flags.sample_depends_on == 2 {
166 return true;
167 }
168 }
169 }
170 }
171
172 false
173 }
174}
175
176impl BoxType for Traf {
177 const NAME: [u8; 4] = *b"traf";
178
179 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
180 let mut reader = io::Cursor::new(data);
181
182 let mut tfhd = None;
183 let mut trun = None;
184 let mut sbgp = None;
185 let mut subs = None;
186 let mut tfdt = None;
187
188 let mut unknown = Vec::new();
189
190 while reader.has_remaining() {
191 let box_ = DynBox::demux(&mut reader)?;
192 match box_ {
193 DynBox::Tfhd(b) => {
194 tfhd = Some(*b);
195 }
196 DynBox::Trun(b) => {
197 trun = Some(*b);
198 }
199 DynBox::Sbgp(b) => {
200 sbgp = Some(*b);
201 }
202 DynBox::Subs(b) => {
203 subs = Some(*b);
204 }
205 DynBox::Tfdt(b) => {
206 tfdt = Some(*b);
207 }
208 _ => unknown.push(box_),
209 }
210 }
211
212 let tfhd = tfhd.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "traf box must contain tfhd box"))?;
213
214 Ok(Self {
215 header,
216 tfhd,
217 trun,
218 sbgp,
219 subs,
220 tfdt,
221 unknown,
222 })
223 }
224
225 fn primitive_size(&self) -> u64 {
226 self.tfhd.size()
227 + self.trun.as_ref().map(|box_| box_.size()).unwrap_or(0)
228 + self.sbgp.as_ref().map(|box_| box_.size()).unwrap_or(0)
229 + self.subs.as_ref().map(|box_| box_.size()).unwrap_or(0)
230 + self.tfdt.as_ref().map(|box_| box_.size()).unwrap_or(0)
231 + self.unknown.iter().map(|box_| box_.size()).sum::<u64>()
232 }
233
234 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
235 self.tfhd.mux(writer)?;
236
237 if let Some(box_) = &self.sbgp {
238 box_.mux(writer)?;
239 }
240
241 if let Some(box_) = &self.subs {
242 box_.mux(writer)?;
243 }
244
245 if let Some(box_) = &self.tfdt {
246 box_.mux(writer)?;
247 }
248
249 for box_ in &self.unknown {
250 box_.mux(writer)?;
251 }
252
253 if let Some(box_) = &self.trun {
254 box_.mux(writer)?;
255 }
256
257 Ok(())
258 }
259}