Text output formats¶
Shaka Packager supports several text/subtitle formats for both input and output. We only support certain formats for output, other formats are converted to the specified output format. With the exception of TTML pass-through, there are no restrictions of input vs output formats.
Examples¶
TTML pass-through:
$ packager in=input.ttml,stream=text,output=output.ttml
Convert WebVTT to TTML:
$ packager in=input.vtt,stream=text,output=output.ttml
Embed WebVTT in MP4 (single-file):
$ packager in=input.vtt,stream=text,output=output.mp4
Embed WebVTT in MP4 (segmented):
$ packager 'in=input.vtt,stream=text,init_segment=init.mp4,segment_template=text_$Number$.mp4'
Convert WebVTT to TTML in MP4:
$ packager in=input.vtt,stream=text,format=ttml+mp4,output=output.mp4
Convert DVB-SUB to TTML in MP4:
$ packager in=input.ts,stream=text,format=ttml+mp4,output=output.mp4 $ packager 'in=input.ts,stream=text,format=ttml+mp4,init_segment=init.mp4,segment_template=text_$Number$.mp4'
Get a single page from DVB-SUB and set language:
$ packager in=input.ts,stream=text,cc_index=3,lang=en,format=ttml+mp4,output=output.mp4
Multiple languages:
$ packager \ in=in_en.vtt,stream=text,language=en,output=out_en.mp4 \ in=in_sp.vtt,stream=text,language=sp,output=out_sp.mp4 \ in=in_fr.vtt,stream=text,language=fr,output=out_fr.mp4
Get a single 3-digit page from DVB-teletext and set language for output formats stpp (TTML in mp4), wvtt (WebVTT in mp4) and HLS WebVTT:
$ packager in=input.ts,stream=text,cc_index=888,lang=en,format=ttml+mp4,output=output.mp4 $ packager in=input.ts,stream=text,cc_index=888,lang=en,output=output.mp4 $ packager in=input.ts,stream=text,cc_index=888,segment_template=text/$Number$.vtt,playlist_name=text/main.m3u8,hls_group_id=text,hls_name=ENGLISH
DVB-Teletext¶
DVB-Teletext subtitles are commonly used in European broadcast systems. They are embedded in MPEG-2 Transport Streams and identified by a 3-digit page number (e.g., 888 for subtitles in many countries).
Page numbering¶
Teletext pages are identified by a magazine number (1-8) and a two-digit page
number (00-99). The cc_index parameter uses a 3-digit format where the first
digit is the magazine and the last two digits are the page number:
cc_index=888- Magazine 8, page 88 (common for subtitles)cc_index=100- Magazine 1, page 00cc_index=777- Magazine 7, page 77
Heartbeat mechanism¶
Teletext subtitles are “sparse” - they only contain data when subtitles are displayed. This creates a problem for segmented output (DASH/HLS): if no subtitle appears during a segment’s time window, that segment might be missing or have incorrect timing.
To solve this, Shaka Packager uses a “heartbeat” mechanism when processing teletext from MPEG-TS input. The video stream’s PTS timestamps are used to generate periodic timing signals that ensure:
Text segments are generated continuously, even during gaps in subtitles
Text segment boundaries align with video segment boundaries
Ongoing subtitles that span multiple segments are properly handled
This mechanism is automatic when processing MPEG-TS files with both video and teletext streams.
Heartbeat shift parameter¶
The --ts_ttx_heartbeat_shift parameter controls the timing offset between
when video timestamps arrive and when they trigger text segment generation.
This is needed because video is typically processed slightly ahead of teletext
in the pipeline.
The default value (90000 at 90kHz timescale = 1 second) works for most cases. You may need to adjust this if:
Text segments are generated later than video segments (value too large)
Some text cues are missing from the output (value too small)
Example with custom heartbeat shift (3 seconds):
$ packager \
--ts_ttx_heartbeat_shift 270000 \
'in=input.ts,stream=video,init_segment=v/init.mp4,segment_template=v/$Number$.m4s' \
'in=input.ts,stream=audio,init_segment=a/init.mp4,segment_template=a/$Number$.m4s' \
'in=input.ts,stream=text,cc_index=888,lang=en,init_segment=t/init.mp4,segment_template=t/$Number$.m4s'
Segment alignment¶
When generating DASH or HLS output with teletext, the text segments are automatically aligned with video segment boundaries. This ensures that:
All adaptation sets have the same segment timeline
Seeking works correctly across all media types
There are no gaps or overlaps between segments
For best results, always include video and teletext streams from the same MPEG-TS source in the same packager invocation:
$ packager \
--segment_duration 6 \
--mpd_output manifest.mpd \
'in=input.ts,stream=video,init_segment=video/init.mp4,segment_template=video/$Number$.m4s' \
'in=input.ts,stream=audio,init_segment=audio/init.mp4,segment_template=audio/$Number$.m4s' \
'in=input.ts,stream=text,cc_index=888,lang=en,init_segment=text/init.mp4,segment_template=text/$Number$.m4s,dash_only=1'
VoD output with non-zero start times¶
When the input MPEG-TS has high PTS values (e.g., from a live recording that
started hours into a broadcast), use the --generate_static_live_mpd flag
to ensure proper presentationTimeOffset values in the DASH manifest:
$ packager \
--generate_static_live_mpd \
--segment_duration 4 \
--mpd_output manifest.mpd \
'in=recording.ts,stream=video,init_segment=video/init.mp4,segment_template=video/$Number$.m4s' \
'in=recording.ts,stream=text,cc_index=888,lang=en,init_segment=text/init.mp4,segment_template=text/$Number$.m4s'
Troubleshooting¶
No subtitles in output
Verify the correct
cc_indexvalue. Use a tool likeccextractorordvbsnoopto identify available teletext pages in the input.Ensure the teletext stream contains actual subtitle data, not just page structure information.
Subtitles cues are missing
Check that video and teletext come from the same MPEG-TS source
Try adjusting
--ts_ttx_heartbeat_shiftif subtitle cues are missing, or text segments are generated too late
Missing segments or gaps
Ensure video stream is included in the same packager run - the heartbeat mechanism requires video PTS to drive text segmentation
Check that segment duration is appropriate for the subtitle density