From 5739a3d86ffbda3b62be8bf57172db499f276ff8 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 7 Nov 2023 00:25:20 +1100 Subject: [PATCH] cea608tocea708: create service's as requested Allows the ability to push multiple Service blocks of the same service into the same packet if necessary (unlikely but possible). Part-of: --- video/closedcaption/src/cea608tocea708/imp.rs | 64 ++++++------- video/closedcaption/src/cea708utils.rs | 93 +++++++++---------- 2 files changed, 71 insertions(+), 86 deletions(-) diff --git a/video/closedcaption/src/cea608tocea708/imp.rs b/video/closedcaption/src/cea608tocea708/imp.rs index 0461a635..d8e3478e 100644 --- a/video/closedcaption/src/cea608tocea708/imp.rs +++ b/video/closedcaption/src/cea608tocea708/imp.rs @@ -101,11 +101,11 @@ impl Cea708ServiceState { 0 }; match cea608_mode { - Cea608Mode::PopOn => self.writer.popon_preamble().unwrap(), - Cea608Mode::PaintOn => self.writer.paint_on_preamble().unwrap(), - Cea608Mode::RollUp2 => self.writer.rollup_preamble(2, base_row).unwrap(), - Cea608Mode::RollUp3 => self.writer.rollup_preamble(3, base_row).unwrap(), - Cea608Mode::RollUp4 => self.writer.rollup_preamble(4, base_row).unwrap(), + Cea608Mode::PopOn => self.writer.popon_preamble(), + Cea608Mode::PaintOn => self.writer.paint_on_preamble(), + Cea608Mode::RollUp2 => self.writer.rollup_preamble(2, base_row), + Cea608Mode::RollUp3 => self.writer.rollup_preamble(3, base_row), + Cea608Mode::RollUp4 => self.writer.rollup_preamble(4, base_row), }; // we have redefined then window so all the attributes have been reset self.pen_location.row = new_row; @@ -117,20 +117,20 @@ impl Cea708ServiceState { fn handle_text(&mut self, text: Cea608Text) { if text.code_space == CodeSpace::WestEU { - self.writer.push_codes(&[Code::BS]).unwrap(); + self.writer.push_codes(&[Code::BS]); } if let Some(c) = text.char1 { if self.pen_location.column > 31 { - self.writer.push_codes(&[Code::BS]).unwrap(); + self.writer.push_codes(&[Code::BS]); } - self.writer.write_char(c).unwrap(); + self.writer.write_char(c); self.pen_location.column = std::cmp::min(self.pen_location.column + 1, 32); } if let Some(c) = text.char2 { if self.pen_location.column > 31 { - self.writer.push_codes(&[Code::BS]).unwrap(); + self.writer.push_codes(&[Code::BS]); } - self.writer.write_char(c).unwrap(); + self.writer.write_char(c); self.pen_location.column = std::cmp::min(self.pen_location.column + 1, 32); } } @@ -150,7 +150,7 @@ impl Cea708ServiceState { } if need_pen_location { - self.writer.set_pen_location(self.pen_location).unwrap(); + self.writer.set_pen_location(self.pen_location); } let mut need_pen_attributes = false; @@ -165,20 +165,20 @@ impl Cea708ServiceState { } if need_pen_attributes { - self.writer.set_pen_attributes(self.pen_attributes).unwrap(); + self.writer.set_pen_attributes(self.pen_attributes); } if self.pen_color.foreground_color != textstyle_foreground_color(preamble.style) { self.pen_color.foreground_color = textstyle_foreground_color(preamble.style); - self.writer.set_pen_color(self.pen_color).unwrap(); + self.writer.set_pen_color(self.pen_color); } } fn handle_midrowchange(&mut self, midrowchange: MidRowChange) { - self.writer.write_char(' ').unwrap(); + self.writer.write_char(' '); if self.pen_color.foreground_color != textstyle_foreground_color(midrowchange.style) { self.pen_color.foreground_color = textstyle_foreground_color(midrowchange.style); - self.writer.set_pen_color(self.pen_color).unwrap(); + self.writer.set_pen_color(self.pen_color); } let mut need_pen_attributes = false; @@ -214,7 +214,7 @@ impl Cea708State { self.packet_counter &= 0x3; for state in self.service_state.iter_mut() { - if let Some(service) = state.writer.take_service() { + while let Some(service) = state.writer.take_service(packet.free_space()) { if let Err(e) = packet.push_service(service.clone()) { gst::warning!( CAT, @@ -307,14 +307,8 @@ impl State { { // https://www.law.cornell.edu/cfr/text/47/79.101 (f)(1)(x) gst::trace!(CAT, "change to rollup from pop/paint-on"); - self.cea708.service_state[idx] - .writer - .clear_hidden_window() - .unwrap(); - self.cea708.service_state[idx] - .writer - .clear_current_window() - .unwrap(); + self.cea708.service_state[idx].writer.clear_hidden_window(); + self.cea708.service_state[idx].writer.clear_current_window(); self.cea608.service[idx].base_row = 15; } if old_mode.is_rollup() && cea608_mode.is_rollup() { @@ -331,8 +325,7 @@ impl State { for _ in new_count..old_count { self.cea708.service_state[idx] .writer - .push_codes(&[Code::CR]) - .unwrap(); + .push_codes(&[Code::CR]); } } } @@ -371,8 +364,8 @@ impl State { } Cea608::EndOfCaption(chan) => { let state = self.service_state_from_608_field_channel(field, chan); - state.writer.end_of_caption().unwrap(); - state.writer.etx().unwrap(); + state.writer.end_of_caption(); + state.writer.etx(); } Cea608::Preamble(mut preamble) => { let idx = self.field_channel_to_index(field, preamble.chan); @@ -394,8 +387,7 @@ impl State { if old_base_row != preamble.row as u8 { state .writer - .rollup_preamble(rollup_count, preamble.row as u8) - .unwrap(); + .rollup_preamble(rollup_count, preamble.row as u8); } state.pen_location.row = rollup_count - 1; preamble.row = rollup_count as i32 - 1; @@ -411,10 +403,7 @@ impl State { let state = self.service_state_from_608_field_channel(field, chan); // TODO: handle removing a midrowchange state.pen_location.column = std::cmp::max(state.pen_location.column - 1, 0); - state - .writer - .push_codes(&[cea708_types::tables::Code::BS]) - .unwrap(); + state.writer.push_codes(&[cea708_types::tables::Code::BS]); } Cea608::CarriageReturn(chan) => { if let Some(mode) = @@ -428,11 +417,11 @@ impl State { } Cea608::EraseDisplay(chan) => { let state = self.service_state_from_608_field_channel(field, chan); - state.writer.clear_current_window().unwrap(); + state.writer.clear_current_window(); } Cea608::EraseNonDisplay(chan) => { let state = self.service_state_from_608_field_channel(field, chan); - state.writer.clear_hidden_window().unwrap(); + state.writer.clear_hidden_window(); } Cea608::TabOffset(chan, count) => { let state = self.service_state_from_608_field_channel(field, chan); @@ -453,8 +442,7 @@ impl State { // and we need to send ETX self.cea708.service_state[idx] .writer - .push_codes(&[cea708_types::tables::Code::ETX]) - .unwrap(); + .push_codes(&[cea708_types::tables::Code::ETX]); } } } diff --git a/video/closedcaption/src/cea708utils.rs b/video/closedcaption/src/cea708utils.rs index 577d2a01..2bc0abf3 100644 --- a/video/closedcaption/src/cea708utils.rs +++ b/video/closedcaption/src/cea708utils.rs @@ -88,14 +88,8 @@ pub fn textstyle_to_pen_color(style: TextStyle) -> SetPenColorArgs { } } -#[derive(Debug)] -pub enum WriteError { - // returns the number of characters/bytes written - WouldOverflow(usize), -} - pub(crate) struct Cea708ServiceWriter { - service: Option, + codes: Vec, service_no: u8, active_window: WindowBits, hidden_window: WindowBits, @@ -104,24 +98,44 @@ pub(crate) struct Cea708ServiceWriter { impl Cea708ServiceWriter { pub fn new(service_no: u8) -> Self { Self { - service: None, + codes: vec![], service_no, active_window: WindowBits::ZERO, hidden_window: WindowBits::ONE, } } - fn ensure_service(&mut self) { - if self.service.is_none() { - self.service = Some(Service::new(self.service_no)); + pub fn take_service(&mut self, available_bytes: usize) -> Option { + if self.codes.is_empty() { + return None; } + + gst::trace!(CAT, "New service block {}", self.service_no); + let mut service = Service::new(self.service_no); + let mut i = 0; + for code in self.codes.iter() { + if code.byte_len() > service.free_space() { + gst::trace!(CAT, "service is full"); + break; + } + if service.len() + code.byte_len() > available_bytes { + gst::trace!(CAT, "packet is full"); + break; + } + gst::trace!(CAT, "Adding code {code:?} to service"); + match service.push_code(code) { + Ok(_) => i += 1, + Err(_) => break, + } + } + if i == 0 { + return None; + } + self.codes = self.codes.split_off(i); + Some(service) } - pub fn take_service(&mut self) -> Option { - self.service.take() - } - - pub fn popon_preamble(&mut self) -> Result { + pub fn popon_preamble(&mut self) { gst::trace!(CAT, "popon_preamble"); let window = match self.hidden_window { // switch up the newly defined window @@ -152,26 +166,24 @@ impl Cea708ServiceWriter { self.push_codes(&codes) } - pub fn clear_current_window(&mut self) -> Result { + pub fn clear_current_window(&mut self) { gst::trace!(CAT, "clear_current_window {:?}", self.active_window); self.push_codes(&[Code::ClearWindows(self.active_window)]) } - pub fn clear_hidden_window(&mut self) -> Result { + pub fn clear_hidden_window(&mut self) { gst::trace!(CAT, "clear_hidden_window"); self.push_codes(&[Code::ClearWindows(self.hidden_window)]) } - pub fn end_of_caption(&mut self) -> Result { + pub fn end_of_caption(&mut self) { gst::trace!(CAT, "end_of_caption"); - let ret = - self.push_codes(&[Code::ToggleWindows(self.active_window | self.hidden_window)])?; + self.push_codes(&[Code::ToggleWindows(self.active_window | self.hidden_window)]); std::mem::swap(&mut self.active_window, &mut self.hidden_window); gst::trace!(CAT, "active window {:?}", self.active_window); - Ok(ret) } - pub fn paint_on_preamble(&mut self) -> Result { + pub fn paint_on_preamble(&mut self) { gst::trace!(CAT, "paint_on_preamble"); let window = match self.active_window { WindowBits::ZERO => 0, @@ -198,7 +210,7 @@ impl Cea708ServiceWriter { ]) } - pub fn rollup_preamble(&mut self, rollup_count: u8, base_row: u8) -> Result { + pub fn rollup_preamble(&mut self, rollup_count: u8, base_row: u8) { let base_row = std::cmp::max(rollup_count, base_row); let anchor_vertical = (base_row as u32 * 100 / 15) as u8; gst::trace!( @@ -229,49 +241,34 @@ impl Cea708ServiceWriter { self.push_codes(&codes) } - pub fn write_char(&mut self, c: char) -> Result { + pub fn write_char(&mut self, c: char) { if let Some(code) = Code::from_char(c) { self.push_codes(&[code]) - } else { - Ok(0) } } - pub fn push_codes(&mut self, codes: &[Code]) -> Result { - self.ensure_service(); - let service = self.service.as_mut().unwrap(); - let start_len = service.len(); - if service.free_space() < codes.iter().map(|c| c.byte_len()).sum::() { - return Err(WriteError::WouldOverflow(0)); - } - for code in codes.iter() { - gst::trace!( - CAT, - "pushing for service:{} code: {code:?}", - service.number() - ); - service.push_code(code).unwrap(); - } - Ok(service.len() - start_len) + pub fn push_codes(&mut self, codes: &[Code]) { + gst::log!(CAT, "pushing codes: {codes:?}"); + self.codes.extend(codes.iter().cloned()); } - pub fn etx(&mut self) -> Result { + pub fn etx(&mut self) { self.push_codes(&[Code::ETX]) } - pub fn carriage_return(&mut self) -> Result { + pub fn carriage_return(&mut self) { self.push_codes(&[Code::CR]) } - pub fn set_pen_attributes(&mut self, args: SetPenAttributesArgs) -> Result { + pub fn set_pen_attributes(&mut self, args: SetPenAttributesArgs) { self.push_codes(&[Code::SetPenAttributes(args)]) } - pub fn set_pen_location(&mut self, args: SetPenLocationArgs) -> Result { + pub fn set_pen_location(&mut self, args: SetPenLocationArgs) { self.push_codes(&[Code::SetPenLocation(args)]) } - pub fn set_pen_color(&mut self, args: SetPenColorArgs) -> Result { + pub fn set_pen_color(&mut self, args: SetPenColorArgs) { self.push_codes(&[Code::SetPenColor(args)]) } }