• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * The list of section types defined and used by the ATSC specifications can be
39  * seen in %GstMpegtsSectionATSCTableID.
40  *
41  * # Supported ATSC MPEG-TS sections
42  * These are the sections for which parsing and packetizing code exists.
43  *
44  * ## Master Guide Table (MGT)
45  * See:
46  * * gst_mpegts_section_get_atsc_mgt()
47  * * %GstMpegtsAtscMGT
48  * * %GstMpegtsAtscMGTTable
49  * * gst_mpegts_atsc_mgt_new()
50  *
51  * ## Terrestrial (TVCT) and Cable (CVCT) Virtual Channel Table
52  * See:
53  * * gst_mpegts_section_get_atsc_tvct()
54  * * gst_mpegts_section_get_atsc_cvct()
55  * * %GstMpegtsAtscVCT
56  * * %GstMpegtsAtscVCTSource
57  *
58  * ## Rating Region Table (RRT)
59  * See:
60  * * gst_mpegts_section_get_atsc_rrt()
61  * * %GstMpegtsAtscRRT
62  * * gst_mpegts_atsc_rrt_new()
63  *
64  * ## Event Information Table (EIT)
65  * See:
66  * * gst_mpegts_section_get_atsc_eit()
67  * * %GstMpegtsAtscEIT
68  * * %GstMpegtsAtscEITEvent
69  *
70  * ## Extended Text Table (ETT)
71  * See:
72  * * gst_mpegts_section_get_atsc_ett()
73  * * %GstMpegtsAtscETT
74  *
75  * ## System Time Table (STT)
76  * See:
77  * * gst_mpegts_section_get_atsc_stt()
78  * * %GstMpegtsAtscSTT
79  * * gst_mpegts_atsc_stt_new()
80  *
81  * # API
82  */
83 
84 /* Terrestrial/Cable Virtual Channel Table TVCT/CVCT */
85 static GstMpegtsAtscVCTSource *
_gst_mpegts_atsc_vct_source_copy(GstMpegtsAtscVCTSource * source)86 _gst_mpegts_atsc_vct_source_copy (GstMpegtsAtscVCTSource * source)
87 {
88   GstMpegtsAtscVCTSource *copy;
89 
90   copy = g_slice_dup (GstMpegtsAtscVCTSource, source);
91   copy->descriptors = g_ptr_array_ref (source->descriptors);
92 
93   return copy;
94 }
95 
96 static void
_gst_mpegts_atsc_vct_source_free(GstMpegtsAtscVCTSource * source)97 _gst_mpegts_atsc_vct_source_free (GstMpegtsAtscVCTSource * source)
98 {
99   g_free (source->short_name);
100   if (source->descriptors)
101     g_ptr_array_unref (source->descriptors);
102   g_slice_free (GstMpegtsAtscVCTSource, source);
103 }
104 
105 G_DEFINE_BOXED_TYPE (GstMpegtsAtscVCTSource, gst_mpegts_atsc_vct_source,
106     (GBoxedCopyFunc) _gst_mpegts_atsc_vct_source_copy,
107     (GFreeFunc) _gst_mpegts_atsc_vct_source_free);
108 
109 static GstMpegtsAtscVCT *
_gst_mpegts_atsc_vct_copy(GstMpegtsAtscVCT * vct)110 _gst_mpegts_atsc_vct_copy (GstMpegtsAtscVCT * vct)
111 {
112   GstMpegtsAtscVCT *copy;
113 
114   copy = g_slice_dup (GstMpegtsAtscVCT, vct);
115   copy->sources = g_ptr_array_ref (vct->sources);
116   copy->descriptors = g_ptr_array_ref (vct->descriptors);
117 
118   return copy;
119 }
120 
121 static void
_gst_mpegts_atsc_vct_free(GstMpegtsAtscVCT * vct)122 _gst_mpegts_atsc_vct_free (GstMpegtsAtscVCT * vct)
123 {
124   if (vct->sources)
125     g_ptr_array_unref (vct->sources);
126   if (vct->descriptors)
127     g_ptr_array_unref (vct->descriptors);
128   g_slice_free (GstMpegtsAtscVCT, vct);
129 }
130 
131 G_DEFINE_BOXED_TYPE (GstMpegtsAtscVCT, gst_mpegts_atsc_vct,
132     (GBoxedCopyFunc) _gst_mpegts_atsc_vct_copy,
133     (GFreeFunc) _gst_mpegts_atsc_vct_free);
134 
135 static gpointer
_parse_atsc_vct(GstMpegtsSection * section)136 _parse_atsc_vct (GstMpegtsSection * section)
137 {
138   GstMpegtsAtscVCT *vct = NULL;
139   guint8 *data, *end, source_nb;
140   guint32 tmp32;
141   guint16 descriptors_loop_length, tmp16;
142   guint i;
143   GError *err = NULL;
144 
145   vct = g_slice_new0 (GstMpegtsAtscVCT);
146 
147   data = section->data;
148   end = data + section->section_length;
149 
150   vct->transport_stream_id = section->subtable_extension;
151 
152   /* Skip already parsed data */
153   data += 8;
154 
155   /* minimum size */
156   if (end - data < 2 + 2 + 4)
157     goto error;
158 
159   vct->protocol_version = *data;
160   data += 1;
161 
162   source_nb = *data;
163   data += 1;
164 
165   vct->sources = g_ptr_array_new_full (source_nb,
166       (GDestroyNotify) _gst_mpegts_atsc_vct_source_free);
167 
168   for (i = 0; i < source_nb; i++) {
169     GstMpegtsAtscVCTSource *source;
170 
171     /* minimum 32 bytes for a entry, 2 bytes second descriptor
172        loop-length, 4 bytes crc */
173     if (end - data < 32 + 2 + 4)
174       goto error;
175 
176     source = g_slice_new0 (GstMpegtsAtscVCTSource);
177     g_ptr_array_add (vct->sources, source);
178 
179     source->short_name =
180         g_convert ((gchar *) data, 14, "utf-8", "utf-16be", NULL, NULL, &err);
181     if (err) {
182       GST_WARNING ("Failed to convert VCT Source short_name to utf-8: %d %s",
183           err->code, err->message);
184       GST_MEMDUMP ("UTF-16 string", data, 14);
185       g_error_free (err);
186     }
187     data += 14;
188 
189     tmp32 = GST_READ_UINT32_BE (data);
190     source->major_channel_number = (tmp32 >> 18) & 0x03FF;
191     source->minor_channel_number = (tmp32 >> 8) & 0x03FF;
192     source->modulation_mode = tmp32 & 0xF;
193     data += 4;
194 
195     source->carrier_frequency = GST_READ_UINT32_BE (data);
196     data += 4;
197 
198     source->channel_TSID = GST_READ_UINT16_BE (data);
199     data += 2;
200 
201     source->program_number = GST_READ_UINT16_BE (data);
202     data += 2;
203 
204     tmp16 = GST_READ_UINT16_BE (data);
205     source->ETM_location = (tmp16 >> 14) & 0x3;
206     source->access_controlled = (tmp16 >> 13) & 0x1;
207     source->hidden = (tmp16 >> 12) & 0x1;
208 
209     /* only used in CVCT */
210     source->path_select = (tmp16 >> 11) & 0x1;
211     source->out_of_band = (tmp16 >> 10) & 0x1;
212 
213     source->hide_guide = (tmp16 >> 9) & 0x1;
214     source->service_type = tmp16 & 0x3f;
215     data += 2;
216 
217     source->source_id = GST_READ_UINT16_BE (data);
218     data += 2;
219 
220     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x03FF;
221     data += 2;
222 
223     if (end - data < descriptors_loop_length + 6)
224       goto error;
225 
226     source->descriptors =
227         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
228     if (source->descriptors == NULL)
229       goto error;
230     data += descriptors_loop_length;
231   }
232 
233   descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x03FF;
234   data += 2;
235 
236   if (end - data < descriptors_loop_length + 4)
237     goto error;
238 
239   vct->descriptors =
240       gst_mpegts_parse_descriptors (data, descriptors_loop_length);
241   if (vct->descriptors == NULL)
242     goto error;
243 
244   return (gpointer) vct;
245 
246 error:
247   _gst_mpegts_atsc_vct_free (vct);
248 
249   return NULL;
250 }
251 
252 /**
253  * gst_mpegts_section_get_atsc_tvct:
254  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_TVCT
255  *
256  * Returns the #GstMpegtsAtscVCT contained in the @section
257  *
258  * Returns: The #GstMpegtsAtscVCT contained in the section, or %NULL if an error
259  * happened.
260  */
261 const GstMpegtsAtscVCT *
gst_mpegts_section_get_atsc_tvct(GstMpegtsSection * section)262 gst_mpegts_section_get_atsc_tvct (GstMpegtsSection * section)
263 {
264   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_TVCT,
265       NULL);
266   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
267 
268   if (!section->cached_parsed)
269     section->cached_parsed =
270         __common_section_checks (section, 16, _parse_atsc_vct,
271         (GDestroyNotify) _gst_mpegts_atsc_vct_free);
272 
273   return (const GstMpegtsAtscVCT *) section->cached_parsed;
274 }
275 
276 /**
277  * gst_mpegts_section_get_atsc_cvct:
278  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_CVCT
279  *
280  * Returns the #GstMpegtsAtscVCT contained in the @section
281  *
282  * Returns: The #GstMpegtsAtscVCT contained in the section, or %NULL if an error
283  * happened.
284  */
285 const GstMpegtsAtscVCT *
gst_mpegts_section_get_atsc_cvct(GstMpegtsSection * section)286 gst_mpegts_section_get_atsc_cvct (GstMpegtsSection * section)
287 {
288   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_CVCT,
289       NULL);
290   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
291 
292   if (!section->cached_parsed)
293     section->cached_parsed =
294         __common_section_checks (section, 16, _parse_atsc_vct,
295         (GDestroyNotify) _gst_mpegts_atsc_vct_free);
296 
297   return (const GstMpegtsAtscVCT *) section->cached_parsed;
298 }
299 
300 /* MGT */
301 
302 static GstMpegtsAtscMGTTable *
_gst_mpegts_atsc_mgt_table_copy(GstMpegtsAtscMGTTable * mgt_table)303 _gst_mpegts_atsc_mgt_table_copy (GstMpegtsAtscMGTTable * mgt_table)
304 {
305   GstMpegtsAtscMGTTable *copy;
306 
307   copy = g_slice_dup (GstMpegtsAtscMGTTable, mgt_table);
308   copy->descriptors = g_ptr_array_ref (mgt_table->descriptors);
309 
310   return copy;
311 }
312 
313 static void
_gst_mpegts_atsc_mgt_table_free(GstMpegtsAtscMGTTable * mgt_table)314 _gst_mpegts_atsc_mgt_table_free (GstMpegtsAtscMGTTable * mgt_table)
315 {
316   g_ptr_array_unref (mgt_table->descriptors);
317   g_slice_free (GstMpegtsAtscMGTTable, mgt_table);
318 }
319 
320 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMGTTable, gst_mpegts_atsc_mgt_table,
321     (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_table_copy,
322     (GFreeFunc) _gst_mpegts_atsc_mgt_table_free);
323 
324 static GstMpegtsAtscMGT *
_gst_mpegts_atsc_mgt_copy(GstMpegtsAtscMGT * mgt)325 _gst_mpegts_atsc_mgt_copy (GstMpegtsAtscMGT * mgt)
326 {
327   GstMpegtsAtscMGT *copy;
328 
329   copy = g_slice_dup (GstMpegtsAtscMGT, mgt);
330   copy->tables = g_ptr_array_ref (mgt->tables);
331   copy->descriptors = g_ptr_array_ref (mgt->descriptors);
332 
333   return copy;
334 }
335 
336 static void
_gst_mpegts_atsc_mgt_free(GstMpegtsAtscMGT * mgt)337 _gst_mpegts_atsc_mgt_free (GstMpegtsAtscMGT * mgt)
338 {
339   g_ptr_array_unref (mgt->tables);
340   g_ptr_array_unref (mgt->descriptors);
341   g_slice_free (GstMpegtsAtscMGT, mgt);
342 }
343 
344 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMGT, gst_mpegts_atsc_mgt,
345     (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_copy,
346     (GFreeFunc) _gst_mpegts_atsc_mgt_free);
347 
348 static gpointer
_parse_atsc_mgt(GstMpegtsSection * section)349 _parse_atsc_mgt (GstMpegtsSection * section)
350 {
351   GstMpegtsAtscMGT *mgt = NULL;
352   guint i = 0;
353   guint8 *data, *end;
354   guint16 descriptors_loop_length;
355 
356   mgt = g_slice_new0 (GstMpegtsAtscMGT);
357 
358   data = section->data;
359   end = data + section->section_length;
360 
361   /* Skip already parsed data */
362   data += 8;
363 
364   mgt->protocol_version = GST_READ_UINT8 (data);
365   data += 1;
366   mgt->tables_defined = GST_READ_UINT16_BE (data);
367   data += 2;
368   mgt->tables = g_ptr_array_new_full (mgt->tables_defined,
369       (GDestroyNotify) _gst_mpegts_atsc_mgt_table_free);
370   for (i = 0; i < mgt->tables_defined && data + 11 < end; i++) {
371     GstMpegtsAtscMGTTable *mgt_table;
372 
373     if (data + 11 >= end) {
374       GST_WARNING ("MGT data too short to parse inner table num %d", i);
375       goto error;
376     }
377 
378     mgt_table = g_slice_new0 (GstMpegtsAtscMGTTable);
379     g_ptr_array_add (mgt->tables, mgt_table);
380 
381     mgt_table->table_type = GST_READ_UINT16_BE (data);
382     data += 2;
383     mgt_table->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
384     data += 2;
385     mgt_table->version_number = GST_READ_UINT8 (data) & 0x1F;
386     data += 1;
387     mgt_table->number_bytes = GST_READ_UINT32_BE (data);
388     data += 4;
389     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
390     data += 2;
391 
392     if (data + descriptors_loop_length >= end) {
393       GST_WARNING ("MGT data too short to parse inner table descriptors (table "
394           "num %d", i);
395       goto error;
396     }
397     mgt_table->descriptors =
398         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
399     data += descriptors_loop_length;
400   }
401 
402   descriptors_loop_length = GST_READ_UINT16_BE (data) & 0xFFF;
403   data += 2;
404   if (data + descriptors_loop_length >= end) {
405     GST_WARNING ("MGT data too short to parse descriptors");
406     goto error;
407   }
408   mgt->descriptors =
409       gst_mpegts_parse_descriptors (data, descriptors_loop_length);
410 
411   return (gpointer) mgt;
412 
413 error:
414   _gst_mpegts_atsc_mgt_free (mgt);
415 
416   return NULL;
417 }
418 
419 static gboolean
_packetize_mgt(GstMpegtsSection * section)420 _packetize_mgt (GstMpegtsSection * section)
421 {
422   const GstMpegtsAtscMGT *mgt;
423   guint8 *pos, *data;
424   gsize length;
425   guint i, j;
426 
427   mgt = gst_mpegts_section_get_atsc_mgt (section);
428 
429   if (mgt == NULL)
430     return FALSE;
431 
432   if (mgt->tables_defined != mgt->tables->len)
433     return FALSE;
434 
435   /* 8 byte common section fields
436    * 1 byte protocol version
437    * 2 byte tables_defined
438    * 2 byte reserved / descriptors_length
439    * 4 byte CRC
440    */
441   length = 17;
442 
443   for (i = 0; i < mgt->tables->len; i++) {
444     GstMpegtsAtscMGTTable *mgt_table = g_ptr_array_index (mgt->tables, 1);
445     /* 2 byte table_type
446      * 2 byte reserved / table_type_PID
447      * 1 byte reserved / table_type_version_number
448      * 4 byte number bytes
449      * 2 byte reserved / table_type_descriptors_length
450      */
451     length += 11;
452 
453     if (mgt_table->descriptors) {
454       for (j = 0; j < mgt_table->descriptors->len; j++) {
455         GstMpegtsDescriptor *descriptor =
456             g_ptr_array_index (mgt_table->descriptors, j);
457         length += descriptor->length + 2;
458       }
459     }
460   }
461 
462   if (mgt->descriptors) {
463     for (i = 0; i < mgt->descriptors->len; i++) {
464       GstMpegtsDescriptor *descriptor = g_ptr_array_index (mgt->descriptors, i);
465       length += descriptor->length + 2;
466     }
467   }
468 
469   _packetize_common_section (section, length);
470 
471   data = section->data + 8;
472 
473   /* protocol_version - 8 bit */
474   GST_WRITE_UINT8 (data, mgt->protocol_version);
475   data += 1;
476 
477   /* tables_defined - 16 bit uimsbf */
478   GST_WRITE_UINT16_BE (data, mgt->tables_defined);
479   data += 2;
480 
481   for (i = 0; i < mgt->tables_defined; i++) {
482     GstMpegtsAtscMGTTable *mgt_table = g_ptr_array_index (mgt->tables, 1);
483 
484     /* table_type - 16 bit uimsbf */
485     GST_WRITE_UINT16_BE (data, mgt_table->table_type);
486     data += 2;
487 
488     /* 3 bit reserved, 13 bit table_type_PID uimsbf */
489     GST_WRITE_UINT16_BE (data, mgt_table->pid | 0xe000);
490     data += 2;
491 
492     /* 3 bit reserved, 5 bit table_type_version_number uimsbf */
493     GST_WRITE_UINT8 (data, mgt_table->version_number | 0xe0);
494     data += 1;
495 
496     /* 4 bit reserved, 12 bit table_type_descriptor_length uimsbf */
497     pos = data;
498     *data++ = 0xF0;
499     *data++ = 0x00;
500 
501     _packetize_descriptor_array (mgt_table->descriptors, &data);
502 
503     /* Go back and update the descriptor length */
504     GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
505   }
506 
507   /* 4 bit reserved, 12 bit descriptor_length uimsbf */
508   pos = data;
509   *data++ = 0xF0;
510   *data++ = 0x00;
511 
512   _packetize_descriptor_array (mgt->descriptors, &data);
513 
514   /* Go back and update the descriptor length */
515   GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
516 
517   return TRUE;
518 }
519 
520 /**
521  * gst_mpegts_section_from_atsc_mgt:
522  * @mgt: (transfer full): a #GstMpegtsAtscMGT to create the #GstMpegtsSection from
523  *
524  * Returns: (transfer full): the #GstMpegtsSection
525  * Since: 1.18
526  */
527 GstMpegtsSection *
gst_mpegts_section_from_atsc_mgt(GstMpegtsAtscMGT * mgt)528 gst_mpegts_section_from_atsc_mgt (GstMpegtsAtscMGT * mgt)
529 {
530   GstMpegtsSection *section;
531 
532   g_return_val_if_fail (mgt != NULL, NULL);
533 
534   section = _gst_mpegts_section_init (0x1ffb,
535       GST_MTS_TABLE_ID_ATSC_MASTER_GUIDE);
536 
537   section->subtable_extension = 0x0000;
538   section->cached_parsed = (gpointer) mgt;
539   section->packetizer = _packetize_mgt;
540   section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_mgt_free;
541 
542   return section;
543 }
544 
545 /**
546  * gst_mpegts_section_get_atsc_mgt:
547  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_MGT
548  *
549  * Returns the #GstMpegtsAtscMGT contained in the @section.
550  *
551  * Returns: The #GstMpegtsAtscMGT contained in the section, or %NULL if an error
552  * happened.
553  */
554 const GstMpegtsAtscMGT *
gst_mpegts_section_get_atsc_mgt(GstMpegtsSection * section)555 gst_mpegts_section_get_atsc_mgt (GstMpegtsSection * section)
556 {
557   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_MGT,
558       NULL);
559   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
560 
561   if (!section->cached_parsed)
562     section->cached_parsed =
563         __common_section_checks (section, 17, _parse_atsc_mgt,
564         (GDestroyNotify) _gst_mpegts_atsc_mgt_free);
565 
566   return (const GstMpegtsAtscMGT *) section->cached_parsed;
567 }
568 
569 /**
570  * gst_mpegts_section_atsc_mgt_new:
571  *
572  * Returns: (transfer full): #GstMpegtsAtscMGT
573  * Since: 1.18
574  */
575 GstMpegtsAtscMGT *
gst_mpegts_atsc_mgt_new(void)576 gst_mpegts_atsc_mgt_new (void)
577 {
578   GstMpegtsAtscMGT *mgt;
579 
580   mgt = g_slice_new0 (GstMpegtsAtscMGT);
581 
582   mgt->tables = g_ptr_array_new_with_free_func ((GDestroyNotify)
583       _gst_mpegts_atsc_mgt_table_free);
584 
585   mgt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
586       gst_mpegts_descriptor_free);
587 
588   return mgt;
589 }
590 
591 /* Multi string structure */
592 
593 static GstMpegtsAtscStringSegment *
_gst_mpegts_atsc_string_segment_copy(GstMpegtsAtscStringSegment * seg)594 _gst_mpegts_atsc_string_segment_copy (GstMpegtsAtscStringSegment * seg)
595 {
596   GstMpegtsAtscStringSegment *copy;
597 
598   copy = g_slice_dup (GstMpegtsAtscStringSegment, seg);
599 
600   return copy;
601 }
602 
603 static void
_gst_mpegts_atsc_string_segment_free(GstMpegtsAtscStringSegment * seg)604 _gst_mpegts_atsc_string_segment_free (GstMpegtsAtscStringSegment * seg)
605 {
606   g_free (seg->cached_string);
607   g_slice_free (GstMpegtsAtscStringSegment, seg);
608 }
609 
610 static void
_gst_mpegts_atsc_string_segment_decode_string(GstMpegtsAtscStringSegment * seg)611 _gst_mpegts_atsc_string_segment_decode_string (GstMpegtsAtscStringSegment * seg)
612 {
613   const gchar *from_encoding;
614 
615   g_return_if_fail (seg->cached_string == NULL);
616 
617   if (seg->compression_type != 0) {
618     GST_FIXME ("Compressed strings not yet supported");
619     return;
620   }
621 
622   /* FIXME add more encodings */
623   switch (seg->mode) {
624     case 0x3F:
625       from_encoding = "UTF-16BE";
626       break;
627     default:
628       from_encoding = NULL;
629       break;
630   }
631 
632   if (from_encoding != NULL && seg->compressed_data_size > 0) {
633     GError *err = NULL;
634 
635     seg->cached_string =
636         g_convert ((gchar *) seg->compressed_data,
637         (gssize) seg->compressed_data_size, "UTF-8", from_encoding, NULL, NULL,
638         &err);
639 
640     if (err) {
641       GST_WARNING ("Failed to convert input string from codeset %s",
642           from_encoding);
643       g_error_free (err);
644     }
645   } else {
646     seg->cached_string =
647         g_strndup ((gchar *) seg->compressed_data, seg->compressed_data_size);
648   }
649 }
650 
651 const gchar *
gst_mpegts_atsc_string_segment_get_string(GstMpegtsAtscStringSegment * seg)652 gst_mpegts_atsc_string_segment_get_string (GstMpegtsAtscStringSegment * seg)
653 {
654   if (!seg->cached_string)
655     _gst_mpegts_atsc_string_segment_decode_string (seg);
656 
657   return seg->cached_string;
658 }
659 
660 gboolean
gst_mpegts_atsc_string_segment_set_string(GstMpegtsAtscStringSegment * seg,gchar * string,guint8 compression_type,guint8 mode)661 gst_mpegts_atsc_string_segment_set_string (GstMpegtsAtscStringSegment * seg,
662     gchar * string, guint8 compression_type, guint8 mode)
663 {
664   const gchar *to_encoding = NULL;
665   gboolean ret = FALSE;
666   gsize written;
667   GError *err = NULL;
668   unsigned long len;
669 
670   if (compression_type) {
671     GST_FIXME ("Compressed strings not yet supported");
672     goto done;
673   }
674 
675   switch (mode) {
676     case 0x3f:
677       to_encoding = "UTF-16BE";
678       break;
679     default:
680       break;
681   }
682 
683   if (seg->cached_string)
684     g_free (seg->cached_string);
685 
686   if (seg->compressed_data)
687     g_free (seg->compressed_data);
688 
689   seg->cached_string = g_strdup (string);
690   seg->compression_type = compression_type;
691   seg->mode = mode;
692 
693   len = strlen (string);
694 
695   if (to_encoding && len) {
696     gchar *converted = g_convert (string, len, to_encoding, "UTF-8",
697         NULL, &written, &err);
698 
699     if (err) {
700       GST_WARNING ("Failed to convert input string to codeset %s (%s)",
701           to_encoding, err->message);
702       g_error_free (err);
703       goto done;
704     }
705 
706     seg->compressed_data = (guint8 *) g_strndup (converted, written);
707     seg->compressed_data_size = written;
708     g_free (converted);
709   } else {
710     seg->compressed_data = (guint8 *) g_strndup (string, len);
711     seg->compressed_data_size = len;
712   }
713 
714   ret = TRUE;
715 
716 done:
717   return ret;
718 }
719 
720 G_DEFINE_BOXED_TYPE (GstMpegtsAtscStringSegment, gst_mpegts_atsc_string_segment,
721     (GBoxedCopyFunc) _gst_mpegts_atsc_string_segment_copy,
722     (GFreeFunc) _gst_mpegts_atsc_string_segment_free);
723 
724 static GstMpegtsAtscMultString *
_gst_mpegts_atsc_mult_string_copy(GstMpegtsAtscMultString * mstring)725 _gst_mpegts_atsc_mult_string_copy (GstMpegtsAtscMultString * mstring)
726 {
727   GstMpegtsAtscMultString *copy;
728 
729   copy = g_slice_dup (GstMpegtsAtscMultString, mstring);
730   copy->segments = g_ptr_array_ref (mstring->segments);
731 
732   return copy;
733 }
734 
735 static void
_gst_mpegts_atsc_mult_string_free(GstMpegtsAtscMultString * mstring)736 _gst_mpegts_atsc_mult_string_free (GstMpegtsAtscMultString * mstring)
737 {
738   g_ptr_array_unref (mstring->segments);
739   g_slice_free (GstMpegtsAtscMultString, mstring);
740 }
741 
742 G_DEFINE_BOXED_TYPE (GstMpegtsAtscMultString, gst_mpegts_atsc_mult_string,
743     (GBoxedCopyFunc) _gst_mpegts_atsc_mult_string_copy,
744     (GFreeFunc) _gst_mpegts_atsc_mult_string_free);
745 
746 static GPtrArray *
_parse_atsc_mult_string(guint8 * data,guint datasize)747 _parse_atsc_mult_string (guint8 * data, guint datasize)
748 {
749   guint8 num_strings;
750   GPtrArray *res = NULL;
751   guint8 *end = data + datasize;
752   gint i;
753 
754   if (datasize > 0) {
755     /* 1 is the minimum entry size, so no need to check here */
756     num_strings = GST_READ_UINT8 (data);
757     data += 1;
758 
759     res =
760         g_ptr_array_new_full (num_strings,
761         (GDestroyNotify) _gst_mpegts_atsc_mult_string_free);
762 
763     for (i = 0; i < num_strings; i++) {
764       GstMpegtsAtscMultString *mstring;
765       guint8 num_segments;
766       gint j;
767 
768       mstring = g_slice_new0 (GstMpegtsAtscMultString);
769       g_ptr_array_add (res, mstring);
770       mstring->segments =
771           g_ptr_array_new_full (num_strings,
772           (GDestroyNotify) _gst_mpegts_atsc_string_segment_free);
773 
774       /* each entry needs at least 4 bytes (lang code and segments number) */
775       if (end - data < 4) {
776         GST_WARNING ("Data too short for multstring parsing %d",
777             (gint) (end - data));
778         goto error;
779       }
780 
781       mstring->iso_639_langcode[0] = GST_READ_UINT8 (data);
782       data += 1;
783       mstring->iso_639_langcode[1] = GST_READ_UINT8 (data);
784       data += 1;
785       mstring->iso_639_langcode[2] = GST_READ_UINT8 (data);
786       data += 1;
787       num_segments = GST_READ_UINT8 (data);
788       data += 1;
789 
790       for (j = 0; j < num_segments; j++) {
791         GstMpegtsAtscStringSegment *seg;
792 
793         seg = g_slice_new0 (GstMpegtsAtscStringSegment);
794         g_ptr_array_add (mstring->segments, seg);
795 
796         /* each entry needs at least 3 bytes */
797         if (end - data < 3) {
798           GST_WARNING ("Data too short for multstring parsing %d", datasize);
799           goto error;
800         }
801 
802         seg->compression_type = GST_READ_UINT8 (data);
803         data += 1;
804         seg->mode = GST_READ_UINT8 (data);
805         data += 1;
806         seg->compressed_data_size = GST_READ_UINT8 (data);
807         data += 1;
808 
809         if (end - data < seg->compressed_data_size) {
810           GST_WARNING ("Data too short for multstring parsing %d", datasize);
811           goto error;
812         }
813 
814         if (seg->compressed_data_size)
815           seg->compressed_data = data;
816         data += seg->compressed_data_size;
817       }
818 
819     }
820   }
821   return res;
822 
823 error:
824   if (res)
825     g_ptr_array_unref (res);
826   return NULL;
827 }
828 
829 static void
_packetize_atsc_mult_string(GPtrArray * strings,guint8 ** data)830 _packetize_atsc_mult_string (GPtrArray * strings, guint8 ** data)
831 {
832   guint i;
833 
834   if (strings == NULL)
835     return;
836 
837   /* 8 bit number_strings */
838   GST_WRITE_UINT8 (*data, strings->len);
839   *data += 1;
840 
841   for (i = 0; i < strings->len; i++) {
842     GstMpegtsAtscMultString *string;
843     guint j;
844 
845     string = g_ptr_array_index (strings, i);
846 
847     /* 24 bit ISO_639_langcode */
848     GST_WRITE_UINT8 (*data, string->iso_639_langcode[0]);
849     *data += 1;
850     GST_WRITE_UINT8 (*data, string->iso_639_langcode[1]);
851     *data += 1;
852     GST_WRITE_UINT8 (*data, string->iso_639_langcode[2]);
853     *data += 1;
854     /* 8 bit number_segments */
855     GST_WRITE_UINT8 (*data, string->segments->len);
856     *data += 1;
857 
858     for (j = 0; j < string->segments->len; j++) {
859       GstMpegtsAtscStringSegment *seg;
860 
861       seg = g_ptr_array_index (string->segments, j);
862 
863       /* 8 bit compression_type */
864       GST_WRITE_UINT8 (*data, seg->compression_type);
865       *data += 1;
866       /* 8 bit mode */
867       GST_WRITE_UINT8 (*data, seg->mode);
868       *data += 1;
869       /* 8 bit number_bytes */
870       GST_WRITE_UINT8 (*data, seg->compressed_data_size);
871       *data += 1;
872       /* number_bytes compressed string */
873       memcpy (*data, seg->compressed_data, seg->compressed_data_size);
874       *data += seg->compressed_data_size;
875     }
876   }
877 }
878 
879 static gsize
_get_atsc_mult_string_packetized_length(GPtrArray * strings)880 _get_atsc_mult_string_packetized_length (GPtrArray * strings)
881 {
882   gsize length = 1;
883   guint i;
884 
885   for (i = 0; i < strings->len; i++) {
886     GstMpegtsAtscMultString *string;
887     guint j;
888 
889     string = g_ptr_array_index (strings, i);
890 
891     length += 4;
892 
893     for (j = 0; j < string->segments->len; j++) {
894       GstMpegtsAtscStringSegment *seg;
895 
896       seg = g_ptr_array_index (string->segments, j);
897 
898       length += 3 + seg->compressed_data_size;
899     }
900   }
901 
902   return length;
903 }
904 
905 /* EIT */
906 
907 static GstMpegtsAtscEITEvent *
_gst_mpegts_atsc_eit_event_copy(GstMpegtsAtscEITEvent * event)908 _gst_mpegts_atsc_eit_event_copy (GstMpegtsAtscEITEvent * event)
909 {
910   GstMpegtsAtscEITEvent *copy;
911 
912   copy = g_slice_dup (GstMpegtsAtscEITEvent, event);
913   copy->titles = g_ptr_array_ref (event->titles);
914   copy->descriptors = g_ptr_array_ref (event->descriptors);
915 
916   return copy;
917 }
918 
919 static void
_gst_mpegts_atsc_eit_event_free(GstMpegtsAtscEITEvent * event)920 _gst_mpegts_atsc_eit_event_free (GstMpegtsAtscEITEvent * event)
921 {
922   if (event->titles)
923     g_ptr_array_unref (event->titles);
924   if (event->descriptors)
925     g_ptr_array_unref (event->descriptors);
926   g_slice_free (GstMpegtsAtscEITEvent, event);
927 }
928 
929 G_DEFINE_BOXED_TYPE (GstMpegtsAtscEITEvent, gst_mpegts_atsc_eit_event,
930     (GBoxedCopyFunc) _gst_mpegts_atsc_eit_event_copy,
931     (GFreeFunc) _gst_mpegts_atsc_eit_event_free);
932 
933 static GstMpegtsAtscEIT *
_gst_mpegts_atsc_eit_copy(GstMpegtsAtscEIT * eit)934 _gst_mpegts_atsc_eit_copy (GstMpegtsAtscEIT * eit)
935 {
936   GstMpegtsAtscEIT *copy;
937 
938   copy = g_slice_dup (GstMpegtsAtscEIT, eit);
939   copy->events = g_ptr_array_ref (eit->events);
940 
941   return copy;
942 }
943 
944 static void
_gst_mpegts_atsc_eit_free(GstMpegtsAtscEIT * eit)945 _gst_mpegts_atsc_eit_free (GstMpegtsAtscEIT * eit)
946 {
947   if (eit->events)
948     g_ptr_array_unref (eit->events);
949   g_slice_free (GstMpegtsAtscEIT, eit);
950 }
951 
952 G_DEFINE_BOXED_TYPE (GstMpegtsAtscEIT, gst_mpegts_atsc_eit,
953     (GBoxedCopyFunc) _gst_mpegts_atsc_eit_copy,
954     (GFreeFunc) _gst_mpegts_atsc_eit_free);
955 
956 static gpointer
_parse_atsc_eit(GstMpegtsSection * section)957 _parse_atsc_eit (GstMpegtsSection * section)
958 {
959   GstMpegtsAtscEIT *eit = NULL;
960   guint i = 0;
961   guint8 *data, *end;
962   guint8 num_events;
963 
964   eit = g_slice_new0 (GstMpegtsAtscEIT);
965 
966   data = section->data;
967   end = data + section->section_length;
968 
969   eit->source_id = section->subtable_extension;
970 
971   /* Skip already parsed data */
972   data += 8;
973 
974   eit->protocol_version = GST_READ_UINT8 (data);
975   data += 1;
976   num_events = GST_READ_UINT8 (data);
977   data += 1;
978 
979   eit->events = g_ptr_array_new_with_free_func ((GDestroyNotify)
980       _gst_mpegts_atsc_eit_event_free);
981 
982   for (i = 0; i < num_events; i++) {
983     GstMpegtsAtscEITEvent *event;
984     guint32 tmp;
985     guint8 text_length;
986     guint16 descriptors_loop_length;
987 
988     if (end - data < 12) {
989       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
990           section->pid, (gint) (end - 4 - data), num_events);
991       goto error;
992     }
993 
994     event = g_slice_new0 (GstMpegtsAtscEITEvent);
995     g_ptr_array_add (eit->events, event);
996 
997     event->event_id = GST_READ_UINT16_BE (data) & 0x3FFF;
998     data += 2;
999     event->start_time = GST_READ_UINT32_BE (data);
1000     data += 4;
1001 
1002     tmp = GST_READ_UINT32_BE (data);
1003     data += 4;
1004     event->etm_location = (tmp >> 28) & 0x3;
1005     event->length_in_seconds = (tmp >> 8) & 0x0FFFFF;
1006     text_length = tmp & 0xFF;
1007 
1008     if (text_length > end - data - 4 - 2) {
1009       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
1010           section->pid, (gint) (end - 4 - data), num_events);
1011       goto error;
1012     }
1013     event->titles = _parse_atsc_mult_string (data, text_length);
1014     data += text_length;
1015 
1016     descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
1017     data += 2;
1018 
1019     if (end - data - 4 < descriptors_loop_length) {
1020       GST_WARNING ("PID %d invalid EIT entry length %d with %u events",
1021           section->pid, (gint) (end - 4 - data), num_events);
1022       goto error;
1023     }
1024 
1025     event->descriptors =
1026         gst_mpegts_parse_descriptors (data, descriptors_loop_length);
1027     data += descriptors_loop_length;
1028   }
1029 
1030   if (data != end - 4) {
1031     GST_WARNING ("PID %d invalid EIT parsed %d length %d",
1032         section->pid, (gint) (data - section->data), section->section_length);
1033     goto error;
1034   }
1035 
1036   return (gpointer) eit;
1037 
1038 error:
1039   _gst_mpegts_atsc_eit_free (eit);
1040 
1041   return NULL;
1042 
1043 }
1044 
1045 /**
1046  * gst_mpegts_section_get_atsc_eit:
1047  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_EIT
1048  *
1049  * Returns the #GstMpegtsAtscEIT contained in the @section.
1050  *
1051  * Returns: The #GstMpegtsAtscEIT contained in the section, or %NULL if an error
1052  * happened.
1053  */
1054 const GstMpegtsAtscEIT *
gst_mpegts_section_get_atsc_eit(GstMpegtsSection * section)1055 gst_mpegts_section_get_atsc_eit (GstMpegtsSection * section)
1056 {
1057   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_EIT,
1058       NULL);
1059   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1060 
1061   if (!section->cached_parsed)
1062     section->cached_parsed =
1063         __common_section_checks (section, 14, _parse_atsc_eit,
1064         (GDestroyNotify) _gst_mpegts_atsc_eit_free);
1065 
1066   return (const GstMpegtsAtscEIT *) section->cached_parsed;
1067 }
1068 
1069 
1070 static GstMpegtsAtscETT *
_gst_mpegts_atsc_ett_copy(GstMpegtsAtscETT * ett)1071 _gst_mpegts_atsc_ett_copy (GstMpegtsAtscETT * ett)
1072 {
1073   GstMpegtsAtscETT *copy;
1074 
1075   copy = g_slice_dup (GstMpegtsAtscETT, ett);
1076   copy->messages = g_ptr_array_ref (ett->messages);
1077 
1078   return copy;
1079 }
1080 
1081 static void
_gst_mpegts_atsc_ett_free(GstMpegtsAtscETT * ett)1082 _gst_mpegts_atsc_ett_free (GstMpegtsAtscETT * ett)
1083 {
1084   if (ett->messages)
1085     g_ptr_array_unref (ett->messages);
1086   g_slice_free (GstMpegtsAtscETT, ett);
1087 }
1088 
1089 G_DEFINE_BOXED_TYPE (GstMpegtsAtscETT, gst_mpegts_atsc_ett,
1090     (GBoxedCopyFunc) _gst_mpegts_atsc_ett_copy,
1091     (GFreeFunc) _gst_mpegts_atsc_ett_free);
1092 
1093 static gpointer
_parse_ett(GstMpegtsSection * section)1094 _parse_ett (GstMpegtsSection * section)
1095 {
1096   GstMpegtsAtscETT *ett = NULL;
1097   guint8 *data, *end;
1098 
1099   ett = g_slice_new0 (GstMpegtsAtscETT);
1100 
1101   data = section->data;
1102   end = data + section->section_length;
1103 
1104   ett->ett_table_id_extension = section->subtable_extension;
1105 
1106   /* Skip already parsed data */
1107   data += 8;
1108 
1109   ett->protocol_version = GST_READ_UINT8 (data);
1110   data += 1;
1111   ett->etm_id = GST_READ_UINT32_BE (data);
1112   data += 4;
1113 
1114   ett->messages = _parse_atsc_mult_string (data, end - data - 4);
1115   data += end - data - 4;
1116 
1117   if (data != end - 4) {
1118     GST_WARNING ("PID %d invalid ETT parsed %d length %d",
1119         section->pid, (gint) (data - section->data), section->section_length);
1120     goto error;
1121   }
1122 
1123   return (gpointer) ett;
1124 
1125 error:
1126   _gst_mpegts_atsc_ett_free (ett);
1127 
1128   return NULL;
1129 
1130 }
1131 
1132 /**
1133  * gst_mpegts_section_get_atsc_ett:
1134  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_ETT
1135  *
1136  * Returns the #GstMpegtsAtscETT contained in the @section.
1137  *
1138  * Returns: The #GstMpegtsAtscETT contained in the section, or %NULL if an error
1139  * happened.
1140  */
1141 const GstMpegtsAtscETT *
gst_mpegts_section_get_atsc_ett(GstMpegtsSection * section)1142 gst_mpegts_section_get_atsc_ett (GstMpegtsSection * section)
1143 {
1144   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_ETT,
1145       NULL);
1146   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1147 
1148   if (!section->cached_parsed)
1149     section->cached_parsed = __common_section_checks (section, 17, _parse_ett,
1150         (GDestroyNotify) _gst_mpegts_atsc_ett_free);
1151 
1152   return (const GstMpegtsAtscETT *) section->cached_parsed;
1153 }
1154 
1155 /* STT */
1156 
1157 static GstMpegtsAtscSTT *
_gst_mpegts_atsc_stt_copy(GstMpegtsAtscSTT * stt)1158 _gst_mpegts_atsc_stt_copy (GstMpegtsAtscSTT * stt)
1159 {
1160   GstMpegtsAtscSTT *copy;
1161 
1162   copy = g_slice_dup (GstMpegtsAtscSTT, stt);
1163   copy->descriptors = g_ptr_array_ref (stt->descriptors);
1164 
1165   return copy;
1166 }
1167 
1168 static void
_gst_mpegts_atsc_stt_free(GstMpegtsAtscSTT * stt)1169 _gst_mpegts_atsc_stt_free (GstMpegtsAtscSTT * stt)
1170 {
1171   if (stt->descriptors)
1172     g_ptr_array_unref (stt->descriptors);
1173   if (stt->utc_datetime)
1174     gst_date_time_unref (stt->utc_datetime);
1175 
1176   g_slice_free (GstMpegtsAtscSTT, stt);
1177 }
1178 
1179 G_DEFINE_BOXED_TYPE (GstMpegtsAtscSTT, gst_mpegts_atsc_stt,
1180     (GBoxedCopyFunc) _gst_mpegts_atsc_stt_copy,
1181     (GFreeFunc) _gst_mpegts_atsc_stt_free);
1182 
1183 static gpointer
_parse_atsc_stt(GstMpegtsSection * section)1184 _parse_atsc_stt (GstMpegtsSection * section)
1185 {
1186   GstMpegtsAtscSTT *stt = NULL;
1187   guint8 *data, *end;
1188   guint16 daylight_saving;
1189 
1190   stt = g_slice_new0 (GstMpegtsAtscSTT);
1191 
1192   data = section->data;
1193   end = data + section->section_length;
1194 
1195   /* Skip already parsed data */
1196   data += 8;
1197 
1198   stt->protocol_version = GST_READ_UINT8 (data);
1199   data += 1;
1200   stt->system_time = GST_READ_UINT32_BE (data);
1201   data += 4;
1202   stt->gps_utc_offset = GST_READ_UINT8 (data);
1203   data += 1;
1204 
1205   daylight_saving = GST_READ_UINT16_BE (data);
1206   data += 2;
1207   stt->ds_status = daylight_saving >> 15;
1208   stt->ds_dayofmonth = (daylight_saving >> 8) & 0x1F;
1209   stt->ds_hour = daylight_saving & 0xFF;
1210 
1211   stt->descriptors = gst_mpegts_parse_descriptors (data, end - data - 4);
1212   if (stt->descriptors == NULL)
1213     goto error;
1214 
1215   return (gpointer) stt;
1216 
1217 error:
1218   _gst_mpegts_atsc_stt_free (stt);
1219 
1220   return NULL;
1221 }
1222 
1223 static gboolean
_packetize_stt(GstMpegtsSection * section)1224 _packetize_stt (GstMpegtsSection * section)
1225 {
1226   const GstMpegtsAtscSTT *stt;
1227   guint8 *data;
1228   gsize length;
1229   guint i;
1230 
1231   stt = gst_mpegts_section_get_atsc_stt (section);
1232 
1233   if (stt == NULL)
1234     return FALSE;
1235 
1236   /* 8 byte common section fields
1237    * 1 byte protocol version
1238    * 4 byte system time
1239    * 1 byte GPS_UTC_offset
1240    * 2 byte daylight saving
1241    * 4 byte CRC
1242    */
1243   length = 20;
1244 
1245   if (stt->descriptors) {
1246     for (i = 0; i < stt->descriptors->len; i++) {
1247       GstMpegtsDescriptor *descriptor = g_ptr_array_index (stt->descriptors, i);
1248       length += descriptor->length + 2;
1249     }
1250   }
1251 
1252   _packetize_common_section (section, length);
1253 
1254   data = section->data + 8;
1255 
1256   /* protocol_version - 8 bit */
1257   GST_WRITE_UINT8 (data, stt->protocol_version);
1258   data += 1;
1259   /* system time - 32 bit uimsbf */
1260   GST_WRITE_UINT32_BE (data, stt->system_time);
1261   data += 4;
1262   /* GPS_UTC_offset - 8 bit */
1263   GST_WRITE_UINT8 (data, stt->gps_utc_offset);
1264   data += 1;
1265   /* daylight_saving - 16 bit uimsbf */
1266   GST_WRITE_UINT8 (data,
1267       (stt->ds_status << 7) | 0x60 | (stt->ds_dayofmonth & 0x1f));
1268   data += 1;
1269   GST_WRITE_UINT8 (data, stt->ds_hour);
1270   data += 1;
1271 
1272   _packetize_descriptor_array (stt->descriptors, &data);
1273 
1274   return TRUE;
1275 }
1276 
1277 /**
1278  * gst_mpegts_section_section_from_atsc_stt:
1279  * @stt: (transfer full): a #GstMpegtsAtscSTT to create the #GstMpegtsSection from
1280  *
1281  * Returns: (transfer full): the #GstMpegtsSection
1282  * Since: 1.18
1283  */
1284 GstMpegtsSection *
gst_mpegts_section_from_atsc_stt(GstMpegtsAtscSTT * stt)1285 gst_mpegts_section_from_atsc_stt (GstMpegtsAtscSTT * stt)
1286 {
1287   GstMpegtsSection *section;
1288 
1289   g_return_val_if_fail (stt != NULL, NULL);
1290 
1291   section = _gst_mpegts_section_init (0x1ffb,
1292       GST_MTS_TABLE_ID_ATSC_SYSTEM_TIME);
1293 
1294   section->subtable_extension = 0x0000;
1295   section->cached_parsed = (gpointer) stt;
1296   section->packetizer = _packetize_stt;
1297   section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_stt_free;
1298 
1299   return section;
1300 }
1301 
1302 /**
1303  * gst_mpegts_section_get_atsc_stt:
1304  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_STT
1305  *
1306  * Returns the #GstMpegtsAtscSTT contained in the @section.
1307  *
1308  * Returns: The #GstMpegtsAtscSTT contained in the section, or %NULL if an error
1309  * happened.
1310  */
1311 const GstMpegtsAtscSTT *
gst_mpegts_section_get_atsc_stt(GstMpegtsSection * section)1312 gst_mpegts_section_get_atsc_stt (GstMpegtsSection * section)
1313 {
1314   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_STT,
1315       NULL);
1316   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1317 
1318   if (!section->cached_parsed)
1319     section->cached_parsed =
1320         __common_section_checks (section, 20, _parse_atsc_stt,
1321         (GDestroyNotify) _gst_mpegts_atsc_stt_free);
1322 
1323   return (const GstMpegtsAtscSTT *) section->cached_parsed;
1324 }
1325 
1326 /**
1327  * gst_mpegts_section_atsc_stt_new:
1328  *
1329  * Returns: (transfer full): #GstMpegtsAtscSTT
1330  * Since: 1.18
1331  */
1332 GstMpegtsAtscSTT *
gst_mpegts_atsc_stt_new(void)1333 gst_mpegts_atsc_stt_new (void)
1334 {
1335   GstMpegtsAtscSTT *stt;
1336 
1337   stt = g_slice_new0 (GstMpegtsAtscSTT);
1338   stt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
1339       gst_mpegts_descriptor_free);
1340 
1341   return stt;
1342 }
1343 
1344 #define GPS_TO_UTC_TICKS G_GINT64_CONSTANT(315964800)
1345 static GstDateTime *
_gst_mpegts_atsc_gps_time_to_datetime(guint32 systemtime,guint8 gps_offset)1346 _gst_mpegts_atsc_gps_time_to_datetime (guint32 systemtime, guint8 gps_offset)
1347 {
1348   return gst_date_time_new_from_unix_epoch_utc (systemtime - gps_offset +
1349       GPS_TO_UTC_TICKS);
1350 }
1351 
1352 GstDateTime *
gst_mpegts_atsc_stt_get_datetime_utc(GstMpegtsAtscSTT * stt)1353 gst_mpegts_atsc_stt_get_datetime_utc (GstMpegtsAtscSTT * stt)
1354 {
1355   if (stt->utc_datetime == NULL)
1356     stt->utc_datetime = _gst_mpegts_atsc_gps_time_to_datetime (stt->system_time,
1357         stt->gps_utc_offset);
1358 
1359   if (stt->utc_datetime)
1360     return gst_date_time_ref (stt->utc_datetime);
1361   return NULL;
1362 }
1363 
1364 /* RRT */
1365 
1366 static GstMpegtsAtscRRTDimensionValue *
_gst_mpegts_atsc_rrt_dimension_value_copy(GstMpegtsAtscRRTDimensionValue * value)1367 _gst_mpegts_atsc_rrt_dimension_value_copy (GstMpegtsAtscRRTDimensionValue *
1368     value)
1369 {
1370   GstMpegtsAtscRRTDimensionValue *copy;
1371 
1372   copy = g_slice_dup (GstMpegtsAtscRRTDimensionValue, value);
1373   copy->abbrev_ratings = g_ptr_array_ref (value->abbrev_ratings);
1374   copy->ratings = g_ptr_array_ref (value->ratings);
1375 
1376   return copy;
1377 }
1378 
1379 static void
_gst_mpegts_atsc_rrt_dimension_value_free(GstMpegtsAtscRRTDimensionValue * value)1380 _gst_mpegts_atsc_rrt_dimension_value_free (GstMpegtsAtscRRTDimensionValue *
1381     value)
1382 {
1383   if (value->abbrev_ratings)
1384     g_ptr_array_unref (value->abbrev_ratings);
1385   if (value->ratings)
1386     g_ptr_array_unref (value->ratings);
1387 
1388   g_slice_free (GstMpegtsAtscRRTDimensionValue, value);
1389 }
1390 
1391 G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRTDimensionValue,
1392     gst_mpegts_atsc_rrt_dimension_value,
1393     (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_dimension_value_copy,
1394     (GFreeFunc) _gst_mpegts_atsc_rrt_dimension_value_free);
1395 
1396 static GstMpegtsAtscRRTDimension *
_gst_mpegts_atsc_rrt_dimension_copy(GstMpegtsAtscRRTDimension * dim)1397 _gst_mpegts_atsc_rrt_dimension_copy (GstMpegtsAtscRRTDimension * dim)
1398 {
1399   GstMpegtsAtscRRTDimension *copy;
1400 
1401   copy = g_slice_dup (GstMpegtsAtscRRTDimension, dim);
1402   copy->names = g_ptr_array_ref (dim->names);
1403   copy->values = g_ptr_array_ref (dim->values);
1404 
1405   return copy;
1406 }
1407 
1408 static void
_gst_mpegts_atsc_rrt_dimension_free(GstMpegtsAtscRRTDimension * dim)1409 _gst_mpegts_atsc_rrt_dimension_free (GstMpegtsAtscRRTDimension * dim)
1410 {
1411   if (dim->names)
1412     g_ptr_array_unref (dim->names);
1413   if (dim->values)
1414     g_ptr_array_unref (dim->values);
1415 
1416   g_slice_free (GstMpegtsAtscRRTDimension, dim);
1417 }
1418 
1419 G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRTDimension, gst_mpegts_atsc_rrt_dimension,
1420     (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_dimension_copy,
1421     (GFreeFunc) _gst_mpegts_atsc_rrt_dimension_free);
1422 
1423 static GstMpegtsAtscRRT *
_gst_mpegts_atsc_rrt_copy(GstMpegtsAtscRRT * rrt)1424 _gst_mpegts_atsc_rrt_copy (GstMpegtsAtscRRT * rrt)
1425 {
1426   GstMpegtsAtscRRT *copy;
1427 
1428   copy = g_slice_dup (GstMpegtsAtscRRT, rrt);
1429   copy->names = g_ptr_array_ref (rrt->names);
1430   copy->dimensions = g_ptr_array_ref (rrt->dimensions);
1431   copy->descriptors = g_ptr_array_ref (rrt->descriptors);
1432 
1433   return copy;
1434 }
1435 
1436 static void
_gst_mpegts_atsc_rrt_free(GstMpegtsAtscRRT * rrt)1437 _gst_mpegts_atsc_rrt_free (GstMpegtsAtscRRT * rrt)
1438 {
1439   if (rrt->names)
1440     g_ptr_array_unref (rrt->names);
1441   if (rrt->dimensions)
1442     g_ptr_array_unref (rrt->dimensions);
1443   if (rrt->descriptors)
1444     g_ptr_array_unref (rrt->descriptors);
1445 
1446   g_slice_free (GstMpegtsAtscRRT, rrt);
1447 }
1448 
1449 G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRT, gst_mpegts_atsc_rrt,
1450     (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_copy,
1451     (GFreeFunc) _gst_mpegts_atsc_rrt_free);
1452 
1453 static gpointer
_parse_rrt(GstMpegtsSection * section)1454 _parse_rrt (GstMpegtsSection * section)
1455 {
1456   GstMpegtsAtscRRT *rrt = NULL;
1457   guint i = 0;
1458   guint8 *data;
1459   guint16 descriptors_loop_length;
1460   guint8 text_length;
1461 
1462   rrt = g_slice_new0 (GstMpegtsAtscRRT);
1463 
1464   data = section->data;
1465 
1466   /* Skip already parsed data */
1467   data += 8;
1468 
1469   rrt->protocol_version = GST_READ_UINT8 (data);
1470   data += 1;
1471 
1472   text_length = GST_READ_UINT8 (data);
1473   data += 1;
1474   rrt->names = _parse_atsc_mult_string (data, text_length);
1475   data += text_length;
1476 
1477   rrt->dimensions_defined = GST_READ_UINT8 (data);
1478   data += 1;
1479 
1480   rrt->dimensions = g_ptr_array_new_full (rrt->dimensions_defined,
1481       (GDestroyNotify) _gst_mpegts_atsc_rrt_dimension_free);
1482 
1483   for (i = 0; i < rrt->dimensions_defined; i++) {
1484     GstMpegtsAtscRRTDimension *dim;
1485     guint8 tmp;
1486     guint j = 0;
1487 
1488     dim = g_slice_new0 (GstMpegtsAtscRRTDimension);
1489     g_ptr_array_add (rrt->dimensions, dim);
1490 
1491     text_length = GST_READ_UINT8 (data);
1492     data += 1;
1493     dim->names = _parse_atsc_mult_string (data, text_length);
1494     data += text_length;
1495 
1496     tmp = GST_READ_UINT8 (data);
1497     data += 1;
1498 
1499     dim->graduated_scale = tmp & 0x10;
1500     dim->values_defined = tmp & 0x0f;
1501 
1502     dim->values = g_ptr_array_new_full (dim->values_defined,
1503         (GDestroyNotify) _gst_mpegts_atsc_rrt_dimension_value_free);
1504 
1505     for (j = 0; j < dim->values_defined; j++) {
1506       GstMpegtsAtscRRTDimensionValue *val;
1507 
1508       val = g_slice_new0 (GstMpegtsAtscRRTDimensionValue);
1509       g_ptr_array_add (dim->values, val);
1510 
1511       text_length = GST_READ_UINT8 (data);
1512       data += 1;
1513       val->abbrev_ratings = _parse_atsc_mult_string (data, text_length);
1514       data += text_length;
1515 
1516       text_length = GST_READ_UINT8 (data);
1517       data += 1;
1518       val->ratings = _parse_atsc_mult_string (data, text_length);
1519       data += text_length;
1520     }
1521   }
1522 
1523   descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x3FF;
1524   data += 2;
1525   rrt->descriptors =
1526       gst_mpegts_parse_descriptors (data, descriptors_loop_length);
1527 
1528   return (gpointer) rrt;
1529 }
1530 
1531 static gboolean
_packetize_rrt(GstMpegtsSection * section)1532 _packetize_rrt (GstMpegtsSection * section)
1533 {
1534   const GstMpegtsAtscRRT *rrt;
1535   guint8 *data, *pos;
1536   gsize length;
1537   gsize names_length;
1538   guint i, j;
1539 
1540   rrt = gst_mpegts_section_get_atsc_rrt (section);
1541 
1542   if (rrt == NULL)
1543     return FALSE;
1544 
1545   names_length = _get_atsc_mult_string_packetized_length (rrt->names);
1546 
1547   /* 8 byte common section fields
1548    * 1 byte protocol version
1549    * 1 byte rating_region_name_length
1550    * name_length bytes
1551    * 1 byte dimensions_defined
1552    * 2 byte reserved / descriptors_length
1553    * 4 byte CRC
1554    */
1555   length = names_length + 17;
1556 
1557   for (i = 0; i < rrt->dimensions->len; i++) {
1558     GstMpegtsAtscRRTDimension *dim = g_ptr_array_index (rrt->dimensions, i);
1559 
1560     /* 1 byte dimension_name_length
1561      * 1 byte reserved / graduated_scale / values_defined
1562      */
1563     length += 2;
1564     length += _get_atsc_mult_string_packetized_length (dim->names);
1565     for (j = 0; j < dim->values->len; j++) {
1566       GstMpegtsAtscRRTDimensionValue *val = g_ptr_array_index (dim->values, j);
1567 
1568       /* 1 byte abbrev_rating_value_length
1569        * 1 byte rating_value_length
1570        */
1571       length += 2;
1572       length += _get_atsc_mult_string_packetized_length (val->abbrev_ratings);
1573       length += _get_atsc_mult_string_packetized_length (val->ratings);
1574     }
1575   }
1576 
1577   if (rrt->descriptors) {
1578     for (i = 0; i < rrt->descriptors->len; i++) {
1579       GstMpegtsDescriptor *descriptor = g_ptr_array_index (rrt->descriptors, i);
1580       length += descriptor->length + 2;
1581     }
1582   }
1583 
1584   if (length > 1024) {
1585     GST_WARNING ("RRT size can not exceed 1024");
1586     return FALSE;
1587   }
1588 
1589   _packetize_common_section (section, length);
1590 
1591   data = section->data + 8;
1592 
1593   /* protocol_version - 8 bit */
1594   GST_WRITE_UINT8 (data, rrt->protocol_version);
1595   data += 1;
1596 
1597   /* rating_region_name_length - 8 bit */
1598   GST_WRITE_UINT8 (data, names_length);
1599   data += 1;
1600 
1601   _packetize_atsc_mult_string (rrt->names, &data);
1602 
1603   for (i = 0; i < rrt->dimensions->len; i++) {
1604     GstMpegtsAtscRRTDimension *dim = g_ptr_array_index (rrt->dimensions, i);
1605 
1606     /* dimension_name_length - 8 bit */
1607     GST_WRITE_UINT8 (data,
1608         _get_atsc_mult_string_packetized_length (dim->names));
1609     data += 1;
1610 
1611     _packetize_atsc_mult_string (rrt->names, &data);
1612 
1613     /* 3 bit reserved / 1 bit graduated_scale / 4 bit values_defined */
1614     GST_WRITE_UINT8 (data,
1615         0xe0 | ((dim->graduated_scale ? 1 : 0) << 4) | (dim->
1616             values_defined & 0x0f));
1617     data += 1;
1618 
1619     for (j = 0; j < dim->values->len; j++) {
1620       GstMpegtsAtscRRTDimensionValue *val = g_ptr_array_index (dim->values, j);
1621 
1622       /* abbrev_rating_value_length - 8 bit */
1623       GST_WRITE_UINT8 (data,
1624           _get_atsc_mult_string_packetized_length (val->abbrev_ratings));
1625       data += 1;
1626 
1627       _packetize_atsc_mult_string (val->abbrev_ratings, &data);
1628 
1629       /* rating_value_length - 8 bit */
1630       GST_WRITE_UINT8 (data,
1631           _get_atsc_mult_string_packetized_length (val->ratings));
1632       data += 1;
1633 
1634       _packetize_atsc_mult_string (val->ratings, &data);
1635     }
1636   }
1637 
1638   /* 6 bit reserved, 10 bit descriptor_length uimsbf */
1639   pos = data;
1640   *data++ = 0xFC;
1641   *data++ = 0x00;
1642 
1643   _packetize_descriptor_array (rrt->descriptors, &data);
1644 
1645   /* Go back and update the descriptor length */
1646   GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xFC00);
1647 
1648   return TRUE;
1649 }
1650 
1651 /**
1652  * gst_mpegts_section_section_from_atsc_rrt:
1653  * @rrt: (transfer full): a #GstMpegtsAtscRRT to create the #GstMpegtsSection from
1654  *
1655  * Returns: (transfer full): the #GstMpegtsSection
1656  * Since: 1.18
1657  */
1658 GstMpegtsSection *
gst_mpegts_section_from_atsc_rrt(GstMpegtsAtscRRT * rrt)1659 gst_mpegts_section_from_atsc_rrt (GstMpegtsAtscRRT * rrt)
1660 {
1661   GstMpegtsSection *section;
1662 
1663   g_return_val_if_fail (rrt != NULL, NULL);
1664 
1665   section = _gst_mpegts_section_init (0x1ffb,
1666       GST_MTS_TABLE_ID_ATSC_RATING_REGION);
1667 
1668   /* FIXME random rating_region, what should be the default? */
1669   section->subtable_extension = 0xff01;
1670   section->cached_parsed = (gpointer) rrt;
1671   section->packetizer = _packetize_rrt;
1672   section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_rrt_free;
1673 
1674   return section;
1675 }
1676 
1677 /**
1678  * gst_mpegts_section_get_atsc_rrt:
1679  * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_RRT
1680  *
1681  * Returns the #GstMpegtsAtscRRT contained in the @section.
1682  *
1683  * Returns: The #GstMpegtsAtscRRT contained in the section, or %NULL if an error
1684  * happened.
1685  * Since: 1.18
1686  */
1687 const GstMpegtsAtscRRT *
gst_mpegts_section_get_atsc_rrt(GstMpegtsSection * section)1688 gst_mpegts_section_get_atsc_rrt (GstMpegtsSection * section)
1689 {
1690   g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_RRT,
1691       NULL);
1692   g_return_val_if_fail (section->cached_parsed || section->data, NULL);
1693 
1694   if (!section->cached_parsed)
1695     section->cached_parsed =
1696         __common_section_checks (section, 17, _parse_rrt,
1697         (GDestroyNotify) _gst_mpegts_atsc_rrt_free);
1698 
1699   return (const GstMpegtsAtscRRT *) section->cached_parsed;
1700 }
1701 
1702 /**
1703  * gst_mpegts_section_atsc_rrt_dimension_value_new:
1704  *
1705  * Returns: (transfer full): #GstMpegtsAtscRRTDimensionValue
1706  * Since: 1.18
1707  */
1708 GstMpegtsAtscRRTDimensionValue *
gst_mpegts_atsc_rrt_dimension_value_new(void)1709 gst_mpegts_atsc_rrt_dimension_value_new (void)
1710 {
1711   GstMpegtsAtscRRTDimensionValue *val;
1712 
1713   val = g_slice_new0 (GstMpegtsAtscRRTDimensionValue);
1714   val->abbrev_ratings = g_ptr_array_new_with_free_func ((GDestroyNotify)
1715       _gst_mpegts_atsc_mult_string_free);
1716   val->ratings = g_ptr_array_new_with_free_func ((GDestroyNotify)
1717       _gst_mpegts_atsc_mult_string_free);
1718 
1719   return val;
1720 }
1721 
1722 /**
1723  * gst_mpegts_section_atsc_rrt_dimension_new:
1724  *
1725  * Returns: (transfer full): #GstMpegtsAtscRRTDimension
1726  * Since: 1.18
1727  */
1728 GstMpegtsAtscRRTDimension *
gst_mpegts_atsc_rrt_dimension_new(void)1729 gst_mpegts_atsc_rrt_dimension_new (void)
1730 {
1731   GstMpegtsAtscRRTDimension *dim;
1732 
1733   dim = g_slice_new0 (GstMpegtsAtscRRTDimension);
1734   dim->names = g_ptr_array_new_with_free_func ((GDestroyNotify)
1735       _gst_mpegts_atsc_mult_string_free);
1736   dim->values = g_ptr_array_new_with_free_func ((GDestroyNotify)
1737       _gst_mpegts_atsc_rrt_dimension_value_free);
1738 
1739   return dim;
1740 }
1741 
1742 /**
1743  * gst_mpegts_section_atsc_rrt_new:
1744  *
1745  * Returns: (transfer full): #GstMpegtsAtscRRT
1746  * Since: 1.18
1747  */
1748 GstMpegtsAtscRRT *
gst_mpegts_atsc_rrt_new(void)1749 gst_mpegts_atsc_rrt_new (void)
1750 {
1751   GstMpegtsAtscRRT *rrt;
1752 
1753   rrt = g_slice_new0 (GstMpegtsAtscRRT);
1754   rrt->names = g_ptr_array_new_with_free_func ((GDestroyNotify)
1755       _gst_mpegts_atsc_mult_string_free);
1756   rrt->dimensions = g_ptr_array_new_with_free_func ((GDestroyNotify)
1757       _gst_mpegts_atsc_rrt_dimension_free);
1758   rrt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
1759       gst_mpegts_descriptor_free);
1760 
1761   return rrt;
1762 }
1763