• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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