flowly_mp4/mp4box/
tx3g.rs

1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct Tx3gBox {
9    pub data_reference_index: u16,
10    pub display_flags: u32,
11    pub horizontal_justification: i8,
12    pub vertical_justification: i8,
13    pub bg_color_rgba: RgbaColor,
14    pub box_record: [i16; 4],
15    pub style_record: [u8; 12],
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
19pub struct RgbaColor {
20    pub red: u8,
21    pub green: u8,
22    pub blue: u8,
23    pub alpha: u8,
24}
25
26impl Default for Tx3gBox {
27    fn default() -> Self {
28        Tx3gBox {
29            data_reference_index: 0,
30            display_flags: 0,
31            horizontal_justification: 1,
32            vertical_justification: -1,
33            bg_color_rgba: RgbaColor {
34                red: 0,
35                green: 0,
36                blue: 0,
37                alpha: 255,
38            },
39            box_record: [0, 0, 0, 0],
40            style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
41        }
42    }
43}
44
45impl Tx3gBox {
46    pub fn get_type(&self) -> BoxType {
47        BoxType::Tx3gBox
48    }
49
50    pub fn get_size(&self) -> u64 {
51        HEADER_SIZE + 6 + 32
52    }
53}
54
55impl Mp4Box for Tx3gBox {
56    const TYPE: BoxType = BoxType::Tx3gBox;
57
58    fn box_size(&self) -> u64 {
59        self.get_size()
60    }
61
62    fn to_json(&self) -> Result<String, Error> {
63        Ok(serde_json::to_string(&self).unwrap())
64    }
65
66    fn summary(&self) -> Result<String, Error> {
67        let s = format!("data_reference_index={} horizontal_justification={} vertical_justification={} rgba={}{}{}{}",
68            self.data_reference_index, self.horizontal_justification,
69            self.vertical_justification, self.bg_color_rgba.red,
70            self.bg_color_rgba.green, self.bg_color_rgba.blue, self.bg_color_rgba.alpha);
71        Ok(s)
72    }
73}
74
75impl BlockReader for Tx3gBox {
76    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
77        reader.get_u32(); // reserved
78        reader.get_u16(); // reserved
79        let data_reference_index = reader.get_u16();
80
81        let display_flags = reader.get_u32();
82        let horizontal_justification = reader.get_i8();
83        let vertical_justification = reader.get_i8();
84        let bg_color_rgba = RgbaColor {
85            red: reader.get_u8(),
86            green: reader.get_u8(),
87            blue: reader.get_u8(),
88            alpha: reader.get_u8(),
89        };
90        let box_record: [i16; 4] = [
91            reader.get_i16(),
92            reader.get_i16(),
93            reader.get_i16(),
94            reader.get_i16(),
95        ];
96        let style_record: [u8; 12] = [
97            reader.get_u8(),
98            reader.get_u8(),
99            reader.get_u8(),
100            reader.get_u8(),
101            reader.get_u8(),
102            reader.get_u8(),
103            reader.get_u8(),
104            reader.get_u8(),
105            reader.get_u8(),
106            reader.get_u8(),
107            reader.get_u8(),
108            reader.get_u8(),
109        ];
110
111        Ok(Tx3gBox {
112            data_reference_index,
113            display_flags,
114            horizontal_justification,
115            vertical_justification,
116            bg_color_rgba,
117            box_record,
118            style_record,
119        })
120    }
121
122    fn size_hint() -> usize {
123        34
124    }
125}
126
127impl<W: Write> WriteBox<&mut W> for Tx3gBox {
128    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
129        let size = self.box_size();
130        BoxHeader::new(Self::TYPE, size).write(writer)?;
131
132        writer.write_u32::<BigEndian>(0)?; // reserved
133        writer.write_u16::<BigEndian>(0)?; // reserved
134        writer.write_u16::<BigEndian>(self.data_reference_index)?;
135        writer.write_u32::<BigEndian>(self.display_flags)?;
136        writer.write_i8(self.horizontal_justification)?;
137        writer.write_i8(self.vertical_justification)?;
138        writer.write_u8(self.bg_color_rgba.red)?;
139        writer.write_u8(self.bg_color_rgba.green)?;
140        writer.write_u8(self.bg_color_rgba.blue)?;
141        writer.write_u8(self.bg_color_rgba.alpha)?;
142        for n in 0..4 {
143            writer.write_i16::<BigEndian>(self.box_record[n])?;
144        }
145        for n in 0..12 {
146            writer.write_u8(self.style_record[n])?;
147        }
148
149        Ok(size)
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156    use crate::mp4box::BoxHeader;
157
158    #[tokio::test]
159    async fn test_tx3g() {
160        let src_box = Tx3gBox {
161            data_reference_index: 1,
162            display_flags: 0,
163            horizontal_justification: 1,
164            vertical_justification: -1,
165            bg_color_rgba: RgbaColor {
166                red: 0,
167                green: 0,
168                blue: 0,
169                alpha: 255,
170            },
171            box_record: [0, 0, 0, 0],
172            style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
173        };
174        let mut buf = Vec::new();
175        src_box.write_box(&mut buf).unwrap();
176        assert_eq!(buf.len(), src_box.box_size() as usize);
177
178        let mut reader = buf.as_slice();
179        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
180        assert_eq!(header.kind, BoxType::Tx3gBox);
181        assert_eq!(src_box.box_size(), header.size);
182
183        let dst_box = Tx3gBox::read_block(&mut reader).unwrap();
184        assert_eq!(src_box, dst_box);
185    }
186}