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 */
48
49
50 /*
51 * TODO
52 *
53 * * Check minimum size for section parsing in the various
54 * gst_mpegts_section_get_<tabld>() methods
55 *
56 * * Implement parsing code for
57 * * BAT
58 * * CAT
59 * * TSDT
60 */
61
62 static inline GstDateTime *
_parse_utc_time(guint8 * data)63 _parse_utc_time (guint8 * data)
64 {
65 guint year, month, day, hour, minute, second;
66 guint16 mjd;
67 guint8 *utc_ptr;
68
69 mjd = GST_READ_UINT16_BE (data);
70
71 if (mjd == G_MAXUINT16)
72 return NULL;
73
74 /* See EN 300 468 Annex C */
75 year = (guint32) (((mjd - 15078.2) / 365.25));
76 month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001);
77 day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001);
78 if (month == 14 || month == 15) {
79 year++;
80 month = month - 1 - 12;
81 } else {
82 month--;
83 }
84 year += 1900;
85
86 utc_ptr = data + 2;
87
88 /* First digit of hours cannot exceed 1 (max: 23 hours) */
89 hour = ((utc_ptr[0] & 0x30) >> 4) * 10 + (utc_ptr[0] & 0x0F);
90 /* First digit of minutes cannot exced 5 (max: 59 mins) */
91 minute = ((utc_ptr[1] & 0x70) >> 4) * 10 + (utc_ptr[1] & 0x0F);
92 /* first digit of seconds cannot exceed 5 (max: 59 seconds) */
93 second = ((utc_ptr[2] & 0x70) >> 4) * 10 + (utc_ptr[2] & 0x0F);
94
95 /* Time is UTC */
96 if (hour < 24 && minute < 60 && second < 60) {
97 return gst_date_time_new (0.0, year, month, day, hour, minute,
98 (gdouble) second);
99 } else if (utc_ptr[0] == 0xFF && utc_ptr[1] == 0xFF && utc_ptr[2] == 0xFF) {
100 return gst_date_time_new (0.0, year, month, day, -1, -1, -1);
101 }
102
103 return NULL;
104 }
105
106 /* Event Information Table */
107 static GstMpegtsEITEvent *
_gst_mpegts_eit_event_copy(GstMpegtsEITEvent * eit)108 _gst_mpegts_eit_event_copy (GstMpegtsEITEvent * eit)
109 {
110 GstMpegtsEITEvent *copy;
111
112 copy = g_slice_dup (GstMpegtsEITEvent, eit);
113 copy->start_time = gst_date_time_ref (eit->start_time);
114 copy->descriptors = g_ptr_array_ref (eit->descriptors);
115
116 return copy;
117 }
118
119 static void
_gst_mpegts_eit_event_free(GstMpegtsEITEvent * eit)120 _gst_mpegts_eit_event_free (GstMpegtsEITEvent * eit)
121 {
122 if (eit->start_time)
123 gst_date_time_unref (eit->start_time);
124 if (eit->descriptors)
125 g_ptr_array_unref (eit->descriptors);
126 g_slice_free (GstMpegtsEITEvent, eit);
127 }
128
129 G_DEFINE_BOXED_TYPE (GstMpegtsEITEvent, gst_mpegts_eit_event,
130 (GBoxedCopyFunc) _gst_mpegts_eit_event_copy,
131 (GFreeFunc) _gst_mpegts_eit_event_free);
132
133 static GstMpegtsEIT *
_gst_mpegts_eit_copy(GstMpegtsEIT * eit)134 _gst_mpegts_eit_copy (GstMpegtsEIT * eit)
135 {
136 GstMpegtsEIT *copy;
137
138 copy = g_slice_dup (GstMpegtsEIT, eit);
139 copy->events = g_ptr_array_ref (eit->events);
140
141 return copy;
142 }
143
144 static void
_gst_mpegts_eit_free(GstMpegtsEIT * eit)145 _gst_mpegts_eit_free (GstMpegtsEIT * eit)
146 {
147 g_ptr_array_unref (eit->events);
148 g_slice_free (GstMpegtsEIT, eit);
149 }
150
151 G_DEFINE_BOXED_TYPE (GstMpegtsEIT, gst_mpegts_eit,
152 (GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_free);
153
154 static gpointer
_parse_eit(GstMpegtsSection * section)155 _parse_eit (GstMpegtsSection * section)
156 {
157 GstMpegtsEIT *eit = NULL;
158 guint i = 0, allocated_events = 12;
159 guint8 *data, *end, *duration_ptr;
160 guint16 descriptors_loop_length;
161
162 eit = g_slice_new0 (GstMpegtsEIT);
163
164 data = section->data;
165 end = data + section->section_length;
166
167 /* Skip already parsed data */
168 data += 8;
169
170 eit->transport_stream_id = GST_READ_UINT16_BE (data);
171 data += 2;
172 eit->original_network_id = GST_READ_UINT16_BE (data);
173 data += 2;
174 eit->segment_last_section_number = *data++;
175 eit->last_table_id = *data++;
176
177 eit->actual_stream = (section->table_id == 0x4E ||
178 (section->table_id >= 0x50 && section->table_id <= 0x5F));
179 eit->present_following = (section->table_id == 0x4E
180 || section->table_id == 0x4F);
181
182 eit->events =
183 g_ptr_array_new_full (allocated_events,
184 (GDestroyNotify) _gst_mpegts_eit_event_free);
185
186 while (data < end - 4) {
187 GstMpegtsEITEvent *event;
188
189 /* 12 is the minimum entry size + CRC */
190 if (end - data < 12 + 4) {
191 GST_WARNING ("PID %d invalid EIT entry length %d",
192 section->pid, (gint) (end - 4 - data));
193 goto error;
194 }
195
196 event = g_slice_new0 (GstMpegtsEITEvent);
197 g_ptr_array_add (eit->events, event);
198
199 event->event_id = GST_READ_UINT16_BE (data);
200 data += 2;
201
202 event->start_time = _parse_utc_time (data);
203 duration_ptr = data + 5;
204 event->duration = (((duration_ptr[0] & 0xF0) >> 4) * 10 +
205 (duration_ptr[0] & 0x0F)) * 60 * 60 +
206 (((duration_ptr[1] & 0xF0) >> 4) * 10 +
207 (duration_ptr[1] & 0x0F)) * 60 +
208 ((duration_ptr[2] & 0xF0) >> 4) * 10 + (duration_ptr[2] & 0x0F);
209
210 data += 8;
211 event->running_status = *data >> 5;
212 event->free_CA_mode = (*data >> 4) & 0x01;
213
214 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
215 data += 2;
216
217 event->descriptors =
218 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
219 if (event->descriptors == NULL)
220 goto error;
221 data += descriptors_loop_length;
222
223 i += 1;
224 }
225
226 if (data != end - 4) {
227 GST_WARNING ("PID %d invalid EIT parsed %d length %d",
228 section->pid, (gint) (data - section->data), section->section_length);
229 goto error;
230 }
231
232 return (gpointer) eit;
233
234 error:
235 if (eit)
236 _gst_mpegts_eit_free (eit);
237
238 return NULL;
239
240 }
241
242 /**
243 * gst_mpegts_section_get_eit:
244 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_EIT
245 *
246 * Returns the #GstMpegtsEIT contained in the @section.
247 *
248 * Returns: The #GstMpegtsEIT contained in the section, or %NULL if an error
249 * happened.
250 */
251 const GstMpegtsEIT *
gst_mpegts_section_get_eit(GstMpegtsSection * section)252 gst_mpegts_section_get_eit (GstMpegtsSection * section)
253 {
254 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_EIT, NULL);
255 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
256
257 if (!section->cached_parsed)
258 section->cached_parsed = __common_section_checks (section, 18, _parse_eit,
259 (GDestroyNotify) _gst_mpegts_eit_free);
260
261 return (const GstMpegtsEIT *) section->cached_parsed;
262 }
263
264 /* Bouquet Association Table */
265 static GstMpegtsBATStream *
_gst_mpegts_bat_stream_copy(GstMpegtsBATStream * bat)266 _gst_mpegts_bat_stream_copy (GstMpegtsBATStream * bat)
267 {
268 GstMpegtsBATStream *copy;
269
270 copy = g_slice_dup (GstMpegtsBATStream, bat);
271 copy->descriptors = g_ptr_array_ref (bat->descriptors);
272
273 return copy;
274 }
275
276 static void
_gst_mpegts_bat_stream_free(GstMpegtsBATStream * bat)277 _gst_mpegts_bat_stream_free (GstMpegtsBATStream * bat)
278 {
279 if (bat->descriptors)
280 g_ptr_array_unref (bat->descriptors);
281 g_slice_free (GstMpegtsBATStream, bat);
282 }
283
284 G_DEFINE_BOXED_TYPE (GstMpegtsBATStream, gst_mpegts_bat_stream,
285 (GBoxedCopyFunc) _gst_mpegts_bat_stream_copy,
286 (GFreeFunc) _gst_mpegts_bat_stream_free);
287
288 static GstMpegtsBAT *
_gst_mpegts_bat_copy(GstMpegtsBAT * bat)289 _gst_mpegts_bat_copy (GstMpegtsBAT * bat)
290 {
291 GstMpegtsBAT *copy;
292
293 copy = g_slice_dup (GstMpegtsBAT, bat);
294 copy->descriptors = g_ptr_array_ref (bat->descriptors);
295 copy->streams = g_ptr_array_ref (bat->streams);
296
297 return copy;
298 }
299
300 static void
_gst_mpegts_bat_free(GstMpegtsBAT * bat)301 _gst_mpegts_bat_free (GstMpegtsBAT * bat)
302 {
303 if (bat->descriptors)
304 g_ptr_array_unref (bat->descriptors);
305 if (bat->streams)
306 g_ptr_array_unref (bat->streams);
307 g_slice_free (GstMpegtsBAT, bat);
308 }
309
310 G_DEFINE_BOXED_TYPE (GstMpegtsBAT, gst_mpegts_bat,
311 (GBoxedCopyFunc) _gst_mpegts_bat_copy, (GFreeFunc) _gst_mpegts_bat_free);
312
313 static gpointer
_parse_bat(GstMpegtsSection * section)314 _parse_bat (GstMpegtsSection * section)
315 {
316 GstMpegtsBAT *bat = NULL;
317 guint i = 0, allocated_streams = 12;
318 guint8 *data, *end, *entry_begin;
319 guint16 descriptors_loop_length, transport_stream_loop_length;
320
321 GST_DEBUG ("BAT");
322
323 bat = g_slice_new0 (GstMpegtsBAT);
324
325 data = section->data;
326 end = data + section->section_length;
327
328 /* Skip already parsed data */
329 data += 8;
330
331 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
332 data += 2;
333
334 /* see if the buffer is large enough */
335 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
336 GST_WARNING ("PID %d invalid BAT descriptors loop length %d",
337 section->pid, descriptors_loop_length);
338 goto error;
339 }
340 bat->descriptors =
341 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
342 if (bat->descriptors == NULL)
343 goto error;
344 data += descriptors_loop_length;
345
346 transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
347 data += 2;
348 if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
349 GST_WARNING
350 ("PID 0x%04x invalid BAT (transport_stream_loop_length too big)",
351 section->pid);
352 goto error;
353 }
354
355 bat->streams =
356 g_ptr_array_new_full (allocated_streams,
357 (GDestroyNotify) _gst_mpegts_bat_stream_free);
358
359 /* read up to the CRC */
360 while (transport_stream_loop_length - 4 > 0) {
361 GstMpegtsBATStream *stream = g_slice_new0 (GstMpegtsBATStream);
362
363 g_ptr_array_add (bat->streams, stream);
364
365 if (transport_stream_loop_length < 6) {
366 /* each entry must be at least 6 bytes (+ 4 bytes CRC) */
367 GST_WARNING ("PID %d invalid BAT entry size %d",
368 section->pid, transport_stream_loop_length);
369 goto error;
370 }
371
372 entry_begin = data;
373
374 stream->transport_stream_id = GST_READ_UINT16_BE (data);
375 data += 2;
376
377 stream->original_network_id = GST_READ_UINT16_BE (data);
378 data += 2;
379
380 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
381 data += 2;
382
383 GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
384
385 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
386 GST_WARNING
387 ("PID %d invalid BAT entry %d descriptors loop length %d (only have %"
388 G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
389 descriptors_loop_length, (gsize) (end - 4 - data));
390 goto error;
391 }
392 stream->descriptors =
393 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
394 if (stream->descriptors == NULL)
395 goto error;
396
397 data += descriptors_loop_length;
398
399 i += 1;
400 transport_stream_loop_length -= data - entry_begin;
401 }
402
403 if (data != end - 4) {
404 GST_WARNING ("PID %d invalid BAT parsed %d length %d",
405 section->pid, (gint) (data - section->data), section->section_length);
406 goto error;
407 }
408
409 return (gpointer) bat;
410
411 error:
412 if (bat)
413 _gst_mpegts_bat_free (bat);
414
415 return NULL;
416 }
417
418 /**
419 * gst_mpegts_section_get_bat:
420 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_BAT
421 *
422 * Returns the #GstMpegtsBAT contained in the @section.
423 *
424 * Returns: The #GstMpegtsBAT contained in the section, or %NULL if an error
425 * happened.
426 */
427 const GstMpegtsBAT *
gst_mpegts_section_get_bat(GstMpegtsSection * section)428 gst_mpegts_section_get_bat (GstMpegtsSection * section)
429 {
430 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_BAT, NULL);
431 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
432
433 if (!section->cached_parsed)
434 section->cached_parsed =
435 __common_section_checks (section, 16, _parse_bat,
436 (GDestroyNotify) _gst_mpegts_bat_free);
437
438 return (const GstMpegtsBAT *) section->cached_parsed;
439 }
440
441
442 /* Network Information Table */
443
444 static GstMpegtsNITStream *
_gst_mpegts_nit_stream_copy(GstMpegtsNITStream * nit)445 _gst_mpegts_nit_stream_copy (GstMpegtsNITStream * nit)
446 {
447 GstMpegtsNITStream *copy;
448
449 copy = g_slice_dup (GstMpegtsNITStream, nit);
450 copy->descriptors = g_ptr_array_ref (nit->descriptors);
451
452 return copy;
453 }
454
455 static void
_gst_mpegts_nit_stream_free(GstMpegtsNITStream * nit)456 _gst_mpegts_nit_stream_free (GstMpegtsNITStream * nit)
457 {
458 if (nit->descriptors)
459 g_ptr_array_unref (nit->descriptors);
460 g_slice_free (GstMpegtsNITStream, nit);
461 }
462
463 G_DEFINE_BOXED_TYPE (GstMpegtsNITStream, gst_mpegts_nit_stream,
464 (GBoxedCopyFunc) _gst_mpegts_nit_stream_copy,
465 (GFreeFunc) _gst_mpegts_nit_stream_free);
466
467 static GstMpegtsNIT *
_gst_mpegts_nit_copy(GstMpegtsNIT * nit)468 _gst_mpegts_nit_copy (GstMpegtsNIT * nit)
469 {
470 GstMpegtsNIT *copy = g_slice_dup (GstMpegtsNIT, nit);
471
472 copy->descriptors = g_ptr_array_ref (nit->descriptors);
473 copy->streams = g_ptr_array_ref (nit->streams);
474
475 return copy;
476 }
477
478 static void
_gst_mpegts_nit_free(GstMpegtsNIT * nit)479 _gst_mpegts_nit_free (GstMpegtsNIT * nit)
480 {
481 if (nit->descriptors)
482 g_ptr_array_unref (nit->descriptors);
483 g_ptr_array_unref (nit->streams);
484 g_slice_free (GstMpegtsNIT, nit);
485 }
486
487 G_DEFINE_BOXED_TYPE (GstMpegtsNIT, gst_mpegts_nit,
488 (GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_free);
489
490
491 static gpointer
_parse_nit(GstMpegtsSection * section)492 _parse_nit (GstMpegtsSection * section)
493 {
494 GstMpegtsNIT *nit = NULL;
495 guint i = 0, allocated_streams = 12;
496 guint8 *data, *end, *entry_begin;
497 guint16 descriptors_loop_length, transport_stream_loop_length;
498
499 GST_DEBUG ("NIT");
500
501 nit = g_slice_new0 (GstMpegtsNIT);
502
503 data = section->data;
504 end = data + section->section_length;
505
506 /* Set network id, and skip the rest of what is already parsed */
507 nit->network_id = section->subtable_extension;
508 data += 8;
509
510 nit->actual_network = section->table_id == 0x40;
511
512 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
513 data += 2;
514
515 /* see if the buffer is large enough */
516 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
517 GST_WARNING ("PID %d invalid NIT descriptors loop length %d",
518 section->pid, descriptors_loop_length);
519 goto error;
520 }
521 nit->descriptors =
522 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
523 if (nit->descriptors == NULL)
524 goto error;
525 data += descriptors_loop_length;
526
527 transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
528 data += 2;
529 if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
530 GST_WARNING
531 ("PID 0x%04x invalid NIT (transport_stream_loop_length too big)",
532 section->pid);
533 goto error;
534 }
535
536 nit->streams =
537 g_ptr_array_new_full (allocated_streams,
538 (GDestroyNotify) _gst_mpegts_nit_stream_free);
539
540 /* read up to the CRC */
541 while (transport_stream_loop_length - 4 > 0) {
542 GstMpegtsNITStream *stream = g_slice_new0 (GstMpegtsNITStream);
543
544 g_ptr_array_add (nit->streams, stream);
545
546 if (transport_stream_loop_length < 6) {
547 /* each entry must be at least 6 bytes (+ 4 bytes CRC) */
548 GST_WARNING ("PID %d invalid NIT entry size %d",
549 section->pid, transport_stream_loop_length);
550 goto error;
551 }
552
553 entry_begin = data;
554
555 stream->transport_stream_id = GST_READ_UINT16_BE (data);
556 data += 2;
557
558 stream->original_network_id = GST_READ_UINT16_BE (data);
559 data += 2;
560
561 descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
562 data += 2;
563
564 GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
565
566 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
567 GST_WARNING
568 ("PID %d invalid NIT entry %d descriptors loop length %d (only have %"
569 G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
570 descriptors_loop_length, (gsize) (end - 4 - data));
571 goto error;
572 }
573 stream->descriptors =
574 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
575 if (stream->descriptors == NULL)
576 goto error;
577
578 data += descriptors_loop_length;
579
580 i += 1;
581 transport_stream_loop_length -= data - entry_begin;
582 }
583
584 if (data != end - 4) {
585 GST_WARNING ("PID %d invalid NIT parsed %d length %d",
586 section->pid, (gint) (data - section->data), section->section_length);
587 goto error;
588 }
589
590 return (gpointer) nit;
591
592 error:
593 if (nit)
594 _gst_mpegts_nit_free (nit);
595
596 return NULL;
597 }
598
599 /**
600 * gst_mpegts_section_get_nit:
601 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_NIT
602 *
603 * Returns the #GstMpegtsNIT contained in the @section.
604 *
605 * Returns: The #GstMpegtsNIT contained in the section, or %NULL if an error
606 * happened.
607 */
608 const GstMpegtsNIT *
gst_mpegts_section_get_nit(GstMpegtsSection * section)609 gst_mpegts_section_get_nit (GstMpegtsSection * section)
610 {
611 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_NIT, NULL);
612 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
613
614 if (!section->cached_parsed)
615 section->cached_parsed =
616 __common_section_checks (section, 16, _parse_nit,
617 (GDestroyNotify) _gst_mpegts_nit_free);
618
619 return (const GstMpegtsNIT *) section->cached_parsed;
620 }
621
622 /**
623 * gst_mpegts_nit_new:
624 *
625 * Allocates and initializes a #GstMpegtsNIT.
626 *
627 * Returns: (transfer full): A newly allocated #GstMpegtsNIT
628 */
629 GstMpegtsNIT *
gst_mpegts_nit_new(void)630 gst_mpegts_nit_new (void)
631 {
632 GstMpegtsNIT *nit;
633
634 nit = g_slice_new0 (GstMpegtsNIT);
635
636 nit->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
637 gst_mpegts_descriptor_free);
638 nit->streams = g_ptr_array_new_with_free_func ((GDestroyNotify)
639 _gst_mpegts_nit_stream_free);
640
641 return nit;
642 }
643
644 /**
645 * gst_mpegts_nit_stream_new:
646 *
647 * Allocates and initializes a #GstMpegtsNITStream
648 *
649 * Returns: (transfer full): A newly allocated #GstMpegtsNITStream
650 */
651 GstMpegtsNITStream *
gst_mpegts_nit_stream_new(void)652 gst_mpegts_nit_stream_new (void)
653 {
654 GstMpegtsNITStream *stream;
655
656 stream = g_slice_new0 (GstMpegtsNITStream);
657
658 stream->descriptors = g_ptr_array_new_with_free_func (
659 (GDestroyNotify) gst_mpegts_descriptor_free);
660
661 return stream;
662 }
663
664 static gboolean
_packetize_nit(GstMpegtsSection * section)665 _packetize_nit (GstMpegtsSection * section)
666 {
667 gsize length, network_length, loop_length;
668 const GstMpegtsNIT *nit;
669 GstMpegtsNITStream *stream;
670 GstMpegtsDescriptor *descriptor;
671 guint i, j;
672 guint8 *data, *pos;
673
674 nit = gst_mpegts_section_get_nit (section);
675
676 if (nit == NULL)
677 return FALSE;
678
679 /* 8 byte common section fields
680 2 byte network_descriptors_length
681 2 byte transport_stream_loop_length
682 4 byte CRC */
683 length = 16;
684
685 /* Find length of network descriptors */
686 network_length = 0;
687 if (nit->descriptors) {
688 for (i = 0; i < nit->descriptors->len; i++) {
689 descriptor = g_ptr_array_index (nit->descriptors, i);
690 network_length += descriptor->length + 2;
691 }
692 }
693
694 /* Find length of loop */
695 loop_length = 0;
696 if (nit->streams) {
697 for (i = 0; i < nit->streams->len; i++) {
698 stream = g_ptr_array_index (nit->streams, i);
699 loop_length += 6;
700 if (stream->descriptors) {
701 for (j = 0; j < stream->descriptors->len; j++) {
702 descriptor = g_ptr_array_index (stream->descriptors, j);
703 loop_length += descriptor->length + 2;
704 }
705 }
706 }
707 }
708
709 length += network_length + loop_length;
710
711 /* Max length of NIT section is 1024 bytes */
712 g_return_val_if_fail (length <= 1024, FALSE);
713
714 _packetize_common_section (section, length);
715
716 data = section->data + 8;
717 /* reserved - 4 bit
718 network_descriptors_length - 12 bit uimsbf */
719 GST_WRITE_UINT16_BE (data, network_length | 0xF000);
720 data += 2;
721
722 _packetize_descriptor_array (nit->descriptors, &data);
723
724 /* reserved - 4 bit
725 transport_stream_loop_length - 12 bit uimsbf */
726 GST_WRITE_UINT16_BE (data, loop_length | 0xF000);
727 data += 2;
728
729 if (nit->streams) {
730 for (i = 0; i < nit->streams->len; i++) {
731 stream = g_ptr_array_index (nit->streams, i);
732 /* transport_stream_id - 16 bit uimsbf */
733 GST_WRITE_UINT16_BE (data, stream->transport_stream_id);
734 data += 2;
735
736 /* original_network_id - 16 bit uimsbf */
737 GST_WRITE_UINT16_BE (data, stream->original_network_id);
738 data += 2;
739
740 /* reserved - 4 bit
741 transport_descriptors_length - 12 bit uimsbf
742
743 Set length to zero, and update in loop */
744 pos = data;
745 *data++ = 0xF0;
746 *data++ = 0x00;
747
748 _packetize_descriptor_array (stream->descriptors, &data);
749
750 /* Go back and update the descriptor length */
751 GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
752 }
753 }
754
755 return TRUE;
756 }
757
758 /**
759 * gst_mpegts_section_from_nit:
760 * @nit: (transfer full): a #GstMpegtsNIT to create the #GstMpegtsSection from
761 *
762 * Ownership of @nit is taken. The data in @nit is managed by the #GstMpegtsSection
763 *
764 * Returns: (transfer full): the #GstMpegtsSection
765 */
766 GstMpegtsSection *
gst_mpegts_section_from_nit(GstMpegtsNIT * nit)767 gst_mpegts_section_from_nit (GstMpegtsNIT * nit)
768 {
769 GstMpegtsSection *section;
770
771 g_return_val_if_fail (nit != NULL, NULL);
772
773 if (nit->actual_network)
774 section = _gst_mpegts_section_init (0x10,
775 GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK);
776 else
777 section = _gst_mpegts_section_init (0x10,
778 GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK);
779
780 section->subtable_extension = nit->network_id;
781 section->cached_parsed = (gpointer) nit;
782 section->packetizer = _packetize_nit;
783 section->destroy_parsed = (GDestroyNotify) _gst_mpegts_nit_free;
784
785 return section;
786 }
787
788 /* Service Description Table (SDT) */
789
790 static GstMpegtsSDTService *
_gst_mpegts_sdt_service_copy(GstMpegtsSDTService * sdt)791 _gst_mpegts_sdt_service_copy (GstMpegtsSDTService * sdt)
792 {
793 GstMpegtsSDTService *copy = g_slice_dup (GstMpegtsSDTService, sdt);
794
795 copy->descriptors = g_ptr_array_ref (sdt->descriptors);
796
797 return copy;
798 }
799
800 static void
_gst_mpegts_sdt_service_free(GstMpegtsSDTService * sdt)801 _gst_mpegts_sdt_service_free (GstMpegtsSDTService * sdt)
802 {
803 if (sdt->descriptors)
804 g_ptr_array_unref (sdt->descriptors);
805 g_slice_free (GstMpegtsSDTService, sdt);
806 }
807
808 G_DEFINE_BOXED_TYPE (GstMpegtsSDTService, gst_mpegts_sdt_service,
809 (GBoxedCopyFunc) _gst_mpegts_sdt_service_copy,
810 (GFreeFunc) _gst_mpegts_sdt_service_free);
811
812 static GstMpegtsSDT *
_gst_mpegts_sdt_copy(GstMpegtsSDT * sdt)813 _gst_mpegts_sdt_copy (GstMpegtsSDT * sdt)
814 {
815 GstMpegtsSDT *copy = g_slice_dup (GstMpegtsSDT, sdt);
816
817 copy->services = g_ptr_array_ref (sdt->services);
818
819 return copy;
820 }
821
822 static void
_gst_mpegts_sdt_free(GstMpegtsSDT * sdt)823 _gst_mpegts_sdt_free (GstMpegtsSDT * sdt)
824 {
825 g_ptr_array_unref (sdt->services);
826 g_slice_free (GstMpegtsSDT, sdt);
827 }
828
829 G_DEFINE_BOXED_TYPE (GstMpegtsSDT, gst_mpegts_sdt,
830 (GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_free);
831
832
833 static gpointer
_parse_sdt(GstMpegtsSection * section)834 _parse_sdt (GstMpegtsSection * section)
835 {
836 GstMpegtsSDT *sdt = NULL;
837 guint i = 0, allocated_services = 8;
838 guint8 *data, *end, *entry_begin;
839 guint tmp;
840 guint sdt_info_length;
841 guint descriptors_loop_length;
842
843 GST_DEBUG ("SDT");
844
845 sdt = g_slice_new0 (GstMpegtsSDT);
846
847 data = section->data;
848 end = data + section->section_length;
849
850 sdt->transport_stream_id = section->subtable_extension;
851
852 /* Skip common fields */
853 data += 8;
854
855 sdt->original_network_id = GST_READ_UINT16_BE (data);
856 data += 2;
857
858 /* skip reserved byte */
859 data += 1;
860
861 sdt->actual_ts = section->table_id == 0x42;
862
863 sdt_info_length = section->section_length - 11;
864
865 sdt->services = g_ptr_array_new_full (allocated_services,
866 (GDestroyNotify) _gst_mpegts_sdt_service_free);
867
868 /* read up to the CRC */
869 while (sdt_info_length - 4 > 0) {
870 GstMpegtsSDTService *service = g_slice_new0 (GstMpegtsSDTService);
871 g_ptr_array_add (sdt->services, service);
872
873 entry_begin = data;
874
875 if (sdt_info_length - 4 < 5) {
876 /* each entry must be at least 5 bytes (+4 bytes for the CRC) */
877 GST_WARNING ("PID %d invalid SDT entry size %d",
878 section->pid, sdt_info_length);
879 goto error;
880 }
881
882 service->service_id = GST_READ_UINT16_BE (data);
883 data += 2;
884
885 service->EIT_schedule_flag = ((*data & 0x02) == 2);
886 service->EIT_present_following_flag = (*data & 0x01) == 1;
887
888 data += 1;
889 tmp = GST_READ_UINT16_BE (data);
890
891 service->running_status = (*data >> 5) & 0x07;
892 service->free_CA_mode = (*data >> 4) & 0x01;
893
894 descriptors_loop_length = tmp & 0x0FFF;
895 data += 2;
896
897 if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
898 GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d",
899 section->pid, service->service_id, descriptors_loop_length);
900 goto error;
901 }
902 service->descriptors =
903 gst_mpegts_parse_descriptors (data, descriptors_loop_length);
904 if (!service->descriptors)
905 goto error;
906 data += descriptors_loop_length;
907
908 sdt_info_length -= data - entry_begin;
909 i += 1;
910 }
911
912 if (data != end - 4) {
913 GST_WARNING ("PID %d invalid SDT parsed %d length %d",
914 section->pid, (gint) (data - section->data), section->section_length);
915 goto error;
916 }
917
918 return sdt;
919
920 error:
921 if (sdt)
922 _gst_mpegts_sdt_free (sdt);
923
924 return NULL;
925 }
926
927 /**
928 * gst_mpegts_section_get_sdt:
929 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SDT
930 *
931 * Returns the #GstMpegtsSDT contained in the @section.
932 *
933 * Returns: The #GstMpegtsSDT contained in the section, or %NULL if an error
934 * happened.
935 */
936 const GstMpegtsSDT *
gst_mpegts_section_get_sdt(GstMpegtsSection * section)937 gst_mpegts_section_get_sdt (GstMpegtsSection * section)
938 {
939 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SDT, NULL);
940 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
941
942 if (!section->cached_parsed)
943 section->cached_parsed =
944 __common_section_checks (section, 15, _parse_sdt,
945 (GDestroyNotify) _gst_mpegts_sdt_free);
946
947 return (const GstMpegtsSDT *) section->cached_parsed;
948 }
949
950 /**
951 * gst_mpegts_sdt_new:
952 *
953 * Allocates and initializes a #GstMpegtsSDT.
954 *
955 * Returns: (transfer full): A newly allocated #GstMpegtsSDT
956 */
957 GstMpegtsSDT *
gst_mpegts_sdt_new(void)958 gst_mpegts_sdt_new (void)
959 {
960 GstMpegtsSDT *sdt;
961
962 sdt = g_slice_new0 (GstMpegtsSDT);
963
964 sdt->services = g_ptr_array_new_with_free_func ((GDestroyNotify)
965 _gst_mpegts_sdt_service_free);
966
967 return sdt;
968 }
969
970 /**
971 * gst_mpegts_sdt_service_new:
972 *
973 * Allocates and initializes a #GstMpegtsSDTService.
974 *
975 * Returns: (transfer full): A newly allocated #GstMpegtsSDTService
976 */
977 GstMpegtsSDTService *
gst_mpegts_sdt_service_new(void)978 gst_mpegts_sdt_service_new (void)
979 {
980 GstMpegtsSDTService *service;
981
982 service = g_slice_new0 (GstMpegtsSDTService);
983
984 service->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
985 gst_mpegts_descriptor_free);
986
987 return service;
988 }
989
990 static gboolean
_packetize_sdt(GstMpegtsSection * section)991 _packetize_sdt (GstMpegtsSection * section)
992 {
993 gsize length, service_length;
994 const GstMpegtsSDT *sdt;
995 GstMpegtsSDTService *service;
996 GstMpegtsDescriptor *descriptor;
997 guint i, j;
998 guint8 *data, *pos;
999
1000 sdt = gst_mpegts_section_get_sdt (section);
1001
1002 if (sdt == NULL)
1003 return FALSE;
1004
1005 /* 8 byte common section fields
1006 2 byte original_network_id
1007 1 byte reserved
1008 4 byte CRC */
1009 length = 15;
1010
1011 /* Find length of services */
1012 service_length = 0;
1013 if (sdt->services) {
1014 for (i = 0; i < sdt->services->len; i++) {
1015 service = g_ptr_array_index (sdt->services, i);
1016 service_length += 5;
1017 if (service->descriptors) {
1018 for (j = 0; j < service->descriptors->len; j++) {
1019 descriptor = g_ptr_array_index (service->descriptors, j);
1020 service_length += descriptor->length + 2;
1021 }
1022 }
1023 }
1024 }
1025
1026 length += service_length;
1027
1028 /* Max length if SDT section is 1024 bytes */
1029 g_return_val_if_fail (length <= 1024, FALSE);
1030
1031 _packetize_common_section (section, length);
1032
1033 data = section->data + 8;
1034 /* original_network_id - 16 bit uimsbf */
1035 GST_WRITE_UINT16_BE (data, sdt->original_network_id);
1036 data += 2;
1037 /* reserved - 8 bit */
1038 *data++ = 0xFF;
1039
1040 if (sdt->services) {
1041 for (i = 0; i < sdt->services->len; i++) {
1042 service = g_ptr_array_index (sdt->services, i);
1043 /* service_id - 16 bit uimsbf */
1044 GST_WRITE_UINT16_BE (data, service->service_id);
1045 data += 2;
1046
1047 /* reserved - 6 bit
1048 EIT_schedule_flag - 1 bit
1049 EIT_present_following_flag - 1 bit */
1050 *data = 0xFC;
1051 if (service->EIT_schedule_flag)
1052 *data |= 0x02;
1053 if (service->EIT_present_following_flag)
1054 *data |= 0x01;
1055 data++;
1056
1057 /* running_status - 3 bit uimsbf
1058 free_CA_mode - 1 bit
1059 descriptors_loop_length - 12 bit uimsbf */
1060 /* Set length to zero for now */
1061 pos = data;
1062 *data++ = 0x00;
1063 *data++ = 0x00;
1064
1065 _packetize_descriptor_array (service->descriptors, &data);
1066
1067 /* Go back and update the descriptor length */
1068 GST_WRITE_UINT16_BE (pos, data - pos - 2);
1069
1070 *pos |= service->running_status << 5;
1071 if (service->free_CA_mode)
1072 *pos |= 0x10;
1073 }
1074 }
1075
1076 return TRUE;
1077 }
1078
1079 /**
1080 * gst_mpegts_section_from_sdt:
1081 * @sdt: (transfer full): a #GstMpegtsSDT to create the #GstMpegtsSection from
1082 *
1083 * Ownership of @sdt is taken. The data in @sdt is managed by the #GstMpegtsSection
1084 *
1085 * Returns: (transfer full): the #GstMpegtsSection
1086 */
1087 GstMpegtsSection *
gst_mpegts_section_from_sdt(GstMpegtsSDT * sdt)1088 gst_mpegts_section_from_sdt (GstMpegtsSDT * sdt)
1089 {
1090 GstMpegtsSection *section;
1091
1092 g_return_val_if_fail (sdt != NULL, NULL);
1093
1094 if (sdt->actual_ts)
1095 section = _gst_mpegts_section_init (0x11,
1096 GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_ACTUAL_TS);
1097 else
1098 section = _gst_mpegts_section_init (0x11,
1099 GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_OTHER_TS);
1100
1101 section->subtable_extension = sdt->transport_stream_id;
1102 section->cached_parsed = (gpointer) sdt;
1103 section->packetizer = _packetize_sdt;
1104 section->destroy_parsed = (GDestroyNotify) _gst_mpegts_sdt_free;
1105
1106 return section;
1107 }
1108
1109 /* Time and Date Table (TDT) */
1110 static gpointer
_parse_tdt(GstMpegtsSection * section)1111 _parse_tdt (GstMpegtsSection * section)
1112 {
1113 return (gpointer) _parse_utc_time (section->data + 3);
1114 }
1115
1116 /**
1117 * gst_mpegts_section_get_tdt:
1118 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_TDT
1119 *
1120 * Returns the #GstDateTime of the TDT
1121 *
1122 * Returns: The #GstDateTime contained in the section, or %NULL
1123 * if an error happened. Release with #gst_date_time_unref when done.
1124 */
1125 GstDateTime *
gst_mpegts_section_get_tdt(GstMpegtsSection * section)1126 gst_mpegts_section_get_tdt (GstMpegtsSection * section)
1127 {
1128 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TDT, NULL);
1129 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1130
1131 if (!section->cached_parsed)
1132 section->cached_parsed =
1133 __common_section_checks (section, 8, _parse_tdt,
1134 (GDestroyNotify) gst_date_time_unref);
1135
1136 if (section->cached_parsed)
1137 return gst_date_time_ref ((GstDateTime *) section->cached_parsed);
1138 return NULL;
1139 }
1140
1141
1142 /* Time Offset Table (TOT) */
1143 static GstMpegtsTOT *
_gst_mpegts_tot_copy(GstMpegtsTOT * tot)1144 _gst_mpegts_tot_copy (GstMpegtsTOT * tot)
1145 {
1146 GstMpegtsTOT *copy = g_slice_dup (GstMpegtsTOT, tot);
1147
1148 if (tot->utc_time)
1149 copy->utc_time = gst_date_time_ref (tot->utc_time);
1150 copy->descriptors = g_ptr_array_ref (tot->descriptors);
1151
1152 return copy;
1153 }
1154
1155 static void
_gst_mpegts_tot_free(GstMpegtsTOT * tot)1156 _gst_mpegts_tot_free (GstMpegtsTOT * tot)
1157 {
1158 if (tot->utc_time)
1159 gst_date_time_unref (tot->utc_time);
1160 if (tot->descriptors)
1161 g_ptr_array_unref (tot->descriptors);
1162 g_slice_free (GstMpegtsTOT, tot);
1163 }
1164
1165 G_DEFINE_BOXED_TYPE (GstMpegtsTOT, gst_mpegts_tot,
1166 (GBoxedCopyFunc) _gst_mpegts_tot_copy, (GFreeFunc) _gst_mpegts_tot_free);
1167
1168 static gpointer
_parse_tot(GstMpegtsSection * section)1169 _parse_tot (GstMpegtsSection * section)
1170 {
1171 guint8 *data;
1172 GstMpegtsTOT *tot;
1173 guint16 desc_len;
1174
1175 GST_DEBUG ("TOT");
1176
1177 tot = g_slice_new0 (GstMpegtsTOT);
1178
1179 tot->utc_time = _parse_utc_time (section->data + 3);
1180
1181 /* Skip 5 bytes from utc_time (+3 of initial offset) */
1182 data = section->data + 8;
1183
1184 desc_len = GST_READ_UINT16_BE (data) & 0xFFF;
1185 data += 2;
1186 tot->descriptors = gst_mpegts_parse_descriptors (data, desc_len);
1187
1188 return (gpointer) tot;
1189 }
1190
1191 /**
1192 * gst_mpegts_section_get_tot:
1193 * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_TOT
1194 *
1195 * Returns the #GstMpegtsTOT contained in the @section.
1196 *
1197 * Returns: The #GstMpegtsTOT contained in the section, or %NULL if an error
1198 * happened.
1199 */
1200 const GstMpegtsTOT *
gst_mpegts_section_get_tot(GstMpegtsSection * section)1201 gst_mpegts_section_get_tot (GstMpegtsSection * section)
1202 {
1203 g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TOT, NULL);
1204 g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1205
1206 if (!section->cached_parsed)
1207 section->cached_parsed =
1208 __common_section_checks (section, 14, _parse_tot,
1209 (GDestroyNotify) _gst_mpegts_tot_free);
1210
1211 return (const GstMpegtsTOT *) section->cached_parsed;
1212 }
1213