mp4_atom/moov/trak/mdia/minf/stbl/stsd/
wvtt.rs1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct VttC {
7 pub config: String,
8}
9
10impl Atom for VttC {
11 const KIND: FourCC = FourCC::new(b"vttC");
12
13 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
14 Ok(Self {
15 config: decode_utf8_string(buf)?,
16 })
17 }
18
19 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
20 self.config.as_bytes().encode(buf)
21 }
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct Vlab {
28 pub source_label: String,
29}
30
31impl Atom for Vlab {
32 const KIND: FourCC = FourCC::new(b"vlab");
33
34 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
35 Ok(Self {
36 source_label: decode_utf8_string(buf)?,
37 })
38 }
39
40 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
41 self.source_label.as_bytes().encode(buf)
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Wvtt {
49 pub plaintext: PlainText,
50 pub config: VttC,
51 pub label: Option<Vlab>,
52 pub btrt: Option<Btrt>,
53}
54
55impl Atom for Wvtt {
56 const KIND: FourCC = FourCC::new(b"wvtt");
57
58 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
59 let plaintext = PlainText::decode(buf)?;
60
61 let mut vtcc = None;
62 let mut vlab = None;
63 let mut btrt = None;
64
65 while let Some(atom) = Any::decode_maybe(buf)? {
66 match atom {
67 Any::VttC(atom) => vtcc = atom.into(),
68 Any::Vlab(atom) => vlab = atom.into(),
69 Any::Btrt(atom) => btrt = atom.into(),
70 unknown => Self::decode_unknown(&unknown)?,
71 }
72 }
73 skip_trailing_padding(buf);
74
75 Ok(Self {
76 plaintext,
77 config: vtcc.ok_or(Error::MissingBox(VttC::KIND))?,
78 label: vlab,
79 btrt,
80 })
81 }
82
83 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
84 self.plaintext.encode(buf)?;
85 self.config.encode(buf)?;
86 self.label.encode(buf)?;
87 self.btrt.encode(buf)?;
88 Ok(())
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 const ENCODED_WVTT: &[u8] = &[
98 0x00, 0x00, 0x00, 0x3d, 0x77, 0x76, 0x74, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x01, 0x00, 0x00, 0x00, 0x2d, 0x76, 0x74, 0x74, 0x43, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54,
100 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x68, 0x65, 0x61,
101 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e,
102 0x0a,
103 ];
104
105 #[test]
106 fn test_wvtt_decode() {
107 let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_WVTT);
108
109 let wvtt = Wvtt::decode(buf).expect("failed to decode wvtt");
110
111 assert_eq!(
112 wvtt,
113 Wvtt {
114 plaintext: PlainText {
115 data_reference_index: 1
116 },
117 config: VttC {
118 config: "WEBVTT\nSome dummy header information\n".into()
119 },
120 label: None,
121 btrt: None,
122 }
123 );
124 }
125
126 #[test]
127 fn test_wvtt_encode() {
128 let wvtt = Wvtt {
129 plaintext: PlainText {
130 data_reference_index: 1,
131 },
132 config: VttC {
133 config: "WEBVTT\nSome dummy header information\n".into(),
134 },
135 label: None,
136 btrt: None,
137 };
138
139 let mut buf = Vec::new();
140 wvtt.encode(&mut buf).unwrap();
141
142 assert_eq!(buf.as_slice(), ENCODED_WVTT);
143 }
144
145 #[test]
146 fn test_round_trip_with_label() {
147 let wvtt = Wvtt {
148 plaintext: PlainText {
149 data_reference_index: 1,
150 },
151 config: VttC {
152 config: "WEBVTT\nSome dummy header information\n".into(),
153 },
154 label: Some(Vlab {
155 source_label: "uri://dummy/label".into(),
156 }),
157 btrt: Some(Btrt {
158 buffer_size_db: 1,
159 max_bitrate: 2000,
160 avg_bitrate: 400,
161 }),
162 };
163
164 let mut buf = Vec::new();
165 wvtt.encode(&mut buf).unwrap();
166 let decoded = Wvtt::decode(&mut buf.as_ref()).expect("failed to decode wvtt");
167
168 assert_eq!(decoded, wvtt,);
169 }
170}