dash_mpd/
scte35.rs

1//! Support for the SCTE-35 standard for insertion of alternate content
2//
3// Society of Cable Telecommunications Engineers (SCTE) standard 35 "Digital Program Insertion
4// Cueing Message" concerns the messages that specify points in a content stream where alternate
5// content (typically advertising or local programming) can be inserted. It is used for example for
6// the digital broadcast of TV content or "replay" (VOD) media, and allows the content provider to
7// specify timestamps where advertising can be inserted dynamically. The advertising content
8// typically comes from a third party ad distributor (Google, Amazon for example) and can be
9// customized based on the viewer's location, account, preferences guessed from prior viewing,
10// viewing time, etc.
11//
12//      https://en.wikipedia.org/wiki/SCTE-35
13//
14// SCTE-35 messages can be included inside the media stream (for example in MPEG TS streams or
15// fragmented MP4 segments), in an HLS manifest, or in a DASH manifest, where they are carried in
16// DASH Event elements within an ElementStream element. This file provides definitions for the XML
17// elements used for DASH support.
18//
19// You won't often find public DASH streams with SCTE-35 events; they are more often used for
20// server-side ad insertion, which helps ensure that viewers benefit from the advertising content
21// instead of blocking or skipping it. For this reason, these definitions have not been well tested.
22//
23// An XML Schema for this embedding is available at
24// https://github.com/Comcast/scte35-go/blob/main/docs/scte_35_20220816.xsd
25
26
27#![allow(non_snake_case)]
28use serde::{Serialize, Deserialize};
29use serde_with::skip_serializing_none;
30
31
32pub fn serialize_scte35_ns<S>(os: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
33where S: serde::Serializer {
34    if let Some(s) = os {
35        serializer.serialize_str(s)
36    } else {
37        serializer.serialize_str("http://www.scte.org/schemas/35/2016")
38    }
39}
40
41
42#[skip_serializing_none]
43#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
44#[serde(default)]
45pub struct AvailDescriptor {
46    #[serde(rename = "@providerAvailId")]
47    pub provider_avail_id: u32,
48}
49
50#[skip_serializing_none]
51#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
52#[serde(default)]
53pub struct DTMFDescriptor {
54    #[serde(rename = "@preroll")]
55    pub preroll: Option<u8>,
56    #[serde(rename = "@chars")]
57    pub chars: Option<String>,
58}
59
60#[skip_serializing_none]
61#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
62#[serde(default)]
63pub struct TimeDescriptor {
64    #[serde(rename = "@taiSeconds")]
65    pub tai_seconds: Option<u64>,
66    #[serde(rename = "@taiNs")]
67    pub tai_ns: Option<u32>,
68    #[serde(rename = "@utcOffset")]
69    pub utc_offset: Option<u16>,
70}
71
72#[skip_serializing_none]
73#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
74#[serde(default)]
75pub struct BreakDuration {
76    // some buggy MPDs in the wild have this as a 0/1
77    #[serde(rename = "@autoReturn")]
78    pub auto_return: bool,
79    #[serde(rename = "@duration")]
80    pub duration: u64,
81}
82
83#[skip_serializing_none]
84#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
85#[serde(default)]
86pub struct ScteEvent {
87    #[serde(rename = "@spliceEventId")]
88    pub splice_event_id: Option<u32>,
89    #[serde(rename = "@spliceEventCancelIndicator")]
90    pub splice_event_cancel_indicator: Option<bool>,
91    #[serde(rename = "@outOfNetworkIndicator")]
92    pub out_of_network_indicator: Option<bool>,
93    #[serde(rename = "@uniqueProgramId")]
94    pub unique_program_id: Option<u16>,
95    #[serde(rename = "@availNum")]
96    pub avail_num: Option<u8>,
97    #[serde(rename = "@availsExpected")]
98    pub avails_expected: Option<u8>,
99    #[serde(rename = "scte35:BreakDuration", alias="BreakDuration")]
100    pub break_duration: Option<BreakDuration>,
101}
102
103#[skip_serializing_none]
104#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
105#[serde(default)]
106pub struct SpliceTime {
107    #[serde(rename = "@xmlns")]
108    pub xmlns: Option<String>,
109    #[serde(rename = "@scte35:ptsTime", alias = "@ptsTime")]
110    pub pts_time: Option<u64>,
111}
112
113#[skip_serializing_none]
114#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
115#[serde(default)]
116pub struct SpliceNull {
117}
118
119#[skip_serializing_none]
120#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
121#[serde(default)]
122pub struct SpliceSchedule {
123    #[serde(rename = "scte35:Event", alias="Event")]
124    pub scte_events: Vec<ScteEvent>,
125    // TODO: SpliceCount?
126}
127
128#[skip_serializing_none]
129#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
130#[serde(default)]
131pub struct BandwidthReservation {
132}
133
134#[skip_serializing_none]
135#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
136#[serde(default)]
137pub struct EncryptedPacket {
138    #[serde(rename = "$value")]
139    pub content: Option<String>,
140}
141
142#[skip_serializing_none]
143#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
144#[serde(default)]
145pub struct PrivateBytes {
146    #[serde(rename = "$value")]
147    pub content: Option<String>,
148}
149
150#[skip_serializing_none]
151#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
152#[serde(default)]
153pub struct PrivateCommand {
154    #[serde(rename = "@identifier")]
155    pub identifier: u32,
156    #[serde(rename = "scte35:PrivateBytes", alias="PrivateBytes")]
157    pub private_bytes: Vec<PrivateBytes>,
158}
159
160#[skip_serializing_none]
161#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
162#[serde(default)]
163pub struct TimeSignal {
164    #[serde(rename = "scte35:SpliceTime", alias="SpliceTime")]
165    pub splice_time: Vec<SpliceTime>,
166}
167
168#[skip_serializing_none]
169#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
170#[serde(default)]
171pub struct SegmentationUpid {
172    #[serde(rename = "@xmlns")]
173    pub xmlns: Option<String>,
174    #[serde(rename = "@segmentationUpidType")]
175    pub segmentation_upid_type: Option<u8>,
176    #[serde(rename = "@formatIdentifier")]
177    pub format_identifier: Option<u32>,
178    #[serde(rename = "@segmentationUpidFormat")]
179    pub segmentation_upid_format: Option<String>,
180    #[serde(rename = "@format")]
181    pub format: Option<String>,
182    #[serde(rename = "$value")]
183    pub content: Option<String>,
184}
185
186#[skip_serializing_none]
187#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
188#[serde(default)]
189pub struct SegmentationDescriptor {
190    #[serde(rename = "@xmlns")]
191    pub xmlns: Option<String>,
192    #[serde(rename = "@segmentationEventId")]
193    pub segmentation_event_id: Option<u32>,
194    #[serde(rename = "@segmentationEventCancelIndicator")]
195    pub segmentation_event_cancel_indicator: Option<bool>,
196    #[serde(rename = "@spliceEventId")]
197    pub splice_event_id: Option<u64>,
198    #[serde(rename = "@segmentationTypeId")]
199    pub segmentation_type_id: Option<u8>,
200    #[serde(rename = "@segmentationDuration")]
201    pub segmentation_duration: Option<u64>,
202    #[serde(rename = "@segmentationUpidType")]
203    pub segmentation_upid_type: Option<u8>,
204    #[serde(rename = "@segmentationUpid")]
205    pub segmentation_upid: Option<u64>,
206    #[serde(rename = "@segmentNum")]
207    pub segment_num: Option<u8>,
208    #[serde(rename = "@segmentsExpected")]
209    pub segments_expected: Option<u8>,
210    #[serde(rename = "@subSegmentNum")]
211    pub sub_segment_num: Option<u8>,
212    #[serde(rename = "@subSegmentsExpected")]
213    pub sub_segments_expected: Option<u8>,
214    #[serde(rename = "scte35:SegmentationUpid", alias="SegmentationUpid")]
215    pub segmentation_upids: Vec<SegmentationUpid>,
216}
217
218#[skip_serializing_none]
219#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
220#[serde(default)]
221pub struct Program {
222    #[serde(rename = "scte35:SpliceTime", alias="SpliceTime")]
223    pub splice_time: Vec<SpliceTime>,
224}
225
226#[skip_serializing_none]
227#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
228#[serde(default)]
229pub struct SpliceInsert {
230    #[serde(rename = "@spliceEventId")]
231    pub splice_event_id: Option<u32>,
232    #[serde(rename = "@spliceEventCancelIndicator")]
233    pub splice_event_cancel_indicator: Option<bool>,
234    #[serde(rename = "@outOfNetworkIndicator")]
235    pub out_of_network_indicator: Option<bool>,
236    #[serde(rename = "@spliceImmediateFlag")]
237    pub splice_immediate_flag: Option<bool>,
238    #[serde(rename = "@uniqueProgramId")]
239    pub unique_program_id: Option<u16>,
240    #[serde(rename = "@availNum")]
241    pub avail_num: Option<u8>,
242    #[serde(rename = "@availsExpected")]
243    pub avails_expected: Option<u8>,
244    #[serde(rename = "scte35:BreakDuration", alias="BreakDuration")]
245    pub break_duration: Option<BreakDuration>,
246}
247
248#[skip_serializing_none]
249#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
250#[serde(default)]
251pub struct SpliceInfoSection {
252    #[serde(rename = "@xmlns")]
253    pub xmlns: Option<String>,
254    #[serde(rename = "@sapType")]
255    pub sap_type: Option<u16>,
256    #[serde(rename = "@preRollMilliSeconds")]
257    pub pre_roll_milliseconds: Option<u32>,
258    #[serde(rename = "@ptsAdjustment")]
259    pub pts_adjustment: Option<u64>,
260    #[serde(rename = "@protocolVersion")]
261    pub protocol_version: Option<u8>,
262    #[serde(rename = "@tier")]
263    pub tier: Option<u16>,
264    #[serde(rename = "scte35:TimeSignal", alias="TimeSignal")]
265    pub time_signal: Option<TimeSignal>,
266    #[serde(rename = "scte35:SegmentationDescriptor", alias="SegmentationDescriptor")]
267    pub segmentation_descriptor: Option<SegmentationDescriptor>,
268    #[serde(rename = "scte35:SpliceNull", alias="SpliceNull")]
269    pub splice_null: Option<SpliceNull>,
270    #[serde(rename = "scte35:SpliceInsert", alias="SpliceInsert")]
271    pub splice_insert: Option<SpliceInsert>,
272    #[serde(rename = "scte35:SpliceSchedule", alias="SpliceSchedule")]
273    pub splice_schedule: Option<SpliceSchedule>,
274    #[serde(rename = "scte35:BandwidthReservation", alias="BandwidthReservation")]
275    pub bandwidth_reservation: Option<BandwidthReservation>,
276    #[serde(rename = "scte35:PrivateCommand", alias="PrivateCommand")]
277    pub private_command: Option<PrivateCommand>,
278    #[serde(rename = "scte35:EncryptedPacket", alias="EncryptedPacket")]
279    pub encrypted_packet: Option<EncryptedPacket>,
280    #[serde(rename = "scte35:AvailDescriptor", alias="AvailDescriptor")]
281    pub avail_descriptor: Option<AvailDescriptor>,
282    #[serde(rename = "scte35:DTMFDescriptor", alias="DTMFDescriptor")]
283    pub dtmf_descriptor: Option<DTMFDescriptor>,
284    #[serde(rename = "scte35:TimeDescriptor", alias="TimeDescriptor")]
285    pub time_descriptor: Option<TimeDescriptor>,
286}
287
288/// A binary representation of a SCTE 35 cue message.
289///
290/// We don't attempt to decode these, but the `scte35-reader` crate is able to parse a subset of the
291/// standard, and the `threefive` Python library provides a full parser.
292///
293/// Basic messages may just be '/' + base64-encoded string
294///   e.g. "/TWFpbiBDb250ZW50" -> "Main Content"
295#[skip_serializing_none]
296#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
297#[serde(default)]
298pub struct Binary {
299    #[serde(rename = "@signalType")]
300    pub signal_type: Option<String>,
301    #[serde(rename = "$value")]
302    pub content: String,
303}
304
305#[skip_serializing_none]
306#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
307#[serde(default)]
308pub struct Signal {
309    #[serde(rename = "@xmlns")]
310    pub xmlns: Option<String>,
311    #[serde(rename = "scte35:SpliceInfoSection", alias="SpliceInfoSection")]
312    pub splice_info_section: Option<SpliceInfoSection>,
313    #[serde(rename = "scte35:Binary", alias="Binary")]
314    pub content: Option<Binary>,
315}
316