1 /*
2  * Copyright (C) 2014 Stefan Ringel
3  *
4  * Authors:
5  *   Stefan Ringel <linuxtv@stefanringel.de>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <string.h>
27 #include <stdlib.h>
28 
29 #include "mpegts.h"
30 #include "gstmpegts-private.h"
31 
32 /**
33  * SECTION:gst-atsc-section
34  * @title: ATSC variants of MPEG-TS sections
35  * @short_description: Sections for the various ATSC specifications
36  * @include: gst/mpegts/mpegts.h
37  *
38  */
39 
40 /* Terrestrial/Cable Virtual Channel Table TVCT/CVCT */
41 static GstMpegtsAtscVCTSource *
_gst_mpegts_atsc_vct_source_copy(GstMpegtsAtscVCTSource * source)42 _gst_mpegts_atsc_vct_source_copy (GstMpegtsAtscVCTSource * source)
43 {
44   GstMpegtsAtscVCTSource *copy;
45 
46   copy = g_slice_dup (GstMpegtsAtscVCTSource, source);
47   copy->descriptors = g_ptr_array_ref (source->descriptors);
48 
49   return copy;
50 }
51 
52 static void
_gst_mpegts_atsc_vct_source_free(GstMpegtsAtscVCTSource * source)53 _gst_mpegts_atsc_vct_source_free (GstMpegtsAtscVCTSource * source)
54 {
55   g_free (source->short_name);
56   if (source->descriptors)
57     g_ptr_array_unref (source->descriptors);
58   g_slice_free (GstMpegtsAtscVCTSource, source);
59 }
60 
61 G_DEFINE_BOXED_TYPE (GstMpegtsAtscVCTSource, gst_mpegts_atsc_vct_source,
62     (GBoxedCopyFunc) _gst_mpegts_atsc_vct_source_copy,
63     (GFreeFunc) _gst_mpegts_atsc_vct_source_free);
64 
65 static GstMpegtsAtscVCT *
_gst_mpegts_atsc_vct_copy(GstMpegtsAtscVCT * vct)66 _gst_mpegts_atsc_vct_copy (GstMpegtsAtscVCT * vct)
67 {
68   GstMpegtsAtscVCT *copy;
69 
70   copy = g_slice_dup (GstMpegtsAtscVCT, vct);
71   copy->sources = g_ptr_array_ref (vct->sources);
72   copy->descriptors = g_ptr_array_ref (vct->descriptors);
73 
74   return copy;
75 }
76 
77 static void
_gst_mpegts_atsc_vct_free(GstMpegtsAtscVCT * vct)78 _gst_mpegts_atsc_vct_free (GstMpegtsAtscVCT * vct)
79 {
80   if (vct->sources)
81     g_ptr_array_unref (vct->sources);
82   if (vct->descriptors)
83     g_ptr_array_unref (vct->descriptors);
84   g_slice_free (GstMpegtsAtscVCT, vct);
85 }
86 
87 G_DEFINE_BOXED_TYPE (GstMpegtsAtscVCT, gst_mpegts_atsc_vct,
88     (GBoxedCopyFunc) _gst_mpegts_atsc_vct_copy,
89     (GFreeFunc) _gst_mpegts_atsc_vct_free);
90 
91 static gpointer
_parse_atsc_vct(GstMpegtsSection * section)92 _parse_atsc_vct (GstMpegtsSection * section)
93 {
94   GstMpegtsAtscVCT *vct = NULL;
95   guint8 *data, *end, source_nb;
96   guint32 tmp32;
97   guint16 descriptors_loop_length, tmp16;
98   guint i;
99   GError *err = NULL;
100 
101   vct = g_slice_new0 (GstMpegtsAtscVCT);
102 
103   data = section->data;
104   end = data + section->section_length;
105 
106   vct->transport_stream_id = section->subtable_extension;
107 
108   /* Skip already parsed data */
109   data += 8;
110 
111   /* minimum size */
112   if (end - data < 2 + 2 + 4)
113     goto error;
114 
115   vct->protocol_version = *data;
116   data += 1;
117 
118   source_nb = *data;
119   data += 1;
120 
121   vct->sources = g_ptr_array_new_full (source_nb,
122       (GDestroyNotify) _gst_mpegts_atsc_vct_source_free);
123 
124   for (i = 0; i < source_nb; i++) {
125     GstMpegtsAtscVCTSource *source;
126 
127     /* minimum 32 bytes for a entry, 2 bytes second descriptor
128        loop-length, 4 bytes crc */
129     if (end - data < 32 + 2 + 4)
130       goto error;
131 
132     source = g_slice_new0 (GstMpegtsAtscVCTSource);
133     g_ptr_array_add (vct->sources, source);
134 
135     source->short_name =
136         g_convert ((gchar *) data, 14, "utf-8", "utf-16be", NULL, NULL, &err);
137     if (err) {
138       GST_WARNING ("Failed to convert VCT Source short_name to utf-8: %d %s",
139           err->code, err->message);
140       GST_MEMDUMP ("UTF-16 string", data, 14);
141       g_error_free (err);
142     }
143     data += 14;
144 
145     tmp32 = GST_READ_UINT32_BE (data);
146     source->major_channel_number = (tmp32 >> 18) & 0x03FF;
147     source->minor_channel_number = (tmp32 >> 8) & 0x03FF;
148     source->modulation_mode = tmp32 & 0xF;
149     data += 4;
150 
151     source->carrier_frequency = GST_READ_UINT32_BE (data);
152     data += 4;
153 
154     source->channel_TSID = GST_READ_UINT16_BE (data);
155     data += 2;
156 
157     source->program_number = GST_READ_UINT16_BE (data);
158     data += 2;
159 
160     tmp16 = GST_READ_UINT16_BE (data);
161     source->ETM_location = (tmp16 >> 14) & 0x3;
162     source->access_controlled = (tmp16 >> 13) & 0x1;
163     source->hidden = (tmp16 >> 12) & 0x1;
164 
165     /* only used in CVCT */
166     source->path_select = (tmp16 >> 11) & 0x1;
167     source->out_of_band = (tmp16 >> 10) & 0x1;
168 
169     source->hide_guide = (tmp16 >> 9) & 0x1;
170     source->service_type = tmp16 & 0x3f;
171     data += 2;
172 
173     source->source_id = GST_READ_UINT16_BE (data);
174     data += 2;
175 
176     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x03FF;
177     data += 2;
178 
179     if (end - data < descriptors_loop_length + 6)
180       goto error;
181 
182     source->descriptors =
183         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
184     if (source->descriptors == NULL)
185       goto error;
186     data += descriptors_loop_length;
187   }
188 
189   descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x03FF;
190   data += 2;
191 
192   if (end - data < descriptors_loop_length + 4)
193     goto error;
194 
195   vct->descriptors =
196       gst_mpegts_parse_descriptors (data, descriptors_loop_length);
197   if (vct->descriptors == NULL)
198     goto error;
199 
200   return (gpointer) vct;
201 
202 error:
203   _gst_mpegts_atsc_vct_free (vct);
204 
205   return NULL;
206 }
207 
208 /**
209  * gst_mpegts_section_get_atsc_tvct:
210  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_TVCT
211  *
212  * Returns the #GstMpegtsAtscVCT contained in the @section
213  *
214  * Returns: The #GstMpegtsAtscVCT contained in the section, or %NULL if an error
215  * happened.
216  */
217 const GstMpegtsAtscVCT *
gst_mpegts_section_get_atsc_tvct(GstMpegtsSection * section)218 gst_mpegts_section_get_atsc_tvct (GstMpegtsSection * section)
219 {
220   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_TVCT,
221       NULL);
222   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
223 
224   if (!section->cached_parsed)
225     section->cached_parsed =
226         __common_section_checks (section, 16, _parse_atsc_vct,
227         (GDestroyNotify) _gst_mpegts_atsc_vct_free);
228 
229   return (const GstMpegtsAtscVCT *) section->cached_parsed;
230 }
231 
232 /**
233  * gst_mpegts_section_get_atsc_cvct:
234  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_CVCT
235  *
236  * Returns the #GstMpegtsAtscVCT contained in the @section
237  *
238  * Returns: The #GstMpegtsAtscVCT contained in the section, or %NULL if an error
239  * happened.
240  */
241 const GstMpegtsAtscVCT *
gst_mpegts_section_get_atsc_cvct(GstMpegtsSection * section)242 gst_mpegts_section_get_atsc_cvct (GstMpegtsSection * section)
243 {
244   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_CVCT,
245       NULL);
246   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
247 
248   if (!section->cached_parsed)
249     section->cached_parsed =
250         __common_section_checks (section, 16, _parse_atsc_vct,
251         (GDestroyNotify) _gst_mpegts_atsc_vct_free);
252 
253   return (const GstMpegtsAtscVCT *) section->cached_parsed;
254 }
255 
256 /* MGT */
257 
258 static GstMpegtsAtscMGTTable *
_gst_mpegts_atsc_mgt_table_copy(GstMpegtsAtscMGTTable * mgt_table)259 _gst_mpegts_atsc_mgt_table_copy (GstMpegtsAtscMGTTable * mgt_table)
260 {
261   GstMpegtsAtscMGTTable *copy;
262 
263   copy = g_slice_dup (GstMpegtsAtscMGTTable, mgt_table);
264   copy->descriptors = g_ptr_array_ref (mgt_table->descriptors);
265 
266   return copy;
267 }
268 
269 static void
_gst_mpegts_atsc_mgt_table_free(GstMpegtsAtscMGTTable * mgt_table)270 _gst_mpegts_atsc_mgt_table_free (GstMpegtsAtscMGTTable * mgt_table)
271 {
272   g_ptr_array_unref (mgt_table->descriptors);
273   g_slice_free (GstMpegtsAtscMGTTable, mgt_table);
274 }
275 
276 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMGTTable, gst_mpegts_atsc_mgt_table,
277     (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_table_copy,
278     (GFreeFunc) _gst_mpegts_atsc_mgt_table_free);
279 
280 static GstMpegtsAtscMGT *
_gst_mpegts_atsc_mgt_copy(GstMpegtsAtscMGT * mgt)281 _gst_mpegts_atsc_mgt_copy (GstMpegtsAtscMGT * mgt)
282 {
283   GstMpegtsAtscMGT *copy;
284 
285   copy = g_slice_dup (GstMpegtsAtscMGT, mgt);
286   copy->tables = g_ptr_array_ref (mgt->tables);
287   copy->descriptors = g_ptr_array_ref (mgt->descriptors);
288 
289   return copy;
290 }
291 
292 static void
_gst_mpegts_atsc_mgt_free(GstMpegtsAtscMGT * mgt)293 _gst_mpegts_atsc_mgt_free (GstMpegtsAtscMGT * mgt)
294 {
295   g_ptr_array_unref (mgt->tables);
296   g_ptr_array_unref (mgt->descriptors);
297   g_slice_free (GstMpegtsAtscMGT, mgt);
298 }
299 
300 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMGT, gst_mpegts_atsc_mgt,
301     (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_copy,
302     (GFreeFunc) _gst_mpegts_atsc_mgt_free);
303 
304 static gpointer
_parse_atsc_mgt(GstMpegtsSection * section)305 _parse_atsc_mgt (GstMpegtsSection * section)
306 {
307   GstMpegtsAtscMGT *mgt = NULL;
308   guint i = 0;
309   guint8 *data, *end;
310   guint16 descriptors_loop_length;
311 
312   mgt = g_slice_new0 (GstMpegtsAtscMGT);
313 
314   data = section->data;
315   end = data + section->section_length;
316 
317   /* Skip already parsed data */
318   data += 8;
319 
320   mgt->protocol_version = GST_READ_UINT8 (data);
321   data += 1;
322   mgt->tables_defined = GST_READ_UINT16_BE (data);
323   data += 2;
324   mgt->tables = g_ptr_array_new_full (mgt->tables_defined,
325       (GDestroyNotify) _gst_mpegts_atsc_mgt_table_free);
326   for (i = 0; i < mgt->tables_defined && data + 11 < end; i++) {
327     GstMpegtsAtscMGTTable *mgt_table;
328 
329     if (data + 11 >= end) {
330       GST_WARNING ("MGT data too short to parse inner table num %d", i);
331       goto error;
332     }
333 
334     mgt_table = g_slice_new0 (GstMpegtsAtscMGTTable);
335     g_ptr_array_add (mgt->tables, mgt_table);
336 
337     mgt_table->table_type = GST_READ_UINT16_BE (data);
338     data += 2;
339     mgt_table->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
340     data += 2;
341     mgt_table->version_number = GST_READ_UINT8 (data) & 0x1F;
342     data += 1;
343     mgt_table->number_bytes = GST_READ_UINT32_BE (data);
344     data += 4;
345     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
346     data += 2;
347 
348     if (data + descriptors_loop_length >= end) {
349       GST_WARNING ("MGT data too short to parse inner table descriptors (table "
350           "num %d", i);
351       goto error;
352     }
353     mgt_table->descriptors =
354         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
355     data += descriptors_loop_length;
356   }
357 
358   descriptors_loop_length = GST_READ_UINT16_BE (data) & 0xFFF;
359   data += 2;
360   if (data + descriptors_loop_length >= end) {
361     GST_WARNING ("MGT data too short to parse descriptors");
362     goto error;
363   }
364   mgt->descriptors =
365       gst_mpegts_parse_descriptors (data, descriptors_loop_length);
366 
367   return (gpointer) mgt;
368 
369 error:
370   _gst_mpegts_atsc_mgt_free (mgt);
371 
372   return NULL;
373 }
374 
375 
376 /**
377  * gst_mpegts_section_get_atsc_mgt:
378  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_MGT
379  *
380  * Returns the #GstMpegtsAtscMGT contained in the @section.
381  *
382  * Returns: The #GstMpegtsAtscMGT contained in the section, or %NULL if an error
383  * happened.
384  */
385 const GstMpegtsAtscMGT *
gst_mpegts_section_get_atsc_mgt(GstMpegtsSection * section)386 gst_mpegts_section_get_atsc_mgt (GstMpegtsSection * section)
387 {
388   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_MGT,
389       NULL);
390   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
391 
392   if (!section->cached_parsed)
393     section->cached_parsed =
394         __common_section_checks (section, 17, _parse_atsc_mgt,
395         (GDestroyNotify) _gst_mpegts_atsc_mgt_free);
396 
397   return (const GstMpegtsAtscMGT *) section->cached_parsed;
398 }
399 
400 /* Multi string structure */
401 
402 static GstMpegtsAtscStringSegment *
_gst_mpegts_atsc_string_segment_copy(GstMpegtsAtscStringSegment * seg)403 _gst_mpegts_atsc_string_segment_copy (GstMpegtsAtscStringSegment * seg)
404 {
405   GstMpegtsAtscStringSegment *copy;
406 
407   copy = g_slice_dup (GstMpegtsAtscStringSegment, seg);
408 
409   return copy;
410 }
411 
412 static void
_gst_mpegts_atsc_string_segment_free(GstMpegtsAtscStringSegment * seg)413 _gst_mpegts_atsc_string_segment_free (GstMpegtsAtscStringSegment * seg)
414 {
415   g_free (seg->cached_string);
416   g_slice_free (GstMpegtsAtscStringSegment, seg);
417 }
418 
419 static void
_gst_mpegts_atsc_string_segment_decode_string(GstMpegtsAtscStringSegment * seg)420 _gst_mpegts_atsc_string_segment_decode_string (GstMpegtsAtscStringSegment * seg)
421 {
422   const gchar *from_encoding;
423 
424   g_return_if_fail (seg->cached_string == NULL);
425 
426   if (seg->compression_type != 0) {
427     GST_FIXME ("Compressed strings not yet supported");
428     return;
429   }
430 
431   /* FIXME add more encodings */
432   switch (seg->mode) {
433     case 0x3F:
434       from_encoding = "UTF-16BE";
435       break;
436     default:
437       from_encoding = NULL;
438       break;
439   }
440 
441   if (from_encoding != NULL && seg->compressed_data_size > 0) {
442     GError *err = NULL;
443 
444     seg->cached_string =
445         g_convert ((gchar *) seg->compressed_data,
446         (gssize) seg->compressed_data_size, "UTF-8", from_encoding, NULL, NULL,
447         &err);
448 
449     if (err) {
450       GST_WARNING ("Failed to convert input string from codeset %s",
451           from_encoding);
452       g_error_free (err);
453     }
454   } else {
455     seg->cached_string =
456         g_strndup ((gchar *) seg->compressed_data, seg->compressed_data_size);
457   }
458 }
459 
460 const gchar *
gst_mpegts_atsc_string_segment_get_string(GstMpegtsAtscStringSegment * seg)461 gst_mpegts_atsc_string_segment_get_string (GstMpegtsAtscStringSegment * seg)
462 {
463   if (!seg->cached_string)
464     _gst_mpegts_atsc_string_segment_decode_string (seg);
465 
466   return seg->cached_string;
467 }
468 
469 G_DEFINE_BOXED_TYPE (GstMpegtsAtscStringSegment, gst_mpegts_atsc_string_segment,
470     (GBoxedCopyFunc) _gst_mpegts_atsc_string_segment_copy,
471     (GFreeFunc) _gst_mpegts_atsc_string_segment_free);
472 
473 static GstMpegtsAtscMultString *
_gst_mpegts_atsc_mult_string_copy(GstMpegtsAtscMultString * mstring)474 _gst_mpegts_atsc_mult_string_copy (GstMpegtsAtscMultString * mstring)
475 {
476   GstMpegtsAtscMultString *copy;
477 
478   copy = g_slice_dup (GstMpegtsAtscMultString, mstring);
479   copy->segments = g_ptr_array_ref (mstring->segments);
480 
481   return copy;
482 }
483 
484 static void
_gst_mpegts_atsc_mult_string_free(GstMpegtsAtscMultString * mstring)485 _gst_mpegts_atsc_mult_string_free (GstMpegtsAtscMultString * mstring)
486 {
487   g_ptr_array_unref (mstring->segments);
488   g_slice_free (GstMpegtsAtscMultString, mstring);
489 }
490 
491 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMultString, gst_mpegts_atsc_mult_string,
492     (GBoxedCopyFunc) _gst_mpegts_atsc_mult_string_copy,
493     (GFreeFunc) _gst_mpegts_atsc_mult_string_free);
494 
495 static GPtrArray *
_parse_atsc_mult_string(guint8 * data,guint datasize)496 _parse_atsc_mult_string (guint8 * data, guint datasize)
497 {
498   guint8 num_strings;
499   GPtrArray *res = NULL;
500   guint8 *end = data + datasize;
501   gint i;
502 
503   if (datasize > 0) {
504     /* 1 is the minimum entry size, so no need to check here */
505     num_strings = GST_READ_UINT8 (data);
506     data += 1;
507 
508     res =
509         g_ptr_array_new_full (num_strings,
510         (GDestroyNotify) _gst_mpegts_atsc_mult_string_free);
511 
512     for (i = 0; i < num_strings; i++) {
513       GstMpegtsAtscMultString *mstring;
514       guint8 num_segments;
515       gint j;
516 
517       mstring = g_slice_new0 (GstMpegtsAtscMultString);
518       g_ptr_array_add (res, mstring);
519       mstring->segments =
520           g_ptr_array_new_full (num_strings,
521           (GDestroyNotify) _gst_mpegts_atsc_string_segment_free);
522 
523       /* each entry needs at least 4 bytes (lang code and segments number) */
524       if (end - data < 4) {
525         GST_WARNING ("Data too short for multstring parsing %d",
526             (gint) (end - data));
527         goto error;
528       }
529 
530       mstring->iso_639_langcode[0] = GST_READ_UINT8 (data);
531       data += 1;
532       mstring->iso_639_langcode[1] = GST_READ_UINT8 (data);
533       data += 1;
534       mstring->iso_639_langcode[2] = GST_READ_UINT8 (data);
535       data += 1;
536       num_segments = GST_READ_UINT8 (data);
537       data += 1;
538 
539       for (j = 0; j < num_segments; j++) {
540         GstMpegtsAtscStringSegment *seg;
541 
542         seg = g_slice_new0 (GstMpegtsAtscStringSegment);
543         g_ptr_array_add (mstring->segments, seg);
544 
545         /* each entry needs at least 3 bytes */
546         if (end - data < 3) {
547           GST_WARNING ("Data too short for multstring parsing %d", datasize);
548           goto error;
549         }
550 
551         seg->compression_type = GST_READ_UINT8 (data);
552         data += 1;
553         seg->mode = GST_READ_UINT8 (data);
554         data += 1;
555         seg->compressed_data_size = GST_READ_UINT8 (data);
556         data += 1;
557 
558         if (end - data < seg->compressed_data_size) {
559           GST_WARNING ("Data too short for multstring parsing %d", datasize);
560           goto error;
561         }
562 
563         if (seg->compressed_data_size)
564           seg->compressed_data = data;
565         data += seg->compressed_data_size;
566       }
567 
568     }
569   }
570   return res;
571 
572 error:
573   if (res)
574     g_ptr_array_unref (res);
575   return NULL;
576 }
577 
578 /* EIT */
579 
580 static GstMpegtsAtscEITEvent *
_gst_mpegts_atsc_eit_event_copy(GstMpegtsAtscEITEvent * event)581 _gst_mpegts_atsc_eit_event_copy (GstMpegtsAtscEITEvent * event)
582 {
583   GstMpegtsAtscEITEvent *copy;
584 
585   copy = g_slice_dup (GstMpegtsAtscEITEvent, event);
586   copy->titles = g_ptr_array_ref (event->titles);
587   copy->descriptors = g_ptr_array_ref (event->descriptors);
588 
589   return copy;
590 }
591 
592 static void
_gst_mpegts_atsc_eit_event_free(GstMpegtsAtscEITEvent * event)593 _gst_mpegts_atsc_eit_event_free (GstMpegtsAtscEITEvent * event)
594 {
595   if (event->titles)
596     g_ptr_array_unref (event->titles);
597   if (event->descriptors)
598     g_ptr_array_unref (event->descriptors);
599   g_slice_free (GstMpegtsAtscEITEvent, event);
600 }
601 
602 G_DEFINE_BOXED_TYPE (GstMpegtsAtscEITEvent, gst_mpegts_atsc_eit_event,
603     (GBoxedCopyFunc) _gst_mpegts_atsc_eit_event_copy,
604     (GFreeFunc) _gst_mpegts_atsc_eit_event_free);
605 
606 static GstMpegtsAtscEIT *
_gst_mpegts_atsc_eit_copy(GstMpegtsAtscEIT * eit)607 _gst_mpegts_atsc_eit_copy (GstMpegtsAtscEIT * eit)
608 {
609   GstMpegtsAtscEIT *copy;
610 
611   copy = g_slice_dup (GstMpegtsAtscEIT, eit);
612   copy->events = g_ptr_array_ref (eit->events);
613 
614   return copy;
615 }
616 
617 static void
_gst_mpegts_atsc_eit_free(GstMpegtsAtscEIT * eit)618 _gst_mpegts_atsc_eit_free (GstMpegtsAtscEIT * eit)
619 {
620   if (eit->events)
621     g_ptr_array_unref (eit->events);
622   g_slice_free (GstMpegtsAtscEIT, eit);
623 }
624 
625 G_DEFINE_BOXED_TYPE (GstMpegtsAtscEIT, gst_mpegts_atsc_eit,
626     (GBoxedCopyFunc) _gst_mpegts_atsc_eit_copy,
627     (GFreeFunc) _gst_mpegts_atsc_eit_free);
628 
629 static gpointer
_parse_atsc_eit(GstMpegtsSection * section)630 _parse_atsc_eit (GstMpegtsSection * section)
631 {
632   GstMpegtsAtscEIT *eit = NULL;
633   guint i = 0;
634   guint8 *data, *end;
635   guint8 num_events;
636 
637   eit = g_slice_new0 (GstMpegtsAtscEIT);
638 
639   data = section->data;
640   end = data + section->section_length;
641 
642   eit->source_id = section->subtable_extension;
643 
644   /* Skip already parsed data */
645   data += 8;
646 
647   eit->protocol_version = GST_READ_UINT8 (data);
648   data += 1;
649   num_events = GST_READ_UINT8 (data);
650   data += 1;
651 
652   eit->events = g_ptr_array_new_with_free_func ((GDestroyNotify)
653       _gst_mpegts_atsc_eit_event_free);
654 
655   for (i = 0; i < num_events; i++) {
656     GstMpegtsAtscEITEvent *event;
657     guint32 tmp;
658     guint8 text_length;
659     guint16 descriptors_loop_length;
660 
661     if (end - data < 12) {
662       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
663           section->pid, (gint) (end - 4 - data), num_events);
664       goto error;
665     }
666 
667     event = g_slice_new0 (GstMpegtsAtscEITEvent);
668     g_ptr_array_add (eit->events, event);
669 
670     event->event_id = GST_READ_UINT16_BE (data) & 0x3FFF;
671     data += 2;
672     event->start_time = GST_READ_UINT32_BE (data);
673     data += 4;
674 
675     tmp = GST_READ_UINT32_BE (data);
676     data += 4;
677     event->etm_location = (tmp >> 28) & 0x3;
678     event->length_in_seconds = (tmp >> 8) & 0x0FFFFF;
679     text_length = tmp & 0xFF;
680 
681     if (text_length > end - data - 4 - 2) {
682       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
683           section->pid, (gint) (end - 4 - data), num_events);
684       goto error;
685     }
686     event->titles = _parse_atsc_mult_string (data, text_length);
687     data += text_length;
688 
689     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
690     data += 2;
691 
692     if (end - data - 4 < descriptors_loop_length) {
693       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
694           section->pid, (gint) (end - 4 - data), num_events);
695       goto error;
696     }
697 
698     event->descriptors =
699         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
700     data += descriptors_loop_length;
701   }
702 
703   if (data != end - 4) {
704     GST_WARNING ("PID %d invalid EIT parsed %d length %d",
705         section->pid, (gint) (data - section->data), section->section_length);
706     goto error;
707   }
708 
709   return (gpointer) eit;
710 
711 error:
712   _gst_mpegts_atsc_eit_free (eit);
713 
714   return NULL;
715 
716 }
717 
718 /**
719  * gst_mpegts_section_get_atsc_eit:
720  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_EIT
721  *
722  * Returns the #GstMpegtsAtscEIT contained in the @section.
723  *
724  * Returns: The #GstMpegtsAtscEIT contained in the section, or %NULL if an error
725  * happened.
726  */
727 const GstMpegtsAtscEIT *
gst_mpegts_section_get_atsc_eit(GstMpegtsSection * section)728 gst_mpegts_section_get_atsc_eit (GstMpegtsSection * section)
729 {
730   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_EIT,
731       NULL);
732   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
733 
734   if (!section->cached_parsed)
735     section->cached_parsed =
736         __common_section_checks (section, 14, _parse_atsc_eit,
737         (GDestroyNotify) _gst_mpegts_atsc_eit_free);
738 
739   return (const GstMpegtsAtscEIT *) section->cached_parsed;
740 }
741 
742 
743 static GstMpegtsAtscETT *
_gst_mpegts_atsc_ett_copy(GstMpegtsAtscETT * ett)744 _gst_mpegts_atsc_ett_copy (GstMpegtsAtscETT * ett)
745 {
746   GstMpegtsAtscETT *copy;
747 
748   copy = g_slice_dup (GstMpegtsAtscETT, ett);
749   copy->messages = g_ptr_array_ref (ett->messages);
750 
751   return copy;
752 }
753 
754 static void
_gst_mpegts_atsc_ett_free(GstMpegtsAtscETT * ett)755 _gst_mpegts_atsc_ett_free (GstMpegtsAtscETT * ett)
756 {
757   if (ett->messages)
758     g_ptr_array_unref (ett->messages);
759   g_slice_free (GstMpegtsAtscETT, ett);
760 }
761 
762 G_DEFINE_BOXED_TYPE (GstMpegtsAtscETT, gst_mpegts_atsc_ett,
763     (GBoxedCopyFunc) _gst_mpegts_atsc_ett_copy,
764     (GFreeFunc) _gst_mpegts_atsc_ett_free);
765 
766 static gpointer
_parse_ett(GstMpegtsSection * section)767 _parse_ett (GstMpegtsSection * section)
768 {
769   GstMpegtsAtscETT *ett = NULL;
770   guint8 *data, *end;
771 
772   ett = g_slice_new0 (GstMpegtsAtscETT);
773 
774   data = section->data;
775   end = data + section->section_length;
776 
777   ett->ett_table_id_extension = section->subtable_extension;
778 
779   /* Skip already parsed data */
780   data += 8;
781 
782   ett->protocol_version = GST_READ_UINT8 (data);
783   data += 1;
784   ett->etm_id = GST_READ_UINT32_BE (data);
785   data += 4;
786 
787   ett->messages = _parse_atsc_mult_string (data, end - data - 4);
788   data += end - data - 4;
789 
790   if (data != end - 4) {
791     GST_WARNING ("PID %d invalid ETT parsed %d length %d",
792         section->pid, (gint) (data - section->data), section->section_length);
793     goto error;
794   }
795 
796   return (gpointer) ett;
797 
798 error:
799   _gst_mpegts_atsc_ett_free (ett);
800 
801   return NULL;
802 
803 }
804 
805 /**
806  * gst_mpegts_section_get_atsc_ett:
807  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_ETT
808  *
809  * Returns the #GstMpegtsAtscETT contained in the @section.
810  *
811  * Returns: The #GstMpegtsAtscETT contained in the section, or %NULL if an error
812  * happened.
813  */
814 const GstMpegtsAtscETT *
gst_mpegts_section_get_atsc_ett(GstMpegtsSection * section)815 gst_mpegts_section_get_atsc_ett (GstMpegtsSection * section)
816 {
817   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_ETT,
818       NULL);
819   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
820 
821   if (!section->cached_parsed)
822     section->cached_parsed = __common_section_checks (section, 17, _parse_ett,
823         (GDestroyNotify) _gst_mpegts_atsc_ett_free);
824 
825   return (const GstMpegtsAtscETT *) section->cached_parsed;
826 }
827 
828 /* STT */
829 
830 static GstMpegtsAtscSTT *
_gst_mpegts_atsc_stt_copy(GstMpegtsAtscSTT * stt)831 _gst_mpegts_atsc_stt_copy (GstMpegtsAtscSTT * stt)
832 {
833   GstMpegtsAtscSTT *copy;
834 
835   copy = g_slice_dup (GstMpegtsAtscSTT, stt);
836   copy->descriptors = g_ptr_array_ref (stt->descriptors);
837 
838   return copy;
839 }
840 
841 static void
_gst_mpegts_atsc_stt_free(GstMpegtsAtscSTT * stt)842 _gst_mpegts_atsc_stt_free (GstMpegtsAtscSTT * stt)
843 {
844   if (stt->descriptors)
845     g_ptr_array_unref (stt->descriptors);
846   if (stt->utc_datetime)
847     gst_date_time_unref (stt->utc_datetime);
848 
849   g_slice_free (GstMpegtsAtscSTT, stt);
850 }
851 
852 G_DEFINE_BOXED_TYPE (GstMpegtsAtscSTT, gst_mpegts_atsc_stt,
853     (GBoxedCopyFunc) _gst_mpegts_atsc_stt_copy,
854     (GFreeFunc) _gst_mpegts_atsc_stt_free);
855 
856 static gpointer
_parse_atsc_stt(GstMpegtsSection * section)857 _parse_atsc_stt (GstMpegtsSection * section)
858 {
859   GstMpegtsAtscSTT *stt = NULL;
860   guint8 *data, *end;
861   guint16 daylight_saving;
862 
863   stt = g_slice_new0 (GstMpegtsAtscSTT);
864 
865   data = section->data;
866   end = data + section->section_length;
867 
868   /* Skip already parsed data */
869   data += 8;
870 
871   stt->protocol_version = GST_READ_UINT8 (data);
872   data += 1;
873   stt->system_time = GST_READ_UINT32_BE (data);
874   data += 4;
875   stt->gps_utc_offset = GST_READ_UINT8 (data);
876   data += 1;
877 
878   daylight_saving = GST_READ_UINT16_BE (data);
879   data += 2;
880   stt->ds_status = daylight_saving >> 15;
881   stt->ds_dayofmonth = (daylight_saving >> 8) & 0x1F;
882   stt->ds_hour = daylight_saving & 0xFF;
883 
884   stt->descriptors = gst_mpegts_parse_descriptors (data, end - data - 4);
885   if (stt->descriptors == NULL)
886     goto error;
887 
888   return (gpointer) stt;
889 
890 error:
891   _gst_mpegts_atsc_stt_free (stt);
892 
893   return NULL;
894 }
895 
896 
897 /**
898  * gst_mpegts_section_get_atsc_stt:
899  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_STT
900  *
901  * Returns the #GstMpegtsAtscSTT contained in the @section.
902  *
903  * Returns: The #GstMpegtsAtscSTT contained in the section, or %NULL if an error
904  * happened.
905  */
906 const GstMpegtsAtscSTT *
gst_mpegts_section_get_atsc_stt(GstMpegtsSection * section)907 gst_mpegts_section_get_atsc_stt (GstMpegtsSection * section)
908 {
909   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_STT,
910       NULL);
911   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
912 
913   if (!section->cached_parsed)
914     section->cached_parsed =
915         __common_section_checks (section, 20, _parse_atsc_stt,
916         (GDestroyNotify) _gst_mpegts_atsc_stt_free);
917 
918   return (const GstMpegtsAtscSTT *) section->cached_parsed;
919 }
920 
921 #define GPS_TO_UTC_TICKS G_GINT64_CONSTANT(315964800)
922 static GstDateTime *
_gst_mpegts_atsc_gps_time_to_datetime(guint32 systemtime,guint8 gps_offset)923 _gst_mpegts_atsc_gps_time_to_datetime (guint32 systemtime, guint8 gps_offset)
924 {
925   return gst_date_time_new_from_unix_epoch_utc (systemtime - gps_offset +
926       GPS_TO_UTC_TICKS);
927 }
928 
929 GstDateTime *
gst_mpegts_atsc_stt_get_datetime_utc(GstMpegtsAtscSTT * stt)930 gst_mpegts_atsc_stt_get_datetime_utc (GstMpegtsAtscSTT * stt)
931 {
932   if (stt->utc_datetime == NULL)
933     stt->utc_datetime = _gst_mpegts_atsc_gps_time_to_datetime (stt->system_time,
934         stt->gps_utc_offset);
935 
936   if (stt->utc_datetime)
937     return gst_date_time_ref (stt->utc_datetime);
938   return NULL;
939 }
940