Repository navigation
This release brings the parser and writer better in line with the EBU STL spec
(Tech 3264). It contains breaking changes, see
Upgrading.
Breaking changes
-
Getters drop the
get_prefix, e.g.get_disk_format_code()→disk_format_code().
Renames beyond the prefix:0.6 0.7 get_original_program_title()original_programme_title()get_translated_program_title()translated_programme_title()get_timecode_start_of_program()time_code_start_of_programme()get_timecode_first_in_cue()time_code_first_in_cue()get_timecode_status()time_code_status()get_language_code()language()get_justification_code()justification()get_total_number_of_chars_in_row()total_number_of_subtitle_groups()(it always returned TNG)get_subtitle_number_range()subtitle_number()get_text()text()DiskFormatCode::get_fps()DiskFormatCode::fps() -
Fields with a defined format are now validated instead of returned raw:
- GSI:
language(),creation_date(),revision_date(),revision_number(),
time_code_start_of_programme(),time_code_first_in_cue()andcountry_of_origin()
returnResult<Option<T>, InvalidFieldValue<String>>.Nonemeans the field is blank. - TTI:
time_code_in(dfc)andtime_code_out(dfc)returnResult<Time, InvalidFieldValue<Time>>,
justification()andcomment_flag()returnResult<_, InvalidFieldValue<u8>>. - On error,
InvalidFieldValue::value()orinto_value()gives the value as stored.
- GSI:
-
Free text GSI fields (titles, names, contact details, publisher, SLR) return
Option<&str>without the trailing space padding,Noneif blank. -
total_number_of_text_and_timing_blocks()andtotal_number_of_subtitles()return
u32, as the spec allows up to 99 999. -
Stl::add_sub()returnsResult<(), ParseError>. It fails if the text needs more than
241 TTI blocks, or if TNB or the Subtitle Number would overflow. -
ParseErrorhas new variants:SubtitleTextTooLong,TooManyTtiBlocks,
SubtitleNumberOverflowandInvalidFieldValue. -
parse_stl_from_slice()returns a winnow 1.0ModalResult(was winnow 0.7). -
Invalid TTI blocks are errors. An invalid block, a truncated last block or trailing data
used to silently drop the rest of the file.
Behavior changes
- Character code table 00 follows the EBU table:
A4hdecodes as$(was€) and24h
as¤(was$). When writing,$is encoded asA4hand€, which the table lacks, as
?. Stand-alone diacritical marks and unassigned codes no longer drop characters. - Writing with
add_sub()andTtiBlock::new():\nstarts a new row (CR/LF,8Ah), each row is boxed for teletext, and no teletext
control codes are written for open subtitles.- Long text continues in extension blocks instead of being truncated.
- Subtitle Numbers continue from the last block, and the first subtitle sets TCF.
- Nothing is printed to stdout.
- Parsing is more lenient where the spec allows it: files without TTI blocks, and numeric
GSI fields that are space padded or blank (a blank CPN is read as 850 and a blank TCS as
intended for use). Such fields are written back zero padded.
New
Stl::subtitles()groups TTI blocks intoSubtitles.Subtitle::text()decodes the
complete text across extension blocks and skips user data blocks.text_elements()onTtiBlockandSubtitlegives the text with its control codes as
TextElements: teletext colors, double height and boxing, and italics, underline and boxing
for open subtitles.Stl::validate()checks the rules between fields and blocks, e.g. TNB/TNS/TNG, TCF,
ascending SN and TCI, extension block numbering and VP, and returnsValidationIssues.LanguageCode::name(),Date,Time::is_valid(), andis_user_data(),
is_text_block(),is_last_block()andis_comment()onTtiBlock.- All public items are documented, with examples.
Fixes
- Text filling a Text Field to the last byte was dropped by
text(). - TNB/TNS above 65 535, and zero TTI blocks, were rejected.
Upgrading
// 0.6
let title = stl.gsi.get_original_program_title().trim();
let created = stl.gsi.get_creation_date(); // "131010"
for tti in &stl.ttis {
println!("{} {}", tti.get_time_code_in(), tti.get_text());
}
stl.add_sub(tci, tco, "One row\nAnother row", format);
// 0.7
let title = stl.gsi.original_programme_title().unwrap_or("");
let created = stl.gsi.creation_date()?; // Some(Date { year: 2013, month: 10, day: 10 })
let dfc = stl.gsi.disk_format_code();
for subtitle in stl.subtitles() {
// Use the stored time code even if it is outside the ranges in the spec
let tci = subtitle.header_block().time_code_in(dfc).unwrap_or_else(|e| e.into_value());
println!("{} {}", tci.hhmmssff(), subtitle.text());
}
stl.add_sub(tci, tco, "One row\nAnother row", format)?;Iterate stl.subtitles() rather than stl.ttis to get complete subtitles, as a subtitle may
span several TTI blocks.