• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * gst-scte-section.c -
3  * Copyright (C) 2019 Centricular ltd
4  *  Author: Edward Hervey <edward@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <string.h>
26 #include <stdlib.h>
27 
28 #include "mpegts.h"
29 #include "gstmpegts-private.h"
30 #define MPEGTIME_TO_GSTTIME(t) ((t) * (guint64)100000 / 9)
31 
32 /**
33  * SECTION:gst-scte-section
34  * @title: SCTE variants of MPEG-TS sections
35  * @short_description: Sections for the various SCTE specifications
36  * @include: gst/mpegts/mpegts.h
37  *
38  * This contains the %GstMpegtsSection relevent to SCTE specifications.
39  */
40 
41 /* TODO: port to gst_bit_reader / gst_bit_writer */
42 
43 /* Splice Information Table (SIT) */
44 
45 static GstMpegtsSCTESpliceEvent *
_gst_mpegts_scte_splice_event_copy(GstMpegtsSCTESpliceEvent * event)46 _gst_mpegts_scte_splice_event_copy (GstMpegtsSCTESpliceEvent * event)
47 {
48   GstMpegtsSCTESpliceEvent *copy =
49       g_slice_dup (GstMpegtsSCTESpliceEvent, event);
50 
51   copy->components = g_ptr_array_ref (event->components);
52 
53   return copy;
54 }
55 
56 static void
_gst_mpegts_scte_splice_event_free(GstMpegtsSCTESpliceEvent * event)57 _gst_mpegts_scte_splice_event_free (GstMpegtsSCTESpliceEvent * event)
58 {
59   g_ptr_array_unref (event->components);
60   g_slice_free (GstMpegtsSCTESpliceEvent, event);
61 }
62 
63 G_DEFINE_BOXED_TYPE (GstMpegtsSCTESpliceEvent, gst_mpegts_scte_splice_event,
64     (GBoxedCopyFunc) _gst_mpegts_scte_splice_event_copy,
65     (GFreeFunc) _gst_mpegts_scte_splice_event_free);
66 
67 static GstMpegtsSCTESpliceComponent *
_gst_mpegts_scte_splice_component_copy(GstMpegtsSCTESpliceComponent * component)68 _gst_mpegts_scte_splice_component_copy (GstMpegtsSCTESpliceComponent *
69     component)
70 {
71   return g_slice_dup (GstMpegtsSCTESpliceComponent, component);
72 }
73 
74 static void
_gst_mpegts_scte_splice_component_free(GstMpegtsSCTESpliceComponent * component)75 _gst_mpegts_scte_splice_component_free (GstMpegtsSCTESpliceComponent *
76     component)
77 {
78   g_slice_free (GstMpegtsSCTESpliceComponent, component);
79 }
80 
81 G_DEFINE_BOXED_TYPE (GstMpegtsSCTESpliceComponent,
82     gst_mpegts_scte_splice_component,
83     (GBoxedCopyFunc) _gst_mpegts_scte_splice_component_copy,
84     (GFreeFunc) _gst_mpegts_scte_splice_component_free);
85 
86 static GstMpegtsSCTESpliceComponent *
_parse_splice_component(GstMpegtsSCTESpliceEvent * event,guint8 ** orig_data,guint8 * end)87 _parse_splice_component (GstMpegtsSCTESpliceEvent * event, guint8 ** orig_data,
88     guint8 * end)
89 {
90   GstMpegtsSCTESpliceComponent *component =
91       g_slice_new0 (GstMpegtsSCTESpliceComponent);
92   guint8 *data = *orig_data;
93 
94   if (data + 1 + 6 > end)
95     goto error;
96 
97   component->tag = *data;
98   data += 1;
99 
100   if (event->insert_event && event->splice_immediate_flag == 0) {
101     component->splice_time_specified = *data >> 7;
102     if (component->splice_time_specified) {
103       component->splice_time = ((guint64) (*data & 0x01)) << 32;
104       data += 1;
105       component->splice_time += GST_READ_UINT32_BE (data);
106       data += 4;
107       GST_LOG ("component %u splice_time %" G_GUINT64_FORMAT " (%"
108           GST_TIME_FORMAT ")", component->tag, component->splice_time,
109           GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (component->splice_time)));
110     } else {
111       data += 1;
112     }
113   } else if (!event->insert_event) {
114     component->utc_splice_time = GST_READ_UINT32_BE (data);
115     GST_LOG ("component %u utc_splice_time %u", component->tag,
116         component->utc_splice_time);
117     data += 4;
118   }
119 
120   *orig_data = data;
121 
122   return component;
123 
124 error:
125   {
126     if (event)
127       _gst_mpegts_scte_splice_event_free (event);
128     return NULL;
129   }
130 }
131 
132 static GstMpegtsSCTESpliceEvent *
_parse_splice_event(guint8 ** orig_data,guint8 * end,gboolean insert_event)133 _parse_splice_event (guint8 ** orig_data, guint8 * end, gboolean insert_event)
134 {
135   GstMpegtsSCTESpliceEvent *event = g_slice_new0 (GstMpegtsSCTESpliceEvent);
136   guint8 *data = *orig_data;
137 
138   /* Note : +6 is because of the final descriptor_loop_length and CRC */
139   if (data + 5 + 6 > end)
140     goto error;
141 
142   event->components = g_ptr_array_new_with_free_func ((GDestroyNotify)
143       _gst_mpegts_scte_splice_component_free);
144 
145   event->insert_event = insert_event;
146   event->splice_event_id = GST_READ_UINT32_BE (data);
147   GST_LOG ("splice_event_id: 0x%08x", event->splice_event_id);
148   data += 4;
149   event->splice_event_cancel_indicator = *data >> 7;
150   GST_LOG ("splice_event_cancel_indicator: %d",
151       event->splice_event_cancel_indicator);
152   data += 1;
153 
154   GST_DEBUG ("data %p", data);
155 
156   if (event->splice_event_cancel_indicator == 0) {
157     if (data + 5 + 6 > end)
158       goto error;
159     event->out_of_network_indicator = *data >> 7;
160     event->program_splice_flag = (*data >> 6) & 0x01;
161     event->duration_flag = (*data >> 5) & 0x01;
162 
163     if (insert_event)
164       event->splice_immediate_flag = (*data >> 4) & 0x01;
165 
166     GST_LOG ("out_of_network_indicator:%d", event->out_of_network_indicator);
167     GST_LOG ("program_splice_flag:%d", event->program_splice_flag);
168     GST_LOG ("duration_flag:%d", event->duration_flag);
169 
170     if (insert_event)
171       GST_LOG ("splice_immediate_flag:%d", event->splice_immediate_flag);
172 
173     data += 1;
174 
175     if (event->program_splice_flag == 0) {
176       guint component_count = *data;
177       guint i;
178 
179       data += 1;
180 
181       for (i = 0; i < component_count; i++) {
182         GstMpegtsSCTESpliceComponent *component =
183             _parse_splice_component (event, &data, end);
184         if (component == NULL)
185           goto error;
186         g_ptr_array_add (event->components, component);
187       }
188     } else {
189       if (insert_event && event->splice_immediate_flag == 0) {
190         event->program_splice_time_specified = *data >> 7;
191         if (event->program_splice_time_specified) {
192           event->program_splice_time = ((guint64) (*data & 0x01)) << 32;
193           data += 1;
194           event->program_splice_time += GST_READ_UINT32_BE (data);
195           data += 4;
196           GST_LOG ("program_splice_time %" G_GUINT64_FORMAT " (%"
197               GST_TIME_FORMAT ")", event->program_splice_time,
198               GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (event->program_splice_time)));
199         } else
200           data += 1;
201       } else if (!insert_event) {
202         event->utc_splice_time = GST_READ_UINT32_BE (data);
203         GST_LOG ("utc_splice_time %u", event->utc_splice_time);
204         data += 4;
205       }
206     }
207 
208     if (event->duration_flag) {
209       event->break_duration_auto_return = *data >> 7;
210       event->break_duration = ((guint64) (*data & 0x01)) << 32;
211       data += 1;
212       event->break_duration += GST_READ_UINT32_BE (data);
213       data += 4;
214       GST_LOG ("break_duration_auto_return:%d",
215           event->break_duration_auto_return);
216       GST_LOG ("break_duration %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
217           event->break_duration,
218           GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (event->break_duration)));
219     }
220 
221     event->unique_program_id = GST_READ_UINT16_BE (data);
222     GST_LOG ("unique_program_id:%" G_GUINT16_FORMAT, event->unique_program_id);
223     data += 2;
224     event->avail_num = *data++;
225     event->avails_expected = *data++;
226     GST_LOG ("avail %d/%d", event->avail_num, event->avails_expected);
227   }
228 
229   GST_DEBUG ("done");
230   *orig_data = data;
231   return event;
232 
233 error:
234   {
235     if (event)
236       _gst_mpegts_scte_splice_event_free (event);
237     return NULL;
238   }
239 }
240 
241 static GstMpegtsSCTESIT *
_gst_mpegts_scte_sit_copy(GstMpegtsSCTESIT * sit)242 _gst_mpegts_scte_sit_copy (GstMpegtsSCTESIT * sit)
243 {
244   GstMpegtsSCTESIT *copy = g_slice_dup (GstMpegtsSCTESIT, sit);
245 
246   copy->splices = g_ptr_array_ref (sit->splices);
247   copy->descriptors = g_ptr_array_ref (sit->descriptors);
248 
249   return copy;
250 }
251 
252 static void
_gst_mpegts_scte_sit_free(GstMpegtsSCTESIT * sit)253 _gst_mpegts_scte_sit_free (GstMpegtsSCTESIT * sit)
254 {
255   g_ptr_array_unref (sit->splices);
256   g_ptr_array_unref (sit->descriptors);
257   g_slice_free (GstMpegtsSCTESIT, sit);
258 }
259 
260 G_DEFINE_BOXED_TYPE (GstMpegtsSCTESIT, gst_mpegts_scte_sit,
261     (GBoxedCopyFunc) _gst_mpegts_scte_sit_copy,
262     (GFreeFunc) _gst_mpegts_scte_sit_free);
263 
264 
265 static gpointer
_parse_sit(GstMpegtsSection * section)266 _parse_sit (GstMpegtsSection * section)
267 {
268   GstMpegtsSCTESIT *sit = NULL;
269   guint8 *data, *end;
270   guint32 tmp;
271 
272   GST_DEBUG ("SIT");
273 
274   /* Even if the section is not a short one, it still uses CRC */
275   if (_calc_crc32 (section->data, section->section_length) != 0) {
276     GST_WARNING ("PID:0x%04x table_id:0x%02x, Bad CRC on section", section->pid,
277         section->table_id);
278     return NULL;
279   }
280 
281   sit = g_slice_new0 (GstMpegtsSCTESIT);
282 
283   sit->fully_parsed = FALSE;
284 
285   data = section->data;
286   end = data + section->section_length;
287 
288   GST_MEMDUMP ("section", data, section->section_length);
289 
290   /* Skip already-checked fields */
291   data += 3;
292 
293   /* Ensure protocol_version is 0 */
294   if (*data != 0) {
295     GST_WARNING ("Unsupported SCTE SIT protocol version (%d)", *data);
296     goto error;
297   }
298   data += 1;
299 
300   /* encryption */
301   sit->encrypted_packet = (*data) >> 7;
302   sit->encryption_algorithm = (*data) & 0x3f;
303   sit->pts_adjustment = ((guint64) (*data & 0x01)) << 32;
304   data += 1;
305 
306   sit->pts_adjustment += GST_READ_UINT32_BE (data);
307   data += 4;
308 
309   sit->cw_index = *data;
310   data += 1;
311 
312   tmp = GST_READ_UINT24_BE (data);
313   data += 3;
314 
315   sit->tier = (tmp >> 12);
316   sit->splice_command_length = tmp & 0xfff;
317   /* 0xfff is for backwards compatibility when reading */
318   if (sit->splice_command_length == 0xfff)
319     sit->splice_command_length = 0;
320   GST_LOG ("command length %d", sit->splice_command_length);
321 
322   if (sit->encrypted_packet) {
323     GST_LOG ("Encrypted SIT, parsed partially");
324     goto done;
325   }
326 
327   if (sit->splice_command_length
328       && (data + sit->splice_command_length > end - 5)) {
329     GST_WARNING ("PID %d invalid SCTE SIT splice command length %d",
330         section->pid, sit->splice_command_length);
331     goto error;
332   }
333 
334   sit->splice_command_type = *data;
335   data += 1;
336 
337   sit->splices = g_ptr_array_new_with_free_func ((GDestroyNotify)
338       _gst_mpegts_scte_splice_event_free);
339   switch (sit->splice_command_type) {
340     case GST_MTS_SCTE_SPLICE_COMMAND_NULL:
341     case GST_MTS_SCTE_SPLICE_COMMAND_BANDWIDTH:
342       /* These commands have no payload */
343       break;
344     case GST_MTS_SCTE_SPLICE_COMMAND_TIME:
345     {
346       sit->splice_time_specified = (*data >> 7);
347       if (sit->splice_time_specified) {
348         sit->splice_time = ((guint64) (*data & 0x01)) << 32;
349         data += 1;
350         sit->splice_time += GST_READ_UINT32_BE (data);
351         data += 4;
352       } else
353         data += 1;
354     }
355       break;
356     case GST_MTS_SCTE_SPLICE_COMMAND_SCHEDULE:
357     {
358       guint i;
359       guint splice_count = *data;
360       data += 1;
361 
362       for (i = 0; i < splice_count; i++) {
363         GstMpegtsSCTESpliceEvent *event =
364             _parse_splice_event (&data, end, FALSE);
365         if (event == NULL)
366           goto error;
367         g_ptr_array_add (sit->splices, event);
368       }
369     }
370       break;
371     case GST_MTS_SCTE_SPLICE_COMMAND_INSERT:
372     {
373       GstMpegtsSCTESpliceEvent *event = _parse_splice_event (&data, end, TRUE);
374       if (event == NULL)
375         goto error;
376       g_ptr_array_add (sit->splices, event);
377     }
378       break;
379     case GST_MTS_SCTE_SPLICE_COMMAND_PRIVATE:
380     {
381       GST_FIXME ("Implement SCTE-35 private commands");
382       data += sit->splice_command_length;
383     }
384       break;
385     default:
386       GST_WARNING ("Unknown SCTE splice command type (0x%02x) !",
387           sit->splice_command_type);
388       break;;
389   }
390 
391   /* descriptors */
392   tmp = GST_READ_UINT16_BE (data);
393   data += 2;
394   GST_MEMDUMP ("desc ?", data, tmp);
395   sit->descriptors = gst_mpegts_parse_descriptors (data, tmp);
396   if (!sit->descriptors) {
397     GST_DEBUG ("no descriptors %d", tmp);
398     goto error;
399   }
400   data += tmp;
401 
402   GST_DEBUG ("%p - %p", data, end);
403   if (data != end - 4) {
404     GST_WARNING ("PID %d invalid SIT parsed %d length %d",
405         section->pid, (gint) (data - section->data), section->section_length);
406     goto error;
407   }
408 
409   sit->fully_parsed = TRUE;
410 
411 done:
412   return sit;
413 
414 error:
415   if (sit) {
416     _gst_mpegts_scte_sit_free (sit);
417     sit = NULL;
418   }
419 
420   goto done;
421 }
422 
423 /**
424  * gst_mpegts_section_get_scte_sit:
425  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SCTE_SIT
426  *
427  * Returns the #GstMpegtsSCTESIT contained in the @section.
428  *
429  * Returns: The #GstMpegtsSCTESIT contained in the section, or %NULL if an error
430  * happened.
431  */
432 const GstMpegtsSCTESIT *
gst_mpegts_section_get_scte_sit(GstMpegtsSection * section)433 gst_mpegts_section_get_scte_sit (GstMpegtsSection * section)
434 {
435   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT,
436       NULL);
437   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
438 
439   if (!section->cached_parsed)
440     section->cached_parsed =
441         __common_section_checks (section, 18, _parse_sit,
442         (GDestroyNotify) _gst_mpegts_scte_sit_free);
443 
444   return (const GstMpegtsSCTESIT *) section->cached_parsed;
445 }
446 
447 /**
448  * gst_mpegts_scte_sit_new:
449  *
450  * Allocates and initializes a #GstMpegtsSCTESIT.
451  *
452  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESIT
453  */
454 GstMpegtsSCTESIT *
gst_mpegts_scte_sit_new(void)455 gst_mpegts_scte_sit_new (void)
456 {
457   GstMpegtsSCTESIT *sit;
458 
459   sit = g_slice_new0 (GstMpegtsSCTESIT);
460 
461   /* Set all default values (which aren't already 0/NULL) */
462   sit->tier = 0xfff;
463   sit->fully_parsed = TRUE;
464 
465   sit->splices = g_ptr_array_new_with_free_func ((GDestroyNotify)
466       _gst_mpegts_scte_splice_event_free);
467   sit->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
468       gst_mpegts_descriptor_free);
469 
470   sit->is_running_time = TRUE;
471 
472   return sit;
473 }
474 
475 /**
476  * gst_mpegts_scte_null_new:
477  *
478  * Allocates and initializes a NULL command #GstMpegtsSCTESIT.
479  *
480  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESIT
481  */
482 GstMpegtsSCTESIT *
gst_mpegts_scte_null_new(void)483 gst_mpegts_scte_null_new (void)
484 {
485   GstMpegtsSCTESIT *sit = gst_mpegts_scte_sit_new ();
486 
487   sit->splice_command_type = GST_MTS_SCTE_SPLICE_COMMAND_NULL;
488 
489   sit->is_running_time = TRUE;
490 
491   return sit;
492 }
493 
494 /**
495  * gst_mpegts_scte_cancel_new:
496  * @event_id: The event ID to cancel.
497  *
498  * Allocates and initializes a new INSERT command #GstMpegtsSCTESIT
499  * setup to cancel the specified @event_id.
500  *
501  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESIT
502  */
503 GstMpegtsSCTESIT *
gst_mpegts_scte_cancel_new(guint32 event_id)504 gst_mpegts_scte_cancel_new (guint32 event_id)
505 {
506   GstMpegtsSCTESIT *sit = gst_mpegts_scte_sit_new ();
507   GstMpegtsSCTESpliceEvent *event = gst_mpegts_scte_splice_event_new ();
508 
509   sit->splice_command_type = GST_MTS_SCTE_SPLICE_COMMAND_INSERT;
510   event->splice_event_id = event_id;
511   event->splice_event_cancel_indicator = TRUE;
512   g_ptr_array_add (sit->splices, event);
513 
514   sit->is_running_time = TRUE;
515 
516   return sit;
517 }
518 
519 /**
520  * gst_mpegts_scte_splice_in_new:
521  * @event_id: The event ID.
522  * @splice_time: The running time for the splice event
523  *
524  * Allocates and initializes a new "Splice In" INSERT command
525  * #GstMpegtsSCTESIT for the given @event_id and @splice_time.
526  *
527  * If the @splice_time is #G_MAXUINT64 then the event will be
528  * immediate as opposed to for the target @splice_time.
529  *
530  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESIT
531  */
532 GstMpegtsSCTESIT *
gst_mpegts_scte_splice_in_new(guint32 event_id,GstClockTime splice_time)533 gst_mpegts_scte_splice_in_new (guint32 event_id, GstClockTime splice_time)
534 {
535   GstMpegtsSCTESIT *sit = gst_mpegts_scte_sit_new ();
536   GstMpegtsSCTESpliceEvent *event = gst_mpegts_scte_splice_event_new ();
537 
538   sit->splice_command_type = GST_MTS_SCTE_SPLICE_COMMAND_INSERT;
539   event->splice_event_id = event_id;
540   event->insert_event = TRUE;
541   if (splice_time == G_MAXUINT64) {
542     event->splice_immediate_flag = TRUE;
543   } else {
544     event->program_splice_time_specified = TRUE;
545     event->program_splice_time = splice_time;
546   }
547   g_ptr_array_add (sit->splices, event);
548 
549   sit->is_running_time = TRUE;
550 
551   return sit;
552 }
553 
554 /**
555  * gst_mpegts_scte_splice_out_new:
556  * @event_id: The event ID.
557  * @splice_time: The running time for the splice event
558  * @duration: The optional duration.
559  *
560  * Allocates and initializes a new "Splice Out" INSERT command
561  * #GstMpegtsSCTESIT for the given @event_id, @splice_time and
562  * @duration.
563  *
564  * If the @splice_time is #G_MAXUINT64 then the event will be
565  * immediate as opposed to for the target @splice_time.
566  *
567  * If the @duration is 0 it won't be specified in the event.
568  *
569  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESIT
570  */
571 GstMpegtsSCTESIT *
gst_mpegts_scte_splice_out_new(guint32 event_id,GstClockTime splice_time,GstClockTime duration)572 gst_mpegts_scte_splice_out_new (guint32 event_id, GstClockTime splice_time,
573     GstClockTime duration)
574 {
575   GstMpegtsSCTESIT *sit = gst_mpegts_scte_sit_new ();
576   GstMpegtsSCTESpliceEvent *event = gst_mpegts_scte_splice_event_new ();
577 
578   sit->splice_command_type = GST_MTS_SCTE_SPLICE_COMMAND_INSERT;
579   event->splice_event_id = event_id;
580   event->out_of_network_indicator = TRUE;
581   event->insert_event = TRUE;
582   if (splice_time == G_MAXUINT64) {
583     event->splice_immediate_flag = TRUE;
584   } else {
585     event->program_splice_time_specified = TRUE;
586     event->program_splice_time = splice_time;
587   }
588   if (duration != 0) {
589     event->duration_flag = TRUE;
590     event->break_duration = duration;
591   }
592   g_ptr_array_add (sit->splices, event);
593 
594   sit->is_running_time = TRUE;
595 
596   return sit;
597 }
598 
599 /**
600  * gst_mpegts_scte_splice_event_new:
601  *
602  * Allocates and initializes a #GstMpegtsSCTESpliceEvent.
603  *
604  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESpliceEvent
605  */
606 GstMpegtsSCTESpliceEvent *
gst_mpegts_scte_splice_event_new(void)607 gst_mpegts_scte_splice_event_new (void)
608 {
609   GstMpegtsSCTESpliceEvent *event = g_slice_new0 (GstMpegtsSCTESpliceEvent);
610 
611   /* Non-0 Default values */
612   event->program_splice_flag = TRUE;
613   event->components = g_ptr_array_new_with_free_func ((GDestroyNotify)
614       _gst_mpegts_scte_splice_component_free);
615 
616 
617   return event;
618 }
619 
620 /**
621  * gst_mpegts_scte_splice_component_new:
622  * @tag: the elementary PID stream identifier
623  *
624  * Allocates and initializes a #GstMpegtsSCTESpliceComponent.
625  *
626  * Returns: (transfer full): A newly allocated #GstMpegtsSCTESpliceComponent
627  * Since: 1.20
628  */
629 GstMpegtsSCTESpliceComponent *
gst_mpegts_scte_splice_component_new(guint8 tag)630 gst_mpegts_scte_splice_component_new (guint8 tag)
631 {
632   GstMpegtsSCTESpliceComponent *component =
633       g_slice_new0 (GstMpegtsSCTESpliceComponent);
634 
635   component->tag = tag;
636 
637   return component;
638 }
639 
640 static gboolean
_packetize_sit(GstMpegtsSection * section)641 _packetize_sit (GstMpegtsSection * section)
642 {
643   gsize length, command_length, descriptor_length;
644   const GstMpegtsSCTESIT *sit;
645   GstMpegtsDescriptor *descriptor;
646   guint32 tmp32;
647   guint i;
648   guint8 *data;
649 
650   sit = gst_mpegts_section_get_scte_sit (section);
651 
652   if (sit == NULL)
653     return FALSE;
654 
655   if (sit->fully_parsed == FALSE) {
656     GST_WARNING ("Attempted to packetize an incompletely parsed SIT");
657     return FALSE;
658   }
659 
660   /* Skip cases we don't handle for now */
661   if (sit->encrypted_packet) {
662     GST_WARNING ("SCTE encrypted packet is not supported");
663     return FALSE;
664   }
665 
666   switch (sit->splice_command_type) {
667     case GST_MTS_SCTE_SPLICE_COMMAND_PRIVATE:
668       GST_WARNING ("SCTE command not supported");
669       return FALSE;
670     default:
671       break;
672   }
673 
674   /* Smallest splice section are the NULL and bandwith command:
675    * 14 bytes for the header
676    * 0 bytes for the command
677    * 2 bytes for the empty descriptor loop length
678    * 4 bytes for the CRC */
679   length = 20;
680 
681   command_length = 0;
682   /* Add the size of splices */
683   for (i = 0; i < sit->splices->len; i++) {
684     GstMpegtsSCTESpliceEvent *event = g_ptr_array_index (sit->splices, i);
685     /* There is at least 5 bytes */
686     command_length += 5;
687     if (!event->splice_event_cancel_indicator) {
688       /* Add at least 5 bytes for common fields */
689       command_length += 5;
690 
691       if (event->program_splice_flag) {
692         if (event->insert_event) {
693           if (!event->splice_immediate_flag) {
694             if (event->program_splice_time_specified)
695               command_length += 5;
696             else
697               command_length += 1;
698           }
699         } else {
700           /* Schedule events, 4 bytes for utc_splice_time */
701           command_length += 4;
702         }
703       } else {
704         guint j;
705 
706         /* component_count */
707         command_length += 1;
708 
709         for (j = 0; j < event->components->len; j++) {
710           GstMpegtsSCTESpliceComponent *component =
711               g_ptr_array_index (event->components, j);
712 
713           /* component_tag */
714           command_length += 1;
715           if (event->insert_event) {
716             if (!event->splice_immediate_flag) {
717               if (component->splice_time_specified)
718                 command_length += 5;
719               else
720                 command_length += 1;
721             }
722           } else {
723             /* utc_splice_time */
724             command_length += 4;
725           }
726         }
727       }
728 
729       if (event->duration_flag)
730         command_length += 5;
731     }
732   }
733 
734   if (sit->splice_command_type == GST_MTS_SCTE_SPLICE_COMMAND_TIME) {
735     if (sit->splice_time_specified)
736       command_length += 5;
737     else
738       command_length += 1;
739   }
740 
741   length += command_length;
742 
743   /* Calculate size of descriptors */
744 
745   descriptor_length = 0;
746   for (i = 0; i < sit->descriptors->len; i++) {
747     descriptor = g_ptr_array_index (sit->descriptors, i);
748     descriptor_length += descriptor->length + 2;
749   }
750   length += descriptor_length;
751 
752   /* Max length of SIT section is 4093 bytes */
753   g_return_val_if_fail (length <= 4093, FALSE);
754 
755   _packetize_common_section (section, length);
756 
757   data = section->data + 3;
758   /* Protocol version (default 0) */
759   *data++ = 0;
760   /* 7bits for encryption (not supported : 0) */
761   /* 33bits for pts_adjustment */
762   *data++ = (sit->pts_adjustment) >> 32 & 0x01;
763   GST_WRITE_UINT32_BE (data, sit->pts_adjustment & 0xffffffff);
764   data += 4;
765   /* cw_index : 8 bit */
766   *data++ = sit->cw_index;
767   /* tier                  : 12bit
768    * splice_command_length : 12bit
769    * splice_command_type   : 8 bit */
770   tmp32 = (sit->tier & 0xfff) << 20;
771   tmp32 |= (command_length & 0xfff) << 8;
772   tmp32 |= sit->splice_command_type;
773   GST_WRITE_UINT32_BE (data, tmp32);
774   data += 4;
775 
776   if (sit->splice_command_type == GST_MTS_SCTE_SPLICE_COMMAND_TIME) {
777     if (!sit->splice_time_specified) {
778       *data++ = 0x7f;
779     } else {
780       *data++ = 0xf2 | ((sit->splice_time >> 32) & 0x1);
781       GST_WRITE_UINT32_BE (data, sit->splice_time & 0xffffffff);
782       data += 4;
783     }
784   }
785 
786   /* Write the events */
787   for (i = 0; i < sit->splices->len; i++) {
788     GstMpegtsSCTESpliceEvent *event = g_ptr_array_index (sit->splices, i);
789 
790     /* splice_event_id : 32bit */
791     GST_WRITE_UINT32_BE (data, event->splice_event_id);
792     data += 4;
793     /* splice_event_cancel_indicator : 1bit
794      * reserved                      ; 7bit */
795     *data++ = event->splice_event_cancel_indicator ? 0xff : 0x7f;
796 
797     if (!event->splice_event_cancel_indicator) {
798       /* out_of_network_indicator : 1bit
799        * program_splice_flag      : 1bit
800        * duration_flag            : 1bit
801        * splice_immediate_flag    : 1bit
802        * reserved                 : 4bit */
803       *data++ = (event->out_of_network_indicator << 7) |
804           (event->program_splice_flag << 6) |
805           (event->duration_flag << 5) |
806           (event->insert_event ? (event->splice_immediate_flag << 4) : 0) |
807           0x0f;
808       if (event->program_splice_flag) {
809         if (event->insert_event) {
810           if (!event->splice_immediate_flag) {
811             /* program_splice_time_specified : 1bit
812              * reserved : 6/7 bit */
813             if (!event->program_splice_time_specified)
814               *data++ = 0x7f;
815             else {
816               /* time : 33bit */
817               *data++ = 0xf2 | ((event->program_splice_time >> 32) & 0x1);
818               GST_WRITE_UINT32_BE (data,
819                   event->program_splice_time & 0xffffffff);
820               data += 4;
821             }
822           }
823         } else {
824           GST_WRITE_UINT32_BE (data, event->utc_splice_time);
825           data += 4;
826         }
827       } else {
828         guint j;
829 
830         *data++ = event->components->len & 0xff;
831 
832         for (j = 0; j < event->components->len; j++) {
833           GstMpegtsSCTESpliceComponent *component =
834               g_ptr_array_index (event->components, j);
835 
836           *data++ = component->tag;
837 
838           if (event->insert_event) {
839             if (!event->splice_immediate_flag) {
840               /* program_splice_time_specified : 1bit
841                * reserved : 6/7 bit */
842               if (!component->splice_time_specified)
843                 *data++ = 0x7f;
844               else {
845                 /* time : 33bit */
846                 *data++ = 0xf2 | ((component->splice_time >> 32) & 0x1);
847                 GST_WRITE_UINT32_BE (data, component->splice_time & 0xffffffff);
848                 data += 4;
849               }
850             }
851           } else {
852             GST_WRITE_UINT32_BE (data, component->utc_splice_time);
853             data += 4;
854           }
855         }
856       }
857 
858       if (event->duration_flag) {
859         *data = event->break_duration_auto_return ? 0xfe : 0x7e;
860         *data++ |= (event->break_duration >> 32) & 0x1;
861         GST_WRITE_UINT32_BE (data, event->break_duration & 0xffffffff);
862         data += 4;
863       }
864       /* unique_program_id : 16bit */
865       GST_WRITE_UINT16_BE (data, event->unique_program_id);
866       data += 2;
867       /* avail_num : 8bit */
868       *data++ = event->avail_num;
869       /* avails_expected : 8bit */
870       *data++ = event->avails_expected;
871     }
872   }
873 
874   /* Descriptors */
875   GST_WRITE_UINT16_BE (data, descriptor_length);
876   data += 2;
877   _packetize_descriptor_array (sit->descriptors, &data);
878 
879   /* CALCULATE AND WRITE THE CRC ! */
880   GST_WRITE_UINT32_BE (data, _calc_crc32 (section->data, data - section->data));
881 
882   return TRUE;
883 }
884 
885 /**
886  * gst_mpegts_section_from_scte_sit:
887  * @sit: (transfer full): a #GstMpegtsSCTESIT to create the #GstMpegtsSection from
888  *
889  * Ownership of @sit is taken. The data in @sit is managed by the #GstMpegtsSection
890  *
891  * Returns: (transfer full): the #GstMpegtsSection
892  */
893 GstMpegtsSection *
gst_mpegts_section_from_scte_sit(GstMpegtsSCTESIT * sit,guint16 pid)894 gst_mpegts_section_from_scte_sit (GstMpegtsSCTESIT * sit, guint16 pid)
895 {
896   GstMpegtsSection *section;
897 
898   g_return_val_if_fail (sit != NULL, NULL);
899 
900   section = _gst_mpegts_section_init (pid, GST_MTS_TABLE_ID_SCTE_SPLICE);
901 
902   section->short_section = TRUE;
903   section->cached_parsed = (gpointer) sit;
904   section->packetizer = _packetize_sit;
905   section->destroy_parsed = (GDestroyNotify) _gst_mpegts_scte_sit_free;
906   section->short_section = TRUE;
907 
908   return section;
909 }
910