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