Files
shaka-packager/include/packager/chunking_params.h
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

55 lines
2.2 KiB
C++

// Copyright 2017 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef PACKAGER_PUBLIC_CHUNKING_PARAMS_H_
#define PACKAGER_PUBLIC_CHUNKING_PARAMS_H_
#include <cstdint>
namespace shaka {
/// Default heartbeat shift for DVB-Teletext: 1 second at 90kHz timescale.
constexpr int64_t kDefaultTtxHeartbeatShift = 90000;
/// Chunking (segmentation) related parameters.
struct ChunkingParams {
/// Segment duration in seconds.
double segment_duration_in_seconds = 0;
/// Subsegment duration in seconds. Should not be larger than the segment
/// duration.
double subsegment_duration_in_seconds = 0;
/// Force segments to begin with stream access points. Actual segment duration
/// may not be exactly what is specified by segment_duration.
bool segment_sap_aligned = true;
/// Force subsegments to begin with stream access points. Actual subsegment
/// duration may not be exactly what is specified by subsegment_duration.
/// Setting to subsegment_sap_aligned to true but segment_sap_aligned to false
/// is not allowed.
bool subsegment_sap_aligned = true;
/// Enable LL-DASH streaming.
/// Each segment constists of many fragments, and each fragment contains one
/// chunk. A chunk is the smallest unit and is constructed of a single moof
/// and mdat atom. Each chunk is uploaded immediately upon creation,
/// decoupling latency from segment duration.
bool low_latency_dash_mode = false;
/// Indicates the startNumber in DASH SegmentTemplate and HLS segment name.
int64_t start_segment_number = 1;
// For DVB-Teletext in MPEG-2 TS: timing offset (in 90kHz ticks) between
// video PTS timestamps and text segment generation. This compensates for
// the pipeline delay where video is processed ahead of teletext.
// Default is 90000 (1 second). If the value is too large, heartbeat-
// triggered text segments are generated later than video segments.
// If too small, some text cues may be absent in the output.
int64_t ts_ttx_heartbeat_shift = kDefaultTtxHeartbeatShift;
};
} // namespace shaka
#endif // PACKAGER_PUBLIC_CHUNKING_PARAMS_H_