inset_embedder/cue.rs
1//! Subtitles and captions as a player hands them to the app: Media3's `Cue`, field for field, since
2//! Media3 turns every subtitle format it reads into one, and each system's player gives the same
3//! as data (Apple's legible output, Windows' timed text cues). A cue carries the media's own
4//! styling alone, as Media3's does and as Apple's legible output gives it at its
5//! `SourceAndRulesOnly` styling: a field the media says nothing of is `None`, and the app fills it
6//! in from the user's caption style ([`CaptionStyle`](crate::CaptionStyle)) as it draws the cue.
7//!
8//! Sizes and places are fractions of the picture the cue is drawn over, so a cue reads the same
9//! at any size the picture is shown at.
10
11use crate::Color;
12
13/// One subtitle or caption to show: Media3's `Cue`.
14#[derive(Clone, Debug, PartialEq)]
15pub struct Cue {
16 pub content: CueContent,
17 /// Where its box sits from the top: a fraction of the picture's height, or a line number;
18 /// `None` for the default, the bottom.
19 pub line: Option<CueLine>,
20 /// Which side of its box `line` places.
21 pub line_anchor: CueAnchor,
22 /// Where its box sits across, as a fraction of the picture's width; `None` for the default,
23 /// the centre.
24 pub position: Option<f32>,
25 /// Which side of its box `position` places.
26 pub position_anchor: CueAnchor,
27 /// Its box's width as a fraction of the picture's; `None` to fit what it holds.
28 pub size: Option<f32>,
29 pub text_alignment: CueTextAlignment,
30 /// Whether its text runs in columns, and which way they follow each other; `None` for rows.
31 pub vertical: Option<CueVertical>,
32 /// The colour of the box behind it; `None` where the media says none, Media3's
33 /// `windowColorSet` false.
34 pub window_color: Option<Color>,
35}
36
37impl Cue {
38 /// A cue showing `content` where Media3's `Cue.Builder` puts one by default: centred at the
39 /// bottom, its text centred, its box's colour unsaid.
40 pub fn new(content: CueContent) -> Cue {
41 Cue {
42 content,
43 line: None,
44 line_anchor: CueAnchor::Start,
45 position: None,
46 position_anchor: CueAnchor::Start,
47 size: None,
48 text_alignment: CueTextAlignment::Center,
49 vertical: None,
50 window_color: None,
51 }
52 }
53}
54
55/// What a cue shows.
56#[derive(Clone, Debug, PartialEq)]
57pub enum CueContent {
58 /// Its text, in runs of one style.
59 Text(Vec<CueTextRun>),
60 /// A picture subtitle, as Blu-ray, DVD and DVB carry them, decoded.
61 Image(CueImage),
62}
63
64/// Text of one style. Each field the media may leave unsaid is `None` where it does.
65#[derive(Clone, Debug, PartialEq)]
66pub struct CueTextRun {
67 pub text: String,
68 pub bold: bool,
69 pub italic: bool,
70 pub underline: bool,
71 pub color: Option<Color>,
72 /// The colour behind these characters.
73 pub background: Option<Color>,
74 /// The text's height as a fraction of the picture's.
75 pub font_size: Option<f32>,
76 pub font_family: Option<String>,
77 pub edge: Option<CueTextEdge>,
78 pub edge_color: Option<Color>,
79}
80
81impl CueTextRun {
82 /// The height Media3's `SubtitleView` gives text by default, `DEFAULT_TEXT_SIZE_FRACTION`: a
83 /// fraction of the picture's.
84 pub const DEFAULT_FONT_SIZE: f32 = 0.0533;
85
86 /// `text` in no style of its own: neither bold, italic nor underlined, and every other field
87 /// unsaid.
88 pub fn new(text: impl Into<String>) -> CueTextRun {
89 CueTextRun {
90 text: text.into(),
91 bold: false,
92 italic: false,
93 underline: false,
94 color: None,
95 background: None,
96 font_size: None,
97 font_family: None,
98 edge: None,
99 edge_color: None,
100 }
101 }
102}
103
104/// A picture subtitle's pixels.
105#[derive(Clone, Debug, PartialEq)]
106pub struct CueImage {
107 pub width: u32,
108 pub height: u32,
109 /// RGBA, 8 bits a channel, unpremultiplied, rows from the top.
110 pub pixels: Vec<u8>,
111 /// Its height on screen as a fraction of the picture's; its width is the cue's `size`.
112 pub display_height: f32,
113}
114
115/// Where a cue's box sits from the top.
116#[derive(Clone, Copy, Debug, PartialEq)]
117pub enum CueLine {
118 /// A fraction of the picture's height.
119 Fraction(f32),
120 /// A line number: from the top counting from 0, from the bottom counting from -1, in lines
121 /// of the cue's first line's height.
122 Number(i32),
123}
124
125/// Which side of a cue's box its `line` or `position` places.
126#[derive(Clone, Copy, Debug, PartialEq, Eq)]
127pub enum CueAnchor {
128 Start,
129 Middle,
130 End,
131}
132
133/// How a cue's lines align in its box.
134#[derive(Clone, Copy, Debug, PartialEq, Eq)]
135pub enum CueTextAlignment {
136 Start,
137 Center,
138 End,
139}
140
141/// Which way a vertical cue's columns follow each other.
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143pub enum CueVertical {
144 RightToLeft,
145 LeftToRight,
146}
147
148/// What is drawn round a run's characters to set them off from the picture.
149#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum CueTextEdge {
151 None,
152 Outline,
153 DropShadow,
154 Raised,
155 Depressed,
156}