Skip to content

0.7.0

Latest

Choose a tag to compare

@snaggen snaggen released this 21 Sep 09:29

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() and country_of_origin()
      return Result<Option<T>, InvalidFieldValue<String>>. None means the field is blank.
    • TTI: time_code_in(dfc) and time_code_out(dfc) return Result<Time, InvalidFieldValue<Time>>,
      justification() and comment_flag() return Result<_, InvalidFieldValue<u8>>.
    • On error, InvalidFieldValue::value() or into_value() gives the value as stored.
  • Free text GSI fields (titles, names, contact details, publisher, SLR) return
    Option<&str> without the trailing space padding, None if blank.

  • total_number_of_text_and_timing_blocks() and total_number_of_subtitles() return
    u32
    , as the spec allows up to 99 999.

  • Stl::add_sub() returns Result<(), ParseError>. It fails if the text needs more than
    241 TTI blocks, or if TNB or the Subtitle Number would overflow.

  • ParseError has new variants: SubtitleTextTooLong, TooManyTtiBlocks,
    SubtitleNumberOverflow and InvalidFieldValue.

  • parse_stl_from_slice() returns a winnow 1.0 ModalResult (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: A4h decodes as $ (was €) and 24h
    as ¤ (was $). When writing, $ is encoded as A4h and €, which the table lacks, as
    ?. Stand-alone diacritical marks and unassigned codes no longer drop characters.
  • Writing with add_sub() and TtiBlock::new():
    • \n starts 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 into Subtitles. Subtitle::text() decodes the
    complete text across extension blocks and skips user data blocks.
  • text_elements() on TtiBlock and Subtitle gives 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 returns ValidationIssues.
  • LanguageCode::name(), Date, Time::is_valid(), and is_user_data(),
    is_text_block(), is_last_block() and is_comment() on TtiBlock.
  • 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.