Skip to main content

mp4/mp4box/
tx3g.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, 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    fn box_type(&self) -> BoxType {
57        self.get_type()
58    }
59
60    fn box_size(&self) -> u64 {
61        self.get_size()
62    }
63
64    fn to_json(&self) -> Result<String> {
65        Ok(serde_json::to_string(&self).unwrap())
66    }
67
68    fn summary(&self) -> Result<String> {
69        let s = format!("data_reference_index={} horizontal_justification={} vertical_justification={} rgba={}{}{}{}",
70            self.data_reference_index, self.horizontal_justification,
71            self.vertical_justification, self.bg_color_rgba.red,
72            self.bg_color_rgba.green, self.bg_color_rgba.blue, self.bg_color_rgba.alpha);
73        Ok(s)
74    }
75}
76
77impl<R: Read + Seek> ReadBox<&mut R> for Tx3gBox {
78    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
79        let start = box_start(reader)?;
80
81        reader.read_u32::<BigEndian>()?; // reserved
82        reader.read_u16::<BigEndian>()?; // reserved
83        let data_reference_index = reader.read_u16::<BigEndian>()?;
84
85        let display_flags = reader.read_u32::<BigEndian>()?;
86        let horizontal_justification = reader.read_i8()?;
87        let vertical_justification = reader.read_i8()?;
88        let bg_color_rgba = RgbaColor {
89            red: reader.read_u8()?,
90            green: reader.read_u8()?,
91            blue: reader.read_u8()?,
92            alpha: reader.read_u8()?,
93        };
94        let box_record: [i16; 4] = [
95            reader.read_i16::<BigEndian>()?,
96            reader.read_i16::<BigEndian>()?,
97            reader.read_i16::<BigEndian>()?,
98            reader.read_i16::<BigEndian>()?,
99        ];
100        let style_record: [u8; 12] = [
101            reader.read_u8()?,
102            reader.read_u8()?,
103            reader.read_u8()?,
104            reader.read_u8()?,
105            reader.read_u8()?,
106            reader.read_u8()?,
107            reader.read_u8()?,
108            reader.read_u8()?,
109            reader.read_u8()?,
110            reader.read_u8()?,
111            reader.read_u8()?,
112            reader.read_u8()?,
113        ];
114
115        skip_bytes_to(reader, start + size)?;
116
117        Ok(Tx3gBox {
118            data_reference_index,
119            display_flags,
120            horizontal_justification,
121            vertical_justification,
122            bg_color_rgba,
123            box_record,
124            style_record,
125        })
126    }
127}
128
129impl<W: Write> WriteBox<&mut W> for Tx3gBox {
130    fn write_box(&self, writer: &mut W) -> Result<u64> {
131        let size = self.box_size();
132        BoxHeader::new(self.box_type(), size).write(writer)?;
133
134        writer.write_u32::<BigEndian>(0)?; // reserved
135        writer.write_u16::<BigEndian>(0)?; // reserved
136        writer.write_u16::<BigEndian>(self.data_reference_index)?;
137        writer.write_u32::<BigEndian>(self.display_flags)?;
138        writer.write_i8(self.horizontal_justification)?;
139        writer.write_i8(self.vertical_justification)?;
140        writer.write_u8(self.bg_color_rgba.red)?;
141        writer.write_u8(self.bg_color_rgba.green)?;
142        writer.write_u8(self.bg_color_rgba.blue)?;
143        writer.write_u8(self.bg_color_rgba.alpha)?;
144        for n in 0..4 {
145            writer.write_i16::<BigEndian>(self.box_record[n])?;
146        }
147        for n in 0..12 {
148            writer.write_u8(self.style_record[n])?;
149        }
150
151        Ok(size)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    use crate::mp4box::BoxHeader;
159    use std::io::Cursor;
160
161    #[test]
162    fn test_tx3g() {
163        let src_box = Tx3gBox {
164            data_reference_index: 1,
165            display_flags: 0,
166            horizontal_justification: 1,
167            vertical_justification: -1,
168            bg_color_rgba: RgbaColor {
169                red: 0,
170                green: 0,
171                blue: 0,
172                alpha: 255,
173            },
174            box_record: [0, 0, 0, 0],
175            style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
176        };
177        let mut buf = Vec::new();
178        src_box.write_box(&mut buf).unwrap();
179        assert_eq!(buf.len(), src_box.box_size() as usize);
180
181        let mut reader = Cursor::new(&buf);
182        let header = BoxHeader::read(&mut reader).unwrap();
183        assert_eq!(header.name, BoxType::Tx3gBox);
184        assert_eq!(src_box.box_size(), header.size);
185
186        let dst_box = Tx3gBox::read_box(&mut reader, header.size).unwrap();
187        assert_eq!(src_box, dst_box);
188    }
189}