flowly_mp4/mp4box/
tfdt.rs1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
8pub struct TfdtBox {
9 pub version: u8,
10 pub flags: u32,
11 pub base_media_decode_time: u64,
12}
13
14impl TfdtBox {
15 pub fn get_type(&self) -> BoxType {
16 BoxType::TfdtBox
17 }
18
19 pub fn get_size(&self) -> u64 {
20 let mut sum = HEADER_SIZE + HEADER_EXT_SIZE;
21 if self.version == 1 {
22 sum += 8;
23 } else {
24 sum += 4;
25 }
26 sum
27 }
28}
29
30impl Mp4Box for TfdtBox {
31 const TYPE: BoxType = BoxType::TfdtBox;
32
33 fn box_size(&self) -> u64 {
34 self.get_size()
35 }
36
37 fn to_json(&self) -> Result<String, Error> {
38 Ok(serde_json::to_string(&self).unwrap())
39 }
40
41 fn summary(&self) -> Result<String, Error> {
42 let s = format!("base_media_decode_time={}", self.base_media_decode_time);
43 Ok(s)
44 }
45}
46
47impl BlockReader for TfdtBox {
48 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
49 let (version, flags) = read_box_header_ext(reader);
50
51 let base_media_decode_time = if version == 1 {
52 reader.get_u64()
53 } else if version == 0 {
54 reader.get_u32() as u64
55 } else {
56 return Err(Error::InvalidData("version must be 0 or 1"));
57 };
58
59 Ok(TfdtBox {
60 version,
61 flags,
62 base_media_decode_time,
63 })
64 }
65
66 fn size_hint() -> usize {
67 8
68 }
69}
70
71impl<W: Write> WriteBox<&mut W> for TfdtBox {
72 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
73 let size = self.box_size();
74 BoxHeader::new(Self::TYPE, size).write(writer)?;
75
76 write_box_header_ext(writer, self.version, self.flags)?;
77
78 if self.version == 1 {
79 writer.write_u64::<BigEndian>(self.base_media_decode_time)?;
80 } else if self.version == 0 {
81 writer.write_u32::<BigEndian>(self.base_media_decode_time as u32)?;
82 } else {
83 return Err(Error::InvalidData("version must be 0 or 1"));
84 }
85
86 Ok(size)
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::mp4box::BoxHeader;
94
95 #[tokio::test]
96 async fn test_tfdt32() {
97 let src_box = TfdtBox {
98 version: 0,
99 flags: 0,
100 base_media_decode_time: 0,
101 };
102 let mut buf = Vec::new();
103 src_box.write_box(&mut buf).unwrap();
104 assert_eq!(buf.len(), src_box.box_size() as usize);
105
106 let mut reader = buf.as_slice();
107 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
108 assert_eq!(header.kind, BoxType::TfdtBox);
109 assert_eq!(src_box.box_size(), header.size);
110
111 let dst_box = TfdtBox::read_block(&mut reader).unwrap();
112 assert_eq!(src_box, dst_box);
113 }
114
115 #[tokio::test]
116 async fn test_tfdt64() {
117 let src_box = TfdtBox {
118 version: 1,
119 flags: 0,
120 base_media_decode_time: 0,
121 };
122 let mut buf = Vec::new();
123 src_box.write_box(&mut buf).unwrap();
124 assert_eq!(buf.len(), src_box.box_size() as usize);
125
126 let mut reader = buf.as_slice();
127 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
128 assert_eq!(header.kind, BoxType::TfdtBox);
129 assert_eq!(src_box.box_size(), header.size);
130
131 let dst_box = TfdtBox::read_block(&mut reader).unwrap();
132 assert_eq!(src_box, dst_box);
133 }
134}