1 /*****************************************************************************
2 * 35.h: SCTE 35 Digital Program Insertion Cueing Message for Cable
3 *****************************************************************************
4 * Copyright (C) 2015 VideoLAN
5 *
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject
14 * to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *****************************************************************************/
27
28 /*
29 * Normative references:
30 * - SCTE 35 2013 (Digital Program Insertion Cueing Message for Cable)
31 */
32
33 #ifndef __BITSTREAM_SCTE_35_H__
34 #define __BITSTREAM_SCTE_35_H__
35
36 #include <bitstream/common.h>
37 #include <bitstream/mpeg/psi/psi.h>
38 #include <bitstream/mpeg/psi/descriptors.h>
39
40 #ifdef __cplusplus
41 extern "C"
42 {
43 #endif
44
45 /*****************************************************************************
46 * Splice Information Table
47 *****************************************************************************/
48 #define SCTE35_TABLE_ID 0xfc
49 #define SCTE35_HEADER_SIZE (PSI_HEADER_SIZE + 11)
50 #define SCTE35_HEADER2_SIZE 2
51
scte35_init(uint8_t * p_scte35)52 static inline void scte35_init(uint8_t *p_scte35)
53 {
54 psi_set_tableid(p_scte35, SCTE35_TABLE_ID);
55 psi_init(p_scte35, false);
56 p_scte35[1] &= ~0x40; /* private indicator */
57 p_scte35[3] = 0;
58 p_scte35[4] = 0;
59 p_scte35[9] = 0;
60 p_scte35[10] = 0xff;
61 p_scte35[11] = 0xf0;
62 }
63
scte35_get_protocol(const uint8_t * p_scte35)64 static inline uint8_t scte35_get_protocol(const uint8_t *p_scte35)
65 {
66 return p_scte35[3];
67 }
68
scte35_set_protocol(uint8_t * p_scte35,uint8_t i_version)69 static inline void scte35_set_protocol(uint8_t *p_scte35, uint8_t i_version)
70 {
71 p_scte35[3] = i_version;
72 }
73
scte35_is_encrypted(const uint8_t * p_scte35)74 static inline bool scte35_is_encrypted(const uint8_t *p_scte35)
75 {
76 return !!(p_scte35[4] & 0x80);
77 }
78
scte35_set_encrypted(uint8_t * p_scte35,bool b_encrypted)79 static inline void scte35_set_encrypted(uint8_t *p_scte35, bool b_encrypted)
80 {
81 if (b_encrypted)
82 p_scte35[4] |= 0x80;
83 else
84 p_scte35[4] &= ~0x80;
85 }
86
scte35_get_pts_adjustment(const uint8_t * p_scte35)87 static inline uint64_t scte35_get_pts_adjustment(const uint8_t *p_scte35)
88 {
89 return ((uint64_t)(p_scte35[4] & 0x1) << 32) |
90 ((uint64_t)p_scte35[5] << 24) | ((uint64_t)p_scte35[6] << 16) |
91 ((uint64_t)p_scte35[7] << 8) | (uint64_t)p_scte35[8];
92 }
93
scte35_set_pts_adjustment(uint8_t * p_scte35,uint64_t i_adjustment)94 static inline void scte35_set_pts_adjustment(uint8_t *p_scte35,
95 uint64_t i_adjustment)
96 {
97 p_scte35[4] &= ~0x1;
98 p_scte35[4] |= (i_adjustment >> 32) & 0x1;
99 p_scte35[5] = (i_adjustment >> 24) & 0xff;
100 p_scte35[6] = (i_adjustment >> 16) & 0xff;
101 p_scte35[7] = (i_adjustment >> 8) & 0xff;
102 p_scte35[8] = i_adjustment & 0xff;
103 }
104
scte35_get_command_length(const uint8_t * p_scte35)105 static inline uint16_t scte35_get_command_length(const uint8_t *p_scte35)
106 {
107 return ((p_scte35[11] & 0xf) << 8) | p_scte35[12];
108 }
109
scte35_set_command_length(uint8_t * p_scte35,uint16_t i_length)110 static inline void scte35_set_command_length(uint8_t *p_scte35,
111 uint16_t i_length)
112 {
113 p_scte35[11] &= ~0xf;
114 p_scte35[11] |= (i_length >> 8) & 0xf;
115 p_scte35[12] = i_length & 0xff;
116 }
117
scte35_get_command_type(const uint8_t * p_scte35)118 static inline uint8_t scte35_get_command_type(const uint8_t *p_scte35)
119 {
120 return p_scte35[13];
121 }
122
scte35_set_command_type(uint8_t * p_scte35,uint8_t i_type)123 static inline void scte35_set_command_type(uint8_t *p_scte35, uint8_t i_type)
124 {
125 p_scte35[13] = i_type;
126 }
127
scte35_get_command(const uint8_t * p_scte35)128 static inline uint8_t *scte35_get_command(const uint8_t *p_scte35)
129 {
130 return (uint8_t *)p_scte35 + SCTE35_HEADER_SIZE;
131 }
132
scte35_get_desclength(const uint8_t * p_scte35)133 static inline uint16_t scte35_get_desclength(const uint8_t *p_scte35)
134 {
135 uint16_t i_command_length = scte35_get_command_length(p_scte35);
136 if (i_command_length == 0xfff)
137 return 0;
138 const uint8_t *pi_desclength = scte35_get_command(p_scte35) +
139 i_command_length;
140 return (pi_desclength[0] << 8) | pi_desclength[1];
141 }
142
scte35_set_desclength(uint8_t * p_scte35,uint16_t i_length)143 static inline void scte35_set_desclength(uint8_t *p_scte35, uint16_t i_length)
144 {
145 uint8_t *pi_desclength = scte35_get_command(p_scte35) +
146 scte35_get_command_length(p_scte35);
147 pi_desclength[0] = (i_length >> 8) & 0xff;
148 pi_desclength[1] = i_length & 0xff;
149 }
150
scte35_get_descl(const uint8_t * p_scte35)151 static inline uint8_t *scte35_get_descl(const uint8_t *p_scte35)
152 {
153 uint16_t i_command_length = scte35_get_command_length(p_scte35);
154 if (i_command_length == 0xfff)
155 return NULL;
156 return scte35_get_command(p_scte35) + i_command_length +
157 SCTE35_HEADER2_SIZE;
158 }
159
160 /*****************************************************************************
161 * Splice Information Table - splice_time structure
162 *****************************************************************************/
163 #define SCTE35_SPLICE_TIME_HEADER_SIZE 1
164 #define SCTE35_SPLICE_TIME_TIME_SIZE 4
165
scte35_splice_time_init(uint8_t * p_splice_time)166 static inline void scte35_splice_time_init(uint8_t *p_splice_time)
167 {
168 p_splice_time[0] = 0x7f;
169 }
170
scte35_splice_time_has_time_specified(const uint8_t * p_splice_time)171 static inline bool scte35_splice_time_has_time_specified(const uint8_t *p_splice_time)
172 {
173 return !!(p_splice_time[0] & 0x80);
174 }
175
scte35_splice_time_set_time_specified(uint8_t * p_splice_time,bool b_time_specified)176 static inline void scte35_splice_time_set_time_specified(uint8_t *p_splice_time,
177 bool b_time_specified)
178 {
179 if (b_time_specified)
180 p_splice_time[0] |= 0x80;
181 else
182 p_splice_time[0] &= ~0x80;
183 }
184
scte35_splice_time_get_pts_time(const uint8_t * p_splice_time)185 static inline uint64_t scte35_splice_time_get_pts_time(const uint8_t *p_splice_time)
186 {
187 return ((uint64_t)(p_splice_time[0] & 0x1) << 32) |
188 ((uint64_t)p_splice_time[1] << 24) |
189 ((uint64_t)p_splice_time[2] << 16) |
190 ((uint64_t)p_splice_time[3] << 8) |
191 (uint64_t)p_splice_time[4];
192 }
193
scte35_splice_time_set_pts_time(uint8_t * p_splice_time,uint64_t i_pts_time)194 static inline void scte35_splice_time_set_pts_time(uint8_t *p_splice_time,
195 uint64_t i_pts_time)
196 {
197 p_splice_time[0] &= ~0x1;
198 p_splice_time[0] |= (i_pts_time >> 32) & 0x1;
199 p_splice_time[1] = (i_pts_time >> 24) & 0xff;
200 p_splice_time[2] = (i_pts_time >> 16) & 0xff;
201 p_splice_time[3] = (i_pts_time >> 8) & 0xff;
202 p_splice_time[4] = i_pts_time & 0xff;
203 }
204
scte35_splice_time_size(const uint8_t * p_splice_time)205 static inline uint8_t scte35_splice_time_size(const uint8_t *p_splice_time)
206 {
207 return SCTE35_SPLICE_TIME_HEADER_SIZE +
208 (scte35_splice_time_has_time_specified(p_splice_time) ?
209 SCTE35_SPLICE_TIME_TIME_SIZE : 0);
210 }
211
212 /*****************************************************************************
213 * Splice Information Table - break_duration structure
214 *****************************************************************************/
215 #define SCTE35_BREAK_DURATION_HEADER_SIZE 5
216
scte35_break_duration_init(uint8_t * p_break_duration)217 static inline void scte35_break_duration_init(uint8_t *p_break_duration)
218 {
219 p_break_duration[0] = 0xff;
220 }
221
scte35_break_duration_has_auto_return(const uint8_t * p_break_duration)222 static inline bool scte35_break_duration_has_auto_return(const uint8_t *p_break_duration)
223 {
224 return !!(p_break_duration[0] & 0x80);
225 }
226
scte35_break_duration_set_auto_return(uint8_t * p_break_duration,bool b_auto_return)227 static inline void scte35_break_duration_set_auto_return(uint8_t *p_break_duration, bool b_auto_return)
228 {
229 if (b_auto_return)
230 p_break_duration[0] |= 0x80;
231 else
232 p_break_duration[0] &= ~0x80;
233 }
234
scte35_break_duration_get_duration(const uint8_t * p_break_duration)235 static inline uint64_t scte35_break_duration_get_duration(const uint8_t *p_break_duration)
236 {
237 return ((uint64_t)(p_break_duration[0] & 0x1) << 32) |
238 ((uint64_t)p_break_duration[1] << 24) |
239 ((uint64_t)p_break_duration[2] << 16) |
240 ((uint64_t)p_break_duration[3] << 8) |
241 (uint64_t)p_break_duration[4];
242 }
243
scte35_break_duration_set_duration(uint8_t * p_break_duration,uint64_t i_duration)244 static inline void scte35_break_duration_set_duration(uint8_t *p_break_duration,
245 uint64_t i_duration)
246 {
247 p_break_duration[0] &= ~0x1;
248 p_break_duration[0] |= (i_duration >> 32) & 0x1;
249 p_break_duration[1] = (i_duration >> 24) & 0xff;
250 p_break_duration[2] = (i_duration >> 16) & 0xff;
251 p_break_duration[3] = (i_duration >> 8) & 0xff;
252 p_break_duration[4] = i_duration & 0xff;
253 }
254
255 /*****************************************************************************
256 * Splice Information Table - null command
257 *****************************************************************************/
258 #define SCTE35_NULL_COMMAND 0
259 #define SCTE35_NULL_HEADER_SIZE 0
260
scte35_null_init(uint8_t * p_scte35)261 static inline void scte35_null_init(uint8_t *p_scte35)
262 {
263 scte35_init(p_scte35);
264 scte35_set_command_type(p_scte35, SCTE35_NULL_COMMAND);
265 scte35_set_command_length(p_scte35, SCTE35_NULL_HEADER_SIZE);
266 scte35_set_desclength(p_scte35, 0);
267 }
268
scte35_null_validate(const uint8_t * p_scte35)269 static inline bool scte35_null_validate(const uint8_t *p_scte35)
270 {
271 return true;
272 }
273
274 /*****************************************************************************
275 * Splice Information Table - schedule command
276 *****************************************************************************/
277 #define SCTE35_SCHEDULE_COMMAND 4
278
279 /* TODO Not implemented (useless) */
280
281 /*****************************************************************************
282 * Splice Information Table - insert command
283 *****************************************************************************/
284 #define SCTE35_INSERT_COMMAND 5
285 #define SCTE35_INSERT_HEADER_SIZE 5
286 #define SCTE35_INSERT_HEADER2_SIZE 1
287 #define SCTE35_INSERT_COMPONENT_COUNT_SIZE 1
288 #define SCTE35_INSERT_COMPONENT_HEADER_SIZE 1
289 #define SCTE35_INSERT_FOOTER_SIZE 4
290
scte35_insert_init(uint8_t * p_scte35,uint16_t i_length)291 static inline void scte35_insert_init(uint8_t *p_scte35, uint16_t i_length)
292 {
293 scte35_init(p_scte35);
294 scte35_set_command_type(p_scte35, SCTE35_INSERT_COMMAND);
295 scte35_set_command_length(p_scte35,
296 SCTE35_INSERT_HEADER_SIZE + i_length);
297 scte35_set_desclength(p_scte35, 0);
298
299 uint8_t *p_command = scte35_get_command(p_scte35);
300 p_command[4] = 0xff;
301 }
302
scte35_insert_get_event_id(const uint8_t * p_scte35)303 static inline uint32_t scte35_insert_get_event_id(const uint8_t *p_scte35)
304 {
305 const uint8_t *p_command = scte35_get_command(p_scte35);
306 return ((uint32_t)p_command[0] << 24) | (p_command[1] << 16) |
307 (p_command[2] << 8) | p_command[3];
308 }
309
scte35_insert_set_event_id(uint8_t * p_scte35,uint32_t i_event_id)310 static inline void scte35_insert_set_event_id(uint8_t *p_scte35,
311 uint32_t i_event_id)
312 {
313 uint8_t *p_command = scte35_get_command(p_scte35);
314 p_command[0] = (i_event_id >> 24) & 0xff;
315 p_command[1] = (i_event_id >> 16) & 0xff;
316 p_command[2] = (i_event_id >> 8) & 0xff;
317 p_command[3] = i_event_id & 0xff;
318 }
319
scte35_insert_has_cancel(const uint8_t * p_scte35)320 static inline bool scte35_insert_has_cancel(const uint8_t *p_scte35)
321 {
322 const uint8_t *p_command = scte35_get_command(p_scte35);
323 return !!(p_command[4] & 0x80);
324 }
325
scte35_insert_set_cancel(const uint8_t * p_scte35,bool b_cancel)326 static inline void scte35_insert_set_cancel(const uint8_t *p_scte35,
327 bool b_cancel)
328 {
329 uint8_t *p_command = scte35_get_command(p_scte35);
330 if (b_cancel)
331 p_command[4] |= 0x80;
332 else {
333 p_command[4] &= ~0x80;
334 p_command[5] = 0xff;
335 }
336 }
337
scte35_insert_has_out_of_network(const uint8_t * p_scte35)338 static inline bool scte35_insert_has_out_of_network(const uint8_t *p_scte35)
339 {
340 const uint8_t *p_command = scte35_get_command(p_scte35);
341 return !!(p_command[5] & 0x80);
342 }
343
scte35_insert_set_out_of_network(const uint8_t * p_scte35,bool b_out_of_network)344 static inline void scte35_insert_set_out_of_network(const uint8_t *p_scte35,
345 bool b_out_of_network)
346 {
347 uint8_t *p_command = scte35_get_command(p_scte35);
348 if (b_out_of_network)
349 p_command[5] |= 0x80;
350 else
351 p_command[5] &= ~0x80;
352 }
353
scte35_insert_has_program_splice(const uint8_t * p_scte35)354 static inline bool scte35_insert_has_program_splice(const uint8_t *p_scte35)
355 {
356 const uint8_t *p_command = scte35_get_command(p_scte35);
357 return !!(p_command[5] & 0x40);
358 }
359
scte35_insert_set_program_splice(const uint8_t * p_scte35,bool b_program_splice)360 static inline void scte35_insert_set_program_splice(const uint8_t *p_scte35,
361 bool b_program_splice)
362 {
363 uint8_t *p_command = scte35_get_command(p_scte35);
364 if (b_program_splice)
365 p_command[5] |= 0x40;
366 else
367 p_command[5] &= ~0x40;
368 }
369
scte35_insert_has_duration(const uint8_t * p_scte35)370 static inline bool scte35_insert_has_duration(const uint8_t *p_scte35)
371 {
372 const uint8_t *p_command = scte35_get_command(p_scte35);
373 return !!(p_command[5] & 0x20);
374 }
375
scte35_insert_set_duration(const uint8_t * p_scte35,bool b_duration)376 static inline void scte35_insert_set_duration(const uint8_t *p_scte35,
377 bool b_duration)
378 {
379 uint8_t *p_command = scte35_get_command(p_scte35);
380 if (b_duration)
381 p_command[5] |= 0x20;
382 else
383 p_command[5] &= ~0x20;
384 }
385
scte35_insert_has_splice_immediate(const uint8_t * p_scte35)386 static inline bool scte35_insert_has_splice_immediate(const uint8_t *p_scte35)
387 {
388 const uint8_t *p_command = scte35_get_command(p_scte35);
389 return !!(p_command[5] & 0x10);
390 }
391
scte35_insert_set_splice_immediate(const uint8_t * p_scte35,bool b_splice_immediate)392 static inline void scte35_insert_set_splice_immediate(const uint8_t *p_scte35,
393 bool b_splice_immediate)
394 {
395 uint8_t *p_command = scte35_get_command(p_scte35);
396 if (b_splice_immediate)
397 p_command[5] |= 0x10;
398 else
399 p_command[5] &= ~0x10;
400 }
401
scte35_insert_get_splice_time(const uint8_t * p_scte35)402 static inline uint8_t *scte35_insert_get_splice_time(const uint8_t *p_scte35)
403 {
404 uint8_t *p_command = scte35_get_command(p_scte35);
405 return p_command + SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE;
406 }
407
scte35_insert_get_component_count(const uint8_t * p_scte35)408 static inline uint8_t scte35_insert_get_component_count(const uint8_t *p_scte35)
409 {
410 uint8_t *p_command = scte35_get_command(p_scte35);
411 return p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE];
412 }
413
scte35_insert_set_component_count(uint8_t * p_scte35,uint8_t i_component_count)414 static inline void scte35_insert_set_component_count(uint8_t *p_scte35,
415 uint8_t i_component_count)
416 {
417 uint8_t *p_command = scte35_get_command(p_scte35);
418 p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE] =
419 i_component_count;
420 }
421
scte35_insert_component_get_component_tag(const uint8_t * p_component)422 static inline uint8_t scte35_insert_component_get_component_tag(const uint8_t *p_component)
423 {
424 return p_component[0];
425 }
426
scte35_insert_component_set_component_tag(uint8_t * p_component,uint8_t i_component_tag)427 static inline void scte35_insert_component_set_component_tag(uint8_t *p_component, uint8_t i_component_tag)
428 {
429 p_component[0] = i_component_tag;
430 }
431
scte35_insert_component_get_splice_time(const uint8_t * p_component)432 static inline uint8_t *scte35_insert_component_get_splice_time(const uint8_t *p_component)
433 {
434 return (uint8_t *)p_component + SCTE35_INSERT_COMPONENT_HEADER_SIZE;
435 }
436
scte35_insert_get_component(const uint8_t * p_scte35,uint8_t n)437 static inline uint8_t *scte35_insert_get_component(const uint8_t *p_scte35,
438 uint8_t n)
439 {
440 uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
441 - PSI_CRC_SIZE;
442 bool b_splice_immediate = scte35_insert_has_splice_immediate(p_scte35);
443 uint8_t *p_scte35_n = scte35_get_command(p_scte35) +
444 SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
445 SCTE35_INSERT_COMPONENT_COUNT_SIZE;
446 if (p_scte35_n - p_scte35 > i_section_size)
447 return NULL;
448
449 while (n) {
450 if (p_scte35_n + SCTE35_INSERT_COMPONENT_HEADER_SIZE - p_scte35 >
451 i_section_size)
452 return NULL;
453 p_scte35_n += SCTE35_INSERT_COMPONENT_HEADER_SIZE +
454 (b_splice_immediate ?
455 scte35_splice_time_size(
456 scte35_insert_component_get_splice_time(p_scte35_n)) :
457 0);
458 n--;
459 }
460 if (p_scte35_n - p_scte35 >= i_section_size) return NULL;
461 return p_scte35_n;
462 }
463
scte35_insert_get_break_duration(const uint8_t * p_scte35)464 static inline uint8_t *scte35_insert_get_break_duration(const uint8_t *p_scte35)
465 {
466 if (!scte35_insert_has_program_splice(p_scte35))
467 return scte35_insert_get_component(p_scte35,
468 scte35_insert_get_component_count(p_scte35) + 1);
469
470 if (scte35_insert_has_splice_immediate(p_scte35))
471 return scte35_get_command(p_scte35) + SCTE35_INSERT_HEADER_SIZE +
472 SCTE35_INSERT_HEADER2_SIZE;
473
474 uint8_t *p_splice_time = scte35_insert_get_splice_time(p_scte35);
475 return p_splice_time + scte35_splice_time_size(p_splice_time);
476 }
477
scte35_insert_get_footer(const uint8_t * p_scte35)478 static inline uint8_t *scte35_insert_get_footer(const uint8_t *p_scte35)
479 {
480 return scte35_insert_get_break_duration(p_scte35) +
481 (scte35_insert_has_duration(p_scte35) ?
482 SCTE35_BREAK_DURATION_HEADER_SIZE : 0);
483 }
484
scte35_insert_get_unique_program_id(const uint8_t * p_scte35)485 static inline uint16_t scte35_insert_get_unique_program_id(const uint8_t *p_scte35)
486 {
487 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
488 return (p_footer[0] << 8) | p_footer[1];
489 }
490
scte35_insert_set_unique_program_id(uint8_t * p_scte35,uint16_t i_unique_program_id)491 static inline void scte35_insert_set_unique_program_id(uint8_t *p_scte35,
492 uint16_t i_unique_program_id)
493 {
494 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
495 p_footer[0] = (i_unique_program_id >> 8) & 0xff;
496 p_footer[1] = i_unique_program_id & 0xff;
497 }
498
scte35_insert_get_avail_num(const uint8_t * p_scte35)499 static inline uint8_t scte35_insert_get_avail_num(const uint8_t *p_scte35)
500 {
501 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
502 return p_footer[2];
503 }
504
scte35_insert_set_avail_num(uint8_t * p_scte35,uint8_t i_avail_num)505 static inline void scte35_insert_set_avail_num(uint8_t *p_scte35,
506 uint8_t i_avail_num)
507 {
508 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
509 p_footer[2] = i_avail_num;
510 }
511
scte35_insert_get_avails_expected(const uint8_t * p_scte35)512 static inline uint8_t scte35_insert_get_avails_expected(const uint8_t *p_scte35)
513 {
514 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
515 return p_footer[3];
516 }
517
scte35_insert_set_avails_expected(uint8_t * p_scte35,uint8_t i_avails_expected)518 static inline void scte35_insert_set_avails_expected(uint8_t *p_scte35,
519 uint8_t i_avails_expected)
520 {
521 uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
522 p_footer[3] = i_avails_expected;
523 }
524
scte35_insert_validate(const uint8_t * p_scte35)525 static inline bool scte35_insert_validate(const uint8_t *p_scte35)
526 {
527 size_t i_length = scte35_get_command_length(p_scte35);
528 if (i_length < SCTE35_INSERT_HEADER_SIZE)
529 return false;
530
531 if (scte35_insert_has_cancel(p_scte35))
532 return i_length <= SCTE35_INSERT_HEADER_SIZE;
533 if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE)
534 return false;
535
536 if (scte35_insert_has_program_splice(p_scte35)) {
537 if (scte35_insert_has_splice_immediate(p_scte35)) {
538 if (scte35_insert_has_duration(p_scte35))
539 return i_length >= SCTE35_INSERT_HEADER_SIZE +
540 SCTE35_INSERT_HEADER2_SIZE +
541 SCTE35_BREAK_DURATION_HEADER_SIZE +
542 SCTE35_INSERT_FOOTER_SIZE;
543 return i_length >= SCTE35_INSERT_HEADER_SIZE +
544 SCTE35_INSERT_HEADER2_SIZE +
545 SCTE35_INSERT_FOOTER_SIZE;
546 }
547
548 if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
549 SCTE35_SPLICE_TIME_HEADER_SIZE ||
550 i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
551 scte35_splice_time_size(
552 scte35_insert_get_splice_time(p_scte35)))
553 return false;
554
555 if (scte35_insert_has_duration(p_scte35))
556 return i_length >= SCTE35_INSERT_HEADER_SIZE +
557 SCTE35_INSERT_HEADER2_SIZE +
558 scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
559 + SCTE35_BREAK_DURATION_HEADER_SIZE +
560 SCTE35_INSERT_FOOTER_SIZE;
561 return i_length >= SCTE35_INSERT_HEADER_SIZE +
562 SCTE35_INSERT_HEADER2_SIZE +
563 scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
564 + SCTE35_INSERT_FOOTER_SIZE;
565 }
566
567 if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
568 SCTE35_INSERT_COMPONENT_COUNT_SIZE)
569 return false;
570
571 const uint8_t *p_command = scte35_get_command(p_scte35);
572 const uint8_t *p_end = scte35_insert_get_component(p_scte35,
573 scte35_insert_get_component_count(p_scte35) + 1);
574 if (p_end == NULL)
575 return false;
576
577 if (scte35_insert_has_duration(p_scte35))
578 return i_length >= p_end + SCTE35_BREAK_DURATION_HEADER_SIZE +
579 SCTE35_INSERT_FOOTER_SIZE - p_command;
580 return i_length >= p_end + SCTE35_INSERT_FOOTER_SIZE - p_command;
581 }
582
583 /*****************************************************************************
584 * Splice Information Table - time_signal command
585 *****************************************************************************/
586 #define SCTE35_TIME_SIGNAL_COMMAND 6
587 #define SCTE35_TIME_SIGNAL_HEADER_SIZE SCTE35_SPLICE_TIME_HEADER_SIZE
588 #define SCTE35_TIME_SIGNAL_TIME_SIZE SCTE35_SPLICE_TIME_TIME_SIZE
589
scte35_time_signal_init(uint8_t * p_scte35,uint16_t i_length)590 static inline void scte35_time_signal_init(uint8_t *p_scte35, uint16_t i_length)
591 {
592 scte35_init(p_scte35);
593 scte35_set_command_type(p_scte35, SCTE35_TIME_SIGNAL_COMMAND);
594 scte35_set_command_length(p_scte35,
595 SCTE35_TIME_SIGNAL_HEADER_SIZE + i_length);
596 scte35_set_desclength(p_scte35, 0);
597 }
598
scte35_time_signal_get_splice_time(const uint8_t * p_scte35)599 static inline uint8_t *scte35_time_signal_get_splice_time(const uint8_t *p_scte35)
600 {
601 return scte35_get_command(p_scte35);
602 }
603
scte35_time_signal_validate(const uint8_t * p_scte35)604 static inline bool scte35_time_signal_validate(const uint8_t *p_scte35)
605 {
606 return scte35_get_command_length(p_scte35) >=
607 scte35_splice_time_size(scte35_time_signal_get_splice_time(p_scte35));
608 }
609
610 /*****************************************************************************
611 * Splice Information Table - bandwidth_reservation command
612 *****************************************************************************/
613 #define SCTE35_BANDWIDTH_RESERVATION_COMMAND 7
614 #define SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE 0
615
scte35_bandwidth_reservation_init(uint8_t * p_scte35)616 static inline void scte35_bandwidth_reservation_init(uint8_t *p_scte35)
617 {
618 scte35_init(p_scte35);
619 scte35_set_command_type(p_scte35, SCTE35_BANDWIDTH_RESERVATION_COMMAND);
620 scte35_set_command_length(p_scte35,
621 SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE);
622 scte35_set_desclength(p_scte35, 0);
623 }
624
scte35_bandwidth_reservation_validate(const uint8_t * p_scte35)625 static inline bool scte35_bandwidth_reservation_validate(const uint8_t *p_scte35)
626 {
627 return true;
628 }
629
630 /*****************************************************************************
631 * Splice Information Table - private command
632 *****************************************************************************/
633 #define SCTE35_PRIVATE_COMMAND 0xff
634 #define SCTE35_PRIVATE_HEADER_SIZE 4
635
scte35_private_init(uint8_t * p_scte35,uint16_t i_length)636 static inline void scte35_private_init(uint8_t *p_scte35, uint16_t i_length)
637 {
638 scte35_init(p_scte35);
639 scte35_set_command_type(p_scte35, SCTE35_PRIVATE_COMMAND);
640 scte35_set_command_length(p_scte35,
641 SCTE35_PRIVATE_HEADER_SIZE + i_length);
642 scte35_set_desclength(p_scte35, 0);
643 }
644
scte35_private_get_identifier(const uint8_t * p_scte35)645 static inline uint32_t scte35_private_get_identifier(const uint8_t *p_scte35)
646 {
647 const uint8_t *p_command = scte35_get_command(p_scte35);
648 return ((uint32_t)p_command[0] << 24) | (p_command[1] << 16) |
649 (p_command[2] << 8) | p_command[3];
650 }
651
scte35_private_set_identifier(uint8_t * p_scte35,uint32_t i_identifier)652 static inline void scte35_private_set_identifier(uint8_t *p_scte35,
653 uint32_t i_identifier)
654 {
655 uint8_t *p_command = scte35_get_command(p_scte35);
656 p_command[0] = (i_identifier >> 24) & 0xff;
657 p_command[1] = (i_identifier >> 16) & 0xff;
658 p_command[2] = (i_identifier >> 8) & 0xff;
659 p_command[3] = i_identifier & 0xff;
660 }
661
scte35_private_validate(const uint8_t * p_scte35)662 static inline bool scte35_private_validate(const uint8_t *p_scte35)
663 {
664 return scte35_get_command_length(p_scte35) >= SCTE35_PRIVATE_HEADER_SIZE;
665 }
666
667 /*****************************************************************************
668 * Splice Information Table validation
669 *****************************************************************************/
scte35_validate(const uint8_t * p_scte35)670 static inline bool scte35_validate(const uint8_t *p_scte35)
671 {
672 if (psi_get_syntax(p_scte35) ||
673 psi_get_tableid(p_scte35) != SCTE35_TABLE_ID ||
674 psi_get_length(p_scte35) < SCTE35_HEADER2_SIZE + PSI_CRC_SIZE)
675 return false;
676
677 if (!psi_check_crc(p_scte35))
678 return false;
679 if (scte35_get_protocol(p_scte35))
680 return false;
681
682 uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
683 - PSI_CRC_SIZE;
684 if (i_section_size < SCTE35_HEADER_SIZE)
685 return false;
686
687 uint16_t i_command_length = scte35_get_command_length(p_scte35);
688 if (i_command_length != 0xfff &&
689 (i_section_size < SCTE35_HEADER_SIZE + i_command_length +
690 SCTE35_HEADER2_SIZE ||
691 i_section_size < SCTE35_HEADER_SIZE + i_command_length +
692 SCTE35_HEADER2_SIZE +
693 scte35_get_desclength(p_scte35)))
694 return false;
695
696 switch (scte35_get_command_type(p_scte35)) {
697 case SCTE35_NULL_COMMAND:
698 if (!scte35_null_validate(p_scte35))
699 return false;
700 break;
701 case SCTE35_INSERT_COMMAND:
702 if (!scte35_insert_validate(p_scte35))
703 return false;
704 break;
705 case SCTE35_TIME_SIGNAL_COMMAND:
706 if (!scte35_time_signal_validate(p_scte35))
707 return false;
708 break;
709 case SCTE35_BANDWIDTH_RESERVATION_COMMAND:
710 if (!scte35_bandwidth_reservation_validate(p_scte35))
711 return false;
712 break;
713 case SCTE35_PRIVATE_COMMAND:
714 if (!scte35_private_validate(p_scte35))
715 return false;
716 break;
717 default:
718 break;
719 }
720
721 if (i_command_length != 0xfff &&
722 !descl_validate(scte35_get_descl(p_scte35),
723 scte35_get_desclength(p_scte35)))
724 return false;
725
726 return true;
727 }
728
729 #ifdef __cplusplus
730 }
731 #endif
732
733 #endif
734