1use super::constants::*;
11use super::{FieldPreference, VitcReaderConfig};
12use crate::{FrameRate, Timecode, TimecodeError};
13
14pub struct VitcDecoder {
16 config: VitcReaderConfig,
18 last_timecode: Option<Timecode>,
20 crc_error_count: u32,
22 sync_count: u32,
24 threshold: u8,
26}
27
28impl VitcDecoder {
29 pub fn new(config: VitcReaderConfig) -> Self {
31 VitcDecoder {
32 config,
33 last_timecode: None,
34 crc_error_count: 0,
35 sync_count: 0,
36 threshold: 128,
37 }
38 }
39
40 pub fn process_line(
42 &mut self,
43 line_number: u16,
44 field: u8,
45 pixels: &[u8],
46 ) -> Result<Option<Timecode>, TimecodeError> {
47 if !self.config.scan_lines.contains(&line_number) {
49 return Ok(None);
50 }
51
52 match self.config.field_preference {
54 FieldPreference::Field1 if field != 1 => return Ok(None),
55 FieldPreference::Field2 if field != 2 => return Ok(None),
56 _ => {}
57 }
58
59 let bits = self.pixels_to_bits(pixels)?;
61
62 match self.decode_vitc_bits(&bits, field) {
64 Ok(timecode) => {
65 self.sync_count = self.sync_count.saturating_add(1);
66 self.last_timecode = Some(timecode);
67 Ok(Some(timecode))
68 }
69 Err(e) => {
70 if e == TimecodeError::CrcError {
71 self.crc_error_count += 1;
72 }
73 Err(e)
74 }
75 }
76 }
77
78 fn pixels_to_bits(&mut self, pixels: &[u8]) -> Result<[bool; BITS_PER_LINE], TimecodeError> {
80 if pixels.len() < BITS_PER_LINE * PIXELS_PER_BIT {
81 return Err(TimecodeError::BufferTooSmall);
82 }
83
84 self.adjust_threshold(pixels);
86
87 let mut bits = [false; BITS_PER_LINE];
88
89 for (i, bit) in bits.iter_mut().enumerate().take(BITS_PER_LINE) {
90 let pixel_index = i * PIXELS_PER_BIT + PIXELS_PER_BIT / 2;
92 if pixel_index < pixels.len() {
93 *bit = pixels[pixel_index] > self.threshold;
94 }
95 }
96
97 Ok(bits)
98 }
99
100 fn adjust_threshold(&mut self, pixels: &[u8]) {
102 let mut min_level = 255u8;
103 let mut max_level = 0u8;
104
105 for &pixel in pixels.iter().take(BITS_PER_LINE * PIXELS_PER_BIT) {
106 min_level = min_level.min(pixel);
107 max_level = max_level.max(pixel);
108 }
109
110 self.threshold = ((min_level as u16 + max_level as u16) / 2) as u8;
112 }
113
114 fn decode_vitc_bits(
116 &self,
117 bits: &[bool; BITS_PER_LINE],
118 field: u8,
119 ) -> Result<Timecode, TimecodeError> {
120 self.validate_sync_bits(bits)?;
122
123 let mut data_bits = [false; DATA_BITS];
125 data_bits[..DATA_BITS]
126 .copy_from_slice(&bits[SYNC_START_BITS..(DATA_BITS + SYNC_START_BITS)]);
127
128 self.validate_crc(&data_bits)?;
130
131 self.decode_timecode_from_bits(&data_bits, field)
133 }
134
135 fn validate_sync_bits(&self, bits: &[bool; BITS_PER_LINE]) -> Result<(), TimecodeError> {
137 if !bits[0] || !bits[1] {
139 return Err(TimecodeError::SyncNotFound);
140 }
141
142 if bits[84] || bits[85] || !bits[86] || !bits[87] || !bits[88] || !bits[89] {
144 return Err(TimecodeError::SyncNotFound);
145 }
146
147 Ok(())
148 }
149
150 fn validate_crc(&self, data_bits: &[bool; DATA_BITS]) -> Result<(), TimecodeError> {
152 let received_crc = self.extract_crc(data_bits);
154
155 let calculated_crc = self.calculate_crc(&data_bits[0..72]);
157
158 if received_crc != calculated_crc {
159 return Err(TimecodeError::CrcError);
160 }
161
162 Ok(())
163 }
164
165 fn extract_crc(&self, data_bits: &[bool; DATA_BITS]) -> u8 {
167 let mut crc = 0u8;
168 for i in 0..8 {
169 if data_bits[74 + i] {
170 crc |= 1 << i;
171 }
172 }
173 crc
174 }
175
176 fn calculate_crc(&self, bits: &[bool]) -> u8 {
178 let mut crc = 0u8;
179
180 for &bit in bits {
181 let feedback = ((crc & 0x80) != 0) ^ bit;
182 crc <<= 1;
183 if feedback {
184 crc ^= 0x07; }
186 }
187
188 crc
189 }
190
191 fn decode_timecode_from_bits(
193 &self,
194 data_bits: &[bool; DATA_BITS],
195 field: u8,
196 ) -> Result<Timecode, TimecodeError> {
197 let frame_units = self.bits_to_u8(&data_bits[0..4]);
202
203 let _user_bits_1 = self.bits_to_u8(&data_bits[4..8]);
205
206 let frame_tens = self.bits_to_u8(&data_bits[8..10]);
208
209 let drop_frame = data_bits[10];
211
212 let _color_frame = data_bits[11];
214
215 let _user_bits_2 = self.bits_to_u8(&data_bits[12..16]);
217
218 let second_units = self.bits_to_u8(&data_bits[16..20]);
220
221 let _user_bits_3 = self.bits_to_u8(&data_bits[20..24]);
223
224 let second_tens = self.bits_to_u8(&data_bits[24..27]);
226
227 let field_mark = data_bits[27];
229
230 if (field_mark && field != 2) || (!field_mark && field != 1) {
232 }
234
235 let _user_bits_4 = self.bits_to_u8(&data_bits[28..32]);
237
238 let minute_units = self.bits_to_u8(&data_bits[32..36]);
240
241 let _user_bits_5 = self.bits_to_u8(&data_bits[36..40]);
243
244 let minute_tens = self.bits_to_u8(&data_bits[40..43]);
246
247 let _binary_group = data_bits[43];
249
250 let _user_bits_6 = self.bits_to_u8(&data_bits[44..48]);
252
253 let hour_units = self.bits_to_u8(&data_bits[48..52]);
255
256 let _user_bits_7 = self.bits_to_u8(&data_bits[52..56]);
258
259 let hour_tens = self.bits_to_u8(&data_bits[56..58]);
261
262 let frames = frame_tens * 10 + frame_units;
266 let seconds = second_tens * 10 + second_units;
267 let minutes = minute_tens * 10 + minute_units;
268 let hours = hour_tens * 10 + hour_units;
269
270 let frame_rate = if drop_frame && self.config.frame_rate == FrameRate::Fps2997NDF {
272 FrameRate::Fps2997DF
273 } else {
274 self.config.frame_rate
275 };
276
277 let timecode = Timecode::new(hours, minutes, seconds, frames, frame_rate)?;
279
280 Ok(timecode)
281 }
282
283 fn bits_to_u8(&self, bits: &[bool]) -> u8 {
285 let mut value = 0u8;
286 for (i, &bit) in bits.iter().enumerate() {
287 if bit {
288 value |= 1 << i;
289 }
290 }
291 value
292 }
293
294 #[allow(dead_code)]
296 fn extract_user_bits(&self, data_bits: &[bool; DATA_BITS]) -> u32 {
297 let mut user_bits = 0u32;
298
299 user_bits |= self.bits_to_u8(&data_bits[4..8]) as u32;
301 user_bits |= (self.bits_to_u8(&data_bits[12..16]) as u32) << 4;
302 user_bits |= (self.bits_to_u8(&data_bits[20..24]) as u32) << 8;
303 user_bits |= (self.bits_to_u8(&data_bits[28..32]) as u32) << 12;
304 user_bits |= (self.bits_to_u8(&data_bits[36..40]) as u32) << 16;
305 user_bits |= (self.bits_to_u8(&data_bits[44..48]) as u32) << 20;
306 user_bits |= (self.bits_to_u8(&data_bits[52..56]) as u32) << 24;
307
308 user_bits
309 }
310
311 pub fn reset(&mut self) {
313 self.last_timecode = None;
314 self.crc_error_count = 0;
315 self.sync_count = 0;
316 self.threshold = 128;
317 }
318
319 pub fn is_synchronized(&self) -> bool {
321 self.sync_count >= 5 && self.last_timecode.is_some()
322 }
323
324 pub fn crc_errors(&self) -> u32 {
326 self.crc_error_count
327 }
328}
329
330#[allow(dead_code)]
332struct BitPatternAnalyzer {
333 run_lengths: Vec<usize>,
335 current_run: usize,
337 current_bit: bool,
339}
340
341impl BitPatternAnalyzer {
342 #[allow(dead_code)]
343 fn new() -> Self {
344 BitPatternAnalyzer {
345 run_lengths: Vec::new(),
346 current_run: 0,
347 current_bit: false,
348 }
349 }
350
351 #[allow(dead_code)]
353 fn add_bit(&mut self, bit: bool) {
354 if bit == self.current_bit {
355 self.current_run += 1;
356 } else {
357 if self.current_run > 0 {
358 self.run_lengths.push(self.current_run);
359 }
360 self.current_bit = bit;
361 self.current_run = 1;
362 }
363 }
364
365 #[allow(dead_code)]
367 fn finish(&mut self) {
368 if self.current_run > 0 {
369 self.run_lengths.push(self.current_run);
370 }
371 }
372
373 #[allow(dead_code)]
375 fn get_run_lengths(&self) -> &[usize] {
376 &self.run_lengths
377 }
378
379 #[allow(dead_code)]
380 fn reset(&mut self) {
381 self.run_lengths.clear();
382 self.current_run = 0;
383 self.current_bit = false;
384 }
385}
386
387pub struct LineQualityAnalyzer {
389 min_pixel: u8,
391 max_pixel: u8,
393 pixel_count: usize,
395 pixel_sum: u64,
397}
398
399impl Default for LineQualityAnalyzer {
400 fn default() -> Self {
401 Self::new()
402 }
403}
404
405impl LineQualityAnalyzer {
406 pub fn new() -> Self {
407 LineQualityAnalyzer {
408 min_pixel: 255,
409 max_pixel: 0,
410 pixel_count: 0,
411 pixel_sum: 0,
412 }
413 }
414
415 pub fn analyze(&mut self, pixels: &[u8]) {
417 for &pixel in pixels {
418 self.min_pixel = self.min_pixel.min(pixel);
419 self.max_pixel = self.max_pixel.max(pixel);
420 self.pixel_sum += pixel as u64;
421 self.pixel_count += 1;
422 }
423 }
424
425 pub fn get_snr_estimate(&self) -> f32 {
427 let dynamic_range = (self.max_pixel as i16 - self.min_pixel as i16).abs() as f32;
428 if dynamic_range > 0.0 {
429 20.0 * (dynamic_range / 255.0).log10()
430 } else {
431 0.0
432 }
433 }
434
435 pub fn get_average(&self) -> f32 {
437 if self.pixel_count > 0 {
438 self.pixel_sum as f32 / self.pixel_count as f32
439 } else {
440 0.0
441 }
442 }
443
444 pub fn get_dynamic_range(&self) -> u8 {
446 self.max_pixel.saturating_sub(self.min_pixel)
447 }
448
449 pub fn reset(&mut self) {
450 self.min_pixel = 255;
451 self.max_pixel = 0;
452 self.pixel_count = 0;
453 self.pixel_sum = 0;
454 }
455}
456
457pub struct FieldDetector {
459 field_history: Vec<bool>,
461 max_history: usize,
463}
464
465impl FieldDetector {
466 pub fn new(max_history: usize) -> Self {
467 FieldDetector {
468 field_history: Vec::with_capacity(max_history),
469 max_history,
470 }
471 }
472
473 pub fn add_field_mark(&mut self, field_mark: bool) {
475 self.field_history.push(field_mark);
476 if self.field_history.len() > self.max_history {
477 self.field_history.remove(0);
478 }
479 }
480
481 pub fn get_predominant_field(&self) -> Option<u8> {
483 if self.field_history.is_empty() {
484 return None;
485 }
486
487 let field2_count = self.field_history.iter().filter(|&&f| f).count();
488 let field1_count = self.field_history.len() - field2_count;
489
490 if field2_count > field1_count {
491 Some(2)
492 } else {
493 Some(1)
494 }
495 }
496
497 pub fn reset(&mut self) {
498 self.field_history.clear();
499 }
500}
501
502pub struct MultiLineVitcReader {
504 decoders: Vec<(u16, VitcDecoder)>,
506}
507
508impl MultiLineVitcReader {
509 pub fn new(config: VitcReaderConfig) -> Self {
511 let mut decoders = Vec::new();
512
513 for &line in &config.scan_lines {
514 let mut line_config = config.clone();
515 line_config.scan_lines = vec![line];
516 decoders.push((line, VitcDecoder::new(line_config)));
517 }
518
519 MultiLineVitcReader { decoders }
520 }
521
522 pub fn process_line(
524 &mut self,
525 line_number: u16,
526 field: u8,
527 pixels: &[u8],
528 ) -> Vec<(u16, Result<Option<Timecode>, TimecodeError>)> {
529 let mut results = Vec::new();
530
531 for (line, decoder) in &mut self.decoders {
532 if *line == line_number {
533 let result = decoder.process_line(line_number, field, pixels);
534 results.push((*line, result));
535 }
536 }
537
538 results
539 }
540
541 pub fn get_best_timecode(
543 &self,
544 results: &[(u16, Result<Option<Timecode>, TimecodeError>)],
545 ) -> Option<Timecode> {
546 for (_line, result) in results {
547 if let Ok(Some(tc)) = result {
548 return Some(*tc);
549 }
550 }
551 None
552 }
553}
554
555pub struct VitcErrorCorrector {
557 history: Vec<Timecode>,
559 max_history: usize,
561}
562
563impl VitcErrorCorrector {
564 pub fn new(max_history: usize) -> Self {
565 VitcErrorCorrector {
566 history: Vec::with_capacity(max_history),
567 max_history,
568 }
569 }
570
571 pub fn add_timecode(&mut self, timecode: Timecode) {
573 self.history.push(timecode);
574 if self.history.len() > self.max_history {
575 self.history.remove(0);
576 }
577 }
578
579 pub fn correct_timecode(&self, timecode: &Timecode) -> Option<Timecode> {
581 if self.history.is_empty() {
582 return Some(*timecode);
583 }
584
585 if let Some(last) = self.history.last() {
587 let mut expected = *last;
588 if expected.increment().is_ok() {
589 let diff = (timecode.to_frames() as i64 - expected.to_frames() as i64).abs();
591 if diff <= 2 {
592 return Some(*timecode);
593 }
594 }
595 }
596
597 Some(*timecode)
599 }
600
601 pub fn reset(&mut self) {
602 self.history.clear();
603 }
604}
605
606#[cfg(test)]
607mod tests {
608 use super::*;
609
610 #[test]
611 fn test_decoder_creation() {
612 let config = VitcReaderConfig::default();
613 let decoder = VitcDecoder::new(config);
614 assert!(!decoder.is_synchronized());
615 }
616
617 #[test]
618 fn test_crc_calculation() {
619 let config = VitcReaderConfig::default();
620 let decoder = VitcDecoder::new(config);
621
622 let bits = [false; 72];
623 let crc = decoder.calculate_crc(&bits);
624 assert_eq!(crc, 0);
625 }
626
627 #[test]
628 fn test_bits_to_u8() {
629 let config = VitcReaderConfig::default();
630 let decoder = VitcDecoder::new(config);
631
632 let bits = [true, false, true, false]; assert_eq!(decoder.bits_to_u8(&bits), 5);
634 }
635
636 #[test]
637 fn test_line_quality_analyzer() {
638 let mut analyzer = LineQualityAnalyzer::new();
639 let pixels = vec![16, 235, 16, 235]; analyzer.analyze(&pixels);
642 assert!(analyzer.get_dynamic_range() > 200);
643 }
644
645 #[test]
646 fn test_field_detector() {
647 let mut detector = FieldDetector::new(10);
648
649 detector.add_field_mark(true);
651 detector.add_field_mark(true);
652 detector.add_field_mark(false);
653
654 assert_eq!(detector.get_predominant_field(), Some(2));
655 }
656}