1 /*
2 * gstmpegtssection.c -
3 * Copyright (C) 2013 Edward Hervey
4 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
5 * Copyright (C) 2007 Alessandro Decina
6 * 2010 Edward Hervey
7 * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd.
8 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
9 * Author: Edward Hervey <bilboed@bilboed.com>, Collabora Ltd.
10 *
11 * Authors:
12 * Alessandro Decina <alessandro@nnva.org>
13 * Zaheer Abbas Merali <zaheerabbas at merali dot org>
14 * Edward Hervey <edward@collabora.com>
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Library General Public
18 * License as published by the Free Software Foundation; either
19 * version 2 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Library General Public License for more details.
25 *
26 * You should have received a copy of the GNU Library General Public
27 * License along with this library; if not, write to the
28 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
29 * Boston, MA 02110-1301, USA.
30 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <string.h>
36 #include <stdlib.h>
37
38 #include "mpegts.h"
39 #include "gstmpegts-private.h"
40
41 /**
42 * SECTION:gst-dvb-section
43 * @title: DVB variants of MPEG-TS sections
44 * @short_description: Sections for the various DVB specifications
45 * @include: gst/mpegts/mpegts.h
46 *
47 * The list of section types defined and used by the DVB specifications can be
48 * seen in %GstMpegtsSectionDVBTableID.
49 *
50 * # Supported DVB MPEG-TS sections
51 * These are the sections for which parsing and packetizing code exists.
52 *
53 * ## Network Information Table (NIT)
54 * See:
55 * * gst_mpegts_section_get_nit()
56 * * %GstMpegtsNIT
57 * * %GstMpegtsNITStream
58 * * gst_mpegts_nit_new()
59 *
60 * ## Service Description Table (SDT)
61 * See:
62 * * gst_mpegts_section_get_sdt()
63 * * %GstMpegtsSDT
64 * * %GstMpegtsSDTService
65 * * gst_mpegts_sdt_new()
66 *
67 * ## Bouquet Association Table (BAT)
68 * See:
69 * * gst_mpegts_section_get_bat()
70 * * %GstMpegtsBAT
71 * * %GstMpegtsBATStream
72 *
73 * ## Event Information Table (EIT)
74 * See:
75 * * gst_mpegts_section_get_eit()
76 * * %GstMpegtsEIT
77 * * %GstMpegtsEITEvent
78 *
79 * ## Time Date Table (TDT)
80 * See:
81 * * gst_mpegts_section_get_tdt()
82 *
83 * ## Time Offset Table (TOT)
84 * See:
85 * * gst_mpegts_section_get_tot()
86 * * %GstMpegtsTOT
87 *
88 * ## Selection Information Table (SIT)
89 * See:
90 * * gst_mpegts_section_get_sit()
91 * * %GstMpegtsSIT
92 * * %GstMpegtsSITService
93 *
94 * # API
95 */
96
97
98 /*
99 * TODO
100 *
101 * * Check minimum size for section parsing in the various
102 * gst_mpegts_section_get_<tabld>() methods
103 *
104 * * Implement parsing code for
105 * * BAT
106 * * CAT
107 * * TSDT
108 */
109
110 static inline GstDateTime *
_parse_utc_time(guint8 * data)111 _parse_utc_time (guint8 * data)
112 {
113 guint year, month, day, hour, minute, second;
114 guint16 mjd;
115 guint8 *utc_ptr;
116
117 mjd = GST_READ_UINT16_BE (data);
118
119 if (mjd == G_MAXUINT16)
120 return NULL;
121
122 /* See EN 300 468 Annex C */
123 year = (guint32) (((mjd - 15078.2) / 365.25));
124 month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001);
125 day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001);
126 if (month == 14 || month == 15) {
127 year++;
128 month = month - 1 - 12;
129 } else {
130 month--;
131 }
132 year += 1900;
133
134 utc_ptr = data + 2;
135
136 /* First digit of hours cannot exceed 1 (max: 23 hours) */
137 hour = ((utc_ptr[0] & 0x30) >> 4) * 10 + (utc_ptr[0] & 0x0F);
138 /* First digit of minutes cannot exced 5 (max: 59 mins) */
139 minute = ((utc_ptr[1] & 0x70) >> 4) * 10 + (utc_ptr[1] & 0x0F);
140 /* first digit of seconds cannot exceed 5 (max: 59 seconds) */
141 second = ((utc_ptr[2] & 0x70) >> 4) * 10 + (utc_ptr[2] & 0x0F);
142
143 /* Time is UTC */
144 if (hour < 24 && minute < 60 && second < 60) {
145 return gst_date_time_new (0.0, year, month, day, hour, minute,
146 (gdouble) second);
147 } else if (utc_ptr[0] == 0xFF && utc_ptr[1] == 0xFF && utc_ptr[2] == 0xFF) {
148 return gst_date_time_new (0.0, year, month, day, -1, -1, -1);
149 }
150
151 return NULL;
152 }
153
154 /* Event Information Table */
155 static GstMpegtsEITEvent *
_gst_mpegts_eit_event_copy(GstMpegtsEITEvent * eit)156 _gst_mpegts_eit_event_copy (GstMpegtsEITEvent * eit)
157 {
158 GstMpegtsEITEvent *copy;
159
160 copy = g_slice_dup (GstMpegtsEITEvent, eit);
161 copy->start_time = gst_date_time_ref (eit->start_time);
162 copy->descriptors = g_ptr_array_ref (eit->descriptors);
163
164 return copy;
165 }
166
167 static void
_gst_mpegts_eit_event_free(GstMpegtsEITEvent * eit)168 _gst_mpegts_eit_event_free (GstMpegtsEITEvent * eit)
169 {
170 if (eit->start_time)
171 gst_date_time_unref (eit->start_time);
172 if (eit->descriptors)
173 g_ptr_array_unref (eit->descriptors);
174 g_slice_free (GstMpegtsEITEvent, eit);
175 }
176
177 G_DEFINE_BOXED_TYPE (GstMpegtsEITEvent, gst_mpegts_eit_event,
178 (GBoxedCopyFunc) _gst_mpegts_eit_event_copy,
179 (GFreeFunc) _gst_mpegts_eit_event_free);
180
181 static GstMpegtsEIT *
_gst_mpegts_eit_copy(GstMpegtsEIT * eit)182 _gst_mpegts_eit_copy (GstMpegtsEIT * eit)
183 {
184 GstMpegtsEIT *copy;
185
186 copy = g_slice_dup (GstMpegtsEIT, eit);
187 copy->events = g_ptr_array_ref (eit->events);
188
189 return copy;
190 }
191
192 static void
_gst_mpegts_eit_free(GstMpegtsEIT * eit)193 _gst_mpegts_eit_free (GstMpegtsEIT * eit)
194 {
195 g_ptr_array_unref (eit->events);
196 g_slice_free (GstMpegtsEIT, eit);
197 }
198
199 G_DEFINE_BOXED_TYPE (GstMpegtsEIT, gst_mpegts_eit,
200 (GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_free);
201
202 static gpointer
_parse_eit(GstMpegtsSection * section)203 _parse_eit (GstMpegtsSection * section)
204 {
205 GstMpegtsEIT *eit = NULL;
206 guint allocated_events = 12;
207 guint8 *data, *end, *duration_ptr;
208 guint16 descriptors_loop_length;
209
210 eit = g_slice_new0 (GstMpegtsEIT);
211
212 data = section->data;
213 end = data + section->section_length;
214
215 /* Skip already parsed data */
216 data += 8;
217
218 eit->transport_stream_id = GST_READ_UINT16_BE (data);
219 data += 2;
220 eit->original_network_id = GST_READ_UINT16_BE (data);
221 data += 2;
222 eit->segment_last_section_number = *data++;
223 eit->last_table_id = *data++;
224
225 eit->actual_stream = (section->table_id == 0x4E ||
226 (section->table_id >= 0x50 && section->table_id <= 0x5F));
227 eit->present_following = (section->table_id == 0x4E
228 || section->table_id == 0x4F);
229
230 eit->events =
231 g_ptr_array_new_full (allocated_events,
232 (GDestroyNotify) _gst_mpegts_eit_event_free);
233
234 while (data < end - 4) {
235 GstMpegtsEITEvent *event;
236
237 /* 12 is the minimum entry size + CRC */
238 if (end - data < 12 + 4) {
239 GST_WARNING ("PID %d invalid EIT entry length %d",
240 section->pid, (gint) (end - 4 - data));
241 goto error;
242 }
243
244 event = g_slice_new0 (GstMpegtsEITEvent);
245 g_ptr_array_add (eit->events, event);
246
247 event->event_id = GST_READ_UINT16_BE (data);
248 data += 2;
249
250 event->start_time = _parse_utc_time (data);
251 duration_ptr = data + 5;
252 event->duration = (((duration_ptr[0] & 0xF0) >> 4) * 10 +
253 (duration_ptr[0] & 0x0F)) * 60 * 60 +
254 (((duration_ptr[1] & 0xF0) >> 4) * 10 +
255 (duration_ptr[1] & 0x0F)) * 60 +
256 ((duration_ptr[2] & 0xF0) >> 4) * 10 + (duration_ptr[2] & 0x0F);
257
258 data += 8;
259 event->running_status = *data >> 5;
260 event->free_CA_mode = (*data >> 4) & 0x01;
261
262 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
263 data += 2;
264
265 event->descriptors =
266 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
267 if (event->descriptors == NULL)
268 goto error;
269 data += descriptors_loop_length;
270 }
271
272 if (data != end - 4) {
273 GST_WARNING ("PID %d invalid EIT parsed %d length %d",
274 section->pid, (gint) (data - section->data), section->section_length);
275 goto error;
276 }
277
278 return (gpointer) eit;
279
280 error:
281 if (eit)
282 _gst_mpegts_eit_free (eit);
283
284 return NULL;
285
286 }
287
288 /**
289 * gst_mpegts_section_get_eit:
290 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_EIT
291 *
292 * Returns the #GstMpegtsEIT contained in the @section.
293 *
294 * Returns: The #GstMpegtsEIT contained in the section, or %NULL if an error
295 * happened.
296 */
297 const GstMpegtsEIT *
gst_mpegts_section_get_eit(GstMpegtsSection * section)298 gst_mpegts_section_get_eit (GstMpegtsSection * section)
299 {
300 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_EIT, NULL);
301 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
302
303 if (!section->cached_parsed)
304 section->cached_parsed = __common_section_checks (section, 18, _parse_eit,
305 (GDestroyNotify) _gst_mpegts_eit_free);
306
307 return (const GstMpegtsEIT *) section->cached_parsed;
308 }
309
310 /* Bouquet Association Table */
311 static GstMpegtsBATStream *
_gst_mpegts_bat_stream_copy(GstMpegtsBATStream * bat)312 _gst_mpegts_bat_stream_copy (GstMpegtsBATStream * bat)
313 {
314 GstMpegtsBATStream *copy;
315
316 copy = g_slice_dup (GstMpegtsBATStream, bat);
317 copy->descriptors = g_ptr_array_ref (bat->descriptors);
318
319 return copy;
320 }
321
322 static void
_gst_mpegts_bat_stream_free(GstMpegtsBATStream * bat)323 _gst_mpegts_bat_stream_free (GstMpegtsBATStream * bat)
324 {
325 if (bat->descriptors)
326 g_ptr_array_unref (bat->descriptors);
327 g_slice_free (GstMpegtsBATStream, bat);
328 }
329
330 G_DEFINE_BOXED_TYPE (GstMpegtsBATStream, gst_mpegts_bat_stream,
331 (GBoxedCopyFunc) _gst_mpegts_bat_stream_copy,
332 (GFreeFunc) _gst_mpegts_bat_stream_free);
333
334 static GstMpegtsBAT *
_gst_mpegts_bat_copy(GstMpegtsBAT * bat)335 _gst_mpegts_bat_copy (GstMpegtsBAT * bat)
336 {
337 GstMpegtsBAT *copy;
338
339 copy = g_slice_dup (GstMpegtsBAT, bat);
340 copy->descriptors = g_ptr_array_ref (bat->descriptors);
341 copy->streams = g_ptr_array_ref (bat->streams);
342
343 return copy;
344 }
345
346 static void
_gst_mpegts_bat_free(GstMpegtsBAT * bat)347 _gst_mpegts_bat_free (GstMpegtsBAT * bat)
348 {
349 if (bat->descriptors)
350 g_ptr_array_unref (bat->descriptors);
351 if (bat->streams)
352 g_ptr_array_unref (bat->streams);
353 g_slice_free (GstMpegtsBAT, bat);
354 }
355
356 G_DEFINE_BOXED_TYPE (GstMpegtsBAT, gst_mpegts_bat,
357 (GBoxedCopyFunc) _gst_mpegts_bat_copy, (GFreeFunc) _gst_mpegts_bat_free);
358
359 static gpointer
_parse_bat(GstMpegtsSection * section)360 _parse_bat (GstMpegtsSection * section)
361 {
362 GstMpegtsBAT *bat = NULL;
363 guint allocated_streams = 12;
364 guint8 *data, *end, *entry_begin;
365 guint16 descriptors_loop_length, transport_stream_loop_length;
366
367 GST_DEBUG ("BAT");
368
369 bat = g_slice_new0 (GstMpegtsBAT);
370
371 data = section->data;
372 end = data + section->section_length;
373
374 /* Skip already parsed data */
375 data += 8;
376
377 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
378 data += 2;
379
380 /* see if the buffer is large enough */
381 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
382 GST_WARNING ("PID %d invalid BAT descriptors loop length %d",
383 section->pid, descriptors_loop_length);
384 goto error;
385 }
386 bat->descriptors =
387 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
388 if (bat->descriptors == NULL)
389 goto error;
390 data += descriptors_loop_length;
391
392 transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
393 data += 2;
394 if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
395 GST_WARNING
396 ("PID 0x%04x invalid BAT (transport_stream_loop_length too big)",
397 section->pid);
398 goto error;
399 }
400
401 bat->streams =
402 g_ptr_array_new_full (allocated_streams,
403 (GDestroyNotify) _gst_mpegts_bat_stream_free);
404
405 /* read up to the CRC */
406 while (transport_stream_loop_length - 4 > 0) {
407 GstMpegtsBATStream *stream = g_slice_new0 (GstMpegtsBATStream);
408
409 g_ptr_array_add (bat->streams, stream);
410
411 if (transport_stream_loop_length < 6) {
412 /* each entry must be at least 6 bytes (+ 4 bytes CRC) */
413 GST_WARNING ("PID %d invalid BAT entry size %d",
414 section->pid, transport_stream_loop_length);
415 goto error;
416 }
417
418 entry_begin = data;
419
420 stream->transport_stream_id = GST_READ_UINT16_BE (data);
421 data += 2;
422
423 stream->original_network_id = GST_READ_UINT16_BE (data);
424 data += 2;
425
426 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
427 data += 2;
428
429 GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
430
431 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
432 GST_WARNING
433 ("PID %d invalid BAT entry %d descriptors loop length %d (only have %"
434 G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
435 descriptors_loop_length, (gsize) (end - 4 - data));
436 goto error;
437 }
438 stream->descriptors =
439 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
440 if (stream->descriptors == NULL)
441 goto error;
442
443 data += descriptors_loop_length;
444
445 transport_stream_loop_length -= data - entry_begin;
446 }
447
448 if (data != end - 4) {
449 GST_WARNING ("PID %d invalid BAT parsed %d length %d",
450 section->pid, (gint) (data - section->data), section->section_length);
451 goto error;
452 }
453
454 return (gpointer) bat;
455
456 error:
457 if (bat)
458 _gst_mpegts_bat_free (bat);
459
460 return NULL;
461 }
462
463 /**
464 * gst_mpegts_section_get_bat:
465 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_BAT
466 *
467 * Returns the #GstMpegtsBAT contained in the @section.
468 *
469 * Returns: The #GstMpegtsBAT contained in the section, or %NULL if an error
470 * happened.
471 */
472 const GstMpegtsBAT *
gst_mpegts_section_get_bat(GstMpegtsSection * section)473 gst_mpegts_section_get_bat (GstMpegtsSection * section)
474 {
475 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_BAT, NULL);
476 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
477
478 if (!section->cached_parsed)
479 section->cached_parsed =
480 __common_section_checks (section, 16, _parse_bat,
481 (GDestroyNotify) _gst_mpegts_bat_free);
482
483 return (const GstMpegtsBAT *) section->cached_parsed;
484 }
485
486
487 /* Network Information Table */
488
489 static GstMpegtsNITStream *
_gst_mpegts_nit_stream_copy(GstMpegtsNITStream * nit)490 _gst_mpegts_nit_stream_copy (GstMpegtsNITStream * nit)
491 {
492 GstMpegtsNITStream *copy;
493
494 copy = g_slice_dup (GstMpegtsNITStream, nit);
495 copy->descriptors = g_ptr_array_ref (nit->descriptors);
496
497 return copy;
498 }
499
500 static void
_gst_mpegts_nit_stream_free(GstMpegtsNITStream * nit)501 _gst_mpegts_nit_stream_free (GstMpegtsNITStream * nit)
502 {
503 if (nit->descriptors)
504 g_ptr_array_unref (nit->descriptors);
505 g_slice_free (GstMpegtsNITStream, nit);
506 }
507
508 G_DEFINE_BOXED_TYPE (GstMpegtsNITStream, gst_mpegts_nit_stream,
509 (GBoxedCopyFunc) _gst_mpegts_nit_stream_copy,
510 (GFreeFunc) _gst_mpegts_nit_stream_free);
511
512 static GstMpegtsNIT *
_gst_mpegts_nit_copy(GstMpegtsNIT * nit)513 _gst_mpegts_nit_copy (GstMpegtsNIT * nit)
514 {
515 GstMpegtsNIT *copy = g_slice_dup (GstMpegtsNIT, nit);
516
517 copy->descriptors = g_ptr_array_ref (nit->descriptors);
518 copy->streams = g_ptr_array_ref (nit->streams);
519
520 return copy;
521 }
522
523 static void
_gst_mpegts_nit_free(GstMpegtsNIT * nit)524 _gst_mpegts_nit_free (GstMpegtsNIT * nit)
525 {
526 if (nit->descriptors)
527 g_ptr_array_unref (nit->descriptors);
528 g_ptr_array_unref (nit->streams);
529 g_slice_free (GstMpegtsNIT, nit);
530 }
531
532 G_DEFINE_BOXED_TYPE (GstMpegtsNIT, gst_mpegts_nit,
533 (GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_free);
534
535
536 static gpointer
_parse_nit(GstMpegtsSection * section)537 _parse_nit (GstMpegtsSection * section)
538 {
539 GstMpegtsNIT *nit = NULL;
540 guint allocated_streams = 12;
541 guint8 *data, *end, *entry_begin;
542 guint16 descriptors_loop_length, transport_stream_loop_length;
543
544 GST_DEBUG ("NIT");
545
546 nit = g_slice_new0 (GstMpegtsNIT);
547
548 data = section->data;
549 end = data + section->section_length;
550
551 /* Set network id, and skip the rest of what is already parsed */
552 nit->network_id = section->subtable_extension;
553 data += 8;
554
555 nit->actual_network = section->table_id == 0x40;
556
557 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
558 data += 2;
559
560 /* see if the buffer is large enough */
561 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
562 GST_WARNING ("PID %d invalid NIT descriptors loop length %d",
563 section->pid, descriptors_loop_length);
564 goto error;
565 }
566 nit->descriptors =
567 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
568 if (nit->descriptors == NULL)
569 goto error;
570 data += descriptors_loop_length;
571
572 transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
573 data += 2;
574 if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
575 GST_WARNING
576 ("PID 0x%04x invalid NIT (transport_stream_loop_length too big)",
577 section->pid);
578 goto error;
579 }
580
581 nit->streams =
582 g_ptr_array_new_full (allocated_streams,
583 (GDestroyNotify) _gst_mpegts_nit_stream_free);
584
585 /* read up to the CRC */
586 while (transport_stream_loop_length - 4 > 0) {
587 GstMpegtsNITStream *stream = g_slice_new0 (GstMpegtsNITStream);
588
589 g_ptr_array_add (nit->streams, stream);
590
591 if (transport_stream_loop_length < 6) {
592 /* each entry must be at least 6 bytes (+ 4 bytes CRC) */
593 GST_WARNING ("PID %d invalid NIT entry size %d",
594 section->pid, transport_stream_loop_length);
595 goto error;
596 }
597
598 entry_begin = data;
599
600 stream->transport_stream_id = GST_READ_UINT16_BE (data);
601 data += 2;
602
603 stream->original_network_id = GST_READ_UINT16_BE (data);
604 data += 2;
605
606 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
607 data += 2;
608
609 GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
610
611 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
612 GST_WARNING
613 ("PID %d invalid NIT entry %d descriptors loop length %d (only have %"
614 G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
615 descriptors_loop_length, (gsize) (end - 4 - data));
616 goto error;
617 }
618 stream->descriptors =
619 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
620 if (stream->descriptors == NULL)
621 goto error;
622
623 data += descriptors_loop_length;
624
625 transport_stream_loop_length -= data - entry_begin;
626 }
627
628 if (data != end - 4) {
629 GST_WARNING ("PID %d invalid NIT parsed %d length %d",
630 section->pid, (gint) (data - section->data), section->section_length);
631 goto error;
632 }
633
634 return (gpointer) nit;
635
636 error:
637 if (nit)
638 _gst_mpegts_nit_free (nit);
639
640 return NULL;
641 }
642
643 /**
644 * gst_mpegts_section_get_nit:
645 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_NIT
646 *
647 * Returns the #GstMpegtsNIT contained in the @section.
648 *
649 * Returns: The #GstMpegtsNIT contained in the section, or %NULL if an error
650 * happened.
651 */
652 const GstMpegtsNIT *
gst_mpegts_section_get_nit(GstMpegtsSection * section)653 gst_mpegts_section_get_nit (GstMpegtsSection * section)
654 {
655 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_NIT, NULL);
656 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
657
658 if (!section->cached_parsed)
659 section->cached_parsed =
660 __common_section_checks (section, 16, _parse_nit,
661 (GDestroyNotify) _gst_mpegts_nit_free);
662
663 return (const GstMpegtsNIT *) section->cached_parsed;
664 }
665
666 /**
667 * gst_mpegts_nit_new:
668 *
669 * Allocates and initializes a #GstMpegtsNIT.
670 *
671 * Returns: (transfer full): A newly allocated #GstMpegtsNIT
672 */
673 GstMpegtsNIT *
gst_mpegts_nit_new(void)674 gst_mpegts_nit_new (void)
675 {
676 GstMpegtsNIT *nit;
677
678 nit = g_slice_new0 (GstMpegtsNIT);
679
680 nit->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
681 gst_mpegts_descriptor_free);
682 nit->streams = g_ptr_array_new_with_free_func ((GDestroyNotify)
683 _gst_mpegts_nit_stream_free);
684
685 return nit;
686 }
687
688 /**
689 * gst_mpegts_nit_stream_new:
690 *
691 * Allocates and initializes a #GstMpegtsNITStream
692 *
693 * Returns: (transfer full): A newly allocated #GstMpegtsNITStream
694 */
695 GstMpegtsNITStream *
gst_mpegts_nit_stream_new(void)696 gst_mpegts_nit_stream_new (void)
697 {
698 GstMpegtsNITStream *stream;
699
700 stream = g_slice_new0 (GstMpegtsNITStream);
701
702 stream->descriptors = g_ptr_array_new_with_free_func (
703 (GDestroyNotify) gst_mpegts_descriptor_free);
704
705 return stream;
706 }
707
708 static gboolean
_packetize_nit(GstMpegtsSection * section)709 _packetize_nit (GstMpegtsSection * section)
710 {
711 gsize length, network_length, loop_length;
712 const GstMpegtsNIT *nit;
713 GstMpegtsNITStream *stream;
714 GstMpegtsDescriptor *descriptor;
715 guint i, j;
716 guint8 *data, *pos;
717
718 nit = gst_mpegts_section_get_nit (section);
719
720 if (nit == NULL)
721 return FALSE;
722
723 /* 8 byte common section fields
724 2 byte network_descriptors_length
725 2 byte transport_stream_loop_length
726 4 byte CRC */
727 length = 16;
728
729 /* Find length of network descriptors */
730 network_length = 0;
731 if (nit->descriptors) {
732 for (i = 0; i < nit->descriptors->len; i++) {
733 descriptor = g_ptr_array_index (nit->descriptors, i);
734 network_length += descriptor->length + 2;
735 }
736 }
737
738 /* Find length of loop */
739 loop_length = 0;
740 if (nit->streams) {
741 for (i = 0; i < nit->streams->len; i++) {
742 stream = g_ptr_array_index (nit->streams, i);
743 loop_length += 6;
744 if (stream->descriptors) {
745 for (j = 0; j < stream->descriptors->len; j++) {
746 descriptor = g_ptr_array_index (stream->descriptors, j);
747 loop_length += descriptor->length + 2;
748 }
749 }
750 }
751 }
752
753 length += network_length + loop_length;
754
755 /* Max length of NIT section is 1024 bytes */
756 g_return_val_if_fail (length <= 1024, FALSE);
757
758 _packetize_common_section (section, length);
759
760 data = section->data + 8;
761 /* reserved - 4 bit
762 network_descriptors_length - 12 bit uimsbf */
763 GST_WRITE_UINT16_BE (data, network_length | 0xF000);
764 data += 2;
765
766 _packetize_descriptor_array (nit->descriptors, &data);
767
768 /* reserved - 4 bit
769 transport_stream_loop_length - 12 bit uimsbf */
770 GST_WRITE_UINT16_BE (data, loop_length | 0xF000);
771 data += 2;
772
773 if (nit->streams) {
774 for (i = 0; i < nit->streams->len; i++) {
775 stream = g_ptr_array_index (nit->streams, i);
776 /* transport_stream_id - 16 bit uimsbf */
777 GST_WRITE_UINT16_BE (data, stream->transport_stream_id);
778 data += 2;
779
780 /* original_network_id - 16 bit uimsbf */
781 GST_WRITE_UINT16_BE (data, stream->original_network_id);
782 data += 2;
783
784 /* reserved - 4 bit
785 transport_descriptors_length - 12 bit uimsbf
786
787 Set length to zero, and update in loop */
788 pos = data;
789 *data++ = 0xF0;
790 *data++ = 0x00;
791
792 _packetize_descriptor_array (stream->descriptors, &data);
793
794 /* Go back and update the descriptor length */
795 GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
796 }
797 }
798
799 return TRUE;
800 }
801
802 /**
803 * gst_mpegts_section_from_nit:
804 * @nit: (transfer full): a #GstMpegtsNIT to create the #GstMpegtsSection from
805 *
806 * Ownership of @nit is taken. The data in @nit is managed by the #GstMpegtsSection
807 *
808 * Returns: (transfer full): the #GstMpegtsSection
809 */
810 GstMpegtsSection *
gst_mpegts_section_from_nit(GstMpegtsNIT * nit)811 gst_mpegts_section_from_nit (GstMpegtsNIT * nit)
812 {
813 GstMpegtsSection *section;
814
815 g_return_val_if_fail (nit != NULL, NULL);
816
817 if (nit->actual_network)
818 section = _gst_mpegts_section_init (0x10,
819 GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK);
820 else
821 section = _gst_mpegts_section_init (0x10,
822 GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK);
823
824 section->subtable_extension = nit->network_id;
825 section->cached_parsed = (gpointer) nit;
826 section->packetizer = _packetize_nit;
827 section->destroy_parsed = (GDestroyNotify) _gst_mpegts_nit_free;
828
829 return section;
830 }
831
832 /* Service Description Table (SDT) */
833
834 static GstMpegtsSDTService *
_gst_mpegts_sdt_service_copy(GstMpegtsSDTService * sdt)835 _gst_mpegts_sdt_service_copy (GstMpegtsSDTService * sdt)
836 {
837 GstMpegtsSDTService *copy = g_slice_dup (GstMpegtsSDTService, sdt);
838
839 copy->descriptors = g_ptr_array_ref (sdt->descriptors);
840
841 return copy;
842 }
843
844 static void
_gst_mpegts_sdt_service_free(GstMpegtsSDTService * sdt)845 _gst_mpegts_sdt_service_free (GstMpegtsSDTService * sdt)
846 {
847 if (sdt->descriptors)
848 g_ptr_array_unref (sdt->descriptors);
849 g_slice_free (GstMpegtsSDTService, sdt);
850 }
851
852 G_DEFINE_BOXED_TYPE (GstMpegtsSDTService, gst_mpegts_sdt_service,
853 (GBoxedCopyFunc) _gst_mpegts_sdt_service_copy,
854 (GFreeFunc) _gst_mpegts_sdt_service_free);
855
856 static GstMpegtsSDT *
_gst_mpegts_sdt_copy(GstMpegtsSDT * sdt)857 _gst_mpegts_sdt_copy (GstMpegtsSDT * sdt)
858 {
859 GstMpegtsSDT *copy = g_slice_dup (GstMpegtsSDT, sdt);
860
861 copy->services = g_ptr_array_ref (sdt->services);
862
863 return copy;
864 }
865
866 static void
_gst_mpegts_sdt_free(GstMpegtsSDT * sdt)867 _gst_mpegts_sdt_free (GstMpegtsSDT * sdt)
868 {
869 g_ptr_array_unref (sdt->services);
870 g_slice_free (GstMpegtsSDT, sdt);
871 }
872
873 G_DEFINE_BOXED_TYPE (GstMpegtsSDT, gst_mpegts_sdt,
874 (GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_free);
875
876
877 static gpointer
_parse_sdt(GstMpegtsSection * section)878 _parse_sdt (GstMpegtsSection * section)
879 {
880 GstMpegtsSDT *sdt = NULL;
881 guint allocated_services = 8;
882 guint8 *data, *end, *entry_begin;
883 guint tmp;
884 guint sdt_info_length;
885 guint descriptors_loop_length;
886
887 GST_DEBUG ("SDT");
888
889 sdt = g_slice_new0 (GstMpegtsSDT);
890
891 data = section->data;
892 end = data + section->section_length;
893
894 sdt->transport_stream_id = section->subtable_extension;
895
896 /* Skip common fields */
897 data += 8;
898
899 sdt->original_network_id = GST_READ_UINT16_BE (data);
900 data += 2;
901
902 /* skip reserved byte */
903 data += 1;
904
905 sdt->actual_ts = section->table_id == 0x42;
906
907 sdt_info_length = section->section_length - 11;
908
909 sdt->services = g_ptr_array_new_full (allocated_services,
910 (GDestroyNotify) _gst_mpegts_sdt_service_free);
911
912 /* read up to the CRC */
913 while (sdt_info_length - 4 > 0) {
914 GstMpegtsSDTService *service = g_slice_new0 (GstMpegtsSDTService);
915 g_ptr_array_add (sdt->services, service);
916
917 entry_begin = data;
918
919 if (sdt_info_length - 4 < 5) {
920 /* each entry must be at least 5 bytes (+4 bytes for the CRC) */
921 GST_WARNING ("PID %d invalid SDT entry size %d",
922 section->pid, sdt_info_length);
923 goto error;
924 }
925
926 service->service_id = GST_READ_UINT16_BE (data);
927 data += 2;
928
929 service->EIT_schedule_flag = ((*data & 0x02) == 2);
930 service->EIT_present_following_flag = (*data & 0x01) == 1;
931
932 data += 1;
933 tmp = GST_READ_UINT16_BE (data);
934
935 service->running_status = (*data >> 5) & 0x07;
936 service->free_CA_mode = (*data >> 4) & 0x01;
937
938 descriptors_loop_length = tmp & 0x0FFF;
939 data += 2;
940
941 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
942 GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d",
943 section->pid, service->service_id, descriptors_loop_length);
944 goto error;
945 }
946 service->descriptors =
947 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
948 if (!service->descriptors)
949 goto error;
950 data += descriptors_loop_length;
951
952 sdt_info_length -= data - entry_begin;
953 }
954
955 if (data != end - 4) {
956 GST_WARNING ("PID %d invalid SDT parsed %d length %d",
957 section->pid, (gint) (data - section->data), section->section_length);
958 goto error;
959 }
960
961 return sdt;
962
963 error:
964 if (sdt)
965 _gst_mpegts_sdt_free (sdt);
966
967 return NULL;
968 }
969
970 /**
971 * gst_mpegts_section_get_sdt:
972 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SDT
973 *
974 * Returns the #GstMpegtsSDT contained in the @section.
975 *
976 * Returns: The #GstMpegtsSDT contained in the section, or %NULL if an error
977 * happened.
978 */
979 const GstMpegtsSDT *
gst_mpegts_section_get_sdt(GstMpegtsSection * section)980 gst_mpegts_section_get_sdt (GstMpegtsSection * section)
981 {
982 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SDT, NULL);
983 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
984
985 if (!section->cached_parsed)
986 section->cached_parsed =
987 __common_section_checks (section, 15, _parse_sdt,
988 (GDestroyNotify) _gst_mpegts_sdt_free);
989
990 return (const GstMpegtsSDT *) section->cached_parsed;
991 }
992
993 /**
994 * gst_mpegts_sdt_new:
995 *
996 * Allocates and initializes a #GstMpegtsSDT.
997 *
998 * Returns: (transfer full): A newly allocated #GstMpegtsSDT
999 */
1000 GstMpegtsSDT *
gst_mpegts_sdt_new(void)1001 gst_mpegts_sdt_new (void)
1002 {
1003 GstMpegtsSDT *sdt;
1004
1005 sdt = g_slice_new0 (GstMpegtsSDT);
1006
1007 sdt->services = g_ptr_array_new_with_free_func ((GDestroyNotify)
1008 _gst_mpegts_sdt_service_free);
1009
1010 return sdt;
1011 }
1012
1013 /**
1014 * gst_mpegts_sdt_service_new:
1015 *
1016 * Allocates and initializes a #GstMpegtsSDTService.
1017 *
1018 * Returns: (transfer full): A newly allocated #GstMpegtsSDTService
1019 */
1020 GstMpegtsSDTService *
gst_mpegts_sdt_service_new(void)1021 gst_mpegts_sdt_service_new (void)
1022 {
1023 GstMpegtsSDTService *service;
1024
1025 service = g_slice_new0 (GstMpegtsSDTService);
1026
1027 service->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
1028 gst_mpegts_descriptor_free);
1029
1030 return service;
1031 }
1032
1033 static gboolean
_packetize_sdt(GstMpegtsSection * section)1034 _packetize_sdt (GstMpegtsSection * section)
1035 {
1036 gsize length, service_length;
1037 const GstMpegtsSDT *sdt;
1038 GstMpegtsSDTService *service;
1039 GstMpegtsDescriptor *descriptor;
1040 guint i, j;
1041 guint8 *data, *pos;
1042
1043 sdt = gst_mpegts_section_get_sdt (section);
1044
1045 if (sdt == NULL)
1046 return FALSE;
1047
1048 /* 8 byte common section fields
1049 2 byte original_network_id
1050 1 byte reserved
1051 4 byte CRC */
1052 length = 15;
1053
1054 /* Find length of services */
1055 service_length = 0;
1056 if (sdt->services) {
1057 for (i = 0; i < sdt->services->len; i++) {
1058 service = g_ptr_array_index (sdt->services, i);
1059 service_length += 5;
1060 if (service->descriptors) {
1061 for (j = 0; j < service->descriptors->len; j++) {
1062 descriptor = g_ptr_array_index (service->descriptors, j);
1063 service_length += descriptor->length + 2;
1064 }
1065 }
1066 }
1067 }
1068
1069 length += service_length;
1070
1071 /* Max length if SDT section is 1024 bytes */
1072 g_return_val_if_fail (length <= 1024, FALSE);
1073
1074 _packetize_common_section (section, length);
1075
1076 data = section->data + 8;
1077 /* original_network_id - 16 bit uimsbf */
1078 GST_WRITE_UINT16_BE (data, sdt->original_network_id);
1079 data += 2;
1080 /* reserved - 8 bit */
1081 *data++ = 0xFF;
1082
1083 if (sdt->services) {
1084 for (i = 0; i < sdt->services->len; i++) {
1085 service = g_ptr_array_index (sdt->services, i);
1086 /* service_id - 16 bit uimsbf */
1087 GST_WRITE_UINT16_BE (data, service->service_id);
1088 data += 2;
1089
1090 /* reserved - 6 bit
1091 EIT_schedule_flag - 1 bit
1092 EIT_present_following_flag - 1 bit */
1093 *data = 0xFC;
1094 if (service->EIT_schedule_flag)
1095 *data |= 0x02;
1096 if (service->EIT_present_following_flag)
1097 *data |= 0x01;
1098 data++;
1099
1100 /* running_status - 3 bit uimsbf
1101 free_CA_mode - 1 bit
1102 descriptors_loop_length - 12 bit uimsbf */
1103 /* Set length to zero for now */
1104 pos = data;
1105 *data++ = 0x00;
1106 *data++ = 0x00;
1107
1108 _packetize_descriptor_array (service->descriptors, &data);
1109
1110 /* Go back and update the descriptor length */
1111 GST_WRITE_UINT16_BE (pos, data - pos - 2);
1112
1113 *pos |= service->running_status << 5;
1114 if (service->free_CA_mode)
1115 *pos |= 0x10;
1116 }
1117 }
1118
1119 return TRUE;
1120 }
1121
1122 /**
1123 * gst_mpegts_section_from_sdt:
1124 * @sdt: (transfer full): a #GstMpegtsSDT to create the #GstMpegtsSection from
1125 *
1126 * Ownership of @sdt is taken. The data in @sdt is managed by the #GstMpegtsSection
1127 *
1128 * Returns: (transfer full): the #GstMpegtsSection
1129 */
1130 GstMpegtsSection *
gst_mpegts_section_from_sdt(GstMpegtsSDT * sdt)1131 gst_mpegts_section_from_sdt (GstMpegtsSDT * sdt)
1132 {
1133 GstMpegtsSection *section;
1134
1135 g_return_val_if_fail (sdt != NULL, NULL);
1136
1137 if (sdt->actual_ts)
1138 section = _gst_mpegts_section_init (0x11,
1139 GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_ACTUAL_TS);
1140 else
1141 section = _gst_mpegts_section_init (0x11,
1142 GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_OTHER_TS);
1143
1144 section->subtable_extension = sdt->transport_stream_id;
1145 section->cached_parsed = (gpointer) sdt;
1146 section->packetizer = _packetize_sdt;
1147 section->destroy_parsed = (GDestroyNotify) _gst_mpegts_sdt_free;
1148
1149 return section;
1150 }
1151
1152 /* Time and Date Table (TDT) */
1153 static gpointer
_parse_tdt(GstMpegtsSection * section)1154 _parse_tdt (GstMpegtsSection * section)
1155 {
1156 return (gpointer) _parse_utc_time (section->data + 3);
1157 }
1158
1159 /**
1160 * gst_mpegts_section_get_tdt:
1161 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_TDT
1162 *
1163 * Returns the #GstDateTime of the TDT
1164 *
1165 * Returns: The #GstDateTime contained in the section, or %NULL
1166 * if an error happened. Release with #gst_date_time_unref when done.
1167 */
1168 GstDateTime *
gst_mpegts_section_get_tdt(GstMpegtsSection * section)1169 gst_mpegts_section_get_tdt (GstMpegtsSection * section)
1170 {
1171 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TDT, NULL);
1172 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1173
1174 if (!section->cached_parsed)
1175 section->cached_parsed =
1176 __common_section_checks (section, 8, _parse_tdt,
1177 (GDestroyNotify) gst_date_time_unref);
1178
1179 if (section->cached_parsed)
1180 return gst_date_time_ref ((GstDateTime *) section->cached_parsed);
1181 return NULL;
1182 }
1183
1184
1185 /* Time Offset Table (TOT) */
1186 static GstMpegtsTOT *
_gst_mpegts_tot_copy(GstMpegtsTOT * tot)1187 _gst_mpegts_tot_copy (GstMpegtsTOT * tot)
1188 {
1189 GstMpegtsTOT *copy = g_slice_dup (GstMpegtsTOT, tot);
1190
1191 if (tot->utc_time)
1192 copy->utc_time = gst_date_time_ref (tot->utc_time);
1193 copy->descriptors = g_ptr_array_ref (tot->descriptors);
1194
1195 return copy;
1196 }
1197
1198 static void
_gst_mpegts_tot_free(GstMpegtsTOT * tot)1199 _gst_mpegts_tot_free (GstMpegtsTOT * tot)
1200 {
1201 if (tot->utc_time)
1202 gst_date_time_unref (tot->utc_time);
1203 if (tot->descriptors)
1204 g_ptr_array_unref (tot->descriptors);
1205 g_slice_free (GstMpegtsTOT, tot);
1206 }
1207
1208 G_DEFINE_BOXED_TYPE (GstMpegtsTOT, gst_mpegts_tot,
1209 (GBoxedCopyFunc) _gst_mpegts_tot_copy, (GFreeFunc) _gst_mpegts_tot_free);
1210
1211 static gpointer
_parse_tot(GstMpegtsSection * section)1212 _parse_tot (GstMpegtsSection * section)
1213 {
1214 guint8 *data;
1215 GstMpegtsTOT *tot;
1216 guint16 desc_len;
1217
1218 GST_DEBUG ("TOT");
1219
1220 tot = g_slice_new0 (GstMpegtsTOT);
1221
1222 tot->utc_time = _parse_utc_time (section->data + 3);
1223
1224 /* Skip 5 bytes from utc_time (+3 of initial offset) */
1225 data = section->data + 8;
1226
1227 desc_len = GST_READ_UINT16_BE (data) & 0xFFF;
1228 data += 2;
1229 tot->descriptors = gst_mpegts_parse_descriptors (data, desc_len);
1230
1231 return (gpointer) tot;
1232 }
1233
1234 /**
1235 * gst_mpegts_section_get_tot:
1236 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_TOT
1237 *
1238 * Returns the #GstMpegtsTOT contained in the @section.
1239 *
1240 * Returns: The #GstMpegtsTOT contained in the section, or %NULL if an error
1241 * happened.
1242 */
1243 const GstMpegtsTOT *
gst_mpegts_section_get_tot(GstMpegtsSection * section)1244 gst_mpegts_section_get_tot (GstMpegtsSection * section)
1245 {
1246 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TOT, NULL);
1247 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1248
1249 if (!section->cached_parsed)
1250 section->cached_parsed =
1251 __common_section_checks (section, 14, _parse_tot,
1252 (GDestroyNotify) _gst_mpegts_tot_free);
1253
1254 return (const GstMpegtsTOT *) section->cached_parsed;
1255 }
1256
1257
1258 /* Selection Information Table (SIT) */
1259
1260 static GstMpegtsSITService *
_gst_mpegts_sit_service_copy(GstMpegtsSITService * sit)1261 _gst_mpegts_sit_service_copy (GstMpegtsSITService * sit)
1262 {
1263 GstMpegtsSITService *copy = g_slice_dup (GstMpegtsSITService, sit);
1264
1265 copy->service_id = sit->service_id;
1266 copy->running_status = sit->running_status;
1267 copy->descriptors = g_ptr_array_ref (sit->descriptors);
1268
1269 return copy;
1270 }
1271
1272 static void
_gst_mpegts_sit_service_free(GstMpegtsSITService * sit)1273 _gst_mpegts_sit_service_free (GstMpegtsSITService * sit)
1274 {
1275 if (sit->descriptors)
1276 g_ptr_array_unref (sit->descriptors);
1277 g_slice_free (GstMpegtsSITService, sit);
1278 }
1279
1280 G_DEFINE_BOXED_TYPE (GstMpegtsSITService, gst_mpegts_sit_service,
1281 (GBoxedCopyFunc) _gst_mpegts_sit_service_copy,
1282 (GFreeFunc) _gst_mpegts_sit_service_free);
1283
1284 static GstMpegtsSIT *
_gst_mpegts_sit_copy(GstMpegtsSIT * sit)1285 _gst_mpegts_sit_copy (GstMpegtsSIT * sit)
1286 {
1287 GstMpegtsSIT *copy = g_slice_dup (GstMpegtsSIT, sit);
1288
1289 copy->services = g_ptr_array_ref (sit->services);
1290 copy->descriptors = g_ptr_array_ref (sit->descriptors);
1291
1292 return copy;
1293 }
1294
1295 static void
_gst_mpegts_sit_free(GstMpegtsSIT * sit)1296 _gst_mpegts_sit_free (GstMpegtsSIT * sit)
1297 {
1298 g_ptr_array_unref (sit->services);
1299 g_ptr_array_unref (sit->descriptors);
1300 g_slice_free (GstMpegtsSIT, sit);
1301 }
1302
1303 G_DEFINE_BOXED_TYPE (GstMpegtsSIT, gst_mpegts_sit,
1304 (GBoxedCopyFunc) _gst_mpegts_sit_copy, (GFreeFunc) _gst_mpegts_sit_free);
1305
1306
1307 static gpointer
_parse_sit(GstMpegtsSection * section)1308 _parse_sit (GstMpegtsSection * section)
1309 {
1310 GstMpegtsSIT *sit = NULL;
1311 guint allocated_services = 8;
1312 guint8 *data, *end, *entry_begin;
1313 guint sit_info_length;
1314 guint descriptors_loop_length;
1315
1316 GST_DEBUG ("SIT");
1317
1318 sit = g_slice_new0 (GstMpegtsSIT);
1319
1320 data = section->data;
1321 end = data + section->section_length;
1322
1323 /* Skip common fields */
1324 data += 8;
1325
1326 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
1327 data += 2;
1328 sit->descriptors =
1329 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
1330 if (sit->descriptors == NULL)
1331 goto error;
1332 data += descriptors_loop_length;
1333
1334 sit_info_length = end - data;;
1335 sit->services = g_ptr_array_new_full (allocated_services,
1336 (GDestroyNotify) _gst_mpegts_sit_service_free);
1337
1338 /* read up to the CRC */
1339 while (sit_info_length - 4 > 0) {
1340 GstMpegtsSITService *service = g_slice_new0 (GstMpegtsSITService);
1341 g_ptr_array_add (sit->services, service);
1342
1343 entry_begin = data;
1344
1345 if (sit_info_length - 4 < 4) {
1346 /* each entry must be at least 4 bytes (+4 bytes for the CRC) */
1347 GST_WARNING ("PID %d invalid SIT entry size %d",
1348 section->pid, sit_info_length);
1349 goto error;
1350 }
1351
1352 service->service_id = GST_READ_UINT16_BE (data);
1353 data += 2;
1354
1355 service->running_status = (*data >> 5) & 0x07;
1356 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
1357 data += 2;
1358
1359 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
1360 GST_WARNING ("PID %d invalid SIT entry %d descriptors loop length %d",
1361 section->pid, service->service_id, descriptors_loop_length);
1362 goto error;
1363 }
1364 service->descriptors =
1365 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
1366 if (!service->descriptors)
1367 goto error;
1368 data += descriptors_loop_length;
1369
1370 sit_info_length -= data - entry_begin;
1371 }
1372
1373 if (data != end - 4) {
1374 GST_WARNING ("PID %d invalid SIT parsed %d length %d",
1375 section->pid, (gint) (data - section->data), section->section_length);
1376 goto error;
1377 }
1378
1379 return sit;
1380
1381 error:
1382 if (sit)
1383 _gst_mpegts_sit_free (sit);
1384
1385 return NULL;
1386 }
1387
1388 /**
1389 * gst_mpegts_section_get_sit:
1390 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SIT
1391 *
1392 * Returns the #GstMpegtsSIT contained in the @section.
1393 *
1394 * Returns: The #GstMpegtsSIT contained in the section, or %NULL if an error
1395 * happened.
1396 *
1397 * Since: 1.20
1398 */
1399 const GstMpegtsSIT *
gst_mpegts_section_get_sit(GstMpegtsSection * section)1400 gst_mpegts_section_get_sit (GstMpegtsSection * section)
1401 {
1402 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SIT, NULL);
1403 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1404
1405 if (!section->cached_parsed)
1406 section->cached_parsed =
1407 __common_section_checks (section, 18, _parse_sit,
1408 (GDestroyNotify) _gst_mpegts_sit_free);
1409
1410 return (const GstMpegtsSIT *) section->cached_parsed;
1411 }
1412