18 Commits

Author SHA1 Message Date
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
Xavier Laffargue
51e25b56ee feat: DASH - Add signaling for CEA-608/708 captions (#1549)
This change introduces support for signaling CEA-608 and CEA-708 closed
captions in DASH. (Equivalent of
https://github.com/shaka-project/shaka-packager/pull/1532)

It reuses the existing --closed_captions command-line flag. Note that
some options (name, autoselect, and default) are not used for DASH.


```
--closed_captions 'channel=CC1,lang=fra;channel=CC2,lang=eng;channel=SERVICE1,lang=eng'
```


For Dash this adds an Accessibility tag in each video AdaptationSet.

Example output : 
```
<AdaptationSet id="1" contentType="video" ....>
      <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015" value="CC1=fra"/>
      <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015" value="CC2=eng"/>
      <Accessibility schemeIdUri="urn:scte:dash:cc:cea-708:2015" value="1=lang:eng"/> 
```

HLS changes :
* We force the language to 2 characters to be consistent with the
language of the audio files, for example.
* closed_captions is now in packaging_params
2026-03-11 10:55:52 -07:00
Ronak Patel
ef8ed345de feat: Switch VOD to live stream when event/live streams end (#1541)
Implement the MPEG DASH/HLS specifications to switch event/live streams
to VOD when the streams end. Use --event_to_vod_on_end_of_stream.

This change implements the DASH standard by:

1. Change MPD@type to static
2. Set MPD@mediaPresentationDuration to the media duration
3. Removing dynamic specific attributes in element, e.g.
availabilityStartTime, minimumUpdatePeriod, timeShiftBufferDepth etc.
4. Set SegmentTemplate@presentationTimeOffset in Representations

This change implements the HLS standard by:

1. Switch the PLAYLIST-TYPE to VOD at the conclusion of a LIVE stream
2. Append an EXT-X-ENDLIST tag at the end of the stream

Fixes #321
2026-03-07 09:33:41 -08:00
Xavier Laffargue
3aafed82b6 feat: Add signaling for CEA-608/708 captions (#1532)
This change introduces support for signaling CEA-608 and CEA-708 closed
captions in HLS.

New command-line flags, `--closed_captions`, have been added to allow
users to specify the caption tracks. The format for these flags is a
comma-separated list of semicolon-separated key-value pairs, e.g.,

`--closed_captions

"channel=CC1,name=French,lang=fra,default=no,autoselect=yes;channel=SERVICE1,name=English,lang=eng,default=yes,autoselect=yes"`.

For HLS, this change adds `#EXT-X-MEDIA` tags for each caption track
with a common `GROUP-ID` of "cc". The `EXT-X-STREAM-INF` tag for video
streams has been updated to reference this `GROUP-ID`.

Dash will be supported in another PR.

Fixes #986
2026-03-04 17:08:33 -08:00
Jacob Trimble
a792c567c7 feat: Add CENC v1 support (#1539)
CENC v1 (--cencv1) allows generating legacy content for testing purposes.
2026-03-04 17:06:43 -08:00
SteveR-PMP
4fad8d01c0 feat: --local_targetduration (#1519)
Some checks failed
Update Issues / update-issues (push) Has been cancelled
Release / Settings (push) Has been cancelled
Release / release (push) Has been cancelled
Release / Compute latest release flag (push) Has been cancelled
Release / Update docs (push) Has been cancelled
Release / Update docker image (push) Has been cancelled
Release / Build (push) Has been cancelled
Release / Artifacts (push) Has been cancelled
Release / Update NPM (push) Has been cancelled
Change EXT-X-TARGETDURATION to have the value set to the highest
duration for each variant instead of the highest duration for all the
variants.

Fixes #1510
2026-03-04 14:48:15 -08:00
Xavier Laffargue
73b4048492 feat: Add support for EXT-X-PROGRAM-DATE-TIME tag (#1521)
Some checks failed
Update Issues / update-issues (push) Has been cancelled
Release / Settings (push) Has been cancelled
Release / Build (push) Has been cancelled
Release / Artifacts (push) Has been cancelled
Release / Update NPM (push) Has been cancelled
Release / release (push) Has been cancelled
Release / Compute latest release flag (push) Has been cancelled
Release / Update docs (push) Has been cancelled
Release / Update docker image (push) Has been cancelled
Sync Labels / sync-labels (push) Has been cancelled
Inspired by @r0ro
https://github.com/shaka-project/shaka-packager/pull/840

Add a new --add_program_date_time HLS flag to enable or disable this
feature.

Introduces support for the EXT-X-PROGRAM-DATE-TIME tag in HLS media
playlists, aligning with the HLS RFC specifications.

Closes #365
2025-11-21 17:54:58 -08:00
SteveR-PMP
d88ed2798c feat: EXT-X-SESSION-KEY support (#36) (#1427) 2024-10-25 09:55:27 -07:00
zaki699
b5c2cb8b73 fix: Break header installation for the shared library (#1407)
include/file.h is breaking header installation for the shared library build.  macros/classes.h must be included to the public headers.

Closes #1406

Co-authored-by: Zaki Ahmed <zaki.ahmed.perso@gmail.com>
Co-authored-by: Joey Parrish <joeyparrish@users.noreply.github.com>
2024-05-30 21:16:05 -07:00
sr90
bb104fef5d feat: get start number from muxer and specify initial sequence number (#879)
Set the start number in representation to the segment index that is sent by muxer.

With this enhancement, you can now specify the initial sequence number
to be used on the generated segments when calling the packager.
With the old implementation, it was always starting with "1".

---------

Co-authored-by: Cosmin Stejerean <cstejerean@meta.com>
2024-05-02 13:25:49 -07:00
Daniel Cantarín
89376d3c4d feat: Allow LIVE UDP WebVTT input (#1349)
An updated version of PR #1027

That previous PR was done using 2021 code, and there were many changes
in the codebase from there, so a rebase was needed and also some minor
tweak here and there. But it's the same code, just reimplemented on a
newer codebase.

If you want to take a look at this in action, after building shaka
packager with this PR's code included, try this commands in 3 different
simultaneous bash sessions:

1. Video UDP input: `ffmpeg -f lavfi -re -i
"testsrc=s=320x240:r=30,format=yuv420p" -c:v h264 -sc_threshold 0 -g 30
-keyint_min 30 -r 30 -a53cc 1 -b:v 150k -preset ultrafast -r 30 -f
mpegts "udp://127.0.0.1:10000?pkt_size=1316"`
2. WebVTT UDP input: `for sec in $(seq 0 9999) ; do printf
"%02d:%02d.000 --> %02d:%02d.000\ntest second ${sec}\n\n" "$(( ${sec} /
60 ))" "$(( ${sec} % 60 ))" "$(( (${sec} + 1) / 60 ))" "$(( (${sec} + 1)
% 60 ))" ; sleep 1 ; done > /dev/udp/127.0.0.1/12345`
3. shaka packager command line: `timeout 60
path/to/build/packager/packager
'in=udp://127.0.0.1:10000?timeout=8000000,stream_selector=0,init_segment=240_init.m4s,segment_template=240_$Number%09d$.m4s,bandwidth=150000'
'in=udp://127.0.0.1:12345?timeout=8000000,stream_selector=0,input_format=webvtt,format=webvtt+mp4,init_segment=text_init.m4s,segment_template=text_$Number%09d$.m4s,language=eng,dash_roles=subtitle'
--mpd_output ./manifest.mpd --segment_duration 3.2
--suggested_presentation_delay 3.2 --min_buffer_time 3.2
--minimum_update_period 3.2 --time_shift_buffer_depth 60
--preserved_segments_outside_live_window 1 --default_language=eng
--dump_stream_info 2>&1`

Note the added `input_format=webvtt` to the shaka packager command's
second selector. That's new from this PR. If you don't use that, shaka's
format autodetection will not detect the webvtt format from the input,
as explained in
https://github.com/shaka-project/shaka-packager/issues/685#issuecomment-1029407191.
Try the command without it if you want to.

Fixes #685
Fixes #1017

---------

Co-authored-by: Daniel Cantarín <canta@canta.com.ar>
2024-02-23 16:02:19 -08:00
Marcus Wichelmann
76eb2c1575 feat: Add support for the EXT-X-START tag (#973)
adds an optional `--hls_start_time_offset` parameter, that, when
used, adds `EXT-X-START` tags to the HLS media playlists.

The EXT-X-START tag allows to specify the location where the player
starts playing, either from start (positive value) or from end (negative
value).
This is especially useful in case of livestreams where this tag can be
used to set the target latency of the playback.

Reference: https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.5.2

The RFC says, that the `EXT-X-START` tag could also be added to the
master playlist, but my tests have shown that most players only respect
it when it's in the media playlists.

Fixes #970

---------

Co-authored-by: Joey Parrish <joeyparrish@google.com>
2024-02-15 12:06:06 -08:00
Vishal Shah
f73ad0d961 feat: HLS / DASH support forced subtitle (#1020)
Closes #988

---------

Co-authored-by: Cosmin Stejerean <cstejerean@meta.com>
2024-02-14 20:27:57 -08:00
sr90
b1c5a7433e feat(DASH): Add Label element. (#1175)
Add ability to set `Label` tag in MPD, see page 35 of DASH-IF IOP 4.3
https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf

Implements #881 

---------

Co-authored-by: Cosmin Stejerean <cstejerean@meta.com>
2024-02-14 10:36:08 -08:00
SteveR-PMP
aad2a12a9d feat: order streams in manifest based on command-line order (#1329)
This will force the muxer to order streams in the order given on the
command-line.

Closes #560
Closes #1280
Closes #1313

---------

Co-authored-by: Joey Parrish <joeyparrish@users.noreply.github.com>
Co-authored-by: Cosmin Stejerean <cstejerean@meta.com>
2024-02-14 09:21:11 -08:00
Joey Parrish
7ef51671f1 fix: Fix uninitialized value found by Valgrind (#1336) 2024-02-08 12:50:12 -08:00
SteveR-PMP
2ba67bc24c feat: default text zero bias (#1330)
A positive value, in milliseconds. It is the threshold used to determine
if we should assume that the text stream actually starts at time zero.
If the first sample comes before default_text_zero_bias_ms, then the
start will be padded as the stream is assumed to start at zero. If the
first sample comes after default_text_zero_bias_ms then the start of the
stream will not be padded as we cannot assume the start time of the
stream.
2024-02-08 10:39:50 -08:00
Joey Parrish
3e71302ba4 feat!: Rewrite build system and third-party dependencies (#1310)
This work was done over ~80 individual commits in the `cmake` branch,
which are now being merged back into `main`. As a roll-up commit, it is
too big to be reviewable, but each change was reviewed individually in
context of the `cmake` branch. After this, the `cmake` branch will be
renamed `cmake-porting-history` and preserved.

---------

Co-authored-by: Geoff Jukes <geoffjukes@users.noreply.github.com>
Co-authored-by: Bartek Zdanowski <bartek.zdanowski@gmail.com>
Co-authored-by: Carlos Bentzen <cadubentzen@gmail.com>
Co-authored-by: Dennis E. Mungai <2356871+Brainiarc7@users.noreply.github.com>
Co-authored-by: Cosmin Stejerean <cstejerean@gmail.com>
Co-authored-by: Carlos Bentzen <carlos.bentzen@bitmovin.com>
Co-authored-by: Cosmin Stejerean <cstejerean@meta.com>
Co-authored-by: Cosmin Stejerean <cosmin@offbytwo.com>
2023-12-01 09:32:19 -08:00