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