mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-23 18:40:32 +00:00
tttocea608: implement word wrapping in roll-up modes.
In roll-up modes, we open new lines when the last column is reached. This commit implements lookahead on a word basis, in order to avoid splitting words unless absolutely necessary (when a word won't fit on a full row)
This commit is contained in:
parent
95cdd43f4f
commit
7923e26545
2 changed files with 106 additions and 30 deletions
|
@ -540,6 +540,10 @@ impl TtToCea608 {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peek_word_length(&self, chars: std::iter::Peekable<std::str::Chars>) -> u32 {
|
||||||
|
chars.take_while(|c| !c.is_ascii_whitespace()).count() as u32
|
||||||
|
}
|
||||||
|
|
||||||
fn generate(
|
fn generate(
|
||||||
&self,
|
&self,
|
||||||
mut state: &mut State,
|
mut state: &mut State,
|
||||||
|
@ -548,6 +552,7 @@ impl TtToCea608 {
|
||||||
duration: gst::ClockTime,
|
duration: gst::ClockTime,
|
||||||
lines: Lines,
|
lines: Lines,
|
||||||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||||
|
let origin_column = self.settings.lock().unwrap().origin_column;
|
||||||
let mut row = 13;
|
let mut row = 13;
|
||||||
let mut bufferlist = gst::BufferList::new();
|
let mut bufferlist = gst::BufferList::new();
|
||||||
let mut_list = bufferlist.get_mut().unwrap();
|
let mut_list = bufferlist.get_mut().unwrap();
|
||||||
|
@ -585,7 +590,7 @@ impl TtToCea608 {
|
||||||
Cea608Mode::RollUp2 | Cea608Mode::RollUp3 | Cea608Mode::RollUp4 => {
|
Cea608Mode::RollUp2 | Cea608Mode::RollUp3 | Cea608Mode::RollUp4 => {
|
||||||
state.send_roll_up_preamble = true;
|
state.send_roll_up_preamble = true;
|
||||||
}
|
}
|
||||||
_ => col = self.settings.lock().unwrap().origin_column,
|
_ => col = origin_column,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,7 +602,7 @@ impl TtToCea608 {
|
||||||
if state.mode != Cea608Mode::PopOn && state.mode != Cea608Mode::PaintOn {
|
if state.mode != Cea608Mode::PopOn && state.mode != Cea608Mode::PaintOn {
|
||||||
state.send_roll_up_preamble = true;
|
state.send_roll_up_preamble = true;
|
||||||
}
|
}
|
||||||
col = self.settings.lock().unwrap().origin_column;
|
col = origin_column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +642,7 @@ impl TtToCea608 {
|
||||||
}
|
}
|
||||||
col = line_column;
|
col = line_column;
|
||||||
} else if state.mode == Cea608Mode::PopOn || state.mode == Cea608Mode::PaintOn {
|
} else if state.mode == Cea608Mode::PopOn || state.mode == Cea608Mode::PaintOn {
|
||||||
col = self.settings.lock().unwrap().origin_column;
|
col = origin_column;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j, chunk) in line.chunks.iter().enumerate() {
|
for (j, chunk) in line.chunks.iter().enumerate() {
|
||||||
|
@ -722,36 +727,48 @@ impl TtToCea608 {
|
||||||
|
|
||||||
col += 1;
|
col += 1;
|
||||||
|
|
||||||
if col > 31 {
|
if state.mode.is_rollup() {
|
||||||
match state.mode {
|
/* In roll-up mode, we introduce carriage returns automatically.
|
||||||
Cea608Mode::PaintOn | Cea608Mode::PopOn => {
|
* Instead of always wrapping once the last column is reached, we
|
||||||
if chars.peek().is_some() {
|
* want to look ahead and check whether the following word will fit
|
||||||
gst_warning!(
|
* on the current row. If it won't, we insert a carriage return,
|
||||||
CAT,
|
* unless it won't fit on a full row either, in which case it will need
|
||||||
obj: element,
|
* to be broken up.
|
||||||
"Dropping characters after 32nd column: {}",
|
*/
|
||||||
c
|
let next_word_length = if c.is_ascii_whitespace() {
|
||||||
);
|
self.peek_word_length(chars.clone())
|
||||||
}
|
} else {
|
||||||
break;
|
0
|
||||||
}
|
};
|
||||||
Cea608Mode::RollUp2 | Cea608Mode::RollUp3 | Cea608Mode::RollUp4 => {
|
|
||||||
if prev_char != 0 {
|
|
||||||
state.cc_data(element, mut_list, prev_char);
|
|
||||||
prev_char = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.open_line(
|
if (next_word_length <= 32 - origin_column && col + next_word_length > 31)
|
||||||
element,
|
|| col > 31
|
||||||
&mut state,
|
{
|
||||||
chunk,
|
if prev_char != 0 {
|
||||||
mut_list,
|
state.cc_data(element, mut_list, prev_char);
|
||||||
&mut col,
|
prev_char = 0;
|
||||||
row as i32,
|
|
||||||
Some(true),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.open_line(
|
||||||
|
element,
|
||||||
|
&mut state,
|
||||||
|
chunk,
|
||||||
|
mut_list,
|
||||||
|
&mut col,
|
||||||
|
row as i32,
|
||||||
|
Some(true),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
} else if col > 31 {
|
||||||
|
if chars.peek().is_some() {
|
||||||
|
gst_warning!(
|
||||||
|
CAT,
|
||||||
|
obj: element,
|
||||||
|
"Dropping characters after 32nd column: {}",
|
||||||
|
c
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,3 +371,62 @@ fn test_one_timed_buffer_and_eos_roll_up2() {
|
||||||
let event = h.pull_event().unwrap();
|
let event = h.pull_event().unwrap();
|
||||||
assert_eq!(event.type_(), gst::EventType::Eos);
|
assert_eq!(event.type_(), gst::EventType::Eos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Here we test that tttocea608 introduces carriage returns in
|
||||||
|
* judicious places and avoids to break words without rhyme or
|
||||||
|
* reason.
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn test_word_wrap_roll_up() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
let mut h = gst_check::Harness::new_parse("tttocea608 mode=roll-up2 origin-column=24");
|
||||||
|
h.set_src_caps_str("text/x-raw");
|
||||||
|
|
||||||
|
while h.events_in_queue() != 0 {
|
||||||
|
let _event = h.pull_event().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let inbuf = new_timed_buffer(&"Hello World", gst::SECOND, gst::SECOND);
|
||||||
|
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||||
|
|
||||||
|
/* Padding */
|
||||||
|
loop {
|
||||||
|
let outbuf = h.pull().unwrap();
|
||||||
|
if outbuf.pts() + outbuf.duration() >= gst::SECOND {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = outbuf.map_readable().unwrap();
|
||||||
|
assert_eq!(&*data, &[0x80, 0x80]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected: [(gst::ClockTime, gst::ClockTime, [u8; 2usize]); 11] = [
|
||||||
|
(1_000_000_000.into(), 33_333_333.into(), [0x94, 0x25]), /* roll_up_2 */
|
||||||
|
(1_033_333_333.into(), 33_333_334.into(), [0x94, 0x7c]), /* preamble */
|
||||||
|
(1_066_666_667.into(), 33_333_333.into(), [0xc8, 0xe5]), /* H e */
|
||||||
|
(1_100_000_000.into(), 33_333_333.into(), [0xec, 0xec]), /* l l */
|
||||||
|
(1_133_333_333.into(), 33_333_334.into(), [0xef, 0x20]), /* o SPACE */
|
||||||
|
(1_166_666_667.into(), 33_333_333.into(), [0x94, 0xad]), /* carriage return */
|
||||||
|
(1_200_000_000.into(), 33_333_333.into(), [0x94, 0x25]), /* roll_up_2 */
|
||||||
|
(1_233_333_333.into(), 33_333_334.into(), [0x94, 0x7c]), /* preamble */
|
||||||
|
(1_266_666_667.into(), 33_333_333.into(), [0x57, 0xef]), /* W o */
|
||||||
|
(1_300_000_000.into(), 33_333_333.into(), [0xf2, 0xec]), /* r l */
|
||||||
|
(1_333_333_333.into(), 33_333_334.into(), [0x64, 0x80]), /* d nil */
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, e) in expected.iter().enumerate() {
|
||||||
|
let outbuf = h.try_pull().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(e.0, outbuf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||||
|
assert_eq!(
|
||||||
|
e.1,
|
||||||
|
outbuf.duration(),
|
||||||
|
"Unexpected duration for {}th buffer",
|
||||||
|
i + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let data = outbuf.map_readable().unwrap();
|
||||||
|
assert_eq!(e.2, &*data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue