1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! `dvb-emsg` — MPEG-DASH Event Message Box (`emsg`): inband DASH/CMAF timed
//! events (SCTE 35 splice signalling, ID3 metadata, ad/tracking triggers).
//!
//! The `emsg` box delivers sparse, timed application events alongside the media
//! in a DASH/CMAF segment. This crate implements:
//!
//! - [`EmsgBox`] — the `'emsg'` ISOBMFF `FullBox` (`size` / `'emsg'` /
//! `version` / `flags`) plus both version bodies: the two null-terminated
//! UTF-8 strings (`scheme_id_uri`, `value`), the integer fields (`timescale`,
//! `event_duration`, `id`), the version-discriminated presentation-time
//! field, and the opaque `message_data[]`. `size` and `version` are
//! **recomputed/derived on serialize** from the typed fields (no raw
//! passthrough).
//! - [`PresentationTime`] — the version-discriminated timing field:
//! `presentation_time_delta` (u32, version 0, segment-relative) vs
//! `presentation_time` (u64, version 1, representation-relative). Selecting a
//! variant *is* selecting the box version.
//! - [`EmsgVersion`] — the `version` byte (0 / 1) with its spec label.
//! - [`EmsgBox::is_scte35`] — recognises the SCTE 35 scheme
//! ([`SCTE35_SCHEME_PREFIX`], `urn:scte:scte35…`), in which case
//! `message_data` carries a SCTE 35 `splice_info_section`.
//!
//! Note the **v0/v1 field ordering differs**: version 0 places the two strings
//! *first* (before the integer fields); version 1 places the integer fields
//! first and the strings last. Both orderings are parsed and serialized.
//!
//! # ⚠ Source footing — softer than the fully-free crates
//!
//! The `emsg` **field semantics and types** (`scheme_id_uri`, `value`,
//! `timescale`, `presentation_time`/`presentation_time_delta`,
//! `event_duration`, `id`, `message_data`) are render-verified from a **free**
//! source: **DASH-IF IOP Part 10 (Events and Timed Metadata) V5.0.0, §6.1 +
//! Table 6-2** (transcribed in `dvb-emsg/docs/emsg.md`).
//!
//! However, the **normative ISOBMFF box syntax** —
//!
//! ```text
//! aligned(8) class EventMessageBox extends FullBox('emsg', version, flags = 0)
//! ```
//!
//! — i.e. the exact byte-level field *ordering*, the `version`-gated branch
//! (`presentation_time_delta` vs `presentation_time`), and the
//! null-terminated-string layout, lives in **ISO/IEC 23009-1 §5.10.3.3**, which
//! is **paid and NOT vendored** in this repo. DASH-IF Part 10 references it but
//! does not reproduce it. The box layout here is therefore implemented from the
//! **well-known public `emsg` structure** (widely reproduced in MPEG-DASH /
//! CMAF) combined with the free DASH-IF Part 10 semantics, with **ISO/IEC
//! 23009-1 §5.10.3.3 cited as the formal (paid) normative source**. This is
//! **softer footing** than the fully-free crates in this workspace — flagged
//! here per project policy. The v0/v1 ordering in particular is the part most
//! reliant on the non-vendored ISO source.
//!
//! Likewise, the SCTE 35 scheme-URI strings and the `message_data` binding are
//! defined by **SCTE 214-1 / ANSI/SCTE 35** (not vendored); [`is_scte35`] only
//! recognises the well-known `urn:scte:scte35…` URI prefix.
//!
//! [`is_scte35`]: EmsgBox::is_scte35
//!
//! `#![no_std]` + `alloc`; depends only on `dvb-common`.
//!
//! # Examples
//!
//! Build a version 0 (segment-relative) `emsg` from typed fields and round-trip
//! it:
//!
//! ```
//! use dvb_emsg::{EmsgBox, PresentationTime};
//!
//! let scte35 = [0xFCu8, 0x30, 0x11]; // start of a splice_info_section
//! let b = EmsgBox {
//! scheme_id_uri: "urn:scte:scte35:2013:bin",
//! value: "",
//! timescale: 90_000,
//! presentation_time: PresentationTime::Delta(0),
//! event_duration: 0xFFFF_FFFF,
//! id: 1,
//! message_data: &scte35,
//! };
//! assert!(b.is_scte35());
//! let bytes = b.to_vec().unwrap();
//! assert_eq!(EmsgBox::parse(&bytes).unwrap(), b);
//! ```
// Runnable examples, embedded so they render on docs.rs and stay in sync with
// the actual `examples/*.rs` files (shown, not compiled).
extern crate alloc;
pub use ;
pub use ;
pub use ;