oximedia_timecode/vitc/
mod.rs1pub mod decoder;
23pub mod encoder;
24
25use crate::{FrameRate, Timecode, TimecodeError, TimecodeReader, TimecodeWriter};
26
27#[derive(Debug, Clone)]
29pub struct VitcReaderConfig {
30 pub video_standard: VideoStandard,
32 pub frame_rate: FrameRate,
34 pub scan_lines: Vec<u16>,
36 pub field_preference: FieldPreference,
38}
39
40impl Default for VitcReaderConfig {
41 fn default() -> Self {
42 VitcReaderConfig {
43 video_standard: VideoStandard::Pal,
44 frame_rate: FrameRate::Fps25,
45 scan_lines: vec![19, 21], field_preference: FieldPreference::Both,
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum VideoStandard {
54 Ntsc,
56 Pal,
58}
59
60impl VideoStandard {
61 pub fn total_lines(&self) -> u16 {
63 match self {
64 VideoStandard::Ntsc => 525,
65 VideoStandard::Pal => 625,
66 }
67 }
68
69 pub fn active_lines(&self) -> u16 {
71 match self {
72 VideoStandard::Ntsc => 486,
73 VideoStandard::Pal => 576,
74 }
75 }
76
77 pub fn pixels_per_line(&self) -> u16 {
79 match self {
80 VideoStandard::Ntsc => 720,
81 VideoStandard::Pal => 720,
82 }
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum FieldPreference {
89 Field1,
91 Field2,
93 Both,
95}
96
97pub struct VitcReader {
99 decoder: decoder::VitcDecoder,
100 frame_rate: FrameRate,
101}
102
103impl VitcReader {
104 pub fn new(config: VitcReaderConfig) -> Self {
106 let frame_rate = config.frame_rate;
107 VitcReader {
108 decoder: decoder::VitcDecoder::new(config),
109 frame_rate,
110 }
111 }
112
113 pub fn process_line(
115 &mut self,
116 line_number: u16,
117 field: u8,
118 pixels: &[u8],
119 ) -> Result<Option<Timecode>, TimecodeError> {
120 self.decoder.process_line(line_number, field, pixels)
121 }
122
123 pub fn reset(&mut self) {
125 self.decoder.reset();
126 }
127
128 pub fn crc_errors(&self) -> u32 {
130 self.decoder.crc_errors()
131 }
132}
133
134impl TimecodeReader for VitcReader {
135 fn read_timecode(&mut self) -> Result<Option<Timecode>, TimecodeError> {
136 Ok(None)
138 }
139
140 fn frame_rate(&self) -> FrameRate {
141 self.frame_rate
142 }
143
144 fn is_synchronized(&self) -> bool {
145 self.decoder.is_synchronized()
146 }
147}
148
149#[derive(Debug, Clone)]
151pub struct VitcWriterConfig {
152 pub video_standard: VideoStandard,
154 pub frame_rate: FrameRate,
156 pub scan_lines: Vec<u16>,
158 pub both_fields: bool,
160}
161
162impl Default for VitcWriterConfig {
163 fn default() -> Self {
164 VitcWriterConfig {
165 video_standard: VideoStandard::Pal,
166 frame_rate: FrameRate::Fps25,
167 scan_lines: vec![19, 21],
168 both_fields: true,
169 }
170 }
171}
172
173pub struct VitcWriter {
175 encoder: encoder::VitcEncoder,
176 frame_rate: FrameRate,
177}
178
179impl VitcWriter {
180 pub fn new(config: VitcWriterConfig) -> Self {
182 let frame_rate = config.frame_rate;
183 VitcWriter {
184 encoder: encoder::VitcEncoder::new(config),
185 frame_rate,
186 }
187 }
188
189 pub fn encode_line(
191 &mut self,
192 timecode: &Timecode,
193 field: u8,
194 ) -> Result<Vec<u8>, TimecodeError> {
195 self.encoder.encode_line(timecode, field)
196 }
197
198 pub fn reset(&mut self) {
200 self.encoder.reset();
201 }
202}
203
204impl TimecodeWriter for VitcWriter {
205 fn write_timecode(&mut self, timecode: &Timecode) -> Result<(), TimecodeError> {
206 let _pixels_f1 = self.encode_line(timecode, 1)?;
208 let _pixels_f2 = self.encode_line(timecode, 2)?;
210 Ok(())
212 }
213
214 fn frame_rate(&self) -> FrameRate {
215 self.frame_rate
216 }
217
218 fn flush(&mut self) -> Result<(), TimecodeError> {
219 Ok(())
220 }
221}
222
223pub(crate) mod constants {
225 pub const BITS_PER_LINE: usize = 90;
227
228 pub const DATA_BITS: usize = 82;
230
231 pub const SYNC_START_BITS: usize = 2;
233
234 #[allow(dead_code)]
236 pub const SYNC_END_BITS: usize = 6;
237
238 pub const PIXELS_PER_BIT: usize = 2;
240
241 pub const BLACK_LEVEL: u8 = 16;
243
244 pub const WHITE_LEVEL: u8 = 235;
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_vitc_reader_creation() {
254 let config = VitcReaderConfig::default();
255 let _reader = VitcReader::new(config);
256 }
257
258 #[test]
259 fn test_vitc_writer_creation() {
260 let config = VitcWriterConfig::default();
261 let _writer = VitcWriter::new(config);
262 }
263
264 #[test]
265 fn test_video_standard() {
266 assert_eq!(VideoStandard::Ntsc.total_lines(), 525);
267 assert_eq!(VideoStandard::Pal.total_lines(), 625);
268 assert_eq!(VideoStandard::Ntsc.pixels_per_line(), 720);
269 }
270
271 #[test]
272 fn test_constants() {
273 assert_eq!(constants::BITS_PER_LINE, 90);
274 assert_eq!(constants::PIXELS_PER_BIT, 2);
275 }
276}