dvb-subtitle
DVB bitmap subtitling segment parser and serializer, per ETSI EN 300 743 V1.6.1.
What it does / what it does not
Does. Takes the reassembled PES data field of a DVB subtitle stream (the
payload of a PES packet carrying data_identifier 0x20) and returns typed
segments: page, region, CLUT, object, display definition, disparity
signalling, alternative CLUT, end of display set and stuffing. Every segment
serializes back to the same bytes. Typical users are subtitle extractors,
stream analysers and head-end tooling.
Does not.
- It does not render. It decodes 2/4/8-bit pixel-data run codes into runs
(
PixelDataSubBlock::runs), but never composes a page, applies a CLUT to produce RGBA, or draws text from character codes. - It does not inflate the zlib data of a progressive pixel block
(
ProgressivePixelBlock::compressed_datastays opaque). - It does not convert DVB bitmap subtitles to text or WebVTT/SRT (no OCR);
caption-convertdocuments that as a gap. - It does not demultiplex TS or reassemble PES; use
mpeg-tsandmpeg-pes. - It does not parse the PMT
subtitling_descriptor; that lives indvb-si.
Standards supported
| Standard | Edition | Scope | Status | Notes |
|---|---|---|---|---|
| ETSI EN 300 743, Digital Video Broadcasting (DVB); Subtitling systems | V1.6.1 (2018-10), checked against private/specs-md/INDEX.md |
§7.1 PES data field (data_identifier 0x20, subtitle_stream_id 0x00, end marker 0xFF) |
Full | Trailing bytes after the last segment are kept for byte-exact round-trip |
| §7.2.1 display definition (0x14), §7.2.2 page composition (0x10), §7.2.3 region composition (0x11), §7.2.4 CLUT definition (0x12), §7.2.6 end of display set (0x80), Table 7 stuffing (0xFF) | Full | |||
| §7.2.5 object data (0x13): 2/4/8-bit pixel-data sub-blocks, map tables, character strings, progressive pixel block header | Partial | Progressive pixel data is typed-opaque (compressed bytes); pixel runs are decoded on request, no rendering | ||
| §7.2.7 disparity signalling (0x15), §7.2.8 alternative CLUT (0x16) | Full | |||
| Rendering model (§8, §9 decoder behaviour), PMT subtitling descriptor | Not implemented | Descriptor is in dvb-si |
Segment types with no typed implementation parse as AnySegment::Unknown;
a recognised type whose typed parse fails becomes AnySegment::Malformed.
Both re-serialize their body verbatim, so a capture never fails to round-trip
because of one bad segment.
Feature flags
| Feature | Default | Effect |
|---|---|---|
std |
yes | Links std (broadcast-common/std, thiserror/std). Without it the crate is #![no_std] + alloc. |
serde |
no | serde::Serialize on segments (serialize-only, camelCase external tagging). |
Quick start
use Parse;
use ;
let bytes = ;
let field = parse.unwrap;
assert_eq!;
Two runnable examples ship in examples/ (parse_segment, parse_full_pes);
run with cargo run -p dvb-subtitle --example <name>.
What is implemented
- Container:
PesDataField(data identifier, stream id, segment list, end marker) and the dispatch enumAnySegment(9 typed variants plusUnknownandMalformed;AnySegment::DISPATCHED_SEGMENT_TYPESlists the codes). - Composition:
PageCompositionSegment(withPageState),RegionCompositionSegment(RegionDepth,RegionLevelOfCompatibility,ObjectType,ObjectProviderFlag),DisplayDefinitionSegment,EndOfDisplaySetSegment,StuffingSegment. - Colour:
ClutDefinitionSegment/ClutEntry(full and reduced-range entries),AlternativeClutSegment(DynamicRangeColourGamut,OutputBitDepth). - Objects:
ObjectDataSegmentwithObjectDataPayload(interlaced pixel sub-blocks, character codes, progressive block, reserved),PixelDataSubBlock,PixelRuniterator. - 3D:
DisparitySignallingSegment(regions, subregions, shift update sequences). - Errors:
Error(#[non_exhaustive]), includingFieldOverflowfor a value wider than its wire field.
Design notes
- Zero-copy: parsed structs borrow
&'a [u8]from the input. - Symmetric
Parse/Serialize; parse then serialize is byte-identical, and serialize then parse compares equal. Tested against real M6 subtitle PES reassembled fromfixtures/ts/m6-single.ts(tests/fixture_subtitle.rs). - Serializers reject a value wider than its bit-field (
Error::FieldOverflow) instead of masking; reserved code values are carried verbatim asReserved(v). - Hostile input never panics (
tests/hostility.rs: truncation at every length, mutation of every byte). - Public enums are
#[non_exhaustive]and carryname()+Display. no_std+alloc; MSRV 1.95.0.
Related crates
Depends on broadcast-common only at runtime (mpeg-pes is a dev-dependency
for the fixture test). Feed it from mpeg-ts -> mpeg-pes. dvb-si parses the
PMT/SDT descriptors that locate the subtitle PID. caption-convert does
text-caption conversion and documents bitmap subtitles as unsupported.
MSRV and licence
Rust 1.95.0. MIT OR Apache-2.0.