2 * gstmpegtsdescriptor.c -
3 * Copyright (C) 2013 Edward Hervey
6 * Edward Hervey <edward@collabora.com>
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.
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.
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.
31 #include "gstmpegts-private.h"
33 #define DEFINE_STATIC_COPY_FUNCTION(type, name) \
34 static type * _##name##_copy (type * source) \
36 return g_slice_dup (type, source); \
39 #define DEFINE_STATIC_FREE_FUNCTION(type, name) \
40 static void _##name##_free (type * source) \
42 g_slice_free (type, source); \
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
51 * These are the base descriptor types and methods.
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.
60 * * Add common validation code for data presence and minimum/maximum expected
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
69 #define MAX_KNOWN_ICONV 25
71 /* First column is the original encoding,
72 * second column is the target encoding */
74 static GIConv __iconvs[MAX_KNOWN_ICONV][MAX_KNOWN_ICONV];
76 /* All these conversions will be to UTF8 */
102 /* Insert more here if needed */
106 static const gchar *iconvtablename[] = {
129 /* Insert more here if needed */
133 __initialize_descriptors (void)
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);
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
150 * @returns: GIconv for conversion or NULL
152 static LocalIconvCode
153 get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte)
155 LocalIconvCode encoding;
158 *is_multibyte = FALSE;
161 firstbyte = (guint8) text[0];
164 g_return_val_if_fail (firstbyte != 0x00, _ICONV_UNKNOWN);
166 if (firstbyte <= 0x0B) {
167 /* 0x01 => iso 8859-5 */
168 encoding = firstbyte + _ICONV_ISO8859_4;
173 /* ETSI EN 300 468, "Selection of character table" */
180 encoding = _ICONV_UNKNOWN;
186 table = GST_READ_UINT16_BE (text + 1);
189 encoding = _ICONV_UNKNOWN + table;
191 encoding = _ICONV_UNKNOWN;
196 encoding = _ICONV_UCS_2BE;
198 *is_multibyte = TRUE;
201 /* EUC-KR implements KSX1001 */
202 encoding = _ICONV_EUC_KR;
204 *is_multibyte = TRUE;
207 encoding = _ICONV_GB2312;
211 encoding = _ICONV_UTF_16BE;
213 *is_multibyte = TRUE;
216 /* TODO : Where does this come from ?? */
217 encoding = _ICONV_ISO10646_UTF8;
231 encoding = _ICONV_UNKNOWN;
234 encoding = _ICONV_ISO6937;
240 ("Found encoding %d, first byte is 0x%02x, start_text: %u, is_multibyte: %d",
241 encoding, firstbyte, *start_text, *is_multibyte);
247 _get_iconv (LocalIconvCode from, LocalIconvCode to)
249 if (__iconvs[from][to] == (GIConv) - 1)
250 __iconvs[from][to] = g_iconv_open (iconvtablename[to],
251 iconvtablename[from]);
252 return __iconvs[from][to];
256 _encode_control_codes (gchar * text, gsize length, gboolean is_multibyte)
260 while (pos < length) {
262 guint16 code = GST_READ_UINT16_BE (text + pos);
263 if (code == 0x000A) {
265 text[pos + 1] = 0x8A;
269 guint8 code = text[pos];
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
282 * Converts UTF-8 strings to text characters compliant with EN 300 468.
283 * The converted text can be used directly in DVB #GstMpegtsDescriptor
285 * The function will try different character maps until the string is
286 * completely converted.
288 * The function tries the default ISO 6937 character map first.
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 `?`.
293 * Returns: (transfer full): byte array of size @out_size
296 dvb_text_from_utf8 (const gchar * text, gsize * out_size)
298 GError *error = NULL;
299 gchar *out_text = NULL;
302 GIConv giconv = (GIConv) - 1;
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);
311 GST_DEBUG ("Using default ISO6937 encoding");
315 g_clear_error (&error);
317 for (encoding = _ICONV_ISO8859_1; encoding <= _ICONV_ISO10646_UTF8;
319 giconv = _get_iconv (_ICONV_UTF8, encoding);
320 if (giconv == (GIConv) - 1)
322 out_text = g_convert_with_iconv (text, -1, giconv, NULL, out_size, &error);
325 GST_DEBUG ("Found suitable character map - %s", iconvtablename[encoding]);
329 g_clear_error (&error);
332 out_text = g_convert_with_fallback (text, -1, iconvtablename[_ICONV_ISO6937],
333 iconvtablename[_ICONV_UTF8], "?", NULL, out_size, &error);
338 GST_WARNING ("Could not convert from utf-8: %s", error->message);
339 g_error_free (error);
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);
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);
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);
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);
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
418 * Convert text to UTF-8.
421 convert_to_utf8 (const gchar * text, gint length, guint start,
422 GIConv giconv, gboolean is_multibyte, GError ** error)
430 pos = tmp = g_malloc (length * 2);
434 while (*text != '\0') {
435 guint16 code = GST_READ_UINT16_BE (text);
438 case 0xE086: /* emphasis on */
439 case 0xE087: /* emphasis off */
443 pos[0] = 0x00; /* 0x00 0x0A is a new line */
458 for (i = 0; i < length; i += 2) {
459 guint16 code = GST_READ_UINT16_BE (text);
462 case 0xE086: /* emphasis on */
463 case 0xE087: /* emphasis off */
467 pos[0] = 0x00; /* 0x00 0x0A is a new line */
484 while (*text != '\0') {
485 guint8 code = (guint8) (*text);
488 case 0x86: /* emphasis on */
489 case 0x87: /* emphasis off */
505 for (i = 0; i < length; i++) {
506 guint8 code = (guint8) (*text);
509 case 0x86: /* emphasis on */
510 case 0x87: /* emphasis off */
531 g_convert_with_iconv (tmp, pos - tmp, giconv, &bread, NULL, error);
532 GST_DEBUG ("Converted to : %s", new_text);
534 new_text = g_strdup ("");
543 get_encoding_and_convert (const gchar * text, guint length)
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;
552 g_return_val_if_fail (text != NULL, NULL);
554 if (text == NULL || length == 0)
555 return g_strdup ("");
557 encoding = get_encoding (text, &start_text, &is_multibyte);
559 if (encoding > _ICONV_UNKNOWN && encoding < _ICONV_MAX) {
560 GST_DEBUG ("Encoding %s", iconvtablename[encoding]);
561 giconv = _get_iconv (encoding, _ICONV_UTF8);
563 GST_FIXME ("Could not detect encoding. Returning NULL string");
564 converted_str = NULL;
568 converted_str = convert_to_utf8 (text, length - start_text, start_text,
569 giconv, is_multibyte, &error);
571 GST_WARNING ("Could not convert string: %s", error->message);
572 g_free (converted_str);
573 g_error_free (error);
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);
581 GST_INFO ("Trying encoding ISO 8859-1");
582 converted_str = convert_to_utf8 (text, length, 1, giconv, FALSE, &error);
585 ("Could not convert string while assuming encoding ISO 8859-1: %s",
587 g_error_free (error);
590 } else if (encoding == _ICONV_ISO6937) {
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.
597 giconv = _get_iconv (_ICONV_ISO8859_9, _ICONV_UTF8);
599 GST_INFO ("Trying encoding ISO 8859-9");
600 converted_str = convert_to_utf8 (text, length, 0, giconv, FALSE, &error);
603 ("Could not convert string while assuming encoding ISO 8859-9: %s",
605 g_error_free (error);
613 return converted_str;
618 return g_strndup (text, length - start_text);
623 convert_lang_code (guint8 * data)
626 /* the iso language code and country code is always 3 byte long */
627 code = g_malloc0 (4);
628 memcpy (code, data, 3);
634 _packetize_descriptor_array (GPtrArray * array, guint8 ** out_data)
637 GstMpegtsDescriptor *descriptor;
639 g_return_if_fail (out_data != NULL);
640 g_return_if_fail (*out_data != NULL);
645 for (i = 0; i < array->len; i++) {
646 descriptor = g_ptr_array_index (array, i);
648 memcpy (*out_data, descriptor->data, descriptor->length + 2);
649 *out_data += descriptor->length + 2;
653 GstMpegtsDescriptor *
654 _new_descriptor (guint8 tag, guint8 length)
656 GstMpegtsDescriptor *descriptor;
659 descriptor = g_slice_new (GstMpegtsDescriptor);
661 descriptor->tag = tag;
662 descriptor->tag_extension = 0;
663 descriptor->length = length;
665 descriptor->data = g_malloc (length + 2);
667 data = descriptor->data;
669 *data++ = descriptor->tag;
670 *data = descriptor->length;
675 GstMpegtsDescriptor *
676 _new_descriptor_with_extension (guint8 tag, guint8 tag_extension, guint8 length)
678 GstMpegtsDescriptor *descriptor;
681 descriptor = g_slice_new (GstMpegtsDescriptor);
683 descriptor->tag = tag;
684 descriptor->tag_extension = tag_extension;
685 descriptor->length = length + 1;
687 descriptor->data = g_malloc (length + 3);
689 data = descriptor->data;
691 *data++ = descriptor->tag;
692 *data++ = descriptor->length;
693 *data = descriptor->tag_extension;
698 static GstMpegtsDescriptor *
699 _copy_descriptor (GstMpegtsDescriptor * desc)
701 GstMpegtsDescriptor *copy;
703 copy = g_slice_dup (GstMpegtsDescriptor, desc);
704 copy->data = g_memdup2 (desc->data, desc->length + 2);
710 * gst_mpegts_descriptor_free:
711 * @desc: The descriptor to free
716 gst_mpegts_descriptor_free (GstMpegtsDescriptor * desc)
718 g_free ((gpointer) desc->data);
719 g_slice_free (GstMpegtsDescriptor, desc);
722 G_DEFINE_BOXED_TYPE (GstMpegtsDescriptor, gst_mpegts_descriptor,
723 (GBoxedCopyFunc) _copy_descriptor,
724 (GBoxedFreeFunc) gst_mpegts_descriptor_free);
727 * gst_mpegts_parse_descriptors:
728 * @buffer: (transfer none): descriptors to parse
729 * @buf_len: Size of @buffer
731 * Parses the descriptors present in @buffer and returns them as an
734 * Note: The data provided in @buffer will not be copied.
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.
741 gst_mpegts_parse_descriptors (guint8 * buffer, gsize buf_len)
746 guint i, nb_desc = 0;
750 return g_ptr_array_new ();
754 GST_MEMDUMP ("Full descriptor array", buffer, buf_len);
756 while (data - buffer < buf_len) {
757 data++; /* skip tag */
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);
770 GST_DEBUG ("Saw %d descriptors, read %" G_GSIZE_FORMAT " bytes",
771 nb_desc, (gsize) (data - buffer));
773 if (data - buffer != buf_len) {
774 GST_WARNING ("descriptors size %d expected %" G_GSIZE_FORMAT,
775 (gint) (data - buffer), buf_len);
780 g_ptr_array_new_full (nb_desc + 1,
781 (GDestroyNotify) gst_mpegts_descriptor_free);
785 for (i = 0; i < nb_desc; i++) {
786 GstMpegtsDescriptor *desc = g_slice_new0 (GstMpegtsDescriptor);
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;
799 data += desc->length;
801 /* Set the descriptor in the array */
802 g_ptr_array_index (res, i) = desc;
811 * gst_mpegts_find_descriptor:
812 * @descriptors: (element-type GstMpegtsDescriptor) (transfer none): an array
813 * of #GstMpegtsDescriptor
814 * @tag: the tag to look for
816 * Finds the first descriptor of type @tag in the array.
818 * Note: To look for descriptors that can be present more than once in an
819 * array of descriptors, iterate the #GArray manually.
821 * Returns: (transfer none): the first descriptor matching @tag, else %NULL.
823 const GstMpegtsDescriptor *
824 gst_mpegts_find_descriptor (GPtrArray * descriptors, guint8 tag)
828 g_return_val_if_fail (descriptors != NULL, NULL);
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;
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
845 * Finds the first descriptor of type @tag with @tag_extension in the array.
847 * Note: To look for descriptors that can be present more than once in an
848 * array of descriptors, iterate the #GArray manually.
850 * Returns: (transfer none): the first descriptor matchin @tag with @tag_extension, else %NULL.
854 const GstMpegtsDescriptor *
855 gst_mpegts_find_descriptor_with_extension (GPtrArray * descriptors, guint8 tag,
856 guint8 tag_extension)
860 g_return_val_if_fail (descriptors != NULL, NULL);
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;
871 /* GST_MTS_DESC_REGISTRATION (0x05) */
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
878 * Creates a %GST_MTS_DESC_REGISTRATION #GstMpegtsDescriptor
880 * Return: #GstMpegtsDescriptor, %NULL on failure
882 GstMpegtsDescriptor *
883 gst_mpegts_descriptor_from_registration (const gchar * format_identifier,
884 guint8 * additional_info, gsize additional_info_length)
886 GstMpegtsDescriptor *descriptor;
888 g_return_val_if_fail (format_identifier != NULL, NULL);
889 g_return_val_if_fail (additional_info_length > 0 || !additional_info, NULL);
891 descriptor = _new_descriptor (GST_MTS_DESC_REGISTRATION,
892 4 + additional_info_length);
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);
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.
908 * Extracts the Registration information from @descriptor.
910 * Returns: %TRUE if parsing succeeded, else %FALSE.
916 gst_mpegts_descriptor_parse_registration (GstMpegtsDescriptor * descriptor,
917 guint32 * registration_id,
918 guint8 ** additional_info, gsize * additional_info_length)
922 g_return_val_if_fail (descriptor != NULL && registration_id != NULL, FALSE);
924 /* The smallest registration is 4 bytes */
925 __common_desc_checks (descriptor, GST_MTS_DESC_REGISTRATION, 4, FALSE);
927 data = (guint8 *) descriptor->data + 2;
928 *registration_id = GST_READ_UINT32_BE (data);
930 if (additional_info && additional_info_length) {
931 *additional_info_length = descriptor->length - 4;
932 if (descriptor->length > 4) {
933 *additional_info = data;
935 *additional_info = NULL;
942 /* GST_MTS_DESC_CA (0x09) */
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
952 * Extracts the Conditional Access information from @descriptor.
954 * Returns: %TRUE if parsing succeeded, else %FALSE.
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)
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);
970 data = (guint8 *) descriptor->data + 2;
971 *ca_system_id = GST_READ_UINT16_BE (data);
973 *ca_pid = GST_READ_UINT16_BE (data) & 0x1fff;
975 if (private_data && private_data_size) {
976 *private_data = data;
977 *private_data_size = descriptor->length - 4;
983 /* GST_MTS_DESC_ISO_639_LANGUAGE (0x0A) */
984 static GstMpegtsISO639LanguageDescriptor *
985 _gst_mpegts_iso_639_language_descriptor_copy (GstMpegtsISO639LanguageDescriptor
988 GstMpegtsISO639LanguageDescriptor *copy;
991 copy = g_slice_dup (GstMpegtsISO639LanguageDescriptor, source);
993 for (i = 0; i < source->nb_language; i++) {
994 copy->language[i] = g_strdup (source->language[i]);
1001 gst_mpegts_iso_639_language_descriptor_free (GstMpegtsISO639LanguageDescriptor
1006 for (i = 0; i < desc->nb_language; i++) {
1007 g_free (desc->language[i]);
1009 g_slice_free (GstMpegtsISO639LanguageDescriptor, desc);
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);
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
1022 * Extracts the iso 639-2 language information from @descriptor.
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.
1027 * Returns: %TRUE if parsing succeeded, else %FALSE.
1030 gst_mpegts_descriptor_parse_iso_639_language (const GstMpegtsDescriptor *
1031 descriptor, GstMpegtsISO639LanguageDescriptor ** desc)
1035 GstMpegtsISO639LanguageDescriptor *res;
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);
1041 data = (guint8 *) descriptor->data + 2;
1043 res = g_slice_new0 (GstMpegtsISO639LanguageDescriptor);
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];
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
1066 * Extracts the iso 639-2 language information from specific table id in @descriptor.
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.
1071 * Returns: %TRUE if parsing succeeded, else %FALSE.
1074 gst_mpegts_descriptor_parse_iso_639_language_idx (const GstMpegtsDescriptor *
1075 descriptor, guint idx, gchar ** lang, GstMpegtsIso639AudioType * audio_type)
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);
1083 if (descriptor->length / 4 <= idx)
1086 data = (guint8 *) descriptor->data + 2 + idx * 4;
1088 *lang = convert_lang_code (data);
1093 *audio_type = *data;
1099 * gst_mpegts_descriptor_parse_iso_639_language_nb:
1100 * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor
1102 * Returns: The number of languages in @descriptor
1105 gst_mpegts_descriptor_parse_iso_639_language_nb (const GstMpegtsDescriptor *
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);
1112 return descriptor->length / 4;
1116 * gst_mpegts_descriptor_from_iso_639_language:
1117 * @language: (transfer none): ISO-639-2 language 3-char code
1119 * Creates a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegtsDescriptor with
1122 * Return: #GstMpegtsDescriptor, %NULL on failure
1124 GstMpegtsDescriptor *
1125 gst_mpegts_descriptor_from_iso_639_language (const gchar * language)
1127 GstMpegtsDescriptor *descriptor;
1129 g_return_val_if_fail (language != NULL, NULL);
1131 descriptor = _new_descriptor (GST_MTS_DESC_ISO_639_LANGUAGE, 4); /* a language takes 4 bytes */
1133 memcpy (descriptor->data + 2, language, 3);
1134 descriptor->data[2 + 3] = 0; /* set audio type to undefined */
1139 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1140 gst_mpegts_logical_channel_descriptor);
1142 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannelDescriptor,
1143 gst_mpegts_logical_channel_descriptor);
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);
1150 DEFINE_STATIC_COPY_FUNCTION (GstMpegtsLogicalChannel,
1151 gst_mpegts_logical_channel);
1153 DEFINE_STATIC_FREE_FUNCTION (GstMpegtsLogicalChannel,
1154 gst_mpegts_logical_channel);
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);
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
1166 * Extracts the logical channels from @descriptor.
1168 * Returns: %TRUE if parsing succeeded, else %FALSE.
1171 gst_mpegts_descriptor_parse_logical_channel (const GstMpegtsDescriptor *
1172 descriptor, GstMpegtsLogicalChannelDescriptor * res)
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,
1182 data = (guint8 *) descriptor->data + 2;
1184 res->nb_channels = descriptor->length / 4;
1186 for (i = 0; i < res->nb_channels; i++) {
1187 res->channels[i].service_id = GST_READ_UINT16_BE (data);
1189 res->channels[i].visible_service = *data >> 7;
1190 res->channels[i].logical_channel_number =
1191 GST_READ_UINT16_BE (data) & 0x03ff;
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
1204 * Creates a #GstMpegtsDescriptor with custom @tag and @data
1206 * Returns: #GstMpegtsDescriptor
1208 GstMpegtsDescriptor *
1209 gst_mpegts_descriptor_from_custom (guint8 tag, const guint8 * data,
1212 GstMpegtsDescriptor *descriptor;
1214 g_return_val_if_fail (length > 0 || !data, NULL);
1216 descriptor = _new_descriptor (tag, length);
1218 if (data && (length > 0))
1219 memcpy (descriptor->data + 2, data, length);
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
1231 * Creates a #GstMpegtsDescriptor with custom @tag, @tag_extension and @data
1233 * Returns: #GstMpegtsDescriptor
1237 GstMpegtsDescriptor *
1238 gst_mpegts_descriptor_from_custom_with_extension (guint8 tag,
1239 guint8 tag_extension, const guint8 * data, gsize length)
1241 GstMpegtsDescriptor *descriptor;
1243 descriptor = _new_descriptor_with_extension (tag, tag_extension, length);
1245 if (data && (length > 0))
1246 memcpy (descriptor->data + 3, data, length);