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