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