flowly_mp4/mp4box/
tfhd.rs

1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
8pub struct TfhdBox {
9    pub version: u8,
10    pub flags: u32,
11    pub track_id: u32,
12    pub base_data_offset: Option<u64>,
13    pub sample_description_index: Option<u32>,
14    pub default_sample_duration: Option<u32>,
15    pub default_sample_size: Option<u32>,
16    pub default_sample_flags: Option<u32>,
17}
18
19impl TfhdBox {
20    pub const FLAG_BASE_DATA_OFFSET: u32 = 0x01;
21    pub const FLAG_SAMPLE_DESCRIPTION_INDEX: u32 = 0x02;
22    pub const FLAG_DEFAULT_SAMPLE_DURATION: u32 = 0x08;
23    pub const FLAG_DEFAULT_SAMPLE_SIZE: u32 = 0x10;
24    pub const FLAG_DEFAULT_SAMPLE_FLAGS: u32 = 0x20;
25    pub const FLAG_DURATION_IS_EMPTY: u32 = 0x10000;
26    pub const FLAG_DEFAULT_BASE_IS_MOOF: u32 = 0x20000;
27
28    pub fn get_type(&self) -> BoxType {
29        BoxType::TfhdBox
30    }
31
32    pub fn get_size(&self) -> u64 {
33        let mut sum = HEADER_SIZE + HEADER_EXT_SIZE + 4;
34        if TfhdBox::FLAG_BASE_DATA_OFFSET & self.flags > 0 {
35            sum += 8;
36        }
37        if TfhdBox::FLAG_SAMPLE_DESCRIPTION_INDEX & self.flags > 0 {
38            sum += 4;
39        }
40        if TfhdBox::FLAG_DEFAULT_SAMPLE_DURATION & self.flags > 0 {
41            sum += 4;
42        }
43        if TfhdBox::FLAG_DEFAULT_SAMPLE_SIZE & self.flags > 0 {
44            sum += 4;
45        }
46        if TfhdBox::FLAG_DEFAULT_SAMPLE_FLAGS & self.flags > 0 {
47            sum += 4;
48        }
49        sum
50    }
51}
52
53impl Mp4Box for TfhdBox {
54    const TYPE: BoxType = BoxType::TfhdBox;
55
56    fn box_size(&self) -> u64 {
57        self.get_size()
58    }
59
60    fn to_json(&self) -> Result<String, Error> {
61        Ok(serde_json::to_string(&self).unwrap())
62    }
63
64    fn summary(&self) -> Result<String, Error> {
65        let s = format!("track_id={}", self.track_id);
66        Ok(s)
67    }
68}
69
70impl BlockReader for TfhdBox {
71    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
72        let (version, flags) = read_box_header_ext(reader);
73        let track_id = reader.get_u32();
74
75        let base_data_offset = if TfhdBox::FLAG_BASE_DATA_OFFSET & flags > 0 {
76            Some(reader.get_u64())
77        } else {
78            None
79        };
80
81        let sample_description_index = if TfhdBox::FLAG_SAMPLE_DESCRIPTION_INDEX & flags > 0 {
82            Some(reader.get_u32())
83        } else {
84            None
85        };
86
87        let default_sample_duration = if TfhdBox::FLAG_DEFAULT_SAMPLE_DURATION & flags > 0 {
88            Some(reader.get_u32())
89        } else {
90            None
91        };
92
93        let default_sample_size = if TfhdBox::FLAG_DEFAULT_SAMPLE_SIZE & flags > 0 {
94            Some(reader.get_u32())
95        } else {
96            None
97        };
98
99        let default_sample_flags = if TfhdBox::FLAG_DEFAULT_SAMPLE_FLAGS & flags > 0 {
100            Some(reader.get_u32())
101        } else {
102            None
103        };
104
105        Ok(TfhdBox {
106            version,
107            flags,
108            track_id,
109            base_data_offset,
110            sample_description_index,
111            default_sample_duration,
112            default_sample_size,
113            default_sample_flags,
114        })
115    }
116
117    fn size_hint() -> usize {
118        8
119    }
120}
121
122impl<W: Write> WriteBox<&mut W> for TfhdBox {
123    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
124        let size = self.box_size();
125        BoxHeader::new(Self::TYPE, size).write(writer)?;
126
127        write_box_header_ext(writer, self.version, self.flags)?;
128        writer.write_u32::<BigEndian>(self.track_id)?;
129        if let Some(base_data_offset) = self.base_data_offset {
130            writer.write_u64::<BigEndian>(base_data_offset)?;
131        }
132        if let Some(sample_description_index) = self.sample_description_index {
133            writer.write_u32::<BigEndian>(sample_description_index)?;
134        }
135        if let Some(default_sample_duration) = self.default_sample_duration {
136            writer.write_u32::<BigEndian>(default_sample_duration)?;
137        }
138        if let Some(default_sample_size) = self.default_sample_size {
139            writer.write_u32::<BigEndian>(default_sample_size)?;
140        }
141        if let Some(default_sample_flags) = self.default_sample_flags {
142            writer.write_u32::<BigEndian>(default_sample_flags)?;
143        }
144
145        Ok(size)
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152    use crate::mp4box::BoxHeader;
153
154    #[tokio::test]
155    async fn test_tfhd() {
156        let src_box = TfhdBox {
157            version: 0,
158            flags: 0,
159            track_id: 1,
160            base_data_offset: None,
161            sample_description_index: None,
162            default_sample_duration: None,
163            default_sample_size: None,
164            default_sample_flags: None,
165        };
166        let mut buf = Vec::new();
167        src_box.write_box(&mut buf).unwrap();
168        assert_eq!(buf.len(), src_box.box_size() as usize);
169
170        let mut reader = buf.as_slice();
171        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
172        assert_eq!(header.kind, BoxType::TfhdBox);
173        assert_eq!(src_box.box_size(), header.size);
174
175        let dst_box = TfhdBox::read_block(&mut reader).unwrap();
176        assert_eq!(src_box, dst_box);
177    }
178
179    #[tokio::test]
180    async fn test_tfhd_with_flags() {
181        let src_box = TfhdBox {
182            version: 0,
183            flags: TfhdBox::FLAG_SAMPLE_DESCRIPTION_INDEX
184                | TfhdBox::FLAG_DEFAULT_SAMPLE_DURATION
185                | TfhdBox::FLAG_DEFAULT_SAMPLE_FLAGS,
186            track_id: 1,
187            base_data_offset: None,
188            sample_description_index: Some(1),
189            default_sample_duration: Some(512),
190            default_sample_size: None,
191            default_sample_flags: Some(0x1010000),
192        };
193        let mut buf = Vec::new();
194        src_box.write_box(&mut buf).unwrap();
195        assert_eq!(buf.len(), src_box.box_size() as usize);
196
197        let mut reader = buf.as_slice();
198        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
199        assert_eq!(header.kind, BoxType::TfhdBox);
200        assert_eq!(src_box.box_size(), header.size);
201
202        let dst_box = TfhdBox::read_block(&mut reader).unwrap();
203        assert_eq!(src_box, dst_box);
204    }
205}