1 /*
2 * gstmpegtsdescriptor.c -
3 * Copyright (C) 2013 Edward Hervey
4 *
5 * Authors:
6 * Edward Hervey <edward@collabora.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "mpegts.h"
31 #include "gstmpegts-private.h"
32
33 #define DEFINE_STATIC_COPY_FUNCTION(type, name) \
34 static type * _##name##_copy (type * source) \
35 { \
36 return g_slice_dup (type, source); \
37 }
38
39 #define DEFINE_STATIC_FREE_FUNCTION(type, name) \
40 static void _##name##_free (type * source) \
41 { \
42 g_slice_free (type, source); \
43 }
44
45 /**
46 * SECTION:gstmpegtsdescriptor
47 * @title: Base MPEG-TS descriptors
48 * @short_description: Descriptors for ITU H.222.0 | ISO/IEC 13818-1
49 * @include: gst/mpegts/mpegts.h
50 *
51 * These are the base descriptor types and methods.
52 *
53 * For more details, refer to the ITU H.222.0 or ISO/IEC 13818-1 specifications
54 * and other specifications mentioned in the documentation.
55 */
56
57 /*
58 * TODO
59 *
60 * * Add common validation code for data presence and minimum/maximum expected
61 * size.
62 * * Add parsing methods for the following descriptors that were previously
63 * handled in mpegtsbase:
64 * * GST_MTS_DESC_DVB_DATA_BROADCAST_ID
65 * * GST_MTS_DESC_DVB_CAROUSEL_IDENTIFIER
66 * * GST_MTS_DESC_DVB_FREQUENCY_LIST
67 */
68
69 #define MAX_KNOWN_ICONV 25
70
71 /* First column is the original encoding,
72 * second column is the target encoding */
73
74 static GIConv __iconvs[MAX_KNOWN_ICONV][MAX_KNOWN_ICONV];
75
76 /* All these conversions will be to UTF8 */
77 typedef enum
78 {
79 _ICONV_UNKNOWN = -1,
80 _ICONV_ISO8859_1,
81 _ICONV_ISO8859_2,
82 _ICONV_ISO8859_3,
83 _ICONV_ISO8859_4,
84 _ICONV_ISO8859_5,
85 _ICONV_ISO8859_6,
86 _ICONV_ISO8859_7,
87 _ICONV_ISO8859_8,
88 _ICONV_ISO8859_9,
89 _ICONV_ISO8859_10,
90 _ICONV_ISO8859_11,
91 _ICONV_ISO8859_12,
92 _ICONV_ISO8859_13,
93 _ICONV_ISO8859_14,
94 _ICONV_ISO8859_15,
95 _ICONV_UCS_2BE,
96 _ICONV_EUC_KR,
97 _ICONV_GB2312,
98 _ICONV_UTF_16BE,
99 _ICONV_ISO10646_UTF8,
100 _ICONV_ISO6937,
101 _ICONV_UTF8,
102 /* Insert more here if needed */
103 _ICONV_MAX
104 } LocalIconvCode;
105
106 static const gchar *iconvtablename[] = {
107 "iso-8859-1",
108 "iso-8859-2",
109 "iso-8859-3",
110 "iso-8859-4",
111 "iso-8859-5",
112 "iso-8859-6",
113 "iso-8859-7",
114 "iso-8859-8",
115 "iso-8859-9",
116 "iso-8859-10",
117 "iso-8859-11",
118 "iso-8859-12",
119 "iso-8859-13",
120 "iso-8859-14",
121 "iso-8859-15",
122 "UCS-2BE",
123 "EUC-KR",
124 "GB2312",
125 "UTF-16BE",
126 "ISO-10646/UTF8",
127 "iso6937",
128 "utf-8"
129 /* Insert more here if needed */
130 };
131
132 void
__initialize_descriptors(void)133 __initialize_descriptors (void)
134 {
135 guint i, j;
136
137 /* Initialize converters */
138 /* FIXME : How/when should we close them ??? */
139 for (i = 0; i < MAX_KNOWN_ICONV; i++) {
140 for (j = 0; j < MAX_KNOWN_ICONV; j++)
141 __iconvs[i][j] = ((GIConv) - 1);
142 }
143 }
144
145 /*
146 * @text: The text you want to get the encoding from
147 * @start_text: Location where the beginning of the actual text is stored
148 * @is_multibyte: Location where information whether it's a multibyte encoding
149 * or not is stored
150 * @returns: GIconv for conversion or NULL
151 */
152 static LocalIconvCode
get_encoding(const gchar * text,guint * start_text,gboolean * is_multibyte)153 get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte)
154 {
155 LocalIconvCode encoding;
156 guint8 firstbyte;
157
158 *is_multibyte = FALSE;
159 *start_text = 0;
160
161 firstbyte = (guint8) text[0];
162
163 /* A wrong value */
164 g_return_val_if_fail (firstbyte != 0x00, _ICONV_UNKNOWN);
165
166 if (firstbyte <= 0x0B) {
167 /* 0x01 => iso 8859-5 */
168 encoding = firstbyte + _ICONV_ISO8859_4;
169 *start_text = 1;
170 goto beach;
171 }
172
173 /* ETSI EN 300 468, "Selection of character table" */
174 switch (firstbyte) {
175 case 0x0C:
176 case 0x0D:
177 case 0x0E:
178 case 0x0F:
179 /* RESERVED */
180 encoding = _ICONV_UNKNOWN;
181 break;
182 case 0x10:
183 {
184 guint16 table;
185
186 table = GST_READ_UINT16_BE (text + 1);
187
188 if (table < 17)
189 encoding = _ICONV_UNKNOWN + table;
190 else
191 encoding = _ICONV_UNKNOWN;
192 *start_text = 3;
193 break;
194 }
195 case 0x11:
196 encoding = _ICONV_UCS_2BE;
197 *start_text = 1;
198 *is_multibyte = TRUE;
199 break;
200 case 0x12:
201 /* EUC-KR implements KSX1001 */
202 encoding = _ICONV_EUC_KR;
203 *start_text = 1;
204 *is_multibyte = TRUE;
205 break;
206 case 0x13:
207 encoding = _ICONV_GB2312;
208 *start_text = 1;
209 break;
210 case 0x14:
211 encoding = _ICONV_UTF_16BE;
212 *start_text = 1;
213 *is_multibyte = TRUE;
214 break;
215 case 0x15:
216 /* TODO : Where does this come from ?? */
217 encoding = _ICONV_ISO10646_UTF8;
218 *start_text = 1;
219 break;
220 case 0x16:
221 case 0x17:
222 case 0x18:
223 case 0x19:
224 case 0x1A:
225 case 0x1B:
226 case 0x1C:
227 case 0x1D:
228 case 0x1E:
229 case 0x1F:
230 /* RESERVED */
231 encoding = _ICONV_UNKNOWN;
232 break;
233 default:
234 encoding = _ICONV_ISO6937;
235 break;
236 }
237
238 beach:
239 GST_DEBUG
240 ("Found encoding %d, first byte is 0x%02x, start_text: %u, is_multibyte: %d",
241 encoding, firstbyte, *start_text, *is_multibyte);
242
243 return encoding;
244 }
245
246 static GIConv
_get_iconv(LocalIconvCode from,LocalIconvCode to)247 _get_iconv (LocalIconvCode from, LocalIconvCode to)
248 {
249 if (__iconvs[from][to] == (GIConv) - 1)
250 __iconvs[from][to] = g_iconv_open (iconvtablename[to],
251 iconvtablename[from]);
252 return __iconvs[from][to];
253 }
254
255 static void
_encode_control_codes(gchar * text,gsize length,gboolean is_multibyte)256 _encode_control_codes (gchar * text, gsize length, gboolean is_multibyte)
257 {
258 gsize pos = 0;
259
260 while (pos < length) {
261 if (is_multibyte) {
262 guint16 code = GST_READ_UINT16_BE (text + pos);
263 if (code == 0x000A) {
264 text[pos] = 0xE0;
265 text[pos + 1] = 0x8A;
266 }
267 pos += 2;
268 } else {
269 guint8 code = text[pos];
270 if (code == 0x0A)
271 text[pos] = 0x8A;
272 pos++;
273 }
274 }
275 }
276
277 /**
278 * dvb_text_from_utf8:
279 * @text: The text to convert. This should be in UTF-8 format
280 * @out_size: (out): the byte length of the new text
281 *
282 * Converts UTF-8 strings to text characters compliant with EN 300 468.
283 * The converted text can be used directly in DVB #GstMpegtsDescriptor
284 *
285 * The function will try different character maps until the string is
286 * completely converted.
287 *
288 * The function tries the default ISO 6937 character map first.
289 *
290 * If no character map that contains all characters could be found, the
291 * string is converted to ISO 6937 with unknown characters set to `?`.
292 *
293 * Returns: (transfer full): byte array of size @out_size
294 */
295 guint8 *
dvb_text_from_utf8(const gchar * text,gsize * out_size)296 dvb_text_from_utf8 (const gchar * text, gsize * out_size)
297 {
298 GError *error = NULL;
299 gchar *out_text;
300 guint8 *out_buffer;
301 guint encoding;
302 GIConv giconv = (GIConv) - 1;
303
304 /* We test character maps one-by-one. Start with the default */
305 encoding = _ICONV_ISO6937;
306 giconv = _get_iconv (_ICONV_UTF8, encoding);
307 out_text = g_convert_with_iconv (text, -1, giconv, NULL, out_size, &error);
308
309 if (out_text) {
310 GST_DEBUG ("Using default ISO6937 encoding");
311 goto out;
312 }
313
314 g_clear_error (&error);
315
316 for (encoding = _ICONV_ISO8859_1; encoding <= _ICONV_ISO10646_UTF8;
317 encoding++) {
318 giconv = _get_iconv (_ICONV_UTF8, encoding);
319 if (giconv == (GIConv) - 1)
320 continue;
321 out_text = g_convert_with_iconv (text, -1, giconv, NULL, out_size, &error);
322
323 if (out_text) {
324 GST_DEBUG ("Found suitable character map - %s", iconvtablename[encoding]);
325 goto out;
326 }
327
328 g_clear_error (&error);
329 }
330
331 out_text = g_convert_with_fallback (text, -1, iconvtablename[_ICONV_ISO6937],
332 iconvtablename[_ICONV_UTF8], "?", NULL, out_size, &error);
333
334 out:
335
336 if (error) {
337 GST_WARNING ("Could not convert from utf-8: %s", error->message);
338 g_error_free (error);
339 g_free (out_text);
340 return NULL;
341 }
342
343 switch (encoding) {
344 case _ICONV_ISO6937:
345 /* Default encoding contains no selection bytes. */
346 _encode_control_codes (out_text, *out_size, FALSE);
347 return (guint8 *) out_text;
348 case _ICONV_ISO8859_1:
349 case _ICONV_ISO8859_2:
350 case _ICONV_ISO8859_3:
351 case _ICONV_ISO8859_4:
352 /* These character sets requires 3 selection bytes */
353 _encode_control_codes (out_text, *out_size, FALSE);
354 out_buffer = g_malloc (*out_size + 3);
355 out_buffer[0] = 0x10;
356 out_buffer[1] = 0x00;
357 out_buffer[2] = encoding - _ICONV_ISO8859_1 + 1;
358 memcpy (out_buffer + 3, out_text, *out_size);
359 *out_size += 3;
360 g_free (out_text);
361 return out_buffer;
362 case _ICONV_ISO8859_5:
363 case _ICONV_ISO8859_6:
364 case _ICONV_ISO8859_7:
365 case _ICONV_ISO8859_8:
366 case _ICONV_ISO8859_9:
367 case _ICONV_ISO8859_10:
368 case _ICONV_ISO8859_11:
369 case _ICONV_ISO8859_12:
370 case _ICONV_ISO8859_13:
371 case _ICONV_ISO8859_14:
372 case _ICONV_ISO8859_15:
373 /* These character sets requires 1 selection byte */
374 _encode_control_codes (out_text, *out_size, FALSE);
375 out_buffer = g_malloc (*out_size + 1);
376 out_buffer[0] = encoding - _ICONV_ISO8859_5 + 1;
377 memcpy (out_buffer + 1, out_text, *out_size);
378 *out_size += 1;
379 g_free (out_text);
380 return out_buffer;
381 case _ICONV_UCS_2BE:
382 case _ICONV_EUC_KR:
383 case _ICONV_UTF_16BE:
384 /* These character sets requires 1 selection byte */
385 _encode_control_codes (out_text, *out_size, TRUE);
386 out_buffer = g_malloc (*out_size + 1);
387 out_buffer[0] = encoding - _ICONV_UCS_2BE + 0x11;
388 memcpy (out_buffer + 1, out_text, *out_size);
389 *out_size += 1;
390 g_free (out_text);
391 return out_buffer;
392 case _ICONV_GB2312:
393 case _ICONV_ISO10646_UTF8:
394 /* These character sets requires 1 selection byte */
395 _encode_control_codes (out_text, *out_size, FALSE);
396 out_buffer = g_malloc (*out_size + 1);
397 out_buffer[0] = encoding - _ICONV_UCS_2BE + 0x11;
398 memcpy (out_buffer + 1, out_text, *out_size);
399 *out_size += 1;
400 g_free (out_text);
401 return out_buffer;
402 default:
403 g_free (out_text);
404 return NULL;
405 }
406 }
407
408 /*
409 * @text: The text to convert. It may include pango markup (<b> and </b>)
410 * @length: The length of the string -1 if it's nul-terminated
411 * @start: Where to start converting in the text
412 * @encoding: The encoding of text
413 * @is_multibyte: Whether the encoding is a multibyte encoding
414 * @error: The location to store the error, or NULL to ignore errors
415 * @returns: UTF-8 encoded string
416 *
417 * Convert text to UTF-8.
418 */
419 static gchar *
convert_to_utf8(const gchar * text,gint length,guint start,GIConv giconv,gboolean is_multibyte,GError ** error)420 convert_to_utf8 (const gchar * text, gint length, guint start,
421 GIConv giconv, gboolean is_multibyte, GError ** error)
422 {
423 gchar *new_text;
424 gchar *tmp, *pos;
425 gint i;
426
427 text += start;
428
429 pos = tmp = g_malloc (length * 2);
430
431 if (is_multibyte) {
432 if (length == -1) {
433 while (*text != '\0') {
434 guint16 code = GST_READ_UINT16_BE (text);
435
436 switch (code) {
437 case 0xE086: /* emphasis on */
438 case 0xE087: /* emphasis off */
439 /* skip it */
440 break;
441 case 0xE08A:{
442 pos[0] = 0x00; /* 0x00 0x0A is a new line */
443 pos[1] = 0x0A;
444 pos += 2;
445 break;
446 }
447 default:
448 pos[0] = text[0];
449 pos[1] = text[1];
450 pos += 2;
451 break;
452 }
453
454 text += 2;
455 }
456 } else {
457 for (i = 0; i < length; i += 2) {
458 guint16 code = GST_READ_UINT16_BE (text);
459
460 switch (code) {
461 case 0xE086: /* emphasis on */
462 case 0xE087: /* emphasis off */
463 /* skip it */
464 break;
465 case 0xE08A:{
466 pos[0] = 0x00; /* 0x00 0x0A is a new line */
467 pos[1] = 0x0A;
468 pos += 2;
469 break;
470 }
471 default:
472 pos[0] = text[0];
473 pos[1] = text[1];
474 pos += 2;
475 break;
476 }
477
478 text += 2;
479 }
480 }
481 } else {
482 if (length == -1) {
483 while (*text != '\0') {
484 guint8 code = (guint8) (*text);
485
486 switch (code) {
487 case 0x86: /* emphasis on */
488 case 0x87: /* emphasis off */
489 /* skip it */
490 break;
491 case 0x8A:
492 *pos = '\n';
493 pos += 1;
494 break;
495 default:
496 *pos = *text;
497 pos += 1;
498 break;
499 }
500
501 text++;
502 }
503 } else {
504 for (i = 0; i < length; i++) {
505 guint8 code = (guint8) (*text);
506
507 switch (code) {
508 case 0x86: /* emphasis on */
509 case 0x87: /* emphasis off */
510 /* skip it */
511 break;
512 case 0x8A:
513 *pos = '\n';
514 pos += 1;
515 break;
516 default:
517 *pos = *text;
518 pos += 1;
519 break;
520 }
521
522 text++;
523 }
524 }
525 }
526
527 if (pos > tmp) {
528 gsize bread = 0;
529 new_text =
530 g_convert_with_iconv (tmp, pos - tmp, giconv, &bread, NULL, error);
531 GST_DEBUG ("Converted to : %s", new_text);
532 } else {
533 new_text = g_strdup ("");
534 }
535
536 g_free (tmp);
537
538 return new_text;
539 }
540
541 gchar *
get_encoding_and_convert(const gchar * text,guint length)542 get_encoding_and_convert (const gchar * text, guint length)
543 {
544 GError *error = NULL;
545 gchar *converted_str;
546 guint start_text = 0;
547 gboolean is_multibyte;
548 LocalIconvCode encoding;
549 GIConv giconv = (GIConv) - 1;
550
551 g_return_val_if_fail (text != NULL, NULL);
552
553 if (text == NULL || length == 0)
554 return g_strdup ("");
555
556 encoding = get_encoding (text, &start_text, &is_multibyte);
557
558 if (encoding > _ICONV_UNKNOWN && encoding < _ICONV_MAX) {
559 GST_DEBUG ("Encoding %s", iconvtablename[encoding]);
560 giconv = _get_iconv (encoding, _ICONV_UTF8);
561 } else {
562 GST_FIXME ("Could not detect encoding. Returning NULL string");
563 converted_str = NULL;
564 goto beach;
565 }
566
567 converted_str = convert_to_utf8 (text, length - start_text, start_text,
568 giconv, is_multibyte, &error);
569 if (error != NULL) {
570 GST_WARNING ("Could not convert string: %s", error->message);
571 g_free (converted_str);
572 g_error_free (error);
573 error = NULL;
574
575 if (encoding >= _ICONV_ISO8859_2 && encoding <= _ICONV_ISO8859_15) {
576 /* Sometimes using the standard 8859-1 set fixes issues */
577 GST_DEBUG ("Encoding %s", iconvtablename[_ICONV_ISO8859_1]);
578 giconv = _get_iconv (_ICONV_ISO8859_1, _ICONV_UTF8);
579
580 GST_INFO ("Trying encoding ISO 8859-1");
581 converted_str = convert_to_utf8 (text, length, 1, giconv, FALSE, &error);
582 if (error != NULL) {
583 GST_WARNING
584 ("Could not convert string while assuming encoding ISO 8859-1: %s",
585 error->message);
586 g_error_free (error);
587 goto failed;
588 }
589 } else if (encoding == _ICONV_ISO6937) {
590
591 /* The first part of ISO 6937 is identical to ISO 8859-9, but
592 * they differ in the second part. Some channels don't
593 * provide the first byte that indicates ISO 8859-9 encoding.
594 * If decoding from ISO 6937 failed, we try ISO 8859-9 here.
595 */
596 giconv = _get_iconv (_ICONV_ISO8859_9, _ICONV_UTF8);
597
598 GST_INFO ("Trying encoding ISO 8859-9");
599 converted_str = convert_to_utf8 (text, length, 0, giconv, FALSE, &error);
600 if (error != NULL) {
601 GST_WARNING
602 ("Could not convert string while assuming encoding ISO 8859-9: %s",
603 error->message);
604 g_error_free (error);
605 goto failed;
606 }
607 } else
608 goto failed;
609 }
610
611 beach:
612 return converted_str;
613
614 failed:
615 {
616 text += start_text;
617 return g_strndup (text, length - start_text);
618 }
619 }
620
621 gchar *
convert_lang_code(guint8 * data)622 convert_lang_code (guint8 * data)
623 {
624 gchar *code;
625 /* the iso language code and country code is always 3 byte long */
626 code = g_malloc0 (4);
627 memcpy (code, data, 3);
628
629 return code;
630 }
631
632 void
_packetize_descriptor_array(GPtrArray * array,guint8 ** out_data)633 _packetize_descriptor_array (GPtrArray * array, guint8 ** out_data)
634 {
635 guint i;
636 GstMpegtsDescriptor *descriptor;
637
638 g_return_if_fail (out_data != NULL);
639 g_return_if_fail (*out_data != NULL);
640
641 if (array == NULL)
642 return;
643
644 for (i = 0; i < array->len; i++) {
645 descriptor = g_ptr_array_index (array, i);
646
647 memcpy (*out_data, descriptor->data, descriptor->length + 2);
648 *out_data += descriptor->length + 2;
649 }
650 }
651
652 GstMpegtsDescriptor *
_new_descriptor(guint8 tag,guint8 length)653 _new_descriptor (guint8 tag, guint8 length)
654 {
655 GstMpegtsDescriptor *descriptor;
656 guint8 *data;
657
658 descriptor = g_slice_new (GstMpegtsDescriptor);
659
660 descriptor->tag = tag;
661 descriptor->tag_extension = 0;
662 descriptor->length = length;
663
664 descriptor->data = g_malloc (length + 2);
665
666 data = descriptor->data;
667
668 *data++ = descriptor->tag;
669 *data = descriptor->length;
670
671 return descriptor;
672 }
673
674 GstMpegtsDescriptor *
_new_descriptor_with_extension(guint8 tag,guint8 tag_extension,guint8 length)675 _new_descriptor_with_extension (guint8 tag, guint8 tag_extension, guint8 length)
676 {
677 GstMpegtsDescriptor *descriptor;
678 guint8 *data;
679
680 descriptor = g_slice_new (GstMpegtsDescriptor);
681
682 descriptor->tag = tag;
683 descriptor->tag_extension = tag_extension;
684 descriptor->length = length + 1;
685
686 descriptor->data = g_malloc (length + 3);
687
688 data = descriptor->data;
689
690 *data++ = descriptor->tag;
691 *data++ = descriptor->length;
692 *data = descriptor->tag_extension;
693
694 return descriptor;
695 }
696
697 static GstMpegtsDescriptor *
_copy_descriptor(GstMpegtsDescriptor * desc)698 _copy_descriptor (GstMpegtsDescriptor * desc)
699 {
700 GstMpegtsDescriptor *copy;
701
702 copy = g_slice_dup (GstMpegtsDescriptor, desc);
703 copy->data = g_memdup2 (desc->data, desc->length + 2);
704
705 return copy;
706 }
707
708 /**
709 * gst_mpegts_descriptor_free:
710 * @desc: The descriptor to free
711 *
712 * Frees @desc
713 */
714 void
gst_mpegts_descriptor_free(GstMpegtsDescriptor * desc)715 gst_mpegts_descriptor_free (GstMpegtsDescriptor * desc)
716 {
717 g_free ((gpointer) desc->data);
718 g_slice_free (GstMpegtsDescriptor, desc);
719 }
720
721 G_DEFINE_BOXED_TYPE (GstMpegtsDescriptor, gst_mpegts_descriptor,
722 (GBoxedCopyFunc) _copy_descriptor,
723 (GBoxedFreeFunc) gst_mpegts_descriptor_free);
724
725 /**
726 * gst_mpegts_parse_descriptors:
727 * @buffer: (transfer none): descriptors to parse
728 * @buf_len: Size of @buffer
729 *
730 * Parses the descriptors present in @buffer and returns them as an
731 * array.
732 *
733 * Note: The data provided in @buffer will not be copied.
734 *
735 * Returns: (transfer full) (element-type GstMpegtsDescriptor): an
736 * array of the parsed descriptors or %NULL if there was an error.
737 * Release with #g_array_unref when done with it.
738 */
739 GPtrArray *
gst_mpegts_parse_descriptors(guint8 * buffer,gsize buf_len)740 gst_mpegts_parse_descriptors (guint8 * buffer, gsize buf_len)
741 {
742 GPtrArray *res;
743 guint8 length;
744 guint8 *data;
745 guint i, nb_desc = 0;
746
747 /* fast-path */
748 if (buf_len == 0)
749 return g_ptr_array_new ();
750
751 data = buffer;
752
753 GST_MEMDUMP ("Full descriptor array", buffer, buf_len);
754
755 while (data - buffer < buf_len) {
756 data++; /* skip tag */
757 length = *data++;
758
759 if (data - buffer > buf_len) {
760 GST_WARNING ("invalid descriptor length %d now at %d max %"
761 G_GSIZE_FORMAT, length, (gint) (data - buffer), buf_len);
762 return NULL;
763 }
764
765 data += length;
766 nb_desc++;
767 }
768
769 GST_DEBUG ("Saw %d descriptors, read %" G_GSIZE_FORMAT " bytes",
770 nb_desc, (gsize) (data - buffer));
771
772 if (data - buffer != buf_len) {
773 GST_WARNING ("descriptors size %d expected %" G_GSIZE_FORMAT,
774 (gint) (data - buffer), buf_len);
775 return NULL;
776 }
777
778 res =
779 g_ptr_array_new_full (nb_desc + 1,
780 (GDestroyNotify) gst_mpegts_descriptor_free);
781
782 data = buffer;
783
784 for (i = 0; i < nb_desc; i++) {
785 GstMpegtsDescriptor *desc = g_slice_new0 (GstMpegtsDescriptor);
786
787 desc->data = data;
788 desc->tag = *data++;
789 desc->length = *data++;
790 /* Copy the data now that we known the size */
791 desc->data = g_memdup2 (desc->data, desc->length + 2);
792 GST_LOG ("descriptor 0x%02x length:%d", desc->tag, desc->length);
793 GST_MEMDUMP ("descriptor", desc->data + 2, desc->length);
794 /* extended descriptors */
795 if (G_UNLIKELY (desc->tag == 0x7f))
796 desc->tag_extension = *data;
797
798 data += desc->length;
799
800 /* Set the descriptor in the array */
801 g_ptr_array_index (res, i) = desc;
802 }
803
804 res->len = nb_desc;
805
806 return res;
807 }
808
809 /**
810 * gst_mpegts_find_descriptor:
811 * @descriptors: (element-type GstMpegtsDescriptor) (transfer none): an array
812 * of #GstMpegtsDescriptor
813 * @tag: the tag to look for
814 *
815 * Finds the first descriptor of type @tag in the array.
816 *
817 * Note: To look for descriptors that can be present more than once in an
818 * array of descriptors, iterate the #GArray manually.
819 *
820 * Returns: (transfer none): the first descriptor matching @tag, else %NULL.
821 */
822 const GstMpegtsDescriptor *
gst_mpegts_find_descriptor(GPtrArray * descriptors,guint8 tag)823 gst_mpegts_find_descriptor (GPtrArray * descriptors, guint8 tag)
824 {
825 guint i, nb_desc;
826
827 g_return_val_if_fail (descriptors != NULL, NULL);
828
829 nb_desc = descriptors->len;
830 for (i = 0; i < nb_desc; i++) {
831 GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
832 if (desc->tag == tag)
833 return (const GstMpegtsDescriptor *) desc;
834 }
835 return NULL;
836 }
837
838 /**
839 * gst_mpegts_find_descriptor_with_extension:
840 * @descriptors: (element-type GstMpegtsDescriptor) (transfer none): an array
841 * of #GstMpegtsDescriptor
842 * @tag: the tag to look for
843 *
844 * Finds the first descriptor of type @tag with @tag_extension in the array.
845 *
846 * Note: To look for descriptors that can be present more than once in an
847 * array of descriptors, iterate the #GArray manually.
848 *
849 * Returns: (transfer none): the first descriptor matchin @tag with @tag_extension, else %NULL.
850 *
851 * Since: 1.20
852 */
853 const GstMpegtsDescriptor *
gst_mpegts_find_descriptor_with_extension(GPtrArray * descriptors,guint8 tag,guint8 tag_extension)854 gst_mpegts_find_descriptor_with_extension (GPtrArray * descriptors, guint8 tag,
855 guint8 tag_extension)
856 {
857 guint i, nb_desc;
858
859 g_return_val_if_fail (descriptors != NULL, NULL);
860
861 nb_desc = descriptors->len;
862 for (i = 0; i < nb_desc; i++) {
863 GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
864 if ((desc->tag == tag) && (desc->tag_extension == tag_extension))
865 return (const GstMpegtsDescriptor *) desc;
866 }
867 return NULL;
868 }
869
870 /* GST_MTS_DESC_REGISTRATION (0x05) */
871 /**
872 * gst_mpegts_descriptor_from_registration:
873 * @format_identifier: (transfer none): a 4 character format identifier string
874 * @additional_info: (transfer none) (allow-none) (array length=additional_info_length): pointer to optional additional info
875 * @additional_info_length: length of the optional @additional_info
876 *
877 * Creates a %GST_MTS_DESC_REGISTRATION #GstMpegtsDescriptor
878 *
879 * Return: #GstMpegtsDescriptor, %NULL on failure
880 */
881 GstMpegtsDescriptor *
gst_mpegts_descriptor_from_registration(const gchar * format_identifier,guint8 * additional_info,gsize additional_info_length)882 gst_mpegts_descriptor_from_registration (const gchar * format_identifier,
883 guint8 * additional_info, gsize additional_info_length)
884 {
885 GstMpegtsDescriptor *descriptor;
886
887 g_return_val_if_fail (format_identifier != NULL, NULL);
888 g_return_val_if_fail (additional_info_length > 0 || !additional_info, NULL);
889
890 descriptor = _new_descriptor (GST_MTS_DESC_REGISTRATION,
891 4 + additional_info_length);
892
893 memcpy (descriptor->data + 2, format_identifier, 4);
894 if (additional_info && (additional_info_length > 0))
895 memcpy (descriptor->data + 6, additional_info, additional_info_length);
896
897 return descriptor;
898 }
899
900 /**
901 * gst_mpegts_descriptor_parse_registration:
902 * @descriptor: a %GST_MTS_DESC_REGISTRATION #GstMpegtsDescriptor
903 * @registration_id: (out): The registration ID (in host endiannes)
904 * @additional_info: (out) (allow-none) (array length=additional_info_length): The additional information
905 * @additional_info_length: (out) (allow-none): The size of @additional_info in bytes.
906 *
907 * Extracts the Registration information from @descriptor.
908 *
909 * Returns: %TRUE if parsing succeeded, else %FALSE.
910 *
911 * Since: 1.20
912 */
913
914 gboolean
gst_mpegts_descriptor_parse_registration(GstMpegtsDescriptor * descriptor,guint32 * registration_id,guint8 ** additional_info,gsize * additional_info_length)915 gst_mpegts_descriptor_parse_registration (GstMpegtsDescriptor * descriptor,
916 guint32 * registration_id,
917 guint8 ** additional_info, gsize * additional_info_length)
918 {
919 guint8 *data;
920
921 g_return_val_if_fail (descriptor != NULL && registration_id != NULL, FALSE);
922
923 /* The smallest registration is 4 bytes */
924 __common_desc_checks (descriptor, GST_MTS_DESC_REGISTRATION, 4, FALSE);
925
926 data = (guint8 *) descriptor->data + 2;
927 *registration_id = GST_READ_UINT32_BE (data);
928 data += 4;
929 if (additional_info && additional_info_length) {
930 *additional_info_length = descriptor->length - 4;
931 if (descriptor->length > 4) {
932 *additional_info = data;
933 } else {
934 *additional_info = NULL;
935 }
936 }
937
938 return TRUE;
939 }
940
941 /* GST_MTS_DESC_CA (0x09) */
942
943 /**
944 * gst_mpegts_descriptor_parse_ca:
945 * @descriptor: a %GST_MTS_DESC_CA #GstMpegtsDescriptor
946 * @ca_system_id: (out): the type of CA system used
947 * @ca_pid: (out): The PID containing ECM or EMM data
948 * @private_data: (out) (allow-none) (array length=private_data_size): The private data
949 * @private_data_size: (out) (allow-none): The size of @private_data in bytes
950 *
951 * Extracts the Conditional Access information from @descriptor.
952 *
953 * Returns: %TRUE if parsing succeeded, else %FALSE.
954 */
955
956 gboolean
gst_mpegts_descriptor_parse_ca(GstMpegtsDescriptor * descriptor,guint16 * ca_system_id,guint16 * ca_pid,const guint8 ** private_data,gsize * private_data_size)957 gst_mpegts_descriptor_parse_ca (GstMpegtsDescriptor * descriptor,
958 guint16 * ca_system_id, guint16 * ca_pid,
959 const guint8 ** private_data, gsize * private_data_size)
960 {
961 guint8 *data;
962
963 g_return_val_if_fail (descriptor != NULL && ca_system_id != NULL
964 && ca_pid != NULL, FALSE);
965 /* The smallest CA is 4 bytes (though not having any private data
966 * sounds a bit ... weird) */
967 __common_desc_checks (descriptor, GST_MTS_DESC_CA, 4, FALSE);
968
969 data = (guint8 *) descriptor->data + 2;
970 *ca_system_id = GST_READ_UINT16_BE (data);
971 data += 2;
972 *ca_pid = GST_READ_UINT16_BE (data) & 0x1fff;
973 data += 2;
974 if (private_data && private_data_size) {
975 *private_data = data;
976 *private_data_size = descriptor->length - 4;
977 }
978
979 return TRUE;
980 }
981
982 /* GST_MTS_DESC_ISO_639_LANGUAGE (0x0A) */
983 static GstMpegtsISO639LanguageDescriptor *
_gst_mpegts_iso_639_language_descriptor_copy(GstMpegtsISO639LanguageDescriptor * source)984 _gst_mpegts_iso_639_language_descriptor_copy (GstMpegtsISO639LanguageDescriptor
985 * source)
986 {
987 GstMpegtsISO639LanguageDescriptor *copy;
988 guint i;
989
990 copy = g_slice_dup (GstMpegtsISO639LanguageDescriptor, source);
991
992 for (i = 0; i < source->nb_language; i++) {
993 copy->language[i] = g_strdup (source->language[i]);
994 }
995
996 return copy;
997 }
998
999 void
gst_mpegts_iso_639_language_descriptor_free(GstMpegtsISO639LanguageDescriptor * desc)1000 gst_mpegts_iso_639_language_descriptor_free (GstMpegtsISO639LanguageDescriptor
1001 * desc)
1002 {
1003 guint i;
1004
1005 for (i = 0; i < desc->nb_language; i++) {
1006 g_free (desc->language[i]);
1007 }
1008 g_slice_free (GstMpegtsISO639LanguageDescriptor, desc);
1009 }
1010
1011 G_DEFINE_BOXED_TYPE (GstMpegtsISO639LanguageDescriptor,
1012 gst_mpegts_iso_639_language,
1013 (GBoxedCopyFunc) _gst_mpegts_iso_639_language_descriptor_copy,
1014 (GFreeFunc) gst_mpegts_iso_639_language_descriptor_free);
1015
1016 /**
1017 * gst_mpegts_descriptor_parse_iso_639_language:
1018 * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1019 * @res: (out) (transfer full): the #GstMpegtsISO639LanguageDescriptor to fill
1020 *
1021 * Extracts the iso 639-2 language information from @descriptor.
1022 *
1023 * Note: Use #gst_tag_get_language_code if you want to get the the
1024 * ISO 639-1 language code from the returned ISO 639-2 one.
1025 *
1026 * Returns: %TRUE if parsing succeeded, else %FALSE.
1027 */
1028 gboolean
gst_mpegts_descriptor_parse_iso_639_language(const GstMpegtsDescriptor * descriptor,GstMpegtsISO639LanguageDescriptor ** desc)1029 gst_mpegts_descriptor_parse_iso_639_language (const GstMpegtsDescriptor *
1030 descriptor, GstMpegtsISO639LanguageDescriptor ** desc)
1031 {
1032 guint i;
1033 guint8 *data;
1034 GstMpegtsISO639LanguageDescriptor *res;
1035
1036 g_return_val_if_fail (descriptor != NULL && desc != NULL, FALSE);
1037 /* This descriptor can be empty, no size check needed */
1038 __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1039
1040 data = (guint8 *) descriptor->data + 2;
1041
1042 res = g_slice_new0 (GstMpegtsISO639LanguageDescriptor);
1043
1044 /* Each language is 3 + 1 bytes */
1045 res->nb_language = descriptor->length / 4;
1046 for (i = 0; i < res->nb_language; i++) {
1047 res->language[i] = convert_lang_code (data);
1048 res->audio_type[i] = data[3];
1049 data += 4;
1050 }
1051
1052 *desc = res;
1053
1054 return TRUE;
1055
1056 }
1057
1058 /**
1059 * gst_mpegts_descriptor_parse_iso_639_language_idx:
1060 * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1061 * @idx: Table id of the language to parse
1062 * @lang: (out) (transfer full): 4-byte gchar array to hold the language code
1063 * @audio_type: (out) (transfer none) (allow-none): the #GstMpegtsIso639AudioType to set
1064 *
1065 * Extracts the iso 639-2 language information from specific table id in @descriptor.
1066 *
1067 * Note: Use #gst_tag_get_language_code if you want to get the the
1068 * ISO 639-1 language code from the returned ISO 639-2 one.
1069 *
1070 * Returns: %TRUE if parsing succeeded, else %FALSE.
1071 */
1072 gboolean
gst_mpegts_descriptor_parse_iso_639_language_idx(const GstMpegtsDescriptor * descriptor,guint idx,gchar ** lang,GstMpegtsIso639AudioType * audio_type)1073 gst_mpegts_descriptor_parse_iso_639_language_idx (const GstMpegtsDescriptor *
1074 descriptor, guint idx, gchar ** lang, GstMpegtsIso639AudioType * audio_type)
1075 {
1076 guint8 *data;
1077
1078 g_return_val_if_fail (descriptor != NULL && lang != NULL, FALSE);
1079 /* This descriptor can be empty, no size check needed */
1080 __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1081
1082 if (descriptor->length / 4 <= idx)
1083 return FALSE;
1084
1085 data = (guint8 *) descriptor->data + 2 + idx * 4;
1086
1087 *lang = convert_lang_code (data);
1088
1089 data += 3;
1090
1091 if (audio_type)
1092 *audio_type = *data;
1093
1094 return TRUE;
1095 }
1096
1097 /**
1098 * gst_mpegts_descriptor_parse_iso_639_language_nb:
1099 * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1100 *
1101 * Returns: The number of languages in @descriptor
1102 */
1103 guint
gst_mpegts_descriptor_parse_iso_639_language_nb(const GstMpegtsDescriptor * descriptor)1104 gst_mpegts_descriptor_parse_iso_639_language_nb (const GstMpegtsDescriptor *
1105 descriptor)
1106 {
1107 g_return_val_if_fail (descriptor != NULL, 0);
1108 /* This descriptor can be empty, no size check needed */
1109 __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1110
1111 return descriptor->length / 4;
1112 }
1113
1114 /**
1115 * gst_mpegts_descriptor_from_iso_639_language:
1116 * @language: (transfer none): ISO-639-2 language 3-char code
1117 *
1118 * Creates a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor with
1119 * a single language
1120 *
1121 * Return: #GstMpegtsDescriptor, %NULL on failure
1122 */
1123 GstMpegtsDescriptor *
gst_mpegts_descriptor_from_iso_639_language(const gchar * language)1124 gst_mpegts_descriptor_from_iso_639_language (const gchar * language)
1125 {
1126 GstMpegtsDescriptor *descriptor;
1127
1128 g_return_val_if_fail (language != NULL, NULL);
1129
1130 descriptor = _new_descriptor (GST_MTS_DESC_ISO_639_LANGUAGE, 4); /* a language takes 4 bytes */
1131
1132 memcpy (descriptor->data + 2, language, 3);
1133 descriptor->data[2 + 3] = 0; /* set audio type to undefined */
1134
1135 return descriptor;
1136 }
1137
1138 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1139 gst_mpegts_logical_channel_descriptor);
1140
1141 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1142 gst_mpegts_logical_channel_descriptor);
1143
1144 G_DEFINE_BOXED_TYPE (GstMpegtsLogicalChannelDescriptor,
1145 gst_mpegts_logical_channel_descriptor,
1146 (GBoxedCopyFunc) _gst_mpegts_logical_channel_descriptor_copy,
1147 (GFreeFunc) _gst_mpegts_logical_channel_descriptor_free);
1148
1149 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannel,
1150 gst_mpegts_logical_channel);
1151
1152 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannel,
1153 gst_mpegts_logical_channel);
1154
1155 G_DEFINE_BOXED_TYPE (GstMpegtsLogicalChannel,
1156 gst_mpegts_logical_channel,
1157 (GBoxedCopyFunc) _gst_mpegts_logical_channel_copy,
1158 (GFreeFunc) _gst_mpegts_logical_channel_free);
1159
1160 /**
1161 * gst_mpegts_descriptor_parse_logical_channel:
1162 * @descriptor: a %GST_MTS_DESC_DTG_LOGICAL_CHANNEL #GstMpegtsDescriptor
1163 * @res: (out) (transfer none): the #GstMpegtsLogicalChannelDescriptor to fill
1164 *
1165 * Extracts the logical channels from @descriptor.
1166 *
1167 * Returns: %TRUE if parsing succeeded, else %FALSE.
1168 */
1169 gboolean
gst_mpegts_descriptor_parse_logical_channel(const GstMpegtsDescriptor * descriptor,GstMpegtsLogicalChannelDescriptor * res)1170 gst_mpegts_descriptor_parse_logical_channel (const GstMpegtsDescriptor *
1171 descriptor, GstMpegtsLogicalChannelDescriptor * res)
1172 {
1173 guint i;
1174 guint8 *data;
1175
1176 g_return_val_if_fail (descriptor != NULL && res != NULL, FALSE);
1177 /* This descriptor loop can be empty, no size check required */
1178 __common_desc_check_base (descriptor, GST_MTS_DESC_DTG_LOGICAL_CHANNEL,
1179 FALSE);
1180
1181 data = (guint8 *) descriptor->data + 2;
1182
1183 res->nb_channels = descriptor->length / 4;
1184
1185 for (i = 0; i < res->nb_channels; i++) {
1186 res->channels[i].service_id = GST_READ_UINT16_BE (data);
1187 data += 2;
1188 res->channels[i].visible_service = *data >> 7;
1189 res->channels[i].logical_channel_number =
1190 GST_READ_UINT16_BE (data) & 0x03ff;
1191 data += 2;
1192 }
1193
1194 return TRUE;
1195 }
1196
1197 /**
1198 * gst_mpegts_descriptor_from_custom:
1199 * @tag: descriptor tag
1200 * @data: (transfer none) (array length=length): descriptor data (after tag and length field)
1201 * @length: length of @data
1202 *
1203 * Creates a #GstMpegtsDescriptor with custom @tag and @data
1204 *
1205 * Returns: #GstMpegtsDescriptor
1206 */
1207 GstMpegtsDescriptor *
gst_mpegts_descriptor_from_custom(guint8 tag,const guint8 * data,gsize length)1208 gst_mpegts_descriptor_from_custom (guint8 tag, const guint8 * data,
1209 gsize length)
1210 {
1211 GstMpegtsDescriptor *descriptor;
1212
1213 g_return_val_if_fail (length > 0 || !data, NULL);
1214
1215 descriptor = _new_descriptor (tag, length);
1216
1217 if (data && (length > 0))
1218 memcpy (descriptor->data + 2, data, length);
1219
1220 return descriptor;
1221 }
1222
1223 /**
1224 * gst_mpegts_descriptor_from_custom_with_extension:
1225 * @tag: descriptor tag
1226 * @tag_extension: descriptor tag extension
1227 * @data: (transfer none) (array length=length): descriptor data (after tag and length field)
1228 * @length: length of @data
1229 *
1230 * Creates a #GstMpegtsDescriptor with custom @tag, @tag_extension and @data
1231 *
1232 * Returns: #GstMpegtsDescriptor
1233 *
1234 * Since: 1.20
1235 */
1236 GstMpegtsDescriptor *
gst_mpegts_descriptor_from_custom_with_extension(guint8 tag,guint8 tag_extension,const guint8 * data,gsize length)1237 gst_mpegts_descriptor_from_custom_with_extension (guint8 tag,
1238 guint8 tag_extension, const guint8 * data, gsize length)
1239 {
1240 GstMpegtsDescriptor *descriptor;
1241
1242 descriptor = _new_descriptor_with_extension (tag, tag_extension, length);
1243
1244 if (data && (length > 0))
1245 memcpy (descriptor->data + 3, data, length);
1246
1247 return descriptor;
1248 }
1249