mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-23 10:30:40 +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
|
||||
}
|
||||
|
||||
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(
|
||||
&self,
|
||||
mut state: &mut State,
|
||||
|
@ -548,6 +552,7 @@ impl TtToCea608 {
|
|||
duration: gst::ClockTime,
|
||||
lines: Lines,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
let origin_column = self.settings.lock().unwrap().origin_column;
|
||||
let mut row = 13;
|
||||
let mut bufferlist = gst::BufferList::new();
|
||||
let mut_list = bufferlist.get_mut().unwrap();
|
||||
|
@ -585,7 +590,7 @@ impl TtToCea608 {
|
|||
Cea608Mode::RollUp2 | Cea608Mode::RollUp3 | Cea608Mode::RollUp4 => {
|
||||
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 {
|
||||
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;
|
||||
} 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() {
|
||||
|
@ -722,36 +727,48 @@ impl TtToCea608 {
|
|||
|
||||
col += 1;
|
||||
|
||||
if col > 31 {
|
||||
match state.mode {
|
||||
Cea608Mode::PaintOn | Cea608Mode::PopOn => {
|
||||
if chars.peek().is_some() {
|
||||
gst_warning!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"Dropping characters after 32nd column: {}",
|
||||
c
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
Cea608Mode::RollUp2 | Cea608Mode::RollUp3 | Cea608Mode::RollUp4 => {
|
||||
if prev_char != 0 {
|
||||
state.cc_data(element, mut_list, prev_char);
|
||||
prev_char = 0;
|
||||
}
|
||||
if state.mode.is_rollup() {
|
||||
/* In roll-up mode, we introduce carriage returns automatically.
|
||||
* Instead of always wrapping once the last column is reached, we
|
||||
* want to look ahead and check whether the following word will fit
|
||||
* on the current row. If it won't, we insert a carriage return,
|
||||
* unless it won't fit on a full row either, in which case it will need
|
||||
* to be broken up.
|
||||
*/
|
||||
let next_word_length = if c.is_ascii_whitespace() {
|
||||
self.peek_word_length(chars.clone())
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
self.open_line(
|
||||
element,
|
||||
&mut state,
|
||||
chunk,
|
||||
mut_list,
|
||||
&mut col,
|
||||
row as i32,
|
||||
Some(true),
|
||||
);
|
||||
if (next_word_length <= 32 - origin_column && col + next_word_length > 31)
|
||||
|| col > 31
|
||||
{
|
||||
if prev_char != 0 {
|
||||
state.cc_data(element, mut_list, prev_char);
|
||||
prev_char = 0;
|
||||
}
|
||||
|
||||
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();
|
||||
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