mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-29 23:11:01 +00:00
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:
parent
ded4261971
commit
5739a3d86f
2 changed files with 71 additions and 86 deletions
|
@ -101,11 +101,11 @@ impl Cea708ServiceState {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
match cea608_mode {
|
match cea608_mode {
|
||||||
Cea608Mode::PopOn => self.writer.popon_preamble().unwrap(),
|
Cea608Mode::PopOn => self.writer.popon_preamble(),
|
||||||
Cea608Mode::PaintOn => self.writer.paint_on_preamble().unwrap(),
|
Cea608Mode::PaintOn => self.writer.paint_on_preamble(),
|
||||||
Cea608Mode::RollUp2 => self.writer.rollup_preamble(2, base_row).unwrap(),
|
Cea608Mode::RollUp2 => self.writer.rollup_preamble(2, base_row),
|
||||||
Cea608Mode::RollUp3 => self.writer.rollup_preamble(3, base_row).unwrap(),
|
Cea608Mode::RollUp3 => self.writer.rollup_preamble(3, base_row),
|
||||||
Cea608Mode::RollUp4 => self.writer.rollup_preamble(4, base_row).unwrap(),
|
Cea608Mode::RollUp4 => self.writer.rollup_preamble(4, base_row),
|
||||||
};
|
};
|
||||||
// we have redefined then window so all the attributes have been reset
|
// we have redefined then window so all the attributes have been reset
|
||||||
self.pen_location.row = new_row;
|
self.pen_location.row = new_row;
|
||||||
|
@ -117,20 +117,20 @@ impl Cea708ServiceState {
|
||||||
|
|
||||||
fn handle_text(&mut self, text: Cea608Text) {
|
fn handle_text(&mut self, text: Cea608Text) {
|
||||||
if text.code_space == CodeSpace::WestEU {
|
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 let Some(c) = text.char1 {
|
||||||
if self.pen_location.column > 31 {
|
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);
|
self.pen_location.column = std::cmp::min(self.pen_location.column + 1, 32);
|
||||||
}
|
}
|
||||||
if let Some(c) = text.char2 {
|
if let Some(c) = text.char2 {
|
||||||
if self.pen_location.column > 31 {
|
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);
|
self.pen_location.column = std::cmp::min(self.pen_location.column + 1, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ impl Cea708ServiceState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if need_pen_location {
|
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;
|
let mut need_pen_attributes = false;
|
||||||
|
@ -165,20 +165,20 @@ impl Cea708ServiceState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if need_pen_attributes {
|
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) {
|
if self.pen_color.foreground_color != textstyle_foreground_color(preamble.style) {
|
||||||
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) {
|
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) {
|
if self.pen_color.foreground_color != textstyle_foreground_color(midrowchange.style) {
|
||||||
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;
|
let mut need_pen_attributes = false;
|
||||||
|
@ -214,7 +214,7 @@ impl Cea708State {
|
||||||
self.packet_counter &= 0x3;
|
self.packet_counter &= 0x3;
|
||||||
|
|
||||||
for state in self.service_state.iter_mut() {
|
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()) {
|
if let Err(e) = packet.push_service(service.clone()) {
|
||||||
gst::warning!(
|
gst::warning!(
|
||||||
CAT,
|
CAT,
|
||||||
|
@ -307,14 +307,8 @@ impl State {
|
||||||
{
|
{
|
||||||
// https://www.law.cornell.edu/cfr/text/47/79.101 (f)(1)(x)
|
// https://www.law.cornell.edu/cfr/text/47/79.101 (f)(1)(x)
|
||||||
gst::trace!(CAT, "change to rollup from pop/paint-on");
|
gst::trace!(CAT, "change to rollup from pop/paint-on");
|
||||||
self.cea708.service_state[idx]
|
self.cea708.service_state[idx].writer.clear_hidden_window();
|
||||||
.writer
|
self.cea708.service_state[idx].writer.clear_current_window();
|
||||||
.clear_hidden_window()
|
|
||||||
.unwrap();
|
|
||||||
self.cea708.service_state[idx]
|
|
||||||
.writer
|
|
||||||
.clear_current_window()
|
|
||||||
.unwrap();
|
|
||||||
self.cea608.service[idx].base_row = 15;
|
self.cea608.service[idx].base_row = 15;
|
||||||
}
|
}
|
||||||
if old_mode.is_rollup() && cea608_mode.is_rollup() {
|
if old_mode.is_rollup() && cea608_mode.is_rollup() {
|
||||||
|
@ -331,8 +325,7 @@ impl State {
|
||||||
for _ in new_count..old_count {
|
for _ in new_count..old_count {
|
||||||
self.cea708.service_state[idx]
|
self.cea708.service_state[idx]
|
||||||
.writer
|
.writer
|
||||||
.push_codes(&[Code::CR])
|
.push_codes(&[Code::CR]);
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,8 +364,8 @@ impl State {
|
||||||
}
|
}
|
||||||
Cea608::EndOfCaption(chan) => {
|
Cea608::EndOfCaption(chan) => {
|
||||||
let state = self.service_state_from_608_field_channel(field, chan);
|
let state = self.service_state_from_608_field_channel(field, chan);
|
||||||
state.writer.end_of_caption().unwrap();
|
state.writer.end_of_caption();
|
||||||
state.writer.etx().unwrap();
|
state.writer.etx();
|
||||||
}
|
}
|
||||||
Cea608::Preamble(mut preamble) => {
|
Cea608::Preamble(mut preamble) => {
|
||||||
let idx = self.field_channel_to_index(field, preamble.chan);
|
let idx = self.field_channel_to_index(field, preamble.chan);
|
||||||
|
@ -394,8 +387,7 @@ impl State {
|
||||||
if old_base_row != preamble.row as u8 {
|
if old_base_row != preamble.row as u8 {
|
||||||
state
|
state
|
||||||
.writer
|
.writer
|
||||||
.rollup_preamble(rollup_count, preamble.row as u8)
|
.rollup_preamble(rollup_count, preamble.row as u8);
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
state.pen_location.row = rollup_count - 1;
|
state.pen_location.row = rollup_count - 1;
|
||||||
preamble.row = rollup_count as i32 - 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);
|
let state = self.service_state_from_608_field_channel(field, chan);
|
||||||
// TODO: handle removing a midrowchange
|
// TODO: handle removing a midrowchange
|
||||||
state.pen_location.column = std::cmp::max(state.pen_location.column - 1, 0);
|
state.pen_location.column = std::cmp::max(state.pen_location.column - 1, 0);
|
||||||
state
|
state.writer.push_codes(&[cea708_types::tables::Code::BS]);
|
||||||
.writer
|
|
||||||
.push_codes(&[cea708_types::tables::Code::BS])
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
Cea608::CarriageReturn(chan) => {
|
Cea608::CarriageReturn(chan) => {
|
||||||
if let Some(mode) =
|
if let Some(mode) =
|
||||||
|
@ -428,11 +417,11 @@ impl State {
|
||||||
}
|
}
|
||||||
Cea608::EraseDisplay(chan) => {
|
Cea608::EraseDisplay(chan) => {
|
||||||
let state = self.service_state_from_608_field_channel(field, 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) => {
|
Cea608::EraseNonDisplay(chan) => {
|
||||||
let state = self.service_state_from_608_field_channel(field, 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) => {
|
Cea608::TabOffset(chan, count) => {
|
||||||
let state = self.service_state_from_608_field_channel(field, chan);
|
let state = self.service_state_from_608_field_channel(field, chan);
|
||||||
|
@ -453,8 +442,7 @@ impl State {
|
||||||
// and we need to send ETX
|
// and we need to send ETX
|
||||||
self.cea708.service_state[idx]
|
self.cea708.service_state[idx]
|
||||||
.writer
|
.writer
|
||||||
.push_codes(&[cea708_types::tables::Code::ETX])
|
.push_codes(&[cea708_types::tables::Code::ETX]);
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
pub(crate) struct Cea708ServiceWriter {
|
||||||
service: Option<Service>,
|
codes: Vec<Code>,
|
||||||
service_no: u8,
|
service_no: u8,
|
||||||
active_window: WindowBits,
|
active_window: WindowBits,
|
||||||
hidden_window: WindowBits,
|
hidden_window: WindowBits,
|
||||||
|
@ -104,24 +98,44 @@ pub(crate) struct Cea708ServiceWriter {
|
||||||
impl Cea708ServiceWriter {
|
impl Cea708ServiceWriter {
|
||||||
pub fn new(service_no: u8) -> Self {
|
pub fn new(service_no: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
service: None,
|
codes: vec![],
|
||||||
service_no,
|
service_no,
|
||||||
active_window: WindowBits::ZERO,
|
active_window: WindowBits::ZERO,
|
||||||
hidden_window: WindowBits::ONE,
|
hidden_window: WindowBits::ONE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_service(&mut self) {
|
pub fn take_service(&mut self, available_bytes: usize) -> Option<Service> {
|
||||||
if self.service.is_none() {
|
if self.codes.is_empty() {
|
||||||
self.service = Some(Service::new(self.service_no));
|
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> {
|
pub fn popon_preamble(&mut self) {
|
||||||
self.service.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn popon_preamble(&mut self) -> Result<usize, WriteError> {
|
|
||||||
gst::trace!(CAT, "popon_preamble");
|
gst::trace!(CAT, "popon_preamble");
|
||||||
let window = match self.hidden_window {
|
let window = match self.hidden_window {
|
||||||
// switch up the newly defined window
|
// switch up the newly defined window
|
||||||
|
@ -152,26 +166,24 @@ impl Cea708ServiceWriter {
|
||||||
self.push_codes(&codes)
|
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);
|
gst::trace!(CAT, "clear_current_window {:?}", self.active_window);
|
||||||
self.push_codes(&[Code::ClearWindows(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");
|
gst::trace!(CAT, "clear_hidden_window");
|
||||||
self.push_codes(&[Code::ClearWindows(self.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");
|
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);
|
std::mem::swap(&mut self.active_window, &mut self.hidden_window);
|
||||||
gst::trace!(CAT, "active window {:?}", self.active_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");
|
gst::trace!(CAT, "paint_on_preamble");
|
||||||
let window = match self.active_window {
|
let window = match self.active_window {
|
||||||
WindowBits::ZERO => 0,
|
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 base_row = std::cmp::max(rollup_count, base_row);
|
||||||
let anchor_vertical = (base_row as u32 * 100 / 15) as u8;
|
let anchor_vertical = (base_row as u32 * 100 / 15) as u8;
|
||||||
gst::trace!(
|
gst::trace!(
|
||||||
|
@ -229,49 +241,34 @@ impl Cea708ServiceWriter {
|
||||||
self.push_codes(&codes)
|
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) {
|
if let Some(code) = Code::from_char(c) {
|
||||||
self.push_codes(&[code])
|
self.push_codes(&[code])
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_codes(&mut self, codes: &[Code]) -> Result<usize, WriteError> {
|
pub fn push_codes(&mut self, codes: &[Code]) {
|
||||||
self.ensure_service();
|
gst::log!(CAT, "pushing codes: {codes:?}");
|
||||||
let service = self.service.as_mut().unwrap();
|
self.codes.extend(codes.iter().cloned());
|
||||||
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 etx(&mut self) -> Result<usize, WriteError> {
|
pub fn etx(&mut self) {
|
||||||
self.push_codes(&[Code::ETX])
|
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])
|
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)])
|
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)])
|
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)])
|
self.push_codes(&[Code::SetPenColor(args)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue