1use std::collections::VecDeque;
8
9use log::{trace, warn};
10
11use crate::{tables, Cea608, DTVCCPacket};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
15pub enum ParserError {
16 #[error("The length of the data ({actual}) does not match the advertised expected ({expected}) length")]
18 LengthMismatch {
19 expected: usize,
21 actual: usize,
23 },
24 #[error("CEA-608 compatibility bytes were found after CEA-708 bytes at position {byte_pos}")]
26 Cea608AfterCea708 {
27 byte_pos: usize,
29 },
30}
31
32impl From<tables::CodeError> for ParserError {
33 fn from(err: tables::CodeError) -> Self {
34 match err {
35 tables::CodeError::LengthMismatch { expected, actual } => {
36 ParserError::LengthMismatch { expected, actual }
37 }
38 }
39 }
40}
41
42#[derive(Debug, Default)]
44pub struct CCDataParser {
45 pending_data: Vec<u8>,
46 packets: VecDeque<DTVCCPacket>,
47 cea608: Option<Vec<Cea608>>,
48 have_initial_ccp_header: bool,
49 ccp_bytes_needed: usize,
50}
51
52impl CCDataParser {
53 pub fn new() -> Self {
55 Self::default()
56 }
57
58 pub fn handle_cea608(&mut self) {
59 self.cea608 = Some(vec![]);
60 }
61
62 pub fn push(&mut self, data: &[u8]) -> Result<(), ParserError> {
70 trace!("parsing {data:?}");
71 if let Some(ref mut cea608) = self.cea608 {
72 cea608.clear();
73 }
74
75 if data.len() < 5 {
76 return Ok(());
78 }
79 let process_cc_data_flag = data[0] & 0x40 > 0;
80 if !process_cc_data_flag {
81 return Ok(());
82 }
83
84 let cc_count = data[0] & 0x1F;
85 if cc_count == 0 {
86 return Ok(());
87 }
88 trace!("cc_count: {cc_count}, len = {}", data.len());
89 if (cc_count * 3 + 2) as usize != data.len() {
90 return Err(ParserError::LengthMismatch {
91 expected: (cc_count * 3 + 1) as usize,
92 actual: data.len(),
93 });
94 }
95
96 let mut ccp_data = vec![];
97 let mut in_dtvcc = false;
98
99 let mut pending_data = vec![];
101 for (i, d) in self.pending_data.chunks(2).enumerate() {
102 if i == 0 {
103 pending_data.push(0xFF);
104 } else {
105 pending_data.push(0xFE);
106 }
107 pending_data.extend(d);
108 if d.len() == 1 {
109 pending_data.push(0x00);
110 }
111 }
112
113 let ccp_offset;
115 {
116 let mut ret = None;
117 for (i, triple) in data[2..].chunks_exact(3).enumerate() {
118 let cc_valid = (triple[0] & 0x04) == 0x04;
119 let cc_type = triple[0] & 0x3;
120 trace!(
121 "input byte:{} triple 0x{:02x} 0x{:02x} 0x{:02x}. valid: {cc_valid}, type: {cc_type}",
122 i * 3,
123 triple[0],
124 triple[1],
125 triple[2]
126 );
127 if (cc_type & 0b10) > 0 {
128 in_dtvcc = true;
129 }
130 if !cc_valid {
131 continue;
132 }
133 if !in_dtvcc && (cc_type == 0b00 || cc_type == 0b01) {
134 trace!(
135 "have cea608 bytes type {cc_type} 0x{:02x} 0x{:02x}",
136 triple[1],
137 triple[2]
138 );
139 if let Some(ref mut cea608) = self.cea608 {
140 let pair = match cc_type {
141 0b00 => Cea608::Field1(triple[1], triple[2]),
142 0b01 => Cea608::Field2(triple[1], triple[2]),
143 _ => unreachable!(),
144 };
145 cea608.push(pair);
146 }
147 continue;
148 }
149
150 if in_dtvcc && (cc_type == 0b00 || cc_type == 0b01) {
151 warn!("cea608 bytes after cea708 data at byte:{}", i * 3);
153 return Err(ParserError::Cea608AfterCea708 { byte_pos: i * 3 });
154 }
155
156 if ret.is_none() {
157 ret = Some(i * 3);
158 }
159 }
160
161 if let Some(ret) = ret {
162 ccp_offset = 2 + ret
163 } else {
164 return Ok(());
166 }
167 }
168 trace!("ccp offset in input data is at index {ccp_offset}");
169
170 let mut data_iter = pending_data.iter().chain(data[ccp_offset..].iter());
171 let mut i = 0;
172 in_dtvcc = false;
173 loop {
174 let byte0 = data_iter.next();
175 let byte1 = data_iter.next();
176 let byte2 = data_iter.next();
177 let (Some(byte0), Some(byte1), Some(byte2)) = (byte0, byte1, byte2) else {
178 break;
179 };
180 let cc_valid = (byte0 & 0x04) == 0x04;
181 let cc_type = byte0 & 0x3;
182 trace!(
183 "pending byte:{i} triple 0x{byte0:02x} 0x{byte1:02x} 0x{byte2:02x}. valid: {cc_valid}, type: {cc_type}",
184 );
185 i += 3;
186 if (cc_type & 0b10) > 0 {
187 in_dtvcc = true;
188 }
189 if !cc_valid {
190 continue;
191 }
192 if !in_dtvcc && (cc_type == 0b00 || cc_type == 0b01) {
193 unreachable!();
195 }
196
197 if (cc_type & 0b11) == 0b11 {
198 trace!("found ccp header at index {}", i - 3);
199 self.have_initial_ccp_header = true;
200 match DTVCCPacket::parse(&ccp_data) {
202 Ok(packet) => self.packets.push_front(packet),
203 Err(ParserError::LengthMismatch { .. }) => (),
204 Err(e) => {
205 eprintln!("{e:?}");
206 unreachable!()
207 }
208 }
209 in_dtvcc = false;
210 ccp_data = vec![];
211 let (_seq_no, packet_len) = DTVCCPacket::parse_hdr_byte(*byte1);
212 trace!("waiting for {} dtvcc bytes", packet_len + 1);
213 self.ccp_bytes_needed = packet_len + 1;
214 }
215
216 if self.have_initial_ccp_header {
217 trace!("pushing 0x{:02x?}{:02x?}", byte1, byte2);
218 if self.ccp_bytes_needed > 0 {
219 ccp_data.push(*byte1);
220 self.ccp_bytes_needed -= 1;
221 }
222 if self.ccp_bytes_needed > 0 {
223 ccp_data.push(*byte2);
224 self.ccp_bytes_needed -= 1;
225 }
226 }
227 }
228
229 if self.ccp_bytes_needed == 0 {
230 match DTVCCPacket::parse(&ccp_data) {
231 Ok(packet) => self.packets.push_front(packet),
232 Err(ParserError::LengthMismatch { .. }) => (),
233 _ => unreachable!(),
234 }
235 ccp_data = vec![];
236 }
237
238 self.pending_data = ccp_data;
239
240 Ok(())
241 }
242
243 pub fn flush(&mut self) {
245 *self = Self::default();
246 }
247
248 pub fn pop_packet(&mut self) -> Option<DTVCCPacket> {
250 let ret = self.packets.pop_back();
251 trace!("popped {ret:?}");
252 ret
253 }
254
255 pub fn cea608(&mut self) -> Option<&[Cea608]> {
257 self.cea608.as_deref()
258 }
259}