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