Torbjörn Einarsson 19dbd203b0 fix: DVB-Teletext: heartbeat mechanism and segment alignment with video/audio (#1535)
I've finally generated test material and tests to make a PR to fix text
segment generation for MPEG-2 TS streams with sparse teletext data,
making a big improvement compared to the original teletext support in
#1344.


## Problem

When packaging MPEG-TS input containing DVB-Teletext subtitles for
DASH/HLS output, two fundamental issues arise:

1. **Sparse input handling** - Teletext streams only contain data when
subtitles are displayed. During gaps (which can span multiple segments),
no PES packets arrive, leaving the text chunker with no timing
information to drive segment generation. This results in missing
segments or segments with incorrect timing.

2. **Misaligned segment boundaries** - Even when segments are generated,
the text segment timestamps and boundaries differ from video/audio
segments. This causes `<SegmentTimeline>` mismatches in the MPD,
playback issues on some players, and sometimes fewer text segments than
video segments.

## Solution

This PR introduces two complementary mechanisms:

### 1. Heartbeat mechanism (sparse input handling)

The `Mp2tMediaParser` now sends periodic "heartbeat" signals to text
streams:

- Video PTS timestamps are forwarded to all text PIDs as
`MediaHeartBeat` samples
- `EsParserTeletext` emits `TextHeartBeat` samples when PES packets
arrive without displayable content
- `TextChunker` uses these heartbeats to drive segment generation even
during gaps in subtitle content
- Ongoing cues that span segment boundaries are properly split and
continued

A new `heartbeat_shift` stream descriptor parameter (default: 2 seconds
at 90kHz) controls the timing offset between video PTS and text segment
generation, compensating for pipeline processing delays.

### 2. SegmentCoordinator (segment boundary alignment)

A new N-to-N media handler (`SegmentCoordinator`) ensures text segments
align precisely with video:

- Passes all streams through unchanged
- Replicates `SegmentInfo` from video/audio `ChunkingHandler` to
registered teletext streams
- `TextChunker` in "coordinator mode" uses received `SegmentInfo` events
to determine segment boundaries instead of calculating from text
timestamps

This guarantees identical segment timelines across all adaptation sets.

## Testing

- **Integration tests** in `packager_test.cc`:
- `TeletextSegmentAlignmentTest.VideoAndTextSegmentsAligned` - Verifies
segment count, start times, and durations match between video and text
-
`TeletextSegmentAlignmentTest.VideoAndTextSegmentsAlignedWithWrapAround`
- Same verification with PTS timestamps near the 33-bit wrap-around
point (~26.5 hours)

- **Test files** (synthetic teletext with known cue timings at 1.0s,
3.5s, 13.0s):
  - `test_teletext_live.ts` - Normal PTS range
  - `test_teletext_live_wrap.ts` - PTS near wrap-around boundary

- **Unit tests** for `SegmentCoordinator` and updated `TextChunker`
tests

## Documentation

- Extended `docs/source/tutorials/text.rst` with DVB-Teletext section
covering:
  - Page numbering (3-digit cc_index format)
  - Heartbeat mechanism explanation
  - Segment alignment behavior
  - `--ts_ttx_heartbeat_shift` parameter tuning
  - Troubleshooting guide

- Added teletext processing pipeline diagram to `docs/source/design.rst`

## Future work

The heartbeat and `SegmentCoordinator` mechanisms would likely benefit
**DVB-SUB (bitmap subtitles)** as well (Issue #1477) , which faces
similar challenges with sparse subtitle data in MPEG-TS input and
segment alignment. The infrastructure is now in place to extend this
support.

## Example usage

```bash
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'
```


Fixes #1428
Fixes #1401
Fixes #1355
Fixes #1430
2026-03-11 16:06:30 -07:00

Shaka Packager

Shaka Packager is a tool and a media packaging SDK for DASH and HLS packaging and encryption. It can prepare and package media content for online streaming.

Shaka Packager supports:

  • Both Video-On-Demand and Live.

  • Streaming formats:

  • Key systems:

  • Encryption standards:

  • Media Containers and codecs

    Codecs ISO-BMFF WebM MPEG2-TS WVM Packed Audio²
    H264 (AVC) I / O - I / O I -
    H265 (HEVC) I / O - I - -
    VP8 I / O I / O - - -
    VP9 I / O I / O - - -
    AV1 I / O I / O - - -
    AAC I / O - I / O I O
    MP3 O - I / O - O
    Dolby AC3 I / O - I / O - O
    Dolby EAC3 I / O - O - O
    MPEG-H Audio I / O - - - -
    Dolby AC4 I / O - - - -
    DTS I / O - - - -
    FLAC I / O - - - -
    Opus I / O³ I / O - - -
    Vorbis - I / O - - -
    IAMF I / O - - - -

    NOTES:

  • Subtitles

    Format Input Output
    Text WebVTT Y Y
    WebVTT in MP4 #405 Y
    Text TTML Y
    TTML in MP4 - Y
    DVB-SUB Y -
    Teletext #272 -
    • ⁴: TTML input is only supported with TTML output (pass-through, DASH only), see also #584.
  • Platforms
    • Linux
    • Mac
    • Windows
    • Cross compiling for ARM is also supported.

1: Limited support

Getting Shaka Packager

There are several ways you can get Shaka Packager.

Useful Links

Contributing

If you have improvements or fixes, we would love to have your contributions. See https://github.com/shaka-project/shaka-packager/blob/main/CONTRIBUTING.md for details.

Description
A media packaging and development framework for VOD and Live DASH and HLS applications, supporting Common Encryption for Widevine and other DRM Systems.
Readme BSD-3-Clause 680 MiB
Languages
C++ 96.1%
Python 2.5%
CMake 1.1%
C 0.1%