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