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: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1398>
This commit is contained in:
Matthew Waters 2023-11-07 00:25:20 +11:00
parent ded4261971
commit 5739a3d86f
2 changed files with 71 additions and 86 deletions

View file

@ -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]);
}
}
}

View file

@ -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<Service>,
codes: Vec<Code>,
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<Service> {
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<Service> {
self.service.take()
}
pub fn popon_preamble(&mut self) -> Result<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
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::<usize>() {
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<usize, WriteError> {
pub fn etx(&mut self) {
self.push_codes(&[Code::ETX])
}
pub fn carriage_return(&mut self) -> Result<usize, WriteError> {
pub fn carriage_return(&mut self) {
self.push_codes(&[Code::CR])
}
pub fn set_pen_attributes(&mut self, args: SetPenAttributesArgs) -> Result<usize, WriteError> {
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<usize, WriteError> {
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<usize, WriteError> {
pub fn set_pen_color(&mut self, args: SetPenColorArgs) {
self.push_codes(&[Code::SetPenColor(args)])
}
}