Subtitling
Interop (CineCanvas) vs SMPTE ST 428-7 DCP subtitles compared: time formats, fonts, positioning, and which one Netflix and festivals actually require.
If you author DCPs for a living, you already know there are two subtitle formats in circulation. What trips people up is that they are not two dialects of one language — they are two separate specifications with different root elements, different time models, different font models, and different validation regimes. A file that is perfectly legal in one can be meaningless in the other.
This post walks through both formats the way an engineer looks at them: what the XML actually contains, where the sharp edges are, and which one to reach for in a given delivery scenario.
| DLP Cinema (Interop) | SMPTE DCDM subtitle | |
|---|---|---|
| Standard | Texas Instruments CineCanvas, v1.1 (Rev C) | SMPTE ST 428-7:2014 |
| Root element | <DCSubtitle> |
<SubtitleReel> |
| Time format | Ticks (1 tick = 4 ms) or decimal seconds | Frame-based (HH:MM:SS:FF at the reel's EditRate) |
| Fonts | Exactly one font per presentation, max 640 KB | Multiple fonts, referenced by UUID |
| Validation | DTD-based | XSD schema |
| Typical use | Legacy DCP, Netflix default, festivals | SMPTE DCP, HFR / ATMOS / HDR |
Both coexist because the installed base of cinema servers spans two decades. Interop is the older, projector-era format; SMPTE is the standardized successor.
An InterOp subtitle asset is a plain XML file (UTF-8 or UTF-16) that sits in the DCP folder next to a TrueType font. The document structure looks like this:
<DCSubtitle Version="1.1">
<SubtitleID>urn:uuid:...</SubtitleID>
<MovieTitle>My Feature</MovieTitle>
<ReelNumber>1</ReelNumber>
<Language>fr</Language>
<LoadFont Id="FontID" URI="Fred.ttf" />
<Font Id="FontID" Color="FFFFFFFF" Effect="shadow"
EffectColor="FF000000" Size="42">
<Subtitle SpotNumber="1"
TimeIn="00:00:01:000" TimeOut="00:00:04:000">
<Text HPosition="0.0" VPosition="0.9"
HAlign="center" VAlign="bottom">Bonjour.</Text>
</Subtitle>
</Font>
</DCSubtitle>
Interop time is expressed in ticks, where 1 tick = 1/250 s = 4 ms. The timecode format is HH:MM:SS:ttt — the last field is ticks, not frames, and it runs 000–249. So TimeIn="00:00:01:000" means exactly one second. A decimal-seconds form (TimeIn="0.0s") is also legal.
This has a practical consequence: InterOp timing has 4 ms granularity and is frame-rate agnostic in theory, but in practice InterOp DCPs are 24 fps only — which is one of the reasons HFR forces you onto SMPTE.
Interop allows one font per presentation, capped at 640 KB, referenced by URI in <LoadFont Id="FontID" URI="Fred.ttf" />. The font file lives alongside the XML. If your design calls for a second typeface mid-film, InterOp cannot express it.
| Attribute | Values | Default | Notes |
|---|---|---|---|
Color |
AARRGGBB hex | FFFFFFFF (white) |
Alpha first |
Effect |
none, border, shadow |
shadow |
|
EffectColor |
AARRGGBB hex | FF000000 (black) |
|
Italic |
yes, no |
no |
|
Underlined |
yes, no |
no |
Horizontal text only |
Weight |
bold, normal |
normal |
|
Size |
points | 42 |
Reference: an 11 m screen maps to 792 pt |
Spacing |
em units, ≥ −1.0 | 0em |
|
AspectAdjust |
0.25–4.0 | 1.0 |
Horizontal squeeze/stretch |
Script |
normal, super, sub |
normal |
Interop positions text with HPosition / VPosition as fractions of the screen (0.0–1.0): HPosition="0.0" is left, VPosition="0.0" is the top, 1.0 the bottom. The position is interpreted together with HAlign / VAlign, which say which edge of the text block the coordinate refers to. So the classic bottom-centered subtitle is VPosition near 0.9 with VAlign="bottom" and HAlign="center".
Interop documents are validated against a DTD. That matters because DTDs are far weaker than schemas — they cannot constrain value formats like colors or timecodes — so plenty of DTD-valid InterOp files are still broken in practice. Don't treat "validates" as "will play".
Rev C (supported by projector software 9.0 and later) added four elements aimed at CJK and vertical-text workflows:
<Ruby> — ruby annotations (furigana) for CJK text<Space> — forced inter-character spacing<HGroup> — horizontal grouping of text elements<Rotate> — text rotation, 90° counter-clockwiseUseful, but check your target servers before relying on them — they are exactly the kind of feature older projector firmware silently ignores.
The SMPTE format is a different document entirely. Root element <SubtitleReel>, namespace http://www.smpte-ra.org/schemas/428-7/2014/DCST, XSD-validated:
<SubtitleReel xmlns="http://www.smpte-ra.org/schemas/428-7/2014/DCST">
<Id>urn:uuid:099f04f5-7493-4412-9a88-c408f7458145</Id>
<ContentTitleText>Film Title English</ContentTitleText>
<IssueDate>2026-08-17T10:20:11+00:00</IssueDate>
<ReelNumber>1</ReelNumber>
<Language>EN</Language>
<EditRate>25 1</EditRate>
<TimeCodeRate>25</TimeCodeRate>
<StartTime>00:00:00:00</StartTime>
<LoadFont ID="FontID">urn:uuid:25586ca2-816b-4272-ae29-518fa616ff2e</LoadFont>
<SubtitleList>
<Font ID="FontID" Color="FFF2F2F2" Weight="normal" Size="40"
Effect="border" EffectColor="FF000000" AspectAdjust="1.00">
<Subtitle SpotNumber="1"
TimeIn="00:00:13:20" TimeOut="00:00:16:05"
FadeUpTime="00:00:00:00" FadeDownTime="00:00:00:00">
<Text Vposition="8.0" Halign="center" Direction="ltr"
Valign="bottom" Hposition="0.0">
I watched over us for a long time
</Text>
</Subtitle>
</Font>
</SubtitleList>
</SubtitleReel>
SMPTE timing is HH:MM:SS:FF where FF is a frame number at the rate given by <EditRate> — a rational like 25 1 (numerator/denominator). <TimeCodeRate> is a plain integer (24, 25, 30) describing the timecode display rate. Each subtitle also carries FadeUpTime / FadeDownTime (usually zero in practice).
Because timing is frame-quantized, converting a 25 fps SMPTE subtitle to a 24 fps reel is a real edit decision, not a re-labeling — the frame numbers have to be recomputed against the new EditRate.
One hard constraint: <StartTime> is always 00:00:00:00 in a DCP subtitle reel. No hour offsets. The same is true for InterOp — every reel starts at zero.
SMPTE drops the one-font limit. <LoadFont> references the font by UUID:
<LoadFont ID="FontID">urn:uuid:25586ca2-816b-4272-ae29-518fa616ff2e</LoadFont>
The actual .ttf file is a separate asset inside the DCP package, named by that UUID. Multiple <Font> blocks can appear under <SubtitleList>, each pointing at its own loaded font via ID. In real production, facilities tend to standardize: the same subtitle font UUID shows up across a facility's entire catalog of projects.
The <Font> attribute set is a subset of CineCanvas — Color (AARRGGBB), Weight, Size, Effect (none/border/shadow), EffectColor, AspectAdjust — plus one capability InterOp lacks at this level: partial italics, by nesting a <Font> element inside <Text>:
<Text Vposition="14.0" Halign="center" Direction="ltr" Valign="bottom" Hposition="0.0">
<Font Italic="yes">Before she died, my mother,</Font>
</Text>
SMPTE <Text> positioning uses percentages, not fractions — and the vertical axis is inverted relative to InterOp:
| Attribute | Values | Notes |
|---|---|---|
Vposition |
1.0–100.0 | 1.0 = bottom, 100.0 = top |
Hposition |
0.0–100.0 | With Halign left/center/right |
Valign |
top, center, bottom |
|
Direction |
ltr, rtl |
In the wild, single-line subtitles sit at Vposition="8.0", and two-line cues put the top line at 14.0 and the bottom at 8.0 — 6.0 units apart, matching standard line spacing. If you are porting positioning logic from InterOp, the inverted axis is the number one source of subtitles rendered at the top of the screen.
For a SMPTE DCP, the subtitle XML is wrapped into an MXF track file per SMPTE ST 429-5 — it is not a loose XML in the package folder the way InterOp subtitles are. The wrapping is the packaging tool's job; the subtitling tool's job is to produce correct ST 428-7 XML.
| Scenario | Format | Why |
|---|---|---|
| Standard cinema DCP | Interop | Netflix default; widest projector compatibility |
| HFR (48/60 fps) | SMPTE | Interop is 24 fps only |
| Dolby ATMOS | SMPTE | Requires SMPTE audio structure |
| HDR / Dolby Vision | SMPTE | Requires CompositionMetadataAsset |
| Festivals / unknown venues | Interop | Older projectors may not support SMPTE timed text |
| Modern cinema chains | SMPTE | Becoming the default |
Netflix's rule of thumb is the one most deliveries follow: Interop by default; SMPTE only when the title is HFR, ATMOS, or HDR. If the brief doesn't say otherwise and the destination is a festival with unknown servers, Interop is the conservative choice. If the package is SMPTE anyway (because of ATMOS or HFR), the subtitles must be SMPTE too — you don't mix InterOp subtitles into a SMPTE composition.
StartTime is 00:00:00:00 — always, in both formats.VPosition measures down from the top as a 0–1 fraction; SMPTE Vposition measures up from the bottom as a 1–100 percentage. Mixing these up is the classic porting bug.AlphaSUB reads and writes both formats natively — CineCanvas InterOp with tick timing and single-font export, and SMPTE ST 428-7:2014 with EditRate-based frame timing, UUID font references, and per-line italics — including the positioning-axis conversion between the two. If you spend your days moving subtitles between festival DCPs and streaming-deliverable packages, that round-trip is built in: alpha-sub.com.