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