Subtitles¶
PRESTOplay for web has rich support for text tracks. Multiple parsers cover a wide range of subtitle and caption formats, and a choice of displayers lets you match the styling and rendering behavior your application needs.
To render cues, install a text displayer. The HTML text displayer
(HtmlTextDisplayer) is recommended: it handles complex layouts and
styling, and keeps rendering consistent across platforms.
import "@castlabs/prestoplay/cl.htmlcue";
Without the HTML Cue module, the player falls back to the native text displayer based on the capabilities of the browser, which may have varying levels of support for more complex styling and layouts.
Text parsers¶
TTML, SMPTE-TT, and IMSC1¶
The TTML module adds support for Timed Text Markup Language (TTML) and related profiles, including SMPTE Timed Text (SMPTE-TT) and Internet Media Subtitles and Captions 1 (IMSC1) text or image subtitles. Import the module before creating the player:
import "@castlabs/prestoplay/cl.ttml";
Supported features¶
Supported attributes:
tt:begintt:endtt:regiontt:stylettp:cellResolutionttp:frameRatettp:subFrameRatettp:frameRateMultiplierttp:tickRatetts:backgroundColortts:colortts:directiontts:displayAligntts:origintts:extenttts:fontFamilytts:fontSizetts:fontWeighttts:fontStyletts:lineHeighttts:opacitytts:paddingtts:textAligntts:textOutlinetts:textShadowtts:unicodeBiditts:writingModetts:zIndexsmpte:backgroundImage
SMPTE-TT and IMSC1 support covers bitmap images, such as PNG images encoded in Base64. Position the bitmap images by enclosing them in a region.
Support for legacy manifests¶
A well-designed TTML manifest defines a root container and vertical cell definitions, which let the layout adjust to different sizes, such as fullscreen mode. Some legacy manifests use pixels instead to define region or font size, for example:
<?xml version="1.0" encoding="utf-8"?>
<tt
xmlns="http://www.w3.org/ns/ttml"
xmlns:tts="http://www.w3.org/ns/ttml#styling" xml:lang="en">
<head>
<styling>
<style xml:id="s1"
tts:fontSize="16px"
tts:textAlign="center"/>
</styling>
<layout>
<region xml:id="r1"
style="s1"
tts:displayAlign="center"
tts:extent="512px 48px"
tts:origin="48px 512px"/>
</layout>
</head>
<body>
<div xml:lang="en">
<p begin="00:00:00.000000" end="00:00:10.000000" region="r1">
Lorem ipsum
</p>
</div>
</body>
</tt>
For manifests like this, provide hints to the parser:
const playerConfig = {
// ...
ttml: {
containerWidth: 640,
containerHeight: 480,
fontSizeRadix: 16,
},
};
containerWidth and containerHeight convert a region size into
percentages. In this example, the r1 region’s width becomes 80% and its
height becomes 10%; its x-position becomes 80% and its y-position becomes
10%.
fontSizeRadix converts a font size into em. In this example, the cue font
size becomes 1em. The HTML displayer then adjusts the parent font size
based on the video size. See TextStyleConfiguration for details. Cues sized this way are responsive.
SMPTE-TT over HLS¶
HTTP Live Streaming (HLS) doesn’t support SMPTE-TT natively. Harmonic proposed an extension to the HLS specification to work around this, described in SMPTE-TT Embedded in ID3 for HTTP Live Streaming. The HlsSmpte plugin implements this extension. It extends the TTML parser and works exclusively on Safari with native HLS playback — it has no effect on the MSE-based player.
To use it:
Import the TTML module:
import "@castlabs/prestoplay/cl.ttml";
Import the HLS-SMPTE module:
import "@castlabs/prestoplay/cl.hlssmpte";
Enable the
config.hlssmpte.patchMetadataTrackflag if recent Safari versions fail to create the metadata track on load. As a workaround, the plugin briefly switches to another audio track and back to force Safari to create it. This flag is opt-in rather than default because the workaround requires at least two audio tracks and causes an audible track switch.Adjust
config.hlssmpte.timestampOffsetif cues are time-shifted.Provide placeholder text tracks using
config.remoteTextTracks. Each placeholder must definekind,language,mimeType, and an optionallabel. Omiturl— the HlsSmpte plugin injects cues from the metadata track. The language code must match the metadata track’s language codes, and the MIME type must betext/vtt.
In the example below, url is omitted from each placeholder because cues
are delivered through the metadata track; the placeholders are still needed
to expose the language options.
<link rel="stylesheet" href="./clpp.styles.css">
<video id="video" width="640" height="360" controls crossorigin="anonymous"></video>
<script type="module">
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.ttml";
import "@castlabs/prestoplay/cl.htmlcue";
import "@castlabs/prestoplay/cl.hlssmpte";
const player = new clpp.Player('video', { });
player.open({
source: '...',
hlssmpte: {
patchMetadataTrack: true
},
htmlcue: {
stretchSmpteImage: true
},
remoteTextTracks: [
{
kind: 'subtitles',
language: 'ara',
mimeType: 'text/vtt',
label: 'Arabic'
},
{
kind: 'subtitles',
language: 'eng',
mimeType: 'text/vtt',
label: 'English'
}
]
});
</script>
WebVTT and SubRip¶
The VTT module adds support for WebVTT subtitles and SubRip (SRT) files.
Files with the text/srt, application/x-subrip, or text/plain MIME type
are converted to WebVTT internally. Import the module before creating the
player:
import "@castlabs/prestoplay/cl.vtt";
Supported features¶
Inline text formatting
Voice spans
Ruby characters
Text direction
Text alignment
Positioning
Size
Regions
Embedded styles
SubRip (SRT) subtitles¶
SRT files are usually side-loaded next to the stream. Import the VTT module
and add the file as a remote text track with the text/srt MIME type:
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.mse";
import "@castlabs/prestoplay/cl.dash";
import "@castlabs/prestoplay/cl.vtt";
const player = new clpp.Player("video", {});
await player.open({
source: "https://testcontent.castlabs.com/QA/tos_1080_clear/manifest.mpd",
remoteTextTracks: [
{
url: "https://demo.cf.castlabs.com/media/TOS/TOS-ml.srt",
mimeType: "text/srt",
kind: "subtitles",
language: "mal",
label: "Malayalam",
},
],
preferredTextLanguage: "mal",
});
preferredTextLanguage selects the track when playback starts. To switch
tracks later, use the TrackManager (see
Tracks and languages).
The SRT conversion has these requirements and limitations:
The file must be UTF-8 encoded.
Each cue must start with a numeric identifier, followed by a timestamp line in the
00:00:23,000 --> 00:00:24,500format and the cue text. The player drops cues without an identifier.The player removes HTML formatting tags such as
<i>and<b>from the cue text, so cues render as plain text.
The SRT subtitles sample plays a stream with side-loaded SRT subtitles.
Side-loaded remote text tracks¶
Use config.remoteTextTracks to add side-loaded (“sidecar”) subtitle files
that aren’t present in the manifest. Each entry follows
RemoteTextTrack, and mimeType must match a format whose module is
imported, for example text/vtt or text/srt with the VTT module.
Note
With MSE playback, side-loaded text tracks are only supported for video on
demand (VOD). Adding them to a live stream fails with the
CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM error.
<link rel="stylesheet" href="./clpp.styles.css">
<video id="video" width="640" height="360" controls crossorigin="anonymous"></video>
<script type="module">
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.mse";
import "@castlabs/prestoplay/cl.vtt";
import "@castlabs/prestoplay/cl.htmlcue";
const player = new clpp.Player('video', { });
player.open({
source: '...',
remoteTextTracks: [
{
url: 'https://example.com/subtitles/en.vtt',
kind: 'subtitles',
language: 'eng',
mimeType: 'text/vtt',
label: 'English'
},
{
url: 'https://example.com/subtitles/es.vtt',
kind: 'subtitles',
language: 'spa',
mimeType: 'text/vtt',
label: 'Spanish'
}
]
});
</script>
Text displayers¶
HTML displayer¶
The HTML displayer renders text cues using the HTML surface, with rich styling capabilities and consistent results across browsers. It has strong support for rendering parsed TTML, SMPTE-TT, IMSC1, WebVTT, and SRT cues.
To use it:
Add the PRESTOplay default styles to your page:
<link rel="stylesheet" href="clpp.styles.css">
Import the HTML Cue module:
import "@castlabs/prestoplay/cl.htmlcue";
The HTML text displayer is used by default once
@castlabs/prestoplay/cl.htmlcue is imported. Set enableHtmlCue to false
in the player configuration to change this.
<link rel="stylesheet" href="clpp.styles.css">
<video id="video" width="640" height="360" crossorigin="anonymous" controls></video>
<script type="module">
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.mse";
import "@castlabs/prestoplay/cl.dash";
import "@castlabs/prestoplay/cl.ttml";
import "@castlabs/prestoplay/cl.vtt";
import "@castlabs/prestoplay/cl.htmlcue";
const player = new clpp.Player('video', {});
player.open({
source: '//demo.cf.castlabs.com/media/prestodash/Manifest.mpd'
});
</script>
Styling¶
Styles apply in this order, from lowest to highest priority:
Player styles
Website styles
Embedded styles
Text style options
Player styles come from clpp.styles.css and are required — they provide
default styles for text cues and regions.
Override the default styles with your own stylesheet by extending the
.clpp-text-container, .clpp-text-cue, or .clpp-text-cue-region classes.
Website styles take priority over default styles.
A text track can contain embedded styles, which take priority over website and default styles.
Text style options, set in the player configuration or through
player.getTextDisplayer(), take priority over embedded, website, and
default styles. Use these to let your users customize the look and feel of
subtitles. The subtitle text styling sample
sets the font, color, background, and edge style through text style options.
Font size¶
The HTML displayer adjusts a base font size to the container size for responsive design. By default, the font size is 7% of the container height. Adjust it in the player configuration:
const playerConfig = {
// ...
textStyle: {
fontSizePercent: 0.03
}
};
Native text displayer¶
Styling¶
Style text cues using text style options in the player configuration:
const playerConfig = {
// ...
textStyle: {
backgroundColor: 'rgba(207, 0, 15, 0.75)',
fontFamily: 'monospace',
fontColor: 'blue',
fontSize: '1.2em',
edgeColor: 'green',
edgeType: clpp.text.EdgeType.DROP_SHADOW
}
}
Or style cues on the fly through a text displayer instance:
player.getTextDisplayer().setFontColor('blue');
Native text-cue styling has some constraints:
It requires Edge 19 or later.
Background color and opacity are configurable on browsers other than Safari (macOS/iPadOS/iOS) and Chrome (macOS).
Use the HTML displayer to style text cues consistently across all supported browsers.
CEA-608 captions¶
PRESTOplay for web supports CEA-608 captions, the legacy closed-captioning
standard embedded directly in the video signal. The caption parser requires
mux.js (version 5.7.0 or later) available in the global scope:
import * as muxjs from "mux.js";
window.muxjs = muxjs;
See Components for the full mux.js installation steps.