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>()?; reader.read_u16::<BigEndian>()?; 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)?; writer.write_u16::<BigEndian>(0)?; 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}