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