mpegts: Handle when iconv doesn't support ISO 6937
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / mpegts / gstmpegtsdescriptor.c
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
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
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
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
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 *
296 dvb_text_from_utf8 (const gchar * text, gsize * out_size)
297 {
298   GError *error = NULL;
299   gchar *out_text = NULL;
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   if (giconv != (GIConv) - 1)
308     out_text = g_convert_with_iconv (text, -1, giconv, NULL, out_size, &error);
309
310   if (out_text) {
311     GST_DEBUG ("Using default ISO6937 encoding");
312     goto out;
313   }
314
315   g_clear_error (&error);
316
317   for (encoding = _ICONV_ISO8859_1; encoding <= _ICONV_ISO10646_UTF8;
318       encoding++) {
319     giconv = _get_iconv (_ICONV_UTF8, encoding);
320     if (giconv == (GIConv) - 1)
321       continue;
322     out_text = g_convert_with_iconv (text, -1, giconv, NULL, out_size, &error);
323
324     if (out_text) {
325       GST_DEBUG ("Found suitable character map - %s", iconvtablename[encoding]);
326       goto out;
327     }
328
329     g_clear_error (&error);
330   }
331
332   out_text = g_convert_with_fallback (text, -1, iconvtablename[_ICONV_ISO6937],
333       iconvtablename[_ICONV_UTF8], "?", NULL, out_size, &error);
334
335 out:
336
337   if (error) {
338     GST_WARNING ("Could not convert from utf-8: %s", error->message);
339     g_error_free (error);
340     g_free (out_text);
341     return NULL;
342   }
343
344   switch (encoding) {
345     case _ICONV_ISO6937:
346       /* Default encoding contains no selection bytes. */
347       _encode_control_codes (out_text, *out_size, FALSE);
348       return (guint8 *) out_text;
349     case _ICONV_ISO8859_1:
350     case _ICONV_ISO8859_2:
351     case _ICONV_ISO8859_3:
352     case _ICONV_ISO8859_4:
353       /* These character sets requires 3 selection bytes */
354       _encode_control_codes (out_text, *out_size, FALSE);
355       out_buffer = g_malloc (*out_size + 3);
356       out_buffer[0] = 0x10;
357       out_buffer[1] = 0x00;
358       out_buffer[2] = encoding - _ICONV_ISO8859_1 + 1;
359       memcpy (out_buffer + 3, out_text, *out_size);
360       *out_size += 3;
361       g_free (out_text);
362       return out_buffer;
363     case _ICONV_ISO8859_5:
364     case _ICONV_ISO8859_6:
365     case _ICONV_ISO8859_7:
366     case _ICONV_ISO8859_8:
367     case _ICONV_ISO8859_9:
368     case _ICONV_ISO8859_10:
369     case _ICONV_ISO8859_11:
370     case _ICONV_ISO8859_12:
371     case _ICONV_ISO8859_13:
372     case _ICONV_ISO8859_14:
373     case _ICONV_ISO8859_15:
374       /* These character sets requires 1 selection byte */
375       _encode_control_codes (out_text, *out_size, FALSE);
376       out_buffer = g_malloc (*out_size + 1);
377       out_buffer[0] = encoding - _ICONV_ISO8859_5 + 1;
378       memcpy (out_buffer + 1, out_text, *out_size);
379       *out_size += 1;
380       g_free (out_text);
381       return out_buffer;
382     case _ICONV_UCS_2BE:
383     case _ICONV_EUC_KR:
384     case _ICONV_UTF_16BE:
385       /* These character sets requires 1 selection byte */
386       _encode_control_codes (out_text, *out_size, TRUE);
387       out_buffer = g_malloc (*out_size + 1);
388       out_buffer[0] = encoding - _ICONV_UCS_2BE + 0x11;
389       memcpy (out_buffer + 1, out_text, *out_size);
390       *out_size += 1;
391       g_free (out_text);
392       return out_buffer;
393     case _ICONV_GB2312:
394     case _ICONV_ISO10646_UTF8:
395       /* These character sets requires 1 selection byte */
396       _encode_control_codes (out_text, *out_size, FALSE);
397       out_buffer = g_malloc (*out_size + 1);
398       out_buffer[0] = encoding - _ICONV_UCS_2BE + 0x11;
399       memcpy (out_buffer + 1, out_text, *out_size);
400       *out_size += 1;
401       g_free (out_text);
402       return out_buffer;
403     default:
404       g_free (out_text);
405       return NULL;
406   }
407 }
408
409 /*
410  * @text: The text to convert. It may include pango markup (<b> and </b>)
411  * @length: The length of the string -1 if it's nul-terminated
412  * @start: Where to start converting in the text
413  * @encoding: The encoding of text
414  * @is_multibyte: Whether the encoding is a multibyte encoding
415  * @error: The location to store the error, or NULL to ignore errors
416  * @returns: UTF-8 encoded string
417  *
418  * Convert text to UTF-8.
419  */
420 static gchar *
421 convert_to_utf8 (const gchar * text, gint length, guint start,
422     GIConv giconv, gboolean is_multibyte, GError ** error)
423 {
424   gchar *new_text;
425   gchar *tmp, *pos;
426   gint i;
427
428   text += start;
429
430   pos = tmp = g_malloc (length * 2);
431
432   if (is_multibyte) {
433     if (length == -1) {
434       while (*text != '\0') {
435         guint16 code = GST_READ_UINT16_BE (text);
436
437         switch (code) {
438           case 0xE086:         /* emphasis on */
439           case 0xE087:         /* emphasis off */
440             /* skip it */
441             break;
442           case 0xE08A:{
443             pos[0] = 0x00;      /* 0x00 0x0A is a new line */
444             pos[1] = 0x0A;
445             pos += 2;
446             break;
447           }
448           default:
449             pos[0] = text[0];
450             pos[1] = text[1];
451             pos += 2;
452             break;
453         }
454
455         text += 2;
456       }
457     } else {
458       for (i = 0; i < length; i += 2) {
459         guint16 code = GST_READ_UINT16_BE (text);
460
461         switch (code) {
462           case 0xE086:         /* emphasis on */
463           case 0xE087:         /* emphasis off */
464             /* skip it */
465             break;
466           case 0xE08A:{
467             pos[0] = 0x00;      /* 0x00 0x0A is a new line */
468             pos[1] = 0x0A;
469             pos += 2;
470             break;
471           }
472           default:
473             pos[0] = text[0];
474             pos[1] = text[1];
475             pos += 2;
476             break;
477         }
478
479         text += 2;
480       }
481     }
482   } else {
483     if (length == -1) {
484       while (*text != '\0') {
485         guint8 code = (guint8) (*text);
486
487         switch (code) {
488           case 0x86:           /* emphasis on */
489           case 0x87:           /* emphasis off */
490             /* skip it */
491             break;
492           case 0x8A:
493             *pos = '\n';
494             pos += 1;
495             break;
496           default:
497             *pos = *text;
498             pos += 1;
499             break;
500         }
501
502         text++;
503       }
504     } else {
505       for (i = 0; i < length; i++) {
506         guint8 code = (guint8) (*text);
507
508         switch (code) {
509           case 0x86:           /* emphasis on */
510           case 0x87:           /* emphasis off */
511             /* skip it */
512             break;
513           case 0x8A:
514             *pos = '\n';
515             pos += 1;
516             break;
517           default:
518             *pos = *text;
519             pos += 1;
520             break;
521         }
522
523         text++;
524       }
525     }
526   }
527
528   if (pos > tmp) {
529     gsize bread = 0;
530     new_text =
531         g_convert_with_iconv (tmp, pos - tmp, giconv, &bread, NULL, error);
532     GST_DEBUG ("Converted to : %s", new_text);
533   } else {
534     new_text = g_strdup ("");
535   }
536
537   g_free (tmp);
538
539   return new_text;
540 }
541
542 gchar *
543 get_encoding_and_convert (const gchar * text, guint length)
544 {
545   GError *error = NULL;
546   gchar *converted_str;
547   guint start_text = 0;
548   gboolean is_multibyte;
549   LocalIconvCode encoding;
550   GIConv giconv = (GIConv) - 1;
551
552   g_return_val_if_fail (text != NULL, NULL);
553
554   if (text == NULL || length == 0)
555     return g_strdup ("");
556
557   encoding = get_encoding (text, &start_text, &is_multibyte);
558
559   if (encoding > _ICONV_UNKNOWN && encoding < _ICONV_MAX) {
560     GST_DEBUG ("Encoding %s", iconvtablename[encoding]);
561     giconv = _get_iconv (encoding, _ICONV_UTF8);
562   } else {
563     GST_FIXME ("Could not detect encoding. Returning NULL string");
564     converted_str = NULL;
565     goto beach;
566   }
567
568   converted_str = convert_to_utf8 (text, length - start_text, start_text,
569       giconv, is_multibyte, &error);
570   if (error != NULL) {
571     GST_WARNING ("Could not convert string: %s", error->message);
572     g_free (converted_str);
573     g_error_free (error);
574     error = NULL;
575
576     if (encoding >= _ICONV_ISO8859_2 && encoding <= _ICONV_ISO8859_15) {
577       /* Sometimes using the standard 8859-1 set fixes issues */
578       GST_DEBUG ("Encoding %s", iconvtablename[_ICONV_ISO8859_1]);
579       giconv = _get_iconv (_ICONV_ISO8859_1, _ICONV_UTF8);
580
581       GST_INFO ("Trying encoding ISO 8859-1");
582       converted_str = convert_to_utf8 (text, length, 1, giconv, FALSE, &error);
583       if (error != NULL) {
584         GST_WARNING
585             ("Could not convert string while assuming encoding ISO 8859-1: %s",
586             error->message);
587         g_error_free (error);
588         goto failed;
589       }
590     } else if (encoding == _ICONV_ISO6937) {
591
592       /* The first part of ISO 6937 is identical to ISO 8859-9, but
593        * they differ in the second part. Some channels don't
594        * provide the first byte that indicates ISO 8859-9 encoding.
595        * If decoding from ISO 6937 failed, we try ISO 8859-9 here.
596        */
597       giconv = _get_iconv (_ICONV_ISO8859_9, _ICONV_UTF8);
598
599       GST_INFO ("Trying encoding ISO 8859-9");
600       converted_str = convert_to_utf8 (text, length, 0, giconv, FALSE, &error);
601       if (error != NULL) {
602         GST_WARNING
603             ("Could not convert string while assuming encoding ISO 8859-9: %s",
604             error->message);
605         g_error_free (error);
606         goto failed;
607       }
608     } else
609       goto failed;
610   }
611
612 beach:
613   return converted_str;
614
615 failed:
616   {
617     text += start_text;
618     return g_strndup (text, length - start_text);
619   }
620 }
621
622 gchar *
623 convert_lang_code (guint8 * data)
624 {
625   gchar *code;
626   /* the iso language code and country code is always 3 byte long */
627   code = g_malloc0 (4);
628   memcpy (code, data, 3);
629
630   return code;
631 }
632
633 void
634 _packetize_descriptor_array (GPtrArray * array, guint8 ** out_data)
635 {
636   guint i;
637   GstMpegtsDescriptor *descriptor;
638
639   g_return_if_fail (out_data != NULL);
640   g_return_if_fail (*out_data != NULL);
641
642   if (array == NULL)
643     return;
644
645   for (i = 0; i < array->len; i++) {
646     descriptor = g_ptr_array_index (array, i);
647
648     memcpy (*out_data, descriptor->data, descriptor->length + 2);
649     *out_data += descriptor->length + 2;
650   }
651 }
652
653 GstMpegtsDescriptor *
654 _new_descriptor (guint8 tag, guint8 length)
655 {
656   GstMpegtsDescriptor *descriptor;
657   guint8 *data;
658
659   descriptor = g_slice_new (GstMpegtsDescriptor);
660
661   descriptor->tag = tag;
662   descriptor->tag_extension = 0;
663   descriptor->length = length;
664
665   descriptor->data = g_malloc (length + 2);
666
667   data = descriptor->data;
668
669   *data++ = descriptor->tag;
670   *data = descriptor->length;
671
672   return descriptor;
673 }
674
675 GstMpegtsDescriptor *
676 _new_descriptor_with_extension (guint8 tag, guint8 tag_extension, guint8 length)
677 {
678   GstMpegtsDescriptor *descriptor;
679   guint8 *data;
680
681   descriptor = g_slice_new (GstMpegtsDescriptor);
682
683   descriptor->tag = tag;
684   descriptor->tag_extension = tag_extension;
685   descriptor->length = length + 1;
686
687   descriptor->data = g_malloc (length + 3);
688
689   data = descriptor->data;
690
691   *data++ = descriptor->tag;
692   *data++ = descriptor->length;
693   *data = descriptor->tag_extension;
694
695   return descriptor;
696 }
697
698 static GstMpegtsDescriptor *
699 _copy_descriptor (GstMpegtsDescriptor * desc)
700 {
701   GstMpegtsDescriptor *copy;
702
703   copy = g_slice_dup (GstMpegtsDescriptor, desc);
704   copy->data = g_memdup2 (desc->data, desc->length + 2);
705
706   return copy;
707 }
708
709 /**
710  * gst_mpegts_descriptor_free:
711  * @desc: The descriptor to free
712  *
713  * Frees @desc
714  */
715 void
716 gst_mpegts_descriptor_free (GstMpegtsDescriptor * desc)
717 {
718   g_free ((gpointer) desc->data);
719   g_slice_free (GstMpegtsDescriptor, desc);
720 }
721
722 G_DEFINE_BOXED_TYPE (GstMpegtsDescriptor, gst_mpegts_descriptor,
723     (GBoxedCopyFunc) _copy_descriptor,
724     (GBoxedFreeFunc) gst_mpegts_descriptor_free);
725
726 /**
727  * gst_mpegts_parse_descriptors:
728  * @buffer: (transfer none): descriptors to parse
729  * @buf_len: Size of @buffer
730  *
731  * Parses the descriptors present in @buffer and returns them as an
732  * array.
733  *
734  * Note: The data provided in @buffer will not be copied.
735  *
736  * Returns: (transfer full) (element-type GstMpegtsDescriptor): an
737  * array of the parsed descriptors or %NULL if there was an error.
738  * Release with #g_array_unref when done with it.
739  */
740 GPtrArray *
741 gst_mpegts_parse_descriptors (guint8 * buffer, gsize buf_len)
742 {
743   GPtrArray *res;
744   guint8 length;
745   guint8 *data;
746   guint i, nb_desc = 0;
747
748   /* fast-path */
749   if (buf_len == 0)
750     return g_ptr_array_new ();
751
752   data = buffer;
753
754   GST_MEMDUMP ("Full descriptor array", buffer, buf_len);
755
756   while (data - buffer < buf_len) {
757     data++;                     /* skip tag */
758     length = *data++;
759
760     if (data - buffer > buf_len) {
761       GST_WARNING ("invalid descriptor length %d now at %d max %"
762           G_GSIZE_FORMAT, length, (gint) (data - buffer), buf_len);
763       return NULL;
764     }
765
766     data += length;
767     nb_desc++;
768   }
769
770   GST_DEBUG ("Saw %d descriptors, read %" G_GSIZE_FORMAT " bytes",
771       nb_desc, (gsize) (data - buffer));
772
773   if (data - buffer != buf_len) {
774     GST_WARNING ("descriptors size %d expected %" G_GSIZE_FORMAT,
775         (gint) (data - buffer), buf_len);
776     return NULL;
777   }
778
779   res =
780       g_ptr_array_new_full (nb_desc + 1,
781       (GDestroyNotify) gst_mpegts_descriptor_free);
782
783   data = buffer;
784
785   for (i = 0; i < nb_desc; i++) {
786     GstMpegtsDescriptor *desc = g_slice_new0 (GstMpegtsDescriptor);
787
788     desc->data = data;
789     desc->tag = *data++;
790     desc->length = *data++;
791     /* Copy the data now that we known the size */
792     desc->data = g_memdup2 (desc->data, desc->length + 2);
793     GST_LOG ("descriptor 0x%02x length:%d", desc->tag, desc->length);
794     GST_MEMDUMP ("descriptor", desc->data + 2, desc->length);
795     /* extended descriptors */
796     if (G_UNLIKELY (desc->tag == 0x7f))
797       desc->tag_extension = *data;
798
799     data += desc->length;
800
801     /* Set the descriptor in the array */
802     g_ptr_array_index (res, i) = desc;
803   }
804
805   res->len = nb_desc;
806
807   return res;
808 }
809
810 /**
811  * gst_mpegts_find_descriptor:
812  * @descriptors: (element-type GstMpegtsDescriptor) (transfer none): an array
813  * of #GstMpegtsDescriptor
814  * @tag: the tag to look for
815  *
816  * Finds the first descriptor of type @tag in the array.
817  *
818  * Note: To look for descriptors that can be present more than once in an
819  * array of descriptors, iterate the #GArray manually.
820  *
821  * Returns: (transfer none): the first descriptor matching @tag, else %NULL.
822  */
823 const GstMpegtsDescriptor *
824 gst_mpegts_find_descriptor (GPtrArray * descriptors, guint8 tag)
825 {
826   guint i, nb_desc;
827
828   g_return_val_if_fail (descriptors != NULL, NULL);
829
830   nb_desc = descriptors->len;
831   for (i = 0; i < nb_desc; i++) {
832     GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
833     if (desc->tag == tag)
834       return (const GstMpegtsDescriptor *) desc;
835   }
836   return NULL;
837 }
838
839 /**
840  * gst_mpegts_find_descriptor_with_extension:
841  * @descriptors: (element-type GstMpegtsDescriptor) (transfer none): an array
842  * of #GstMpegtsDescriptor
843  * @tag: the tag to look for
844  *
845  * Finds the first descriptor of type @tag with @tag_extension in the array.
846  *
847  * Note: To look for descriptors that can be present more than once in an
848  * array of descriptors, iterate the #GArray manually.
849  *
850  * Returns: (transfer none): the first descriptor matchin @tag with @tag_extension, else %NULL.
851  *
852  * Since: 1.20
853  */
854 const GstMpegtsDescriptor *
855 gst_mpegts_find_descriptor_with_extension (GPtrArray * descriptors, guint8 tag,
856     guint8 tag_extension)
857 {
858   guint i, nb_desc;
859
860   g_return_val_if_fail (descriptors != NULL, NULL);
861
862   nb_desc = descriptors->len;
863   for (i = 0; i < nb_desc; i++) {
864     GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
865     if ((desc->tag == tag) && (desc->tag_extension == tag_extension))
866       return (const GstMpegtsDescriptor *) desc;
867   }
868   return NULL;
869 }
870
871 /* GST_MTS_DESC_REGISTRATION (0x05) */
872 /**
873  * gst_mpegts_descriptor_from_registration:
874  * @format_identifier: (transfer none): a 4 character format identifier string
875  * @additional_info: (transfer none) (allow-none) (array length=additional_info_length): pointer to optional additional info
876  * @additional_info_length: length of the optional @additional_info
877  *
878  * Creates a %GST_MTS_DESC_REGISTRATION #GstMpegtsDescriptor
879  *
880  * Return: #GstMpegtsDescriptor, %NULL on failure
881  */
882 GstMpegtsDescriptor *
883 gst_mpegts_descriptor_from_registration (const gchar * format_identifier,
884     guint8 * additional_info, gsize additional_info_length)
885 {
886   GstMpegtsDescriptor *descriptor;
887
888   g_return_val_if_fail (format_identifier != NULL, NULL);
889   g_return_val_if_fail (additional_info_length > 0 || !additional_info, NULL);
890
891   descriptor = _new_descriptor (GST_MTS_DESC_REGISTRATION,
892       4 + additional_info_length);
893
894   memcpy (descriptor->data + 2, format_identifier, 4);
895   if (additional_info && (additional_info_length > 0))
896     memcpy (descriptor->data + 6, additional_info, additional_info_length);
897
898   return descriptor;
899 }
900
901 /**
902  * gst_mpegts_descriptor_parse_registration:
903  * @descriptor: a %GST_MTS_DESC_REGISTRATION #GstMpegtsDescriptor
904  * @registration_id: (out): The registration ID (in host endiannes)
905  * @additional_info: (out) (allow-none) (array length=additional_info_length): The additional information
906  * @additional_info_length: (out) (allow-none): The size of @additional_info in bytes.
907  *
908  * Extracts the Registration information from @descriptor.
909  *
910  * Returns: %TRUE if parsing succeeded, else %FALSE.
911  *
912  * Since: 1.20
913  */
914
915 gboolean
916 gst_mpegts_descriptor_parse_registration (GstMpegtsDescriptor * descriptor,
917     guint32 * registration_id,
918     guint8 ** additional_info, gsize * additional_info_length)
919 {
920   guint8 *data;
921
922   g_return_val_if_fail (descriptor != NULL && registration_id != NULL, FALSE);
923
924   /* The smallest registration is 4 bytes */
925   __common_desc_checks (descriptor, GST_MTS_DESC_REGISTRATION, 4, FALSE);
926
927   data = (guint8 *) descriptor->data + 2;
928   *registration_id = GST_READ_UINT32_BE (data);
929   data += 4;
930   if (additional_info && additional_info_length) {
931     *additional_info_length = descriptor->length - 4;
932     if (descriptor->length > 4) {
933       *additional_info = data;
934     } else {
935       *additional_info = NULL;
936     }
937   }
938
939   return TRUE;
940 }
941
942 /* GST_MTS_DESC_CA (0x09) */
943
944 /**
945  * gst_mpegts_descriptor_parse_ca:
946  * @descriptor: a %GST_MTS_DESC_CA #GstMpegtsDescriptor
947  * @ca_system_id: (out): the type of CA system used
948  * @ca_pid: (out): The PID containing ECM or EMM data
949  * @private_data: (out) (allow-none) (array length=private_data_size): The private data
950  * @private_data_size: (out) (allow-none): The size of @private_data in bytes
951  *
952  * Extracts the Conditional Access information from @descriptor.
953  *
954  * Returns: %TRUE if parsing succeeded, else %FALSE.
955  */
956
957 gboolean
958 gst_mpegts_descriptor_parse_ca (GstMpegtsDescriptor * descriptor,
959     guint16 * ca_system_id, guint16 * ca_pid,
960     const guint8 ** private_data, gsize * private_data_size)
961 {
962   guint8 *data;
963
964   g_return_val_if_fail (descriptor != NULL && ca_system_id != NULL
965       && ca_pid != NULL, FALSE);
966   /* The smallest CA is 4 bytes (though not having any private data
967    * sounds a bit ... weird) */
968   __common_desc_checks (descriptor, GST_MTS_DESC_CA, 4, FALSE);
969
970   data = (guint8 *) descriptor->data + 2;
971   *ca_system_id = GST_READ_UINT16_BE (data);
972   data += 2;
973   *ca_pid = GST_READ_UINT16_BE (data) & 0x1fff;
974   data += 2;
975   if (private_data && private_data_size) {
976     *private_data = data;
977     *private_data_size = descriptor->length - 4;
978   }
979
980   return TRUE;
981 }
982
983 /* GST_MTS_DESC_ISO_639_LANGUAGE (0x0A) */
984 static GstMpegtsISO639LanguageDescriptor *
985 _gst_mpegts_iso_639_language_descriptor_copy (GstMpegtsISO639LanguageDescriptor
986     * source)
987 {
988   GstMpegtsISO639LanguageDescriptor *copy;
989   guint i;
990
991   copy = g_slice_dup (GstMpegtsISO639LanguageDescriptor, source);
992
993   for (i = 0; i < source->nb_language; i++) {
994     copy->language[i] = g_strdup (source->language[i]);
995   }
996
997   return copy;
998 }
999
1000 void
1001 gst_mpegts_iso_639_language_descriptor_free (GstMpegtsISO639LanguageDescriptor
1002     * desc)
1003 {
1004   guint i;
1005
1006   for (i = 0; i < desc->nb_language; i++) {
1007     g_free (desc->language[i]);
1008   }
1009   g_slice_free (GstMpegtsISO639LanguageDescriptor, desc);
1010 }
1011
1012 G_DEFINE_BOXED_TYPE (GstMpegtsISO639LanguageDescriptor,
1013     gst_mpegts_iso_639_language,
1014     (GBoxedCopyFunc) _gst_mpegts_iso_639_language_descriptor_copy,
1015     (GFreeFunc) gst_mpegts_iso_639_language_descriptor_free);
1016
1017 /**
1018  * gst_mpegts_descriptor_parse_iso_639_language:
1019  * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1020  * @res: (out) (transfer full): the #GstMpegtsISO639LanguageDescriptor to fill
1021  *
1022  * Extracts the iso 639-2 language information from @descriptor.
1023  *
1024  * Note: Use #gst_tag_get_language_code if you want to get the the
1025  * ISO 639-1 language code from the returned ISO 639-2 one.
1026  *
1027  * Returns: %TRUE if parsing succeeded, else %FALSE.
1028  */
1029 gboolean
1030 gst_mpegts_descriptor_parse_iso_639_language (const GstMpegtsDescriptor *
1031     descriptor, GstMpegtsISO639LanguageDescriptor ** desc)
1032 {
1033   guint i;
1034   guint8 *data;
1035   GstMpegtsISO639LanguageDescriptor *res;
1036
1037   g_return_val_if_fail (descriptor != NULL && desc != NULL, FALSE);
1038   /* This descriptor can be empty, no size check needed */
1039   __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1040
1041   data = (guint8 *) descriptor->data + 2;
1042
1043   res = g_slice_new0 (GstMpegtsISO639LanguageDescriptor);
1044
1045   /* Each language is 3 + 1 bytes */
1046   res->nb_language = descriptor->length / 4;
1047   for (i = 0; i < res->nb_language; i++) {
1048     res->language[i] = convert_lang_code (data);
1049     res->audio_type[i] = data[3];
1050     data += 4;
1051   }
1052
1053   *desc = res;
1054
1055   return TRUE;
1056
1057 }
1058
1059 /**
1060  * gst_mpegts_descriptor_parse_iso_639_language_idx:
1061  * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1062  * @idx: Table id of the language to parse
1063  * @lang: (out) (transfer full): 4-byte gchar array to hold the language code
1064  * @audio_type: (out) (transfer none) (allow-none): the #GstMpegtsIso639AudioType to set
1065  *
1066  * Extracts the iso 639-2 language information from specific table id in @descriptor.
1067  *
1068  * Note: Use #gst_tag_get_language_code if you want to get the the
1069  * ISO 639-1 language code from the returned ISO 639-2 one.
1070  *
1071  * Returns: %TRUE if parsing succeeded, else %FALSE.
1072  */
1073 gboolean
1074 gst_mpegts_descriptor_parse_iso_639_language_idx (const GstMpegtsDescriptor *
1075     descriptor, guint idx, gchar ** lang, GstMpegtsIso639AudioType * audio_type)
1076 {
1077   guint8 *data;
1078
1079   g_return_val_if_fail (descriptor != NULL && lang != NULL, FALSE);
1080   /* This descriptor can be empty, no size check needed */
1081   __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1082
1083   if (descriptor->length / 4 <= idx)
1084     return FALSE;
1085
1086   data = (guint8 *) descriptor->data + 2 + idx * 4;
1087
1088   *lang = convert_lang_code (data);
1089
1090   data += 3;
1091
1092   if (audio_type)
1093     *audio_type = *data;
1094
1095   return TRUE;
1096 }
1097
1098 /**
1099  * gst_mpegts_descriptor_parse_iso_639_language_nb:
1100  * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1101  *
1102  * Returns: The number of languages in @descriptor
1103  */
1104 guint
1105 gst_mpegts_descriptor_parse_iso_639_language_nb (const GstMpegtsDescriptor *
1106     descriptor)
1107 {
1108   g_return_val_if_fail (descriptor != NULL, 0);
1109   /* This descriptor can be empty, no size check needed */
1110   __common_desc_check_base (descriptor, GST_MTS_DESC_ISO_639_LANGUAGE, FALSE);
1111
1112   return descriptor->length / 4;
1113 }
1114
1115 /**
1116  * gst_mpegts_descriptor_from_iso_639_language:
1117  * @language: (transfer none): ISO-639-2 language 3-char code
1118  *
1119  * Creates a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor with
1120  * a single language
1121  *
1122  * Return: #GstMpegtsDescriptor, %NULL on failure
1123  */
1124 GstMpegtsDescriptor *
1125 gst_mpegts_descriptor_from_iso_639_language (const gchar * language)
1126 {
1127   GstMpegtsDescriptor *descriptor;
1128
1129   g_return_val_if_fail (language != NULL, NULL);
1130
1131   descriptor = _new_descriptor (GST_MTS_DESC_ISO_639_LANGUAGE, 4);      /* a language takes 4 bytes */
1132
1133   memcpy (descriptor->data + 2, language, 3);
1134   descriptor->data[2 + 3] = 0;  /* set audio type to undefined */
1135
1136   return descriptor;
1137 }
1138
1139 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1140     gst_mpegts_logical_channel_descriptor);
1141
1142 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1143     gst_mpegts_logical_channel_descriptor);
1144
1145 G_DEFINE_BOXED_TYPE (GstMpegtsLogicalChannelDescriptor,
1146     gst_mpegts_logical_channel_descriptor,
1147     (GBoxedCopyFunc) _gst_mpegts_logical_channel_descriptor_copy,
1148     (GFreeFunc) _gst_mpegts_logical_channel_descriptor_free);
1149
1150 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannel,
1151     gst_mpegts_logical_channel);
1152
1153 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannel,
1154     gst_mpegts_logical_channel);
1155
1156 G_DEFINE_BOXED_TYPE (GstMpegtsLogicalChannel,
1157     gst_mpegts_logical_channel,
1158     (GBoxedCopyFunc) _gst_mpegts_logical_channel_copy,
1159     (GFreeFunc) _gst_mpegts_logical_channel_free);
1160
1161 /**
1162  * gst_mpegts_descriptor_parse_logical_channel:
1163  * @descriptor: a %GST_MTS_DESC_DTG_LOGICAL_CHANNEL #GstMpegtsDescriptor
1164  * @res: (out) (transfer none): the #GstMpegtsLogicalChannelDescriptor to fill
1165  *
1166  * Extracts the logical channels from @descriptor.
1167  *
1168  * Returns: %TRUE if parsing succeeded, else %FALSE.
1169  */
1170 gboolean
1171 gst_mpegts_descriptor_parse_logical_channel (const GstMpegtsDescriptor *
1172     descriptor, GstMpegtsLogicalChannelDescriptor * res)
1173 {
1174   guint i;
1175   guint8 *data;
1176
1177   g_return_val_if_fail (descriptor != NULL && res != NULL, FALSE);
1178   /* This descriptor loop can be empty, no size check required */
1179   __common_desc_check_base (descriptor, GST_MTS_DESC_DTG_LOGICAL_CHANNEL,
1180       FALSE);
1181
1182   data = (guint8 *) descriptor->data + 2;
1183
1184   res->nb_channels = descriptor->length / 4;
1185
1186   for (i = 0; i < res->nb_channels; i++) {
1187     res->channels[i].service_id = GST_READ_UINT16_BE (data);
1188     data += 2;
1189     res->channels[i].visible_service = *data >> 7;
1190     res->channels[i].logical_channel_number =
1191         GST_READ_UINT16_BE (data) & 0x03ff;
1192     data += 2;
1193   }
1194
1195   return TRUE;
1196 }
1197
1198 /**
1199  * gst_mpegts_descriptor_from_custom:
1200  * @tag: descriptor tag
1201  * @data: (transfer none) (array length=length): descriptor data (after tag and length field)
1202  * @length: length of @data
1203  *
1204  * Creates a #GstMpegtsDescriptor with custom @tag and @data
1205  *
1206  * Returns: #GstMpegtsDescriptor
1207  */
1208 GstMpegtsDescriptor *
1209 gst_mpegts_descriptor_from_custom (guint8 tag, const guint8 * data,
1210     gsize length)
1211 {
1212   GstMpegtsDescriptor *descriptor;
1213
1214   g_return_val_if_fail (length > 0 || !data, NULL);
1215
1216   descriptor = _new_descriptor (tag, length);
1217
1218   if (data && (length > 0))
1219     memcpy (descriptor->data + 2, data, length);
1220
1221   return descriptor;
1222 }
1223
1224 /**
1225  * gst_mpegts_descriptor_from_custom_with_extension:
1226  * @tag: descriptor tag
1227  * @tag_extension: descriptor tag extension
1228  * @data: (transfer none) (array length=length): descriptor data (after tag and length field)
1229  * @length: length of @data
1230  *
1231  * Creates a #GstMpegtsDescriptor with custom @tag, @tag_extension and @data
1232  *
1233  * Returns: #GstMpegtsDescriptor
1234  *
1235  * Since: 1.20
1236  */
1237 GstMpegtsDescriptor *
1238 gst_mpegts_descriptor_from_custom_with_extension (guint8 tag,
1239     guint8 tag_extension, const guint8 * data, gsize length)
1240 {
1241   GstMpegtsDescriptor *descriptor;
1242
1243   descriptor = _new_descriptor_with_extension (tag, tag_extension, length);
1244
1245   if (data && (length > 0))
1246     memcpy (descriptor->data + 3, data, length);
1247
1248   return descriptor;
1249 }