• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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