Skip to main content

Stl

Struct Stl 

Source
pub struct Stl {
    pub gsi: GsiBlock,
    pub ttis: Vec<TtiBlock>,
}
Expand description

A subtitle list in the EBU STL format: a GSI block followed by TTI blocks.

Fields§

§gsi: GsiBlock

The General Subtitle Information (GSI) block

§ttis: Vec<TtiBlock>

The Text and Timing Information (TTI) blocks, in file order

Implementations§

Source§

impl Stl

Source

pub fn validate(&self) -> Vec<ValidationIssue>

Checks the subtitle list against the rules in the spec, and returns the deviations found. An empty list means that no deviation was found.

The fields are checked one at a time as by the validating accessors, e.g. GsiBlock::creation_date, and together:

  • TND is 1-9 and DSN 1 up to TND.
  • TNB, TNS and TNG match the TTI blocks, when the subtitle list is on a single disk.
  • TCF is the TCI of the first subtitle.
  • Subtitle Numbers are continuous and ascending, and TCI ascending within a subtitle group.
  • Extension blocks have ascending EBN, the last block of a subtitle has EBN FFh and its Text Field ends with unused space (8Fh). EBN F0h-FDh are reserved.
  • TCI, TCO, JC and CF of the first block of each subtitle are valid, and TCO is not before TCI.
  • VP is 1-23 for teletext and at most MNR for open subtitles.
  • The Text Field only has control codes for the Display Standard Code, and no reserved codes.

Time codes are expected to increase with time, as the spec requires ascending TCI (section 4.3.1). A subtitle list that passes midnight, where time codes start over from 00:00:00:00, or that has cuts in the time codes is therefore reported. Comment subtitles (CF 01h) are not included in the time code order and TCF.

§Example
use ebustl_parser::{Stl, Time, TtiFormat};

let time = |seconds| Time { hours: 10, minutes: 0, seconds, frames: 0 };
let format = |vp| TtiFormat { jc: 2, vp, dh: false };
let mut stl = Stl::new();
stl.add_sub(time(1), time(3), "Valid", format(20)).unwrap();
assert!(stl.validate().is_empty());

// Teletext has rows 1-23
stl.add_sub(time(4), time(6), "Below the screen", format(30)).unwrap();
let issues = stl.validate();
assert_eq!(1, issues.len());
assert_eq!("VP", issues[0].field());
assert_eq!(Some(1), issues[0].tti_index());
Source§

impl Stl

Source

pub fn new() -> Stl

Creates an empty subtitle list with a default GSI block, see GsiBlock::new.

Source

pub fn write_to_file<P: AsRef<Path>>( &self, filename: P, ) -> Result<(), ParseError>

Writes the subtitle list to a file.

§Errors

Fails if the file cannot be written, or if a text field in the GSI block cannot be encoded with its code page.

§Example
use ebustl_parser::{Stl, Time, TtiFormat, parse_stl_from_file};

let time = |seconds| Time { hours: 10, minutes: 0, seconds, frames: 0 };
let mut stl = Stl::new();
stl.add_sub(time(1), time(3), "Hello", TtiFormat { jc: 2, vp: 20, dh: false })
    .expect("Add subtitle");

let path = std::env::temp_dir().join("ebustl_parser_write_to_file_example.stl");
stl.write_to_file(&path).expect("Write file");
let written = parse_stl_from_file(&path).expect("Parse file");
assert_eq!("Hello", written.subtitles().next().unwrap().text());
Source

pub fn add_sub( &mut self, tci: Time, tco: Time, txt: &str, opt: TtiFormat, ) -> Result<(), ParseError>

Adds a subtitle after the existing TTI blocks and updates TNB and TNS.

Rows are separated by \n or \r\n. Text that does not fit in one TTI block continues in extension blocks. Teletext control codes boxing each row, and double height if opt.dh is set, are added unless the Display Standard Code is open subtitling.

The Subtitle Number continues from the last block, starting at 1. The first subtitle sets the Time Code: First In-Cue (TCF) of the GSI block.

§Errors

Returns an error, leaving the Stl unchanged, if the text needs more than 241 TTI blocks, if TNB would exceed 99 999 or if the Subtitle Number would exceed FFFFh.

§Example
use ebustl_parser::{Stl, Time, TtiFormat};

let time = |seconds| Time { hours: 10, minutes: 0, seconds, frames: 0 };
let format = TtiFormat { jc: 2, vp: 20, dh: false };

let mut stl = Stl::new();
stl.add_sub(time(1), time(3), "First row\nSecond row", format)
    .expect("Add subtitle");

let subtitle = stl.subtitles().next().unwrap();
assert_eq!("First row\r\nSecond row", subtitle.text());
assert_eq!(1, stl.gsi.total_number_of_subtitles());
Source

pub fn subtitles(&self) -> Subtitles<'_> ⓘ

Iterates over the subtitles, each made up of one or more TTI blocks.

Consecutive blocks with the same Subtitle Number form one subtitle. A subtitle ends at its last block (EBN FFh), although a following user data block (EBN FEh) with the same Subtitle Number still belongs to it.

§Example
use ebustl_parser::parse_stl_from_file;

let stl = parse_stl_from_file("stls/test.stl").expect("Parse stl from file");
let texts: Vec<String> = stl
    .subtitles()
    .filter(|subtitle| !subtitle.is_comment())
    .map(|subtitle| subtitle.text())
    .collect();
assert_eq!("    dans la baie de New York.\r\n", texts[11]);

Trait Implementations§

Source§

impl Debug for Stl

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Stl

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Display for Stl

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Stl

Source§

impl PartialEq for Stl

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Stl

Auto Trait Implementations§

§

impl Freeze for Stl

§

impl RefUnwindSafe for Stl

§

impl Send for Stl

§

impl Sync for Stl

§

impl Unpin for Stl

§

impl UnsafeUnpin for Stl

§

impl UnwindSafe for Stl

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.