gst-libs/gst/insertbin/Makefile
gst-libs/gst/interfaces/Makefile
gst-libs/gst/codecparsers/Makefile
+gst-libs/gst/mpegts/Makefile
gst-libs/gst/uridownloader/Makefile
sys/Makefile
sys/dshowdecwrapper/Makefile
CFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.c
# Header files to ignore when scanning.
-IGNORE_HFILES =
+IGNORE_HFILES = $(top_srcdir)/gst-libs/gst/mpegts/gstmpegts-private.h
# Images to copy into HTML directory.
HTML_IMAGES =
$(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_API_VERSION@.la \
$(top_builddir)/gst-libs/gst/insertbin/libgstinsertbin-@GST_API_VERSION@.la \
$(top_builddir)/gst-libs/gst/uridownloader/libgsturidownloader-@GST_API_VERSION@.la \
+ $(top_builddir)/gst-libs/gst/mpegts/libgstmpegts-@GST_API_VERSION@.la \
$(GST_BASE_LIBS)
GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC)
<para>
This library should be linked to by getting cflags and libs from
<filename>gstreamer-plugins-bad-&GST_API_VERSION;.pc</filename> and adding
- <filename>-lgscodeparsers-&GST_API_VERSION;</filename> to the library flags.
+ <filename>-lgstcodeparsers-&GST_API_VERSION;</filename> to the library flags.
</para>
<xi:include href="xml/gsth264parser.xml" />
<xi:include href="xml/gstmpegvideoparser.xml" />
<xi:include href="xml/gstmpegvideometa.xml" />
</chapter>
+ <chapter id="mpegts">
+ <title>Mpeg TS helper library</title>
+ <para>
+ This library should be linked to by getting cflags and libs from
+ <filename>gstreamer-plugins-bad-&GST_API_VERSION;.pc</filename> and adding
+ <filename>-lgstmpegts-&GST_API_VERSION;</filename> to the library flags.
+ </para>
+ <xi:include href="xml/gstmpegtssection.xml" />
+ <xi:include href="xml/gstmpegtsdescriptor.xml" />
+ </chapter>
+
<chapter id="tools">
<title>Useful elements</title>
<xi:include href="xml/gstinsertbin.xml" />
</SECTION>
<SECTION>
+<FILE>gstmpegtsdescriptor</FILE>
+<SUBSECTION Common>
+GstMpegTSDescriptor
+GstMpegTSDescriptorType
+gst_mpegts_find_descriptor
+gst_mpegts_parse_descriptors
+<SUBSECTION component>
+GstMpegTSComponentDescriptor
+gst_mpegts_descriptor_parse_dvb_component
+<SUBSECTION extended_event>
+GstMpegTSExtendedEventItem
+GstMpegTSExtendedEventDescriptor
+gst_mpegts_descriptor_parse_dvb_extended_event
+<SUBSECTION satellite_delivery>
+GstMpegTSSatelliteDeliverySystemDescriptor
+GstMpegTSDVBCodeRate
+GstMpegTSModulationType
+GstMpegTSSatellitePolarizationType
+GstMpegTSSatelliteRolloff
+gst_mpegts_descriptor_parse_satellite_delivery_system
+<SUBSECTION cable_delivery>
+GstMpegTSCableDeliverySystemDescriptor
+GstMpegTSCableOuterFECScheme
+gst_mpegts_descriptor_parse_cable_delivery_system
+<SUBSECTION short_event>
+gst_mpegts_descriptor_parse_dvb_short_event
+gst_mpegts_descriptor_parse_dvb_network_name
+<SUBSECTION service>
+GstMpegTSDVBServiceType
+gst_mpegts_descriptor_parse_dvb_service
+<SUBSECTION iso639>
+GstMpegTSISO639LanguageDescriptor
+GstMpegTSIso639AudioType
+gst_mpegts_descriptor_parse_iso_639_language
+gst_mpegts_descriptor_parse_dvb_stream_identifier
+<SUBSECTION logical_channel>
+GstMpegTSLogicalChannel
+GstMpegTSLogicalChannelDescriptor
+gst_mpegts_descriptor_parse_logical_channel
+<SUBSECTION Standard>
+GST_TYPE_MPEG_TSDVB_CODE_RATE
+GST_TYPE_MPEG_TS_CABLE_OUTER_FEC_SCHEME
+GST_TYPE_MPEG_TS_MODULATION_TYPE
+GST_TYPE_MPEG_TS_SATELLITE_POLARIZATION_TYPE
+GST_TYPE_MPEG_TS_SATELLITE_ROLLOFF
+GST_TYPE_MPEGTS_DESCRIPTOR
+GST_TYPE_MPEG_TSDVB_SERVICE_TYPE
+GST_TYPE_MPEG_TS_DESCRIPTOR_TYPE
+GST_TYPE_MPEG_TS_ISO639_AUDIO_TYPE
+GST_TYPE_MPEG_TS_RUNNING_STATUS
+gst_mpegts_descriptor_get_type
+gst_mpeg_ts_cable_outer_fec_scheme_get_type
+gst_mpeg_ts_modulation_type_get_type
+gst_mpeg_ts_satellite_polarization_type_get_type
+gst_mpeg_ts_satellite_rolloff_get_type
+gst_mpeg_tsdvb_code_rate_get_type
+gst_mpeg_ts_descriptor_type_get_type
+gst_mpeg_ts_iso639_audio_type_get_type
+gst_mpeg_ts_running_status_get_type
+gst_mpeg_tsdvb_service_type_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gstmpegtssection</FILE>
+<SUBSECTION section>
+GST_MPEGTS_SECTION_TYPE
+GstMpegTSSection
+GstMpegTSSectionTableID
+GstMpegTSSectionType
+gst_message_new_mpegts_section
+gst_message_parse_mpegts_section
+gst_mpegts_section_new
+gst_mpegts_section_ref
+gst_mpegts_section_unref
+<SUBSECTION PAT>
+GstMpegTSPatProgram
+gst_mpegts_section_get_pat
+<SUBSECTION PMT>
+GstMpegTSPMT
+GstMpegTSPMTStream
+gst_mpegts_section_get_pmt
+<SUBSECTION BAT>
+GstMpegTSBAT
+GstMpegTSBATStream
+<SUBSECTION CAT>
+gst_mpegts_section_get_cat
+<SUBSECTION EIT>
+GstMpegTSEIT
+GstMpegTSEITEvent
+GstMpegTSRunningStatus
+gst_mpegts_section_get_eit
+<SUBSECTION NIT>
+GstMpegTSNIT
+GstMpegTSNITStream
+gst_mpegts_section_get_nit
+<SUBSECTION SDT>
+GstMpegTSSDT
+GstMpegTSSDTService
+gst_mpegts_section_get_sdt
+GstMpegTSTOT
+gst_mpegts_section_get_tdt
+gst_mpegts_section_get_tot
+gst_mpegts_section_get_tsdt
+<SUBSECTION Standard>
+GST_TYPE_MPEG_TS_SECTION_TABLE_ID
+GST_TYPE_MPEG_TS_SECTION_TYPE
+GST_MPEGTS_SECTION
+GST_TYPE_MPEGTS_BAT
+GST_TYPE_MPEGTS_EIT
+GST_TYPE_MPEGTS_EIT_EVENT
+GST_TYPE_MPEGTS_NIT
+GST_TYPE_MPEGTS_NIT_STREAM
+GST_TYPE_MPEGTS_PMT
+GST_TYPE_MPEGTS_PMT_STREAM
+GST_TYPE_MPEGTS_SDT
+GST_TYPE_MPEGTS_SDT_SERVICE
+GST_TYPE_MPEGTS_SECTION
+GST_TYPE_MPEGTS_TOT
+gst_mpeg_ts_section_table_id_get_type
+gst_mpeg_ts_section_type_get_type
+gst_mpegts_bat_get_type
+gst_mpegts_eit_event_get_type
+gst_mpegts_eit_get_type
+gst_mpegts_nit_get_type
+gst_mpegts_nit_stream_get_type
+gst_mpegts_pmt_get_type
+gst_mpegts_pmt_stream_get_type
+gst_mpegts_sdt_get_type
+gst_mpegts_sdt_service_get_type
+gst_mpegts_section_get_type
+gst_mpegts_tot_get_type
+</SECTION>
+
+<SECTION>
<FILE>gstphotography</FILE>
GST_PHOTOGRAPHY_AUTOFOCUS_DONE
GST_PHOTOGRAPHY_SHAKE_RISK
#include <gst/codecparsers/gsth264parser.h>
#include <gst/codecparsers/gstmpegvideoparser.h>
#include <gst/insertbin/gstinsertbin.h>
+#include <gst/mpegts/mpegts.h>
+
+gst_mpegts_section_get_type
+gst_mpeg_ts_section_type_get_type
+gst_mpeg_ts_section_table_id_get_type
+
+gst_mpegts_descriptor_get_type
+gst_mpeg_ts_cable_outer_fec_scheme_get_type
+gst_mpeg_ts_modulation_type_get_type
+gst_mpeg_ts_satellite_polarization_type_get_type
+gst_mpeg_ts_satellite_rolloff_get_type
+gst_mpeg_tsdvb_code_rate_get_type
+gst_mpeg_ts_descriptor_type_get_type
+gst_mpeg_ts_iso639_audio_type_get_type
+gst_mpeg_ts_running_status_get_type
+gst_mpeg_tsdvb_service_type_get_type
+
gst_insert_bin_get_type
\ No newline at end of file
endif
SUBDIRS = interfaces basecamerabinsrc codecparsers \
- insertbin uridownloader $(EGL_DIR)
+ insertbin uridownloader mpegts $(EGL_DIR)
noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h
DIST_SUBDIRS = interfaces egl basecamerabinsrc codecparsers \
- insertbin uridownloader
+ insertbin uridownloader mpegts
--- /dev/null
+lib_LTLIBRARIES = libgstmpegts-@GST_API_VERSION@.la
+
+libgstmpegts_@GST_API_VERSION@_la_SOURCES = \
+ gstmpegtssection.c \
+ gstmpegtsdescriptor.c
+
+libgstmpegts_@GST_API_VERSION@includedir = \
+ $(includedir)/gstreamer-@GST_API_VERSION@/gst/mpegts
+
+noinst_HEADERS = gstmpegts-private.h
+
+libgstmpegts_@GST_API_VERSION@include_HEADERS = \
+ gstmpegtssection.h \
+ gstmpegtsdescriptor.h mpegts.h
+
+
+libgstmpegts_@GST_API_VERSION@_la_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) \
+ -DGST_USE_UNSTABLE_API \
+ $(GST_CFLAGS)
+
+libgstmpegts_@GST_API_VERSION@_la_LIBADD = \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS)
+
+libgstmpegts_@GST_API_VERSION@_la_LDFLAGS = \
+ $(GST_LIB_LDFLAGS) \
+ $(GST_ALL_LDFLAGS) \
+ $(GST_LT_LDFLAGS)
+
+glib_enum_headers=gstmpegtssection.h gstmpegtsdescriptor.h
+glib_enum_define=GST_MPEGTS
+glib_gen_prefix=gst_mpegts
+glib_gen_basename=gstmpegts
+
+BUILT_SOURCES = gstmpegts-enumtypes.c gstmpegts-enumtypes.h
+nodist_libgstmpegts_@GST_API_VERSION@_la_SOURCES = $(BUILT_SOURCES)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+if HAVE_INTROSPECTION
+BUILT_GIRSOURCES = GstMpegts-@GST_API_VERSION@.gir
+
+gir_headers=$(patsubst %,$(srcdir)/%, $(libgstmpegts_@GST_API_VERSION@include_HEADERS))
+gir_headers+=$(patsubst %,$(builddir)/%, $(built_headers))
+gir_sources=$(patsubst %,$(srcdir)/%, $(libgstmpegts_@GST_API_VERSION@_la_SOURCES))
+gir_sources+=$(patsubst %,$(builddir)/%, $(built_sources))
+
+GstMpegts-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstmpegts-@GST_API_VERSION@.la
+ $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
+ GST_PLUGIN_SYSTEM_PATH_1_0="" GST_PLUGIN_PATH_1_0="" GST_REGISTRY_UPDATE=no \
+ $(INTROSPECTION_SCANNER) -v --namespace GstMpegts \
+ --nsversion=@GST_API_VERSION@ \
+ --identifier-prefix=GstMpegTS \
+ --symbol-prefix=gst_mpegts \
+ --symbol-prefix=gst \
+ --warn-all -v \
+ --c-include "gst/mpegts/mpegts.h" \
+ -I$(top_srcdir)/gst-libs \
+ -I$(top_builddir)/gst-libs \
+ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \
+ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \
+ --library=libgstmpegts-@GST_API_VERSION@.la \
+ --include=Gst-@GST_API_VERSION@ \
+ --libtool="$(top_builddir)/libtool" \
+ --pkg gstreamer-@GST_API_VERSION@ \
+ --pkg gstreamer-video-@GST_API_VERSION@ \
+ --pkg-export gstreamer-mpegts-@GST_API_VERSION@ \
+ --add-init-section="gst_init(NULL,NULL);" \
+ -DGST_USE_UNSTABLE_API \
+ --output $@ \
+ $(gir_headers) \
+ $(gir_sources)
+
+# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to
+# install anything - we need to install inside our prefix.
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(BUILT_GIRSOURCES)
+
+typelibsdir = $(libdir)/girepository-1.0/
+
+typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
+
+%.typelib: %.gir $(INTROSPECTION_COMPILER)
+ $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
+ $(INTROSPECTION_COMPILER) \
+ --includedir=$(srcdir) \
+ --includedir=$(builddir) \
+ --includedir=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \
+ --includedir=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \
+ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F)
+
+CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
+endif
+
+Android.mk: $(BUILT_SOURCES) Makefile.am
+ androgenizer -:PROJECT libgstmpegts -:STATIC libgstmpegts-@GST_API_VERSION@ \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstmpegts_@GST_API_VERSION@_la_SOURCES) \
+ $(built_sources) \
+ -:CFLAGS $(DEFS) $(libgstmpegts_@GST_API_VERSION@_la_CFLAGS) \
+ -:LDFLAGS $(libgstmpegts_@GST_API_VERSION@_la_LDFLAGS) \
+ $(libgstmpegts@GST_API_VERSION@_la_LIBADD) \
+ -ldl \
+ -:HEADER_TARGET gstreamer-@GST_API_VERSION@/gst/mpegts \
+ -:HEADERS $(libgstmpegtsinclude_HEADERS) \
+ $(built_headers) \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ > $@
+
+include $(top_srcdir)/common/gst-glib-gen.mak
--- /dev/null
+/*
+ * mpegts.h -
+ * Copyright (C) 2013 Edward Hervey
+ *
+ * Authors:
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free softwagre; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_MPEGTS_PRIVATE_H_
+#define _GST_MPEGTS_PRIVATE_H_
+
+GST_DEBUG_CATEGORY_EXTERN (gst_mpegts_debug);
+#define GST_CAT_DEFAULT gst_mpegts_debug
+
+void __initialize_descriptors (void);
+
+#endif /* _GST_MPEGTS_PRIVATE_H_ */
--- /dev/null
+/*
+ * gstmpegtsdescriptor.c -
+ * Copyright (C) 2013 Edward Hervey
+ *
+ * Authors:
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "mpegts.h"
+#include "gstmpegts-private.h"
+
+/**
+ * SECTION:gstmpegtsdescriptor
+ * @short_description: Convenience library for using MPEG-TS descriptors
+ *
+ * For more details, refer to the ITU H.222.0 or ISO/IEC 13818-1 specifications
+ * and other specifications mentionned in the documentation.
+ */
+
+/*
+ * TODO
+ *
+ * * Add common validation code for data presence and minimum/maximum expected
+ * size.
+ * * Add parsing methods for the following descriptors that were previously
+ * handled in mpegtsbase:
+ * * GST_MTS_DESC_DVB_DATA_BROADCAST_ID
+ * * GST_MTS_DESC_DVB_DATA_BROADCAST
+ * * GST_MTS_DESC_DVB_CAROUSEL_IDENTIFIER
+ * * GST_MTS_DESC_DVB_STREAM_IDENTIFIER
+ * * GST_MTS_DESC_DVB_EXTENDED_EVENT
+ * * GST_MTS_DESC_DVB_COMPONENT
+ * * GST_MTS_DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM
+ * * GST_MTS_DESC_DVB_FREQUENCY_LIST
+ */
+
+#define MAX_KNOWN_ICONV 25
+
+static GIConv __iconvs[MAX_KNOWN_ICONV];
+
+/* All these conversions will be to UTF8 */
+typedef enum
+{
+ _ICONV_UNKNOWN = -1,
+ _ICONV_ISO8859_1,
+ _ICONV_ISO8859_2,
+ _ICONV_ISO8859_3,
+ _ICONV_ISO8859_4,
+ _ICONV_ISO8859_5,
+ _ICONV_ISO8859_6,
+ _ICONV_ISO8859_7,
+ _ICONV_ISO8859_8,
+ _ICONV_ISO8859_9,
+ _ICONV_ISO8859_10,
+ _ICONV_ISO8859_11,
+ _ICONV_ISO8859_12,
+ _ICONV_ISO8859_13,
+ _ICONV_ISO8859_14,
+ _ICONV_ISO8859_15,
+ _ICONV_ISO10646_UC2,
+ _ICONV_EUC_KR,
+ _ICONV_GB2312,
+ _ICONV_UTF_16BE,
+ _ICONV_ISO10646_UTF8,
+ _ICONV_ISO6937,
+ /* Insert more here if needed */
+ _ICONV_MAX
+} LocalIconvCode;
+
+static const gchar *iconvtablename[] = {
+ "iso-8859-1",
+ "iso-8859-2",
+ "iso-8859-3",
+ "iso-8859-4",
+ "iso-8859-5",
+ "iso-8859-6",
+ "iso-8859-7",
+ "iso-8859-8",
+ "iso-8859-9",
+ "iso-8859-10",
+ "iso-8859-11",
+ "iso-8859-12",
+ "iso-8859-13",
+ "iso-8859-14",
+ "iso-8859-15",
+ "ISO-10646/UCS2",
+ "EUC-KR",
+ "GB2312",
+ "UTF-16BE",
+ "ISO-10646/UTF8",
+ "iso6937"
+ /* Insert more here if needed */
+};
+
+void
+__initialize_descriptors (void)
+{
+ guint i;
+
+ /* Initialize converters */
+ /* FIXME : How/when should we close them ??? */
+ for (i = 0; i < MAX_KNOWN_ICONV; i++)
+ __iconvs[i] = ((GIConv) - 1);
+}
+
+/*
+ * @text: The text you want to get the encoding from
+ * @start_text: Location where the beginning of the actual text is stored
+ * @is_multibyte: Location where information whether it's a multibyte encoding
+ * or not is stored
+ * @returns: GIconv for conversion or NULL
+ */
+static LocalIconvCode
+get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte)
+{
+ LocalIconvCode encoding;
+ guint8 firstbyte;
+
+ *is_multibyte = FALSE;
+ *start_text = 0;
+
+ firstbyte = (guint8) text[0];
+
+ /* A wrong value */
+ g_return_val_if_fail (firstbyte != 0x00, _ICONV_UNKNOWN);
+
+ if (firstbyte <= 0x0B) {
+ /* 0x01 => iso 8859-5 */
+ encoding = firstbyte + _ICONV_ISO8859_4;
+ *start_text = 1;
+ goto beach;
+ }
+
+ /* ETSI EN 300 468, "Selection of character table" */
+ switch (firstbyte) {
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+ /* RESERVED */
+ encoding = _ICONV_UNKNOWN;
+ break;
+ case 0x10:
+ {
+ guint16 table;
+
+ table = GST_READ_UINT16_BE (text + 1);
+
+ if (table < 17)
+ encoding = _ICONV_UNKNOWN + table;
+ else
+ encoding = _ICONV_UNKNOWN;;
+ *start_text = 3;
+ break;
+ }
+ case 0x11:
+ encoding = _ICONV_ISO10646_UC2;
+ *start_text = 1;
+ *is_multibyte = TRUE;
+ break;
+ case 0x12:
+ /* EUC-KR implements KSX1001 */
+ encoding = _ICONV_EUC_KR;
+ *start_text = 1;
+ *is_multibyte = TRUE;
+ break;
+ case 0x13:
+ encoding = _ICONV_GB2312;
+ *start_text = 1;
+ break;
+ case 0x14:
+ encoding = _ICONV_UTF_16BE;
+ *start_text = 1;
+ *is_multibyte = TRUE;
+ break;
+ case 0x15:
+ /* TODO : Where does this come from ?? */
+ encoding = _ICONV_ISO10646_UTF8;
+ *start_text = 1;
+ break;
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1A:
+ case 0x1B:
+ case 0x1C:
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ /* RESERVED */
+ encoding = _ICONV_UNKNOWN;
+ break;
+ default:
+ encoding = _ICONV_ISO6937;
+ break;
+ }
+
+beach:
+ GST_DEBUG
+ ("Found encoding %d, first byte is 0x%02x, start_text: %u, is_multibyte: %d",
+ encoding, firstbyte, *start_text, *is_multibyte);
+
+ return encoding;
+}
+
+/*
+ * @text: The text to convert. It may include pango markup (<b> and </b>)
+ * @length: The length of the string -1 if it's nul-terminated
+ * @start: Where to start converting in the text
+ * @encoding: The encoding of text
+ * @is_multibyte: Whether the encoding is a multibyte encoding
+ * @error: The location to store the error, or NULL to ignore errors
+ * @returns: UTF-8 encoded string
+ *
+ * Convert text to UTF-8.
+ */
+static gchar *
+convert_to_utf8 (const gchar * text, gint length, guint start,
+ GIConv giconv, gboolean is_multibyte, GError ** error)
+{
+ gchar *new_text;
+ gchar *tmp, *pos;
+ gint i;
+
+ text += start;
+
+ pos = tmp = g_malloc (length * 2);
+
+ if (is_multibyte) {
+ if (length == -1) {
+ while (*text != '\0') {
+ guint16 code = GST_READ_UINT16_BE (text);
+
+ switch (code) {
+ case 0xE086: /* emphasis on */
+ case 0xE087: /* emphasis off */
+ /* skip it */
+ break;
+ case 0xE08A:{
+ pos[0] = 0x00; /* 0x00 0x0A is a new line */
+ pos[1] = 0x0A;
+ pos += 2;
+ break;
+ }
+ default:
+ pos[0] = text[0];
+ pos[1] = text[1];
+ pos += 2;
+ break;
+ }
+
+ text += 2;
+ }
+ } else {
+ for (i = 0; i < length; i += 2) {
+ guint16 code = GST_READ_UINT16_BE (text);
+
+ switch (code) {
+ case 0xE086: /* emphasis on */
+ case 0xE087: /* emphasis off */
+ /* skip it */
+ break;
+ case 0xE08A:{
+ pos[0] = 0x00; /* 0x00 0x0A is a new line */
+ pos[1] = 0x0A;
+ pos += 2;
+ break;
+ }
+ default:
+ pos[0] = text[0];
+ pos[1] = text[1];
+ pos += 2;
+ break;
+ }
+
+ text += 2;
+ }
+ }
+ } else {
+ if (length == -1) {
+ while (*text != '\0') {
+ guint8 code = (guint8) (*text);
+
+ switch (code) {
+ case 0x86: /* emphasis on */
+ case 0x87: /* emphasis off */
+ /* skip it */
+ break;
+ case 0x8A:
+ *pos = '\n';
+ pos += 1;
+ break;
+ default:
+ *pos = *text;
+ pos += 1;
+ break;
+ }
+
+ text++;
+ }
+ } else {
+ for (i = 0; i < length; i++) {
+ guint8 code = (guint8) (*text);
+
+ switch (code) {
+ case 0x86: /* emphasis on */
+ case 0x87: /* emphasis off */
+ /* skip it */
+ break;
+ case 0x8A:
+ *pos = '\n';
+ pos += 1;
+ break;
+ default:
+ *pos = *text;
+ pos += 1;
+ break;
+ }
+
+ text++;
+ }
+ }
+ }
+
+ if (pos > tmp) {
+ gsize bread = 0;
+ new_text =
+ g_convert_with_iconv (tmp, pos - tmp, giconv, &bread, NULL, error);
+ GST_DEBUG ("Converted to : %s", new_text);
+ } else {
+ new_text = g_strdup ("");
+ }
+
+ g_free (tmp);
+
+ return new_text;
+}
+
+static gchar *
+get_encoding_and_convert (const gchar * text, guint length)
+{
+ GError *error = NULL;
+ gchar *converted_str;
+ guint start_text = 0;
+ gboolean is_multibyte;
+ LocalIconvCode encoding;
+ GIConv giconv = (GIConv) - 1;
+
+ g_return_val_if_fail (text != NULL, NULL);
+
+ if (text == NULL || length == 0)
+ return g_strdup ("");
+
+ encoding = get_encoding (text, &start_text, &is_multibyte);
+
+ if (encoding > _ICONV_UNKNOWN && encoding < _ICONV_MAX) {
+ GST_DEBUG ("Encoding %s", iconvtablename[encoding]);
+ if (__iconvs[encoding] == ((GIConv) - 1))
+ __iconvs[encoding] = g_iconv_open ("utf-8", iconvtablename[encoding]);
+ giconv = __iconvs[encoding];
+ }
+
+ if (giconv == ((GIConv) - 1)) {
+ GST_WARNING ("Could not detect encoding");
+ converted_str = g_strndup (text, length);
+ goto beach;
+ }
+
+ converted_str = convert_to_utf8 (text, length - start_text, start_text,
+ giconv, is_multibyte, &error);
+ if (error != NULL) {
+ GST_WARNING ("Could not convert string: %s", error->message);
+ if (converted_str)
+ g_free (converted_str);
+ g_error_free (error);
+ error = NULL;
+
+ if (encoding >= _ICONV_ISO8859_2 && encoding <= _ICONV_ISO8859_15) {
+ /* Sometimes using the standard 8859-1 set fixes issues */
+ GST_DEBUG ("Encoding %s", iconvtablename[_ICONV_ISO8859_1]);
+ if (__iconvs[_ICONV_ISO8859_1] == (GIConv) - 1)
+ __iconvs[_ICONV_ISO8859_1] =
+ g_iconv_open ("utf-8", iconvtablename[_ICONV_ISO8859_1]);
+ giconv = __iconvs[_ICONV_ISO8859_1];
+
+ GST_INFO ("Trying encoding ISO 8859-1");
+ converted_str = convert_to_utf8 (text, length, 1, giconv, FALSE, &error);
+ if (error != NULL) {
+ GST_WARNING
+ ("Could not convert string while assuming encoding ISO 8859-1: %s",
+ error->message);
+ g_error_free (error);
+ goto failed;
+ }
+ } else if (encoding == _ICONV_ISO6937) {
+
+ /* The first part of ISO 6937 is identical to ISO 8859-9, but
+ * they differ in the second part. Some channels don't
+ * provide the first byte that indicates ISO 8859-9 encoding.
+ * If decoding from ISO 6937 failed, we try ISO 8859-9 here.
+ */
+ if (__iconvs[_ICONV_ISO8859_9] == (GIConv) - 1)
+ __iconvs[_ICONV_ISO8859_9] =
+ g_iconv_open ("utf-8", iconvtablename[_ICONV_ISO8859_9]);
+ giconv = __iconvs[_ICONV_ISO8859_9];
+
+ GST_INFO ("Trying encoding ISO 8859-9");
+ converted_str = convert_to_utf8 (text, length, 0, giconv, FALSE, &error);
+ if (error != NULL) {
+ GST_WARNING
+ ("Could not convert string while assuming encoding ISO 8859-9: %s",
+ error->message);
+ g_error_free (error);
+ goto failed;
+ }
+ } else
+ goto failed;
+ }
+
+beach:
+ return converted_str;
+
+failed:
+ {
+ text += start_text;
+ return g_strndup (text, length - start_text);
+ }
+}
+
+/**
+ * gst_mpegts_parse_descriptors:
+ * @buffer: (transfer none): descriptors to parse
+ * @buf_len: Size of @buffer
+ *
+ * Parses the descriptors present in @buffer and returns them as an
+ * array.
+ *
+ * Note: The data provided in @buffer will not be copied.
+ *
+ * Returns: (transfer full) (element-type GstMpegTSDescriptor): an
+ * array of the parsed descriptors or %NULL if there was an error.
+ * Release with #g_array_unref when done with it.
+ */
+GArray *
+gst_mpegts_parse_descriptors (guint8 * buffer, gsize buf_len)
+{
+ GArray *res;
+ guint8 length;
+ guint8 *data;
+ guint i, nb_desc = 0;
+
+ /* fast-path */
+ if (buf_len == 0)
+ return g_array_new (FALSE, FALSE, sizeof (GstMpegTSDescriptor));
+
+ data = buffer;
+
+ while (data - buffer < buf_len) {
+ data++; /* skip tag */
+ length = *data++;
+
+ if (data - buffer > buf_len) {
+ GST_WARNING ("invalid descriptor length %d now at %d max %"
+ G_GSIZE_FORMAT, length, (gint) (data - buffer), buf_len);
+ return NULL;
+ }
+
+ data += length;
+ nb_desc++;
+ }
+
+ GST_DEBUG ("Saw %d descriptors, read %" G_GSIZE_FORMAT " bytes",
+ nb_desc, data - buffer);
+
+ if (data - buffer != buf_len) {
+ GST_WARNING ("descriptors size %d expected %" G_GSIZE_FORMAT,
+ (gint) (data - buffer), buf_len);
+ return NULL;
+ }
+
+ res = g_array_sized_new (FALSE, FALSE, sizeof (GstMpegTSDescriptor), nb_desc);
+
+ data = buffer;
+
+ for (i = 0; i < nb_desc; i++) {
+ GstMpegTSDescriptor *desc = &g_array_index (res, GstMpegTSDescriptor, i);
+
+ desc->descriptor_data = data;
+ desc->descriptor_tag = *data++;
+ desc->descriptor_length = *data++;
+ GST_LOG ("descriptor 0x%02x length:%d", desc->descriptor_tag,
+ desc->descriptor_length);
+ GST_MEMDUMP ("descriptor", desc->descriptor_data + 2,
+ desc->descriptor_length);
+ /* Adjust for extended descriptors */
+ if (G_UNLIKELY (desc->descriptor_tag == 0x7f)) {
+ desc->descriptor_tag_extension = *data++;
+ desc->descriptor_length -= 1;
+ }
+ data += desc->descriptor_length;
+ }
+
+ res->len = nb_desc;
+
+ return res;
+}
+
+/**
+ * gst_mpegts_find_descriptor:
+ * @descriptors: (element-type GstMpegTSDescriptor) (transfer none): an array
+ * of #GstMpegTSDescriptor
+ * @tag: the tag to look for
+ *
+ * Finds the first descriptor of type @tag in the array.
+ *
+ * Note: To look for descriptors that can be present more than once in an
+ * array of descriptors, iterate the #GArray manually.
+ *
+ * Returns: (transfer none): the first descriptor matchin @tag, else %NULL.
+ */
+const GstMpegTSDescriptor *
+gst_mpegts_find_descriptor (GArray * descriptors, guint8 tag)
+{
+ guint i, nb_desc;
+
+ g_return_val_if_fail (descriptors != NULL, NULL);
+
+ nb_desc = descriptors->len;
+ for (i = 0; i < nb_desc; i++) {
+ GstMpegTSDescriptor *desc =
+ &g_array_index (descriptors, GstMpegTSDescriptor, i);
+ if (desc->descriptor_tag == tag)
+ return (const GstMpegTSDescriptor *) desc;
+ }
+ return NULL;
+}
+
+static GstMpegTSDescriptor *
+_copy_descriptor (GstMpegTSDescriptor * desc)
+{
+ GstMpegTSDescriptor *copy;
+
+ copy = g_new0 (GstMpegTSDescriptor, 1);
+ copy->descriptor_tag = desc->descriptor_tag;
+ copy->descriptor_tag_extension = desc->descriptor_tag_extension;
+ copy->descriptor_length = desc->descriptor_length;
+ copy->descriptor_data =
+ g_memdup (desc->descriptor_data, desc->descriptor_length);
+
+ return copy;
+}
+
+/* This freefunc will only ever be used with descriptors returned by the
+ * above function. That is why we free the descriptor data (unlike the
+ * descriptors created in _parse_descriptors()) */
+static void
+_free_descriptor (GstMpegTSDescriptor * desc)
+{
+ g_free ((gpointer) desc->descriptor_data);
+ g_free (desc);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSDescriptor, gst_mpegts_descriptor,
+ (GBoxedCopyFunc) _copy_descriptor, (GBoxedFreeFunc) _free_descriptor);
+
+/* GST_MTS_DESC_ISO_639_LANGUAGE (0x0A) */
+/**
+ * gst_mpegts_descriptor_parse_iso_639_language:
+ * @descriptor: a %GST_MTS_DESC_ISO_639_LANGUAGE #GstMpegTSDescriptor
+ * @res: (out) (transfer none): the #GstMpegTSISO639LanguageDescriptor to fill
+ *
+ * Extracts the iso 639-2 language information from @descriptor.
+ *
+ * Note: Use #gst_tag_get_language_code if you want to get the the
+ * ISO 639-1 language code from the returned ISO 639-2 one.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_iso_639_language (const GstMpegTSDescriptor *
+ descriptor, GstMpegTSISO639LanguageDescriptor * res)
+{
+ guint i;
+ guint8 *data;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (res != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x0A, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data + 2;
+ /* Each language is 3 + 1 bytes */
+ res->nb_language = descriptor->descriptor_length / 4;
+ for (i = 0; i < res->nb_language; i++) {
+ memcpy (res->language[i], data, 3);
+ res->audio_type[i] = data[3];
+ data += 4;
+ }
+ return TRUE;
+
+}
+
+
+/* GST_MTS_DESC_DVB_NETWORK_NAME (0x40) */
+/**
+ * gst_mpegts_descriptor_parse_dvb_network_name:
+ * @descriptor: a %GST_MTS_DESC_DVB_NETWORK_NAME #GstMpegTSDescriptor
+ * @name: (out) (transfer full): the extracted name
+ *
+ * Parses out the dvb network name from the @descriptor:
+ *
+ * Returns: %TRUE if the parsing happened correctly, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_dvb_network_name (const GstMpegTSDescriptor *
+ descriptor, gchar ** name)
+{
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x40, FALSE);
+
+ *name = get_encoding_and_convert ((gchar *) descriptor->descriptor_data + 2,
+ descriptor->descriptor_data[1]);
+ return TRUE;
+}
+
+/* GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM (0x43) */
+/**
+ * gst_mpegts_descriptor_parse_satellite_delivery_system:
+ * @descriptor: a %GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM #GstMpegTSDescriptor
+ * @res: (out) (transfer none): the #GstMpegTSSatelliteDeliverySystemDescriptor to fill
+ *
+ * Extracts the satellite delivery system information from @descriptor.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_satellite_delivery_system (const GstMpegTSDescriptor
+ * descriptor, GstMpegTSSatelliteDeliverySystemDescriptor * res)
+{
+ guint8 *data;
+ guint8 tmp;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (res != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x43, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data + 2;
+
+#define BCD_UN(a) ((a) & 0x0f)
+#define BCD_DEC(a) (((a) >> 4) & 0x0f)
+#define BCD(a) (BCD_UN(a) + 10 * BCD_DEC(a))
+#define BCD_16(a) (BCD(a[1]) + 100 * BCD(a[0]))
+#define BCD_28(a) (BCD_DEC(a[3]) + 10 * BCD(a[2]) + 1000 * BCD(a[1]) + 100000 * BCD(a[0]))
+#define BCD_32(a) (BCD(a[3]) + 100 * BCD(a[2]) + 10000 * BCD(a[1]) + 1000000 * BCD(a[0]))
+
+ /* BCD coded frequency in GHz (decimal point occurs after the 3rd character)
+ * So direct BCD gives us units of (GHz / 100 000) = 10 kHz*/
+ res->frequency = BCD_32 (data) * 10;
+ data += 4;
+ /* BCD codec position in degrees (float pointer after the 3rd character) */
+ res->orbital_position = (BCD_16 (data)) / 10.0;
+ data += 2;
+
+ tmp = *data;
+ res->west_east = (tmp & 0x80) == 0x80;
+ res->polarization = (tmp >> 7) & 0x03;
+ res->modulation_system = (tmp & 0x04) == 0x04;
+ if (res->modulation_system)
+ res->roll_off = (tmp >> 3 & 0x03);
+ else
+ res->roll_off = GST_MPEGTS_ROLLOFF_AUTO;
+ switch (tmp & 0x03) {
+ case 0x00:
+ res->modulation_type = GST_MPEGTS_MODULATION_QAM_AUTO;
+ break;
+ case 0x01:
+ res->modulation_type = GST_MPEGTS_MODULATION_QPSK;
+ break;
+ case 0x10:
+ res->modulation_type = GST_MPEGTS_MODULATION_PSK_8;
+ break;
+ case 0x11:
+ res->modulation_type = GST_MPEGTS_MODULATION_QAM_16;
+ break;
+ default:
+ break;
+ }
+ res->modulation_type = tmp & 0x03;
+ data += 1;
+ /* symbol_rate is in Msymbols/ (decimal point occurs after 3rd character) */
+ /* So direct BCD gives us units of (Msymbol / 10 000) = 100 sym/s */
+ res->symbol_rate = BCD_28 (data) * 100;
+ data += 3;
+ /* fec_inner */
+ res->fec_inner = *data >> 4;
+
+
+ return TRUE;
+}
+
+
+/* GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM (0x44) */
+/**
+ * gst_mpegts_descriptor_parse_cable_delivery_system:
+ * @descriptor: a %GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM #GstMpegTSDescriptor
+ * @res: (out) (transfer none): the #GstMpegTSCableDeliverySystemDescriptor to fill
+ *
+ * Extracts the cable delivery system information from @descriptor.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_cable_delivery_system (const GstMpegTSDescriptor *
+ descriptor, GstMpegTSCableDeliverySystemDescriptor * res)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (res != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x44, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data + 2;
+ /* BCD in MHz, decimal place after the fourth character */
+ res->frequency = BCD_32 (data) * 100;
+ data += 5;
+ /* fec_out (4bits) */
+ res->outer_fec = *data++ & 0x0f;
+ switch (*data) {
+ case 0x00:
+ res->modulation = GST_MPEGTS_MODULATION_NONE;
+ break;
+ case 0x01:
+ res->modulation = GST_MPEGTS_MODULATION_QAM_16;
+ break;
+ case 0x02:
+ res->modulation = GST_MPEGTS_MODULATION_QAM_32;
+ break;
+ case 0x03:
+ res->modulation = GST_MPEGTS_MODULATION_QAM_64;
+ break;
+ case 0x04:
+ res->modulation = GST_MPEGTS_MODULATION_QAM_128;
+ break;
+ case 0x05:
+ res->modulation = GST_MPEGTS_MODULATION_QAM_256;
+ break;
+ default:
+ GST_WARNING ("Unsupported cable modulation type: 0x%02x", *data);
+ res->modulation = GST_MPEGTS_MODULATION_NONE;
+ break;
+ }
+
+ data += 1;
+ /* symbol_rate is in Msymbols/ (decimal point occurs after 3rd character) */
+ /* So direct BCD gives us units of (Msymbol / 10 000) = 100 sym/s */
+ res->symbol_rate = BCD_28 (data) * 100;
+ data += 3;
+ /* fec_inner */
+ res->fec_inner = *data & 0x0f;
+
+ return TRUE;
+}
+
+/* GST_MTS_DESC_DVB_SERVICE (0x48) */
+/**
+ * gst_mpegts_descriptor_parse_dvb_service:
+ * @descriptor: a %GST_MTS_DESC_DVB_SERVICE #GstMpegTSDescriptor
+ * @service_type: (out) (allow-none): the service type
+ * @service_name: (out) (transfer full) (allow-none): the service name
+ * @provider_name: (out) (transfer full) (allow-none): the provider name
+ *
+ * Extracts the dvb service information from @descriptor.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_dvb_service (const GstMpegTSDescriptor *
+ descriptor, GstMpegTSDVBServiceType * service_type, gchar ** service_name,
+ gchar ** provider_name)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x48, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data + 2;
+
+ if (service_type)
+ *service_type = *data;
+ data += 1;
+ if (*provider_name)
+ *provider_name = get_encoding_and_convert ((const gchar *) data + 1, *data);
+ data += *data + 1;
+ if (*service_name)
+ *service_name = get_encoding_and_convert ((const gchar *) data + 1, *data);
+
+ return TRUE;
+}
+
+/* GST_MTS_DESC_DVB_SHORT_EVENT (0x4D) */
+/**
+ * gst_mpegts_descriptor_parse_dvb_short_event:
+ * @descriptor: a %GST_MTS_DESC_DVB_SHORT_EVENT #GstMpegTSDescriptor
+ * @language_code: (out) (transfer full) (allow-none): the language code
+ * @event_name: (out) (transfer full) (allow-none): the event name
+ * @text: (out) (transfer full) (allow-none): the event text
+ *
+ * Extracts the DVB short event information from @descriptor.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_dvb_short_event (const GstMpegTSDescriptor *
+ descriptor, gchar ** language_code, gchar ** event_name, gchar ** text)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x4D, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data + 2;
+
+ if (*language_code) {
+ *language_code = g_malloc0 (4);
+ memcpy (*language_code, data, 3);
+ }
+ data += 3;
+ if (*event_name)
+ *event_name = get_encoding_and_convert ((const gchar *) data + 1, *data);
+ data += *data + 1;
+ if (*text)
+ *text = get_encoding_and_convert ((const gchar *) data + 1, *data);
+ return TRUE;
+}
+
+/**
+ * gst_mpegts_descriptor_parse_logical_channel:
+ * @descriptor: a %GST_MTS_DESC_DTG_LOGICAL_CHANNEL #GstMpegTSDescriptor
+ * @res: (out) (transfer none): the #GstMpegTSLogicalChannelDescriptor to fill
+ *
+ * Extracts the logical channels from @descriptor.
+ *
+ * Returns: %TRUE if parsing succeeded, else %FALSE.
+ */
+gboolean
+gst_mpegts_descriptor_parse_logical_channel (const GstMpegTSDescriptor *
+ descriptor, GstMpegTSLogicalChannelDescriptor * res)
+{
+ guint i;
+ guint8 *data;
+
+ g_return_val_if_fail (descriptor != NULL
+ && descriptor->descriptor_data != NULL, FALSE);
+ g_return_val_if_fail (descriptor->descriptor_tag == 0x83, FALSE);
+
+ data = (guint8 *) descriptor->descriptor_data;
+ res->nb_channels = descriptor->descriptor_length / 4;
+
+ for (i = 0; i < res->nb_channels; i++) {
+ res->channels[i].service_id = GST_READ_UINT16_BE (data);
+ data += 2;
+ res->channels[i].visible_service = *data >> 7;
+ res->channels[i].logical_channel_number =
+ GST_READ_UINT16_BE (data) & 0x03ff;
+ data += 2;
+ }
+
+ return TRUE;
+}
--- /dev/null
+/*
+ * gstmpegtsdescriptor.h -
+ * Copyright (C) 2013 Edward Hervey
+ *
+ * Authors:
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Some parts of this code come from the Fluendo MPEG Demuxer plugin.
+ *
+ * The Initial Developer of the Original Code is Fluendo, S.L.
+ * Portions created by Fluendo, S.L. are Copyright (C) 2005
+ * Fluendo, S.L. All Rights Reserved.
+ *
+ * Contributor(s): Wim Taymans <wim@fluendo.com>
+ */
+
+#ifndef GST_MPEGTS_DESCRIPTOR_H
+#define GST_MPEGTS_DESCRIPTOR_H
+
+#include <gst/gst.h>
+
+/*
+ * descriptor_tag TS PS Identification
+ * 0 n/a n/a Reserved
+ * 1 n/a n/a Reserved
+ * 2 X X video_stream_descriptor
+ * 3 X X audio_stream_descriptor
+ * 4 X X hierarchy_descriptor
+ * 5 X X registration_descriptor
+ * 6 X X data_stream_alignment_descriptor
+ * 7 X X target_background_grid_descriptor
+ * 8 X X video_window_descriptor
+ * 9 X X CA_descriptor
+ * 10 X X ISO_639_language_descriptor
+ * 11 X X system_clock_descriptor
+ * 12 X X multiplex_buffer_utilization_descriptor
+ * 13 X X copyright_descriptor
+ * 14 X maximum bitrate descriptor
+ * 15 X X private data indicator descriptor
+ * 16 X X smoothing buffer descriptor
+ * 17 X STD_descriptor
+ * 18 X X IBP descriptor
+ * 19-63 n/a n/a ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
+ * 64-255 n/a n/a User Private
+ */
+
+/**
+ * GstMpegTSDescriptorType:
+ *
+ * The type of #GstMpegTSDescriptor
+ *
+ * Consult the relevant specifications for more details.
+ */
+typedef enum {
+ /* 0-18 ISO/IEC 13818-1 (H222.0 06/2012) */
+ GST_MTS_DESC_RESERVED_00 = 0x00,
+ GST_MTS_DESC_RESERVED_01 = 0x01,
+ GST_MTS_DESC_VIDEO_STREAM = 0x02,
+ GST_MTS_DESC_AUDIO_STREAM = 0x03,
+ GST_MTS_DESC_HIERARCHY = 0x04,
+ GST_MTS_DESC_REGISTRATION = 0x05,
+ GST_MTS_DESC_DATA_STREAM_ALIGNMENT = 0x06,
+ GST_MTS_DESC_TARGET_BACKGROUND_GRID = 0x07,
+ GST_MTS_DESC_VIDEO_WINDOW = 0x08,
+ GST_MTS_DESC_CA = 0x09,
+ GST_MTS_DESC_ISO_639_LANGUAGE = 0x0A,
+ GST_MTS_DESC_SYSTEM_CLOCK = 0x0B,
+ GST_MTS_DESC_MULTIPLEX_BUFFER_UTILISATION = 0x0C,
+ GST_MTS_DESC_COPYRIGHT = 0x0D,
+ GST_MTS_DESC_MAXIMUM_BITRATE = 0x0E,
+ GST_MTS_DESC_PRIVATE_DATA_INDICATOR = 0x0F,
+ GST_MTS_DESC_SMOOTHING_BUFFER = 0x10,
+ GST_MTS_DESC_STD = 0x11,
+ GST_MTS_DESC_IBP = 0x12,
+
+ /* 19-26 Defined in ISO/IEC 13818-6 (Extensions for DSM-CC) */
+ GST_MTS_DESC_DSMCC_CAROUSEL_IDENTIFIER = 0x13,
+ GST_MTS_DESC_DSMCC_ASSOCIATION_TAG = 0x14,
+ GST_MTS_DESC_DSMCC_DEFERRED_ASSOCIATION_TAG = 0x15,
+ /* 0x16 is reserved (so far) */
+ GST_MTS_DESC_DSMCC_NPT_REFERENCE = 0x17,
+ GST_MTS_DESC_DSMCC_NPT_ENDPOINT = 0x18,
+ GST_MTS_DESC_DSMCC_STREAM_MODE = 0x19,
+ GST_MTS_DESC_DSMCC_STREAM_EVENT = 0x1A,
+
+ /* 27-54 Later additions to ISO/IEC 13818-1 (H222.0 06/2012) */
+ GST_MTS_DESC_MPEG4_VIDEO = 0x1B,
+ GST_MTS_DESC_MPEG4_AUDIO = 0x1C,
+ GST_MTS_DESC_IOD = 0x1D,
+ GST_MTS_DESC_SL = 0x1E,
+ GST_MTS_DESC_FMC = 0x1F,
+ GST_MTS_DESC_EXTERNAL_ES_ID = 0x20,
+ GST_MTS_DESC_MUX_CODE = 0x21,
+ GST_MTS_DESC_FMX_BUFFER_SIZE = 0x22,
+ GST_MTS_DESC_MULTIPLEX_BUFFER = 0x23,
+ GST_MTS_DESC_CONTENT_LABELING = 0x24,
+ GST_MTS_DESC_METADATA_POINTER = 0x25,
+ GST_MTS_DESC_METADATA = 0x26,
+ GST_MTS_DESC_METADATA_STD = 0x27,
+ GST_MTS_DESC_AVC_VIDEO = 0x28,
+ /* defined in ISO/IEC 13818-11, MPEG-2 IPMP */
+ GST_MTS_DESC_IPMP = 0x29,
+ GST_MTS_DESC_AVC_TIMING_AND_HRD = 0x2A,
+ GST_MTS_DESC_MPEG2_AAC_AUDIO = 0x2B,
+ GST_MTS_DESC_FLEX_MUX_TIMING = 0x2C,
+ GST_MTS_DESC_MPEG4_TEXT = 0x2D,
+ GST_MTS_DESC_MPEG4_AUDIO_EXTENSION = 0x2E,
+ GST_MTS_DESC_AUXILIARY_VIDEO_STREAM = 0x2F,
+ GST_MTS_DESC_SVC_EXTENSION = 0x30,
+ GST_MTS_DESC_MVC_EXTENSION = 0x31,
+ GST_MTS_DESC_J2K_VIDEO = 0x32,
+ GST_MTS_DESC_MVC_OPERATION_POINT = 0x33,
+ GST_MTS_DESC_MPEG2_STEREOSCOPIC_VIDEO_FORMAT = 0x34,
+ GST_MTS_DESC_STEREOSCOPIC_PROGRAM_INFO = 0x35,
+ GST_MTS_DESC_STEREOSCOPIC_VIDEO_INFO = 0x36,
+
+ /* 55-63 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved */
+
+ /* 64-127 DVB tags ETSI EN 300 468
+ * (Specification for Service Information (SI) in DVB systems)
+ */
+ GST_MTS_DESC_DVB_NETWORK_NAME = 0x40,
+ GST_MTS_DESC_DVB_SERVICE_LIST = 0x41,
+ GST_MTS_DESC_DVB_STUFFING = 0x42,
+ GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM = 0x43,
+ GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM = 0x44,
+ GST_MTS_DESC_DVB_VBI_DATA = 0x45,
+ GST_MTS_DESC_DVB_VBI_TELETEXT = 0x46,
+ GST_MTS_DESC_DVB_BOUQUET_NAME = 0x47,
+ GST_MTS_DESC_DVB_SERVICE = 0x48,
+ GST_MTS_DESC_DVB_COUNTRY_AVAILABILITY = 0x49,
+ GST_MTS_DESC_DVB_LINKAGE = 0x4A,
+ GST_MTS_DESC_DVB_NVOD_REFERENCE = 0x4B,
+ GST_MTS_DESC_DVB_TIME_SHIFTED_SERVICE = 0x4C,
+ GST_MTS_DESC_DVB_SHORT_EVENT = 0x4D,
+ GST_MTS_DESC_DVB_EXTENDED_EVENT = 0x4E,
+ GST_MTS_DESC_DVB_TIME_SHIFTED_EVENT = 0x4F,
+ GST_MTS_DESC_DVB_COMPONENT = 0x50,
+ GST_MTS_DESC_DVB_MOSAIC = 0x51,
+ GST_MTS_DESC_DVB_STREAM_IDENTIFIER = 0x52,
+ GST_MTS_DESC_DVB_CA_IDENTIFIER = 0x53,
+ GST_MTS_DESC_DVB_CONTENT = 0x54,
+ GST_MTS_DESC_DVB_PARENTAL_RATING = 0x55,
+ GST_MTS_DESC_DVB_TELETEXT = 0x56,
+ GST_MTS_DESC_DVB_TELEPHONE = 0x57,
+ GST_MTS_DESC_DVB_LOCAL_TIME_OFFSET = 0x58,
+ GST_MTS_DESC_DVB_SUBTITLING = 0x59,
+ GST_MTS_DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM = 0x5A,
+ GST_MTS_DESC_DVB_MULTILINGUAL_NETWORK_NAME = 0x5B,
+ GST_MTS_DESC_DVB_MULTILINGUAL_BOUQUET_NAME = 0x5C,
+ GST_MTS_DESC_DVB_MULTILINGUAL_SERVICE_NAME = 0x5D,
+ GST_MTS_DESC_DVB_MULTILINGUAL_COMPONENT = 0x5E,
+ GST_MTS_DESC_DVB_PRIVATE_DATA_SPECIFIER = 0x5F,
+ GST_MTS_DESC_DVB_SERVICE_MOVE = 0x60,
+ GST_MTS_DESC_DVB_SHORT_SMOOTHING_BUFFER = 0x61,
+ GST_MTS_DESC_DVB_FREQUENCY_LIST = 0x62,
+ GST_MTS_DESC_DVB_PARTIAL_TRANSPORT_STREAM = 0x63,
+ GST_MTS_DESC_DVB_DATA_BROADCAST = 0x64,
+ GST_MTS_DESC_DVB_SCRAMBLING = 0x65,
+ GST_MTS_DESC_DVB_DATA_BROADCAST_ID = 0x66,
+ GST_MTS_DESC_DVB_TRANSPORT_STREAM = 0x67,
+ GST_MTS_DESC_DVB_DSNG = 0x68,
+ GST_MTS_DESC_DVB_PDC = 0x69,
+ GST_MTS_DESC_DVB_AC3 = 0x6A,
+ GST_MTS_DESC_DVB_ANCILLARY_DATA = 0x6B,
+ GST_MTS_DESC_DVB_CELL_LIST = 0x6C,
+ GST_MTS_DESC_DVB_CELL_FREQUENCY_LINK = 0x6D,
+ GST_MTS_DESC_DVB_ANNOUNCEMENT_SUPPORT = 0x6E,
+ GST_MTS_DESC_DVB_APPLICATION_SIGNALLING = 0x6F,
+ GST_MTS_DESC_DVB_ADAPTATION_FIELD_DATA = 0x70,
+ GST_MTS_DESC_DVB_SERVICE_IDENTIFIER = 0x71,
+ GST_MTS_DESC_DVB_SERVICE_AVAILABILITY = 0x72,
+ GST_MTS_DESC_DVB_DEFAULT_AUTHORITY = 0x73,
+ GST_MTS_DESC_DVB_RELATED_CONTENT = 0x74,
+ GST_MTS_DESC_DVB_TVA_ID = 0x75,
+ GST_MTS_DESC_DVB_CONTENT_IDENTIFIER = 0x76,
+ GST_MTS_DESC_DVB_TIMESLICE_FEC_IDENTIFIER = 0x77,
+ GST_MTS_DESC_DVB_ECM_REPETITION_RATE = 0x78,
+ GST_MTS_DESC_DVB_S2_SATELLITE_DELIVERY_SYSTEM = 0x79,
+ GST_MTS_DESC_DVB_ENHANCED_AC3 = 0x7A,
+ GST_MTS_DESC_DVB_DTS = 0x7B,
+ GST_MTS_DESC_DVB_AAC = 0x7C,
+ /* 0x7D and 0x7E are reserved for future use */
+ GST_MTS_DESC_DVB_EXTENSION = 0x7F,
+
+ /* 0x80 - 0xFE are user defined */
+ GST_MTS_DESC_AC3_AUDIO_STREAM = 0x81,
+ GST_MTS_DESC_DTG_LOGICAL_CHANNEL = 0x83, /* from DTG D-Book */
+
+ /* ATSC A/65 2009 */
+ GST_MTS_DESC_ATSC_STUFFING = 0x80,
+ GST_MTS_DESC_ATSC_AC3 = 0x83,
+ GST_MTS_DESC_ATSC_CAPTION_SERVICE = 0x86,
+ GST_MTS_DESC_ATSC_CONTENT_ADVISORY = 0x87,
+ GST_MTS_DESC_ATSC_EXTENDED_CHANNEL_NAME = 0xA0,
+ GST_MTS_DESC_ATSC_SERVICE_LOCATION = 0xA1,
+ GST_MTS_DESC_ATSC_TIME_SHIFTED_SERVICE = 0xA2,
+ GST_MTS_DESC_ATSC_COMPONENT_NAME = 0xA3,
+ GST_MTS_DESC_ATSC_DCC_DEPARTING_REQUEST = 0xA8,
+ GST_MTS_DESC_ATSC_DCC_ARRIVING_REQUEST = 0xA9,
+ GST_MTS_DESC_ATSC_REDISTRIBUTION_CONTROL = 0xAA,
+ GST_MTS_DESC_ATSC_GENRE = 0xAB,
+ GST_MTS_DESC_ATSC_PRIVATE_INFORMATION = 0xAD,
+
+ /* ATSC A/53:3 2009 */
+ GST_MTS_DESC_ATSC_ENHANCED_SIGNALING = 0xB2,
+
+ /* ATSC A/90 */
+ GST_MTS_DESC_ATSC_DATA_SERVICE = 0xA4,
+ GST_MTS_DESC_ATSC_PID_COUNT = 0xA5,
+ GST_MTS_DESC_ATSC_DOWNLOAD_DESCRIPTOR = 0xA6,
+ GST_MTS_DESC_ATSC_MULTIPROTOCOL_ENCAPSULATION = 0xA7,
+ GST_MTS_DESC_ATSC_MODULE_LINK = 0xB4,
+ GST_MTS_DESC_ATSC_CRC32 = 0xB5,
+ GST_MTS_DESC_ATSC_GROUP_LINK = 0xB8,
+
+ /* ISDB ARIB B10 v4.6 */
+ GST_MTS_DESC_ISDB_HIERARCHICAL_TRANSMISSION = 0xC0,
+ GST_MTS_DESC_ISDB_DIGITAL_COPY_CONTROL = 0xC1,
+ GST_MTS_DESC_ISDB_NETWORK_IDENTIFICATION = 0xC2,
+ GST_MTS_DESC_ISDB_PARTIAL_TS_TIME = 0xc3,
+ GST_MTS_DESC_ISDB_AUDIO_COMPONENT = 0xc4,
+ GST_MTS_DESC_ISDB_HYPERLINK = 0xc5,
+ GST_MTS_DESC_ISDB_TARGET_REGION = 0xc6,
+ GST_MTS_DESC_ISDB_DATA_CONTENT = 0xc7,
+ GST_MTS_DESC_ISDB_VIDEO_DECODE_CONTROL = 0xc8,
+ GST_MTS_DESC_ISDB_DOWNLOAD_CONTENT = 0xc9,
+ GST_MTS_DESC_ISDB_CA_EMM_TS = 0xca,
+ GST_MTS_DESC_ISDB_CA_CONTRACT_INFORMATION = 0xcb,
+ GST_MTS_DESC_ISDB_CA_SERVICE = 0xcc,
+ GST_MTS_DESC_ISDB_TS_INFORMATION = 0xcd,
+ GST_MTS_DESC_ISDB_EXTENDED_BROADCASTER = 0xce,
+ GST_MTS_DESC_ISDB_LOGO_TRANSMISSION = 0xcf,
+ GST_MTS_DESC_ISDB_BASIC_LOCAL_EVENT = 0xd0,
+ GST_MTS_DESC_ISDB_REFERENCE = 0xd1,
+ GST_MTS_DESC_ISDB_NODE_RELATION = 0xd2,
+ GST_MTS_DESC_ISDB_SHORT_NODE_INFORMATION = 0xd3,
+ GST_MTS_DESC_ISDB_STC_REFERENCE = 0xd4,
+ GST_MTS_DESC_ISDB_SERIES = 0xd5,
+ GST_MTS_DESC_ISDB_EVENT_GROUP = 0xd6,
+ GST_MTS_DESC_ISDB_SI_PARAMETER = 0xd7,
+ GST_MTS_DESC_ISDB_BROADCASTER_NAME = 0xd8,
+ GST_MTS_DESC_ISDB_COMPONENT_GROUP = 0xd9,
+ GST_MTS_DESC_ISDB_SI_PRIME_TS = 0xda,
+ GST_MTS_DESC_ISDB_BOARD_INFORMATION = 0xdb,
+ GST_MTS_DESC_ISDB_LDT_LINKAGE = 0xdc,
+ GST_MTS_DESC_ISDB_CONNECTED_TRANSMISSION = 0xdd,
+ GST_MTS_DESC_ISDB_CONTENT_AVAILABILITY = 0xde,
+ /* ... */
+ GST_MTS_DESC_ISDB_SERVICE_GROUP = 0xe0
+
+} GstMpegTSDescriptorType;
+
+typedef struct _GstMpegTSDescriptor GstMpegTSDescriptor;
+
+#define GST_TYPE_MPEGTS_DESCRIPTOR (gst_mpegts_descriptor_get_type())
+GType gst_mpegts_descriptor_get_type (void);
+
+/**
+ * GstMpegTSDescriptor:
+ * @descriptor_tag: the type of descriptor
+ * @descriptor_tag_extension: the extended type (if @descriptor_tag is 0x7f)
+ * @descriptor_length: the length of the descriptor content (excluding tag/length field)
+ * @descriptor_data: the full descriptor data (including tag, extension, length)
+ *
+ * Mpeg-TS descriptor (ISO/IEC 13818-1).
+ */
+struct _GstMpegTSDescriptor
+{
+ GstMpegTSDescriptorType descriptor_tag;
+ guint8 descriptor_tag_extension;
+ guint8 descriptor_length;
+ const guint8 *descriptor_data;
+};
+
+GArray *gst_mpegts_parse_descriptors (guint8 * buffer, gsize buf_len);
+
+const GstMpegTSDescriptor * gst_mpegts_find_descriptor (GArray *descriptors,
+ guint8 tag);
+
+/* GST_MTS_DESC_ISO_639_LANGUAGE (0x0A) */
+/**
+ * GstMpegTSISO639AudioType:
+ *
+ * Type of audio streams
+ *
+ * Defined in ITU H.222.0 Table 2-60
+ */
+typedef enum {
+ GST_MPEGTS_AUDIO_TYPE_UNDEFINED = 0,
+ GST_MPEGTS_AUDIO_TYPE_CLEAN_EFFECTS,
+ GST_MPEGTS_AUDIO_TYPE_HEARING_IMPAIRED,
+ GST_MPEGTS_AUDIO_TYPE_VISUAL_IMPAIRED_COMMENTARY
+} GstMpegTSIso639AudioType;
+
+/* FIXME: Make two methods. One for getting the number of languages,
+ * and the other for getting the (allocated, null-terminated) language
+ * and audio type */
+typedef struct _GstMpegTSISO639LanguageDescriptor GstMpegTSISO639LanguageDescriptor;
+struct _GstMpegTSISO639LanguageDescriptor
+{
+ guint nb_language;
+ gchar language[64][3];
+ GstMpegTSIso639AudioType audio_type[64];
+};
+
+gboolean gst_mpegts_descriptor_parse_iso_639_language (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSISO639LanguageDescriptor *res);
+
+
+/* GST_MTS_DESC_DVB_CAROUSEL_IDENTIFIER (0x13) */
+/* FIXME : Implement */
+
+/* GST_MTS_DESC_DVB_NETWORK_NAME (0x40) */
+gboolean gst_mpegts_descriptor_parse_dvb_network_name (const GstMpegTSDescriptor *descriptor,
+ gchar **name);
+
+/* GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM (0x43) */
+typedef struct _GstMpegTSSatelliteDeliverySystemDescriptor GstMpegTSSatelliteDeliverySystemDescriptor;
+
+typedef enum {
+ GST_MPEGTS_MODULATION_QPSK = 0,
+ GST_MPEGTS_MODULATION_QAM_16,
+ GST_MPEGTS_MODULATION_QAM_32,
+ GST_MPEGTS_MODULATION_QAM_64,
+ GST_MPEGTS_MODULATION_QAM_128,
+ GST_MPEGTS_MODULATION_QAM_256,
+ GST_MPEGTS_MODULATION_QAM_AUTO,
+ GST_MPEGTS_MODULATION_VSB_8,
+ GST_MPEGTS_MODULATION_VSB_16,
+ GST_MPEGTS_MODULATION_PSK_8,
+ GST_MPEGTS_MODULATION_APSK_16,
+ GST_MPEGTS_MODULATION_APSK_32,
+ GST_MPEGTS_MODULATION_DQPSK,
+ GST_MPEGTS_MODULATION_QAM_4_NR_,
+ GST_MPEGTS_MODULATION_NONE
+} GstMpegTSModulationType;
+
+typedef enum {
+ GST_MPEGTS_FEC_NONE = 0,
+ GST_MPEGTS_FEC_1_2,
+ GST_MPEGTS_FEC_2_3,
+ GST_MPEGTS_FEC_3_4,
+ GST_MPEGTS_FEC_4_5,
+ GST_MPEGTS_FEC_5_6,
+ GST_MPEGTS_FEC_6_7,
+ GST_MPEGTS_FEC_7_8,
+ GST_MPEGTS_FEC_8_9,
+ GST_MPEGTS_FEC_AUTO,
+ GST_MPEGTS_FEC_3_5,
+ GST_MPEGTS_FEC_9_10,
+ GST_MPEGTS_FEC_2_5
+} GstMpegTSDVBCodeRate;
+
+typedef enum {
+ GST_MPEGTS_ROLLOFF_35 = 0,
+ GST_MPEGTS_ROLLOFF_20,
+ GST_MPEGTS_ROLLOFF_25,
+ GST_MPEGTS_ROLLOFF_RESERVED,
+ GST_MPEGTS_ROLLOFF_AUTO
+} GstMpegTSSatelliteRolloff;
+
+typedef enum {
+ GST_MPEGTS_POLARIZATION_LINEAR_HORIZONTAL = 0,
+ GST_MPEGTS_POLARIZATION_LINEAR_VERTICAL,
+ GST_MPEGTS_POLARIZATION_CIRCULAR_LEFT,
+ GST_MPEGTS_POLARIZATION_CIRCULAR_RIGHT
+} GstMpegTSSatellitePolarizationType;
+
+/**
+ * GstMpegTSSatelliteDeliverySystemDescriptor:
+ * @frequency: the frequency in kHz (kiloHertz)
+ * @orbital_position: the orbital position in degrees
+ * @west_east: If %TRUE, the satellite is in the eastern part of the orbit,
+ * else in the western part.
+ * @polarization: The polarization of the transmitted signal
+ * @roll_off: Roll-off factor used in DVB-S2
+ * @modulation_system: modulation system, %TRUE if DVB-S2, else DVB-S
+ * @modulation_type: Modulation scheme used
+ * @symbol_rate: Symbol rate (in symbols per second)
+ * @fec_inner: inner FEC scheme used
+ *
+ * Satellite Delivery System Descriptor (EN 300 468 v.1.13.1)
+ */
+struct _GstMpegTSSatelliteDeliverySystemDescriptor
+{
+ guint32 frequency;
+ gfloat orbital_position;
+ gboolean west_east;
+ GstMpegTSSatellitePolarizationType polarization;
+
+ GstMpegTSSatelliteRolloff roll_off;
+ gboolean modulation_system;
+ GstMpegTSModulationType modulation_type;
+
+ guint32 symbol_rate;
+ GstMpegTSDVBCodeRate fec_inner;
+};
+
+gboolean gst_mpegts_descriptor_parse_satellite_delivery_system (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSSatelliteDeliverySystemDescriptor *res);
+
+
+/* FIXME : Implement */
+
+/* GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM (0x44) */
+typedef enum {
+ GST_MPEGTS_CABLE_OUTER_FEC_UNDEFINED = 0,
+ GST_MPEGTS_CABLE_OUTER_FEC_NONE,
+ GST_MPEGTS_CABLE_OUTER_FEC_RS_204_188,
+} GstMpegTSCableOuterFECScheme;
+
+typedef struct _GstMpegTSCableDeliverySystemDescriptor GstMpegTSCableDeliverySystemDescriptor;
+/**
+ * GstMpegTSCableDeliverySystemDescriptor:
+ * @frequency: the frequency in Hz (Hertz)
+ * @outer_fec: the outer FEC scheme used
+ * @modulation: Modulation scheme used
+ * @symbol_rate: Symbol rate (in symbols per second)
+ * @fec_inner: inner FEC scheme used
+ *
+ * Cable Delivery System Descriptor (EN 300 468 v.1.13.1)
+ */
+struct _GstMpegTSCableDeliverySystemDescriptor
+{
+ guint32 frequency;
+ GstMpegTSCableOuterFECScheme outer_fec;
+ GstMpegTSModulationType modulation;
+
+ guint32 symbol_rate;
+ GstMpegTSDVBCodeRate fec_inner;
+};
+
+gboolean gst_mpegts_descriptor_parse_cable_delivery_system (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSCableDeliverySystemDescriptor *res);
+
+/* GST_MTS_DESC_DVB_SERVICE (0x48) */
+/**
+ * GstMpegTSDVBServiceType:
+ *
+ * The type of service of a channel.
+ *
+ * As specified in Table 87 of ETSI EN 300 468 v1.13.1
+ */
+typedef enum {
+ GST_DVB_SERVICE_RESERVED_00 = 0x00,
+ GST_DVB_SERVICE_DIGITAL_TELEVISION,
+ GST_DVB_SERVICE_DIGITAL_RADIO_SOUND,
+ GST_DVB_SERVICE_TELETEXT,
+ GST_DVB_SERVICE_NVOD_REFERENCE,
+ GST_DVB_SERVICE_NVOD_TIME_SHIFTED,
+ GST_DVB_SERVICE_MOSAIC,
+ GST_DVB_SERVICE_FM_RADIO,
+ GST_DVB_SERVICE_DVB_SRM,
+ GST_DVB_SERVICE_RESERVED_09,
+ GST_DVB_SERVICE_ADVANCED_CODEC_DIGITAL_RADIO_SOUND,
+ GST_DVB_SERVICE_ADVANCED_CODEC_MOSAIC,
+ GST_DVB_SERVICE_DATA_BROADCAST,
+ GST_DVB_SERVICE_RESERVED_0D_COMMON_INTERFACE,
+ GST_DVB_SERVICE_RCS_MAP,
+ GST_DVB_SERVICE_RCS_FLS,
+ GST_DVB_SERVICE_DVB_MHP,
+ GST_DVB_SERVICE_MPEG2_HD_DIGITAL_TELEVISION,
+ /* 0x12 - 015 Reserved for future use */
+ GST_DVB_SERVICE_ADVANCED_CODEC_SD_DIGITAL_TELEVISION = 0x16,
+ GST_DVB_SERVICE_ADVANCED_CODEC_SD_NVOD_TIME_SHIFTED,
+ GST_DVB_SERVICE_ADVANCED_CODEC_SD_NVOD_REFERENCE,
+ GST_DVB_SERVICE_ADVANCED_CODEC_HD_DIGITAL_TELEVISION,
+ GST_DVB_SERVICE_ADVANCED_CODEC_HD_NVOD_TIME_SHIFTED,
+ GST_DVB_SERVICE_ADVANCED_CODEC_HD_NVOD_REFERENCE,
+ GST_DVB_SERVICE_ADVANCED_CODEC_STEREO_HD_DIGITAL_TELEVISION,
+ GST_DVB_SERVICE_ADVANCED_CODEC_STEREO_HD_NVOD_TIME_SHIFTED,
+ GST_DVB_SERVICE_ADVANCED_CODEC_STEREO_HD_NVOD_REFERENCE,
+ /* 0x1F - 0x7f Reserved for future use */
+ /* 0x80 - 0xfe user defined */
+ /* 0xff Reserved for future use */
+ GST_DVB_SERVICE_RESERVED_FF
+} GstMpegTSDVBServiceType;
+
+/* FIXME : enum type for service_type ? */
+gboolean gst_mpegts_descriptor_parse_dvb_service (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSDVBServiceType *service_type,
+ gchar **service_name,
+ gchar **provider_name);
+
+/* GST_MTS_DESC_DVB_SHORT_EVENT (0x4D) */
+gboolean gst_mpegts_descriptor_parse_dvb_short_event (const GstMpegTSDescriptor *descriptor,
+ gchar **language_code,
+ gchar **event_name,
+ gchar **text);
+
+/* GST_MTS_DESC_DVB_EXTENDED_EVENT (0x4E) */
+typedef struct _GstMpegTSExtendedEventDescriptor GstMpegTSExtendedEventDescriptor;
+typedef struct _GstMpegTSExtendedEventItem GstMpegTSExtendedEventItem;
+
+/* FIXME : Maybe make a separate method for getting a specific item entry ? */
+struct _GstMpegTSExtendedEventItem
+{
+ gchar *item_description;
+ gchar *item;
+};
+
+struct _GstMpegTSExtendedEventDescriptor
+{
+ guint8 descriptor_number;
+ guint8 last_descriptor_number;
+ gchar language_code[3];
+ guint8 nb_items;
+ GstMpegTSExtendedEventItem items[128];
+ gchar *text;
+};
+
+gboolean gst_mpegts_descriptor_parse_dvb_extended_event (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSExtendedEventDescriptor *res);
+
+/* GST_MTS_DESC_DVB_COMPONENT (0x50) */
+typedef struct _GstMpegTSComponentDescriptor GstMpegTSComponentDescriptor;
+struct _GstMpegTSComponentDescriptor
+{
+ guint8 stream_content;
+ guint8 component_type;
+ guint8 component_tag;
+ /* FIXME : Make it a separate (allocated, null-terminated) return value */
+ gchar language_code[3];
+ gchar *text;
+};
+
+gboolean gst_mpegts_descriptor_parse_dvb_component (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSComponentDescriptor *res);
+
+/* GST_MTS_DESC_DVB_STREAM_IDENTIFIER (0x52) */
+gboolean gst_mpegts_descriptor_parse_dvb_stream_identifier (const GstMpegTSDescriptor *descriptor,
+ guint8 *component_tag);
+
+/* GST_MTS_DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM (0x5A) */
+/* FIXME : Implement */
+
+/* GST_MTS_DESC_DVB_FREQUENCY_LIST (0x62) */
+/* FIXME : Implement */
+
+/* GST_MTS_DESC_DVB_DATA_BROADCAST (0x64) */
+/* FIXME: Implement */
+
+/* GST_MTS_DESC_DVB_DATA_BROADCAST_ID (0x66) */
+/* FIXME : Implement */
+
+/* GST_MTS_DESC_DVB_AC3 (0x6a) */
+/* FIXME : Implement */
+
+
+/* GST_MTS_DESC_DTG_LOGICAL_CHANNEL (0x83) */
+typedef struct _GstMpegTSLogicalChannelDescriptor GstMpegTSLogicalChannelDescriptor;
+typedef struct _GstMpegTSLogicalChannel GstMpegTSLogicalChannel;
+
+struct _GstMpegTSLogicalChannel
+{
+ guint16 service_id;
+ gboolean visible_service;
+ guint16 logical_channel_number;
+};
+
+struct _GstMpegTSLogicalChannelDescriptor
+{
+ guint nb_channels;
+ GstMpegTSLogicalChannel channels[64];
+};
+
+/* FIXME : Maybe make two methods. One for getting the number of channels,
+ * and the other for getting the content for one channel ? */
+gboolean
+gst_mpegts_descriptor_parse_logical_channel (const GstMpegTSDescriptor *descriptor,
+ GstMpegTSLogicalChannelDescriptor *res);
+
+#endif /* GST_MPEGTS_DESCRIPTOR_H */
--- /dev/null
+/*
+ * gstmpegtssection.c -
+ * Copyright (C) 2013 Edward Hervey
+ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2007 Alessandro Decina
+ * 2010 Edward Hervey
+ * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd.
+ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
+ * Author: Edward Hervey <bilboed@bilboed.com>, Collabora Ltd.
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ * Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free softwagre; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mpegts.h"
+#include "gstmpegts-private.h"
+
+/**
+ * SECTION:gstmpegtssection
+ * @short_description: Convenience library for using MPEG-TS sections
+ *
+ * For more details, refer to the ITU H.222.0 or ISO/IEC 13818-1 specifications
+ * and other specifications mentionned in the documentation.
+ */
+
+/*
+ * TODO
+ *
+ * * Check minimum size for section parsing in the various
+ * gst_mpegts_section_get_<tabld>() methods
+ *
+ * * Implement parsing code for
+ * * BAT
+ * * CAT
+ * * TSDT
+ */
+
+GST_DEBUG_CATEGORY (gst_mpegts_debug);
+
+static GQuark QUARK_PAT;
+static GQuark QUARK_CAT;
+static GQuark QUARK_BAT;
+static GQuark QUARK_PMT;
+static GQuark QUARK_NIT;
+static GQuark QUARK_SDT;
+static GQuark QUARK_EIT;
+static GQuark QUARK_TDT;
+static GQuark QUARK_TOT;
+static GQuark QUARK_SECTION;
+
+static GType _gst_mpegts_section_type = 0;
+#define MPEG_TYPE_TS_SECTION (_gst_mpegts_section_type)
+GST_DEFINE_MINI_OBJECT_TYPE (GstMpegTSSection, gst_mpegts_section);
+
+static const guint32 crc_tab[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+/* _calc_crc32 relicenced to LGPL from fluendo ts demuxer */
+static guint32
+_calc_crc32 (const guint8 * data, guint datalen)
+{
+ gint i;
+ guint32 crc = 0xffffffff;
+
+ for (i = 0; i < datalen; i++) {
+ crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
+ }
+ return crc;
+}
+
+
+static inline GstDateTime *
+_parse_utc_time (guint8 * data)
+{
+ guint year, month, day, hour, minute, second;
+ guint16 mjd;
+ guint8 *utc_ptr;
+
+ mjd = GST_READ_UINT16_BE (data);
+
+ if (mjd == G_MAXUINT16)
+ return NULL;
+
+ /* See EN 300 468 Annex C */
+ year = (guint32) (((mjd - 15078.2) / 365.25));
+ month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001);
+ day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001);
+ if (month == 14 || month == 15) {
+ year++;
+ month = month - 1 - 12;
+ } else {
+ month--;
+ }
+ year += 1900;
+
+ utc_ptr = data + 2;
+
+ hour = ((utc_ptr[0] & 0xF0) >> 4) * 10 + (utc_ptr[0] & 0x0F);
+ minute = ((utc_ptr[1] & 0xF0) >> 4) * 10 + (utc_ptr[1] & 0x0F);
+ second = ((utc_ptr[2] & 0xF0) >> 4) * 10 + (utc_ptr[2] & 0x0F);
+
+ /* Time is UTC */
+ return gst_date_time_new (0.0, year, month, day, hour, minute,
+ (gdouble) second);
+}
+
+/*
+ * GENERIC MPEG-TS SECTION
+ */
+static void
+_gst_mpegts_section_free (GstMpegTSSection * section)
+{
+ GST_DEBUG ("Freeing section type %d", section->section_type);
+
+ /* FIXME : Implement */
+ if (section->cached_parsed) {
+ switch (section->section_type) {
+ case GST_MPEGTS_SECTION_PAT:
+ g_array_unref ((GArray *) section->cached_parsed);
+ break;
+ case GST_MPEGTS_SECTION_PMT:
+ {
+ GstMpegTSPMT *pmt = (GstMpegTSPMT *) section->cached_parsed;
+ g_array_unref (pmt->descriptors);
+ g_ptr_array_unref (pmt->streams);
+ break;
+ }
+ case GST_MPEGTS_SECTION_TOT:
+ {
+ GstMpegTSTOT *tot = (GstMpegTSTOT *) section->cached_parsed;
+ gst_date_time_unref (tot->utc_time);
+ g_array_unref (tot->descriptors);
+ break;
+ }
+ case GST_MPEGTS_SECTION_TDT:
+ gst_date_time_unref ((GstDateTime *) section->cached_parsed);
+ break;
+ case GST_MPEGTS_SECTION_CAT:
+ g_array_unref ((GArray *) section->cached_parsed);
+ break;
+ case GST_MPEGTS_SECTION_NIT:
+ {
+ GstMpegTSNIT *nit = (GstMpegTSNIT *) section->cached_parsed;
+ g_array_unref (nit->descriptors);
+ g_ptr_array_unref (nit->streams);
+ break;
+ }
+ case GST_MPEGTS_SECTION_EIT:
+ {
+ GstMpegTSEIT *eit = (GstMpegTSEIT *) section->cached_parsed;
+ g_ptr_array_unref (eit->events);
+ break;
+ }
+ case GST_MPEGTS_SECTION_SDT:
+ {
+ GstMpegTSSDT *sdt = (GstMpegTSSDT *) section->cached_parsed;
+
+ g_ptr_array_unref (sdt->services);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (section->data)
+ g_free (section->data);
+ g_slice_free (GstMpegTSSection, section);
+}
+
+static GstMpegTSSection *
+_gst_mpegts_section_copy (GstMpegTSSection * section)
+{
+ GstMpegTSSection *copy;
+
+ copy = g_slice_new0 (GstMpegTSSection);
+ gst_mini_object_init (GST_MINI_OBJECT_CAST (copy), 0, MPEG_TYPE_TS_SECTION,
+ (GstMiniObjectCopyFunction) _gst_mpegts_section_copy, NULL,
+ (GstMiniObjectFreeFunction) _gst_mpegts_section_free);
+
+ copy->section_type = section->section_type;
+ copy->pid = section->pid;
+ copy->table_id = section->table_id;
+ copy->subtable_extension = section->subtable_extension;
+ copy->version_number = section->version_number;
+ copy->current_next_indicator = section->current_next_indicator;
+ copy->section_number = section->section_number;
+ copy->last_section_number = section->last_section_number;
+ copy->crc = section->crc;
+
+ copy->data = g_memdup (section->data, section->section_length);
+ copy->section_length = section->section_length;
+ /* Note: We do not copy the cached parsed item, it will be
+ * reconstructed on that copy */
+ copy->cached_parsed = NULL;
+ copy->offset = section->offset;
+ copy->short_section = section->short_section;
+
+ return copy;
+}
+
+
+/**
+ * gst_message_parse_mpegts_section:
+ * @message: a #GstMessage
+ *
+ * Returns the #GstMpegTSSection contained in a message.
+ *
+ * Returns: (transfer full): the contained #GstMpegTSSection, or %NULL.
+ */
+GstMpegTSSection *
+gst_message_parse_mpegts_section (GstMessage * message)
+{
+ const GstStructure *st;
+ GstMpegTSSection *section;
+
+ if (message->type != GST_MESSAGE_ELEMENT)
+ return NULL;
+
+ st = gst_message_get_structure (message);
+ /* FIXME : Add checks against know section names */
+ if (!gst_structure_id_get (st, QUARK_SECTION, GST_TYPE_MPEGTS_SECTION,
+ §ion, NULL))
+ return NULL;
+
+ return section;
+}
+
+/**
+ * gst_message_new_mpegts_section:
+ * @parent: (transfer none): The creator of the message
+ * @section: (transfer none): The #GstMpegTSSection to put in a message
+ *
+ * Creates a new #GstMessage for a @GstMpegTSSection.
+ *
+ * Returns: (transfer full): The new #GstMessage to be posted, or %NULL if the
+ * section is not valid.
+ */
+GstMessage *
+gst_message_new_mpegts_section (GstObject * parent, GstMpegTSSection * section)
+{
+ GstMessage *msg;
+ GstStructure *st;
+ GQuark quark;
+
+ switch (section->section_type) {
+ case GST_MPEGTS_SECTION_PAT:
+ quark = QUARK_PAT;
+ break;
+ case GST_MPEGTS_SECTION_PMT:
+ quark = QUARK_PMT;
+ break;
+ case GST_MPEGTS_SECTION_CAT:
+ quark = QUARK_CAT;
+ break;
+ case GST_MPEGTS_SECTION_EIT:
+ quark = QUARK_EIT;
+ break;
+ case GST_MPEGTS_SECTION_BAT:
+ quark = QUARK_BAT;
+ break;
+ case GST_MPEGTS_SECTION_NIT:
+ quark = QUARK_NIT;
+ break;
+ case GST_MPEGTS_SECTION_SDT:
+ quark = QUARK_SDT;
+ break;
+ case GST_MPEGTS_SECTION_TDT:
+ quark = QUARK_TDT;
+ break;
+ case GST_MPEGTS_SECTION_TOT:
+ quark = QUARK_TOT;
+ break;
+ default:
+ GST_WARNING ("Creating message for unknown GstMpegTSSection");
+ quark = QUARK_SECTION;
+ break;
+ }
+
+ st = gst_structure_new_id (quark, QUARK_SECTION, MPEG_TYPE_TS_SECTION,
+ section, NULL);
+
+ msg = gst_message_new_element (parent, st);
+
+ return msg;
+}
+
+
+/* Program Association Table */
+static GArray *
+_parse_pat (GstMpegTSSection * section)
+{
+ GArray *pat;
+ guint16 i = 0, nb_programs;
+ GstMpegTSPatProgram *program;
+ guint8 *data, *end;
+
+ /* Skip already parsed data */
+ data = section->data + 8;
+
+ /* stop at the CRC */
+ end = section->data + section->section_length;
+
+ /* Initialize program list */
+ nb_programs = (end - 4 - data) / 4;
+ pat =
+ g_array_sized_new (FALSE, FALSE, sizeof (GstMpegTSPatProgram),
+ nb_programs);
+
+ while (data < end - 4) {
+ program = &g_array_index (pat, GstMpegTSPatProgram, i);
+ program->program_number = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ program->network_or_program_map_PID = GST_READ_UINT16_BE (data) & 0x1FFF;
+ data += 2;
+
+ i++;
+ }
+ pat->len = nb_programs;
+
+ if (data != end - 4) {
+ GST_ERROR ("at the end of PAT data != end - 4");
+ g_array_unref (pat);
+
+ return NULL;
+ }
+
+ return pat;
+}
+
+/**
+ * gst_mpegts_section_get_pat:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_PAT
+ *
+ * Parses a Program Association Table (ITU H.222.0, ISO/IEC 13818-1).
+ *
+ * Returns the array of #GstMpegTSPatProgram contained in the section.
+ *
+ * Note: The PAT "transport_id" field corresponds to the "subtable_extension"
+ * field of the provided @section.
+ *
+ * Returns: (transfer container) (element-type GstMpegTSPatProgram): The
+ * #GstMpegTSPatProgram contained in the section, or %NULL if an error
+ * happened. Release with #g_ptr_array_unref when done.
+ */
+GArray *
+gst_mpegts_section_get_pat (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PAT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_pat (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return g_array_ref ((GArray *) section->cached_parsed);
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+
+/* Program Map Table */
+
+static GstMpegTSPMTStream *
+_gst_mpegts_pmt_stream_copy (GstMpegTSPMTStream * pmt)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_pmt_stream_free (GstMpegTSPMTStream * pmt)
+{
+ g_array_unref (pmt->descriptors);
+ g_slice_free (GstMpegTSPMTStream, pmt);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSPMTStream, gst_mpegts_pmt_stream,
+ (GBoxedCopyFunc) _gst_mpegts_pmt_stream_copy,
+ (GFreeFunc) _gst_mpegts_pmt_stream_free);
+
+static GstMpegTSPMT *
+_gst_mpegts_pmt_copy (GstMpegTSPMT * pmt)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_pmt_free (GstMpegTSPMT * pmt)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSPMT, gst_mpegts_pmt,
+ (GBoxedCopyFunc) _gst_mpegts_pmt_copy, (GFreeFunc) _gst_mpegts_pmt_free);
+
+
+static GstMpegTSPMT *
+_parse_pmt (GstMpegTSSection * section)
+{
+ GstMpegTSPMT *pmt = NULL;
+ guint i = 0, allocated_streams = 8;
+ guint8 *data, *end;
+ guint program_info_length;
+ guint stream_info_length;
+
+ /* fixed header + CRC == 16 */
+ if (section->section_length < 16) {
+ GST_WARNING ("PID %d invalid PMT size %d",
+ section->pid, section->section_length);
+ goto error;
+ }
+
+ pmt = g_slice_new0 (GstMpegTSPMT);
+
+ data = section->data;
+ end = data + section->section_length;
+
+ GST_DEBUG ("Parsing %d Program Map Table", section->subtable_extension);
+
+ /* Skip already parsed data */
+ data += 8;
+
+ pmt->pcr_pid = GST_READ_UINT16_BE (data) & 0x1FFF;
+ data += 2;
+
+ program_info_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+
+ /* check that the buffer is large enough to contain at least
+ * program_info_length bytes + CRC */
+ if (program_info_length && (data + program_info_length + 4 > end)) {
+ GST_WARNING ("PID %d invalid program info length %d left %d",
+ section->pid, program_info_length, (gint) (end - data));
+ goto error;
+ }
+ pmt->descriptors = gst_mpegts_parse_descriptors (data, program_info_length);
+ if (pmt->descriptors == NULL)
+ goto error;
+ data += program_info_length;
+
+ pmt->streams =
+ g_ptr_array_new_full (allocated_streams,
+ (GDestroyNotify) _gst_mpegts_pmt_stream_free);
+
+ /* parse entries, cycle until there's space for another entry (at least 5
+ * bytes) plus the CRC */
+ while (data <= end - 4 - 5) {
+ GstMpegTSPMTStream *stream = g_slice_new0 (GstMpegTSPMTStream);
+
+ g_ptr_array_add (pmt->streams, stream);
+
+ stream->stream_type = *data++;
+ GST_DEBUG ("[%d] Stream type 0x%02x found", i, stream->stream_type);
+
+ stream->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
+ data += 2;
+
+ stream_info_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+
+ if (data + stream_info_length + 4 > end) {
+ GST_WARNING ("PID %d invalid stream info length %d left %d", section->pid,
+ stream_info_length, (gint) (end - data));
+ goto error;
+ }
+
+ stream->descriptors =
+ gst_mpegts_parse_descriptors (data, stream_info_length);
+ if (stream->descriptors == NULL)
+ goto error;
+ data += stream_info_length;
+
+ i += 1;
+ }
+
+ g_assert (data == end - 4);
+
+ return pmt;
+
+error:
+ if (pmt)
+ gst_mpegts_section_unref (pmt);
+
+ return NULL;
+}
+
+/**
+ * gst_mpegts_section_get_pmt:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_PMT
+ *
+ * Returns the #GstMpegTSPMT contained in the @section.
+ *
+ * Returns: The #GstMpegTSPMT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTSPMT *
+gst_mpegts_section_get_pmt (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PMT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_pmt (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return (const GstMpegTSPMT *) section->cached_parsed;
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+
+/* Conditional Access Table */
+static GArray *
+_parse_cat (GstMpegTSSection * section)
+{
+ guint8 *data;
+ guint desc_len;
+
+ /* Skip parts already parsed */
+ data = section->data + 8;
+
+ /* descriptors */
+ desc_len = section->section_length - 4 - 8;
+ return gst_mpegts_parse_descriptors (data, desc_len);
+}
+
+/**
+ * gst_mpegts_section_get_cat:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_CAT
+ *
+ * Returns the array of #GstMpegTSDescriptor contained in the Condtional
+ * Access Table.
+ *
+ * Returns: (transfer container) (element-type GstMpegTSDescriptor): The
+ * #GstMpegTSDescriptor contained in the section, or %NULL if an error
+ * happened. Release with #g_array_unref when done.
+ */
+GArray *
+gst_mpegts_section_get_cat (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_CAT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ section->cached_parsed = (gpointer) _parse_cat (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return g_array_ref ((GArray *) section->cached_parsed);
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+/* Transport Stream Description Table (TSDT) */
+/**
+ * gst_mpegts_section_get_tsdt:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_TSDT
+ *
+ * Returns the array of #GstMpegTSDescriptor contained in the section
+ *
+ * Returns: (transfer container) (element-type GstMpegTSDescriptor): The
+ * #GstMpegTSDescriptor contained in the section, or %NULL if an error
+ * happened. Release with #g_array_unref when done.
+ */
+GArray *
+gst_mpegts_section_get_tsdt (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TSDT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (section->cached_parsed)
+ return g_array_ref ((GArray *) section->cached_parsed);
+
+ /* FIXME : parse TSDT */
+ return NULL;
+}
+
+
+/* Event Information Table */
+static GstMpegTSEIT *
+_gst_mpegts_eit_copy (GstMpegTSEIT * eit)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_eit_free (GstMpegTSEIT * eit)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSEIT, gst_mpegts_eit,
+ (GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_free);
+
+static GstMpegTSEITEvent *
+_gst_mpegts_eit_event_copy (GstMpegTSEITEvent * eit)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_eit_event_free (GstMpegTSEITEvent * eit)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSEITEvent, gst_mpegts_eit_event,
+ (GBoxedCopyFunc) _gst_mpegts_eit_event_copy,
+ (GFreeFunc) _gst_mpegts_eit_event_free);
+
+static GstMpegTSEIT *
+_parse_eit (GstMpegTSSection * section)
+{
+ GstMpegTSEIT *eit = NULL;
+ guint i = 0, allocated_events = 12;
+ guint8 *data, *end, *duration_ptr;
+ guint16 descriptors_loop_length;
+
+ /* fixed header + CRC == 16 */
+ if (section->section_length < 18) {
+ GST_WARNING ("PID %d invalid EIT size %d",
+ section->pid, section->section_length);
+ goto error;
+ }
+
+ eit = g_slice_new0 (GstMpegTSEIT);
+
+ data = section->data;
+ end = data + section->section_length;
+
+ /* Skip already parsed data */
+ data += 8;
+
+ eit->transport_stream_id = GST_READ_UINT16_BE (data);
+ data += 2;
+ eit->original_network_id = GST_READ_UINT16_BE (data);
+ data += 2;
+ eit->segment_last_section_number = *data++;
+ eit->last_table_id = *data++;
+
+ eit->actual_stream = (section->table_id == 0x4E ||
+ (section->table_id >= 0x50 && section->table_id <= 0x5F));
+ eit->present_following = (section->table_id == 0x4E
+ || section->table_id == 0x4F);
+
+ eit->events =
+ g_ptr_array_new_full (allocated_events,
+ (GDestroyNotify) _gst_mpegts_eit_event_free);
+
+ while (data < end - 4) {
+ GstMpegTSEITEvent *event;
+
+ /* 12 is the minimum entry size + CRC */
+ if (end - data < 12 + 4) {
+ GST_WARNING ("PID %d invalid EIT entry length %d",
+ section->pid, (gint) (end - 4 - data));
+ goto error;
+ }
+
+ event = g_slice_new0 (GstMpegTSEITEvent);
+ g_ptr_array_add (eit->events, event);
+
+ event->event_id = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ event->start_time = _parse_utc_time (data);
+ duration_ptr = data + 5;
+ event->duration = (((duration_ptr[0] & 0xF0) >> 4) * 10 +
+ (duration_ptr[0] & 0x0F)) * 60 * 60 +
+ (((duration_ptr[1] & 0xF0) >> 4) * 10 +
+ (duration_ptr[1] & 0x0F)) * 60 +
+ ((duration_ptr[2] & 0xF0) >> 4) * 10 + (duration_ptr[2] & 0x0F);
+
+ data += 8;
+ event->running_status = *data >> 5;
+ event->free_CA_mode = (*data >> 4) & 0x01;
+
+ descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+
+ event->descriptors =
+ gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+ if (event->descriptors == NULL)
+ goto error;
+ data += descriptors_loop_length;
+
+ i += 1;
+ }
+
+ if (data != end - 4) {
+ GST_WARNING ("PID %d invalid EIT parsed %d length %d",
+ section->pid, (gint) (data - section->data), section->section_length);
+ goto error;
+ }
+
+ return eit;
+
+error:
+ if (eit)
+ gst_mpegts_section_unref (eit);
+
+ return NULL;
+
+}
+
+/**
+ * gst_mpegts_section_get_eit:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_EIT
+ *
+ * Returns the #GstMpegTSEIT contained in the @section.
+ *
+ * Returns: The #GstMpegTSEIT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTSEIT *
+gst_mpegts_section_get_eit (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_EIT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_eit (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return (const GstMpegTSEIT *) section->cached_parsed;
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+/* Bouquet Association Table */
+static GstMpegTSBAT *
+_gst_mpegts_bat_copy (GstMpegTSBAT * bat)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_bat_free (GstMpegTSBAT * bat)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSBAT, gst_mpegts_bat,
+ (GBoxedCopyFunc) _gst_mpegts_bat_copy, (GFreeFunc) _gst_mpegts_bat_free);
+
+/* Network Information Table */
+static GstMpegTSNIT *
+_gst_mpegts_nit_copy (GstMpegTSNIT * nit)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_nit_free (GstMpegTSNIT * nit)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSNIT, gst_mpegts_nit,
+ (GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_free);
+
+static GstMpegTSNITStream *
+_gst_mpegts_nit_stream_copy (GstMpegTSNITStream * nit)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_nit_stream_free (GstMpegTSNITStream * nit)
+{
+ g_array_unref (nit->descriptors);
+ g_slice_free (GstMpegTSNITStream, nit);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSNITStream, gst_mpegts_nit_stream,
+ (GBoxedCopyFunc) _gst_mpegts_nit_stream_copy,
+ (GFreeFunc) _gst_mpegts_nit_stream_free);
+
+static GstMpegTSNIT *
+_parse_nit (GstMpegTSSection * section)
+{
+ GstMpegTSNIT *nit = NULL;
+ guint i = 0, j, allocated_streams = 12;
+ guint8 *data, *end, *entry_begin;
+ guint16 descriptors_loop_length, transport_stream_loop_length;
+
+ GST_DEBUG ("NIT");
+
+ /* fixed header + CRC == 16 */
+ if (section->section_length < 23) {
+ GST_WARNING ("PID %d invalid NIT size %d",
+ section->pid, section->section_length);
+ goto error;
+ }
+
+ nit = g_slice_new0 (GstMpegTSNIT);
+
+ data = section->data;
+ end = data + section->section_length;
+
+ /* Skip already parsed data */
+ data += 8;
+
+ nit->actual_network = section->table_id == 0x40;
+
+ descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+
+ /* see if the buffer is large enough */
+ if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
+ GST_WARNING ("PID %d invalid NIT descriptors loop length %d",
+ section->pid, descriptors_loop_length);
+ goto error;
+ }
+ nit->descriptors =
+ gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+ if (nit->descriptors == NULL)
+ goto error;
+ data += descriptors_loop_length;
+
+ transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+ if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
+ GST_WARNING
+ ("PID 0x%04x invalid NIT (transport_stream_loop_length too big)",
+ section->pid);
+ goto error;
+ }
+
+ nit->streams =
+ g_ptr_array_new_full (allocated_streams,
+ (GDestroyNotify) _gst_mpegts_nit_stream_free);
+
+ /* read up to the CRC */
+ while (transport_stream_loop_length - 4 > 0) {
+ GstMpegTSNITStream *stream = g_slice_new0 (GstMpegTSNITStream);
+
+ g_ptr_array_add (nit->streams, stream);
+
+ if (transport_stream_loop_length < 10) {
+ /* each entry must be at least 6 bytes (+ 4bytes CRC) */
+ GST_WARNING ("PID %d invalid NIT entry size %d",
+ section->pid, transport_stream_loop_length);
+ goto error;
+ }
+
+ entry_begin = data;
+
+ stream->transport_stream_id = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ stream->original_network_id = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+ data += 2;
+
+ GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
+
+ if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
+ GST_WARNING
+ ("PID %d invalid NIT entry %d descriptors loop length %d (only have %"
+ G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
+ descriptors_loop_length, end - 4 - data);
+ goto error;
+ }
+ stream->descriptors =
+ gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+ if (stream->descriptors == NULL)
+ goto error;
+
+ data += descriptors_loop_length;
+
+ /* At least notify the descriptors we are not handling :( */
+
+ for (j = 0; j < stream->descriptors->len; j++) {
+ GstMpegTSDescriptor *desc =
+ &g_array_index (stream->descriptors, GstMpegTSDescriptor, j);
+
+ switch (desc->descriptor_tag) {
+ case GST_MTS_DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM:
+ case GST_MTS_DESC_DVB_FREQUENCY_LIST:
+ GST_FIXME ("Not handling previously handled tag 0x%02x",
+ desc->descriptor_tag);
+ break;
+ default:
+ GST_LOG ("Not handling tag 0x%02x", desc->descriptor_tag);
+ break;
+ }
+ }
+
+ i += 1;
+ transport_stream_loop_length -= data - entry_begin;
+ }
+
+ if (data != end - 4) {
+ GST_WARNING ("PID %d invalid NIT parsed %d length %d",
+ section->pid, (gint) (data - section->data), section->section_length);
+ goto error;
+ }
+
+ return nit;
+
+error:
+ if (nit)
+ gst_mpegts_section_unref (nit);
+
+ return NULL;
+}
+
+/**
+ * gst_mpegts_section_get_nit:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_NIT
+ *
+ * Returns the #GstMpegTSNIT contained in the @section.
+ *
+ * Returns: The #GstMpegTSNIT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTSNIT *
+gst_mpegts_section_get_nit (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_NIT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_nit (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return (const GstMpegTSNIT *) section->cached_parsed;
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+
+/* Service Description Table (SDT) */
+
+static GstMpegTSSDT *
+_gst_mpegts_sdt_copy (GstMpegTSSDT * sdt)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_sdt_free (GstMpegTSSDT * sdt)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSSDT, gst_mpegts_sdt,
+ (GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_free);
+
+static GstMpegTSSDTService *
+_gst_mpegts_sdt_service_copy (GstMpegTSSDTService * sdt)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_sdt_service_free (GstMpegTSSDTService * sdt)
+{
+ g_array_unref (sdt->descriptors);
+ g_slice_free (GstMpegTSSDTService, sdt);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSSDTService, gst_mpegts_sdt_service,
+ (GBoxedCopyFunc) _gst_mpegts_sdt_service_copy,
+ (GFreeFunc) _gst_mpegts_sdt_service_free);
+
+
+static GstMpegTSSDT *
+_parse_sdt (GstMpegTSSection * section)
+{
+ GstMpegTSSDT *sdt = NULL;
+ guint i = 0, allocated_services = 8;
+ guint8 *data, *end, *entry_begin;
+ guint tmp;
+ guint sdt_info_length;
+ guint descriptors_loop_length;
+
+ GST_DEBUG ("SDT");
+
+ /* fixed header + CRC == 16 */
+ if (section->section_length < 14) {
+ GST_WARNING ("PID %d invalid SDT size %d",
+ section->pid, section->section_length);
+ goto error;
+ }
+
+ sdt = g_slice_new0 (GstMpegTSSDT);
+
+ data = section->data;
+ end = data + section->section_length;
+
+ /* Skip common fields */
+ data += 8;
+
+ sdt->original_network_id = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ /* skip reserved byte */
+ data += 1;
+
+ sdt->actual_ts = section->table_id == 0x42;
+
+ sdt_info_length = section->section_length - 11;
+
+ sdt->services = g_ptr_array_new_full (allocated_services,
+ (GDestroyNotify) _gst_mpegts_sdt_service_free);
+
+ /* read up to the CRC */
+ while (sdt_info_length - 4 > 0) {
+ GstMpegTSSDTService *service = g_slice_new0 (GstMpegTSSDTService);
+ g_ptr_array_add (sdt->services, service);
+
+ entry_begin = data;
+
+ if (sdt_info_length < 9) {
+ /* each entry must be at least 5 bytes (+4 bytes for the CRC) */
+ GST_WARNING ("PID %d invalid SDT entry size %d",
+ section->pid, sdt_info_length);
+ goto error;
+ }
+
+ service->service_id = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ service->EIT_schedule_flag = ((*data & 0x02) == 2);
+ service->EIT_present_following_flag = (*data & 0x01) == 1;
+
+ data += 1;
+ tmp = GST_READ_UINT16_BE (data);
+
+ service->running_status = (*data >> 5) & 0x07;
+ service->free_CA_mode = (*data >> 4) & 0x01;
+
+ descriptors_loop_length = tmp & 0x0FFF;
+ data += 2;
+
+ if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
+ GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d",
+ section->pid, service->service_id, descriptors_loop_length);
+ goto error;
+ }
+ service->descriptors =
+ gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+ if (!service->descriptors)
+ goto error;
+ data += descriptors_loop_length;
+
+ sdt_info_length -= data - entry_begin;
+ i += 1;
+ }
+
+ if (data != end - 4) {
+ GST_WARNING ("PID %d invalid SDT parsed %d length %d",
+ section->pid, (gint) (data - section->data), section->section_length);
+ goto error;
+ }
+
+ return sdt;
+
+error:
+ if (sdt)
+ _gst_mpegts_sdt_free (sdt);
+
+ return NULL;
+}
+
+
+/**
+ * gst_mpegts_section_get_sdt:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_SDT
+ *
+ * Returns the #GstMpegTSSDT contained in the @section.
+ *
+ * Returns: The #GstMpegTSSDT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTSSDT *
+gst_mpegts_section_get_sdt (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SDT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_sdt (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return (const GstMpegTSSDT *) section->cached_parsed;
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+/* Time and Date Table (TDT) */
+static GstDateTime *
+_parse_tdt (GstMpegTSSection * section)
+{
+ /* FIXME : Add length check */
+ return _parse_utc_time (section->data + 3);
+}
+
+/**
+ * gst_mpegts_section_get_tdt:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_TDT
+ *
+ * Returns the #GstDateTime of the TDT
+ *
+ * Returns: The #GstDateTime contained in the section, or %NULL
+ * if an error happened. Release with #gst_date_time_unref when done.
+ */
+GstDateTime *
+gst_mpegts_section_get_tdt (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TDT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ section->cached_parsed = (gpointer) _parse_tdt (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return gst_date_time_ref ((GstDateTime *) section->cached_parsed);
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+
+/* Time Offset Table (TOT) */
+static GstMpegTSTOT *
+_gst_mpegts_tot_copy (GstMpegTSTOT * tot)
+{
+ /* FIXME : IMPLEMENT */
+ return NULL;
+}
+
+static void
+_gst_mpegts_tot_free (GstMpegTSTOT * tot)
+{
+ /* FIXME: IMPLEMENT */
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTSTOT, gst_mpegts_tot,
+ (GBoxedCopyFunc) _gst_mpegts_tot_copy, (GFreeFunc) _gst_mpegts_tot_free);
+
+static GstMpegTSTOT *
+_parse_tot (GstMpegTSSection * section)
+{
+ guint8 *data;
+ GstMpegTSTOT *tot;
+ guint16 desc_len;
+
+ /* FIXME : Check minimum length */
+
+ GST_DEBUG ("TOT");
+
+ tot = g_slice_new0 (GstMpegTSTOT);
+
+ tot->utc_time = _parse_utc_time (section->data + 3);
+
+ /* Skip 5 bytes from utc_time (+3 of initial offset) */
+ data = section->data + 8;
+
+ desc_len = GST_READ_UINT16_BE (data) & 0xFFF;
+ tot->descriptors = gst_mpegts_parse_descriptors (data, desc_len);
+
+ return tot;
+}
+
+/**
+ * gst_mpegts_section_get_tot:
+ * @section: a #GstMpegTSSection of type %GST_MPEGTS_SECTION_TOT
+ *
+ * Returns the #GstMpegTSTOT contained in the @section.
+ *
+ * Returns: The #GstMpegTSTOT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTSTOT *
+gst_mpegts_section_get_tot (GstMpegTSSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TOT, NULL);
+ g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+ if (!section->cached_parsed) {
+ if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0))
+ goto bad_crc;
+
+ section->cached_parsed = (gpointer) _parse_tot (section);
+ if (section->cached_parsed == NULL)
+ goto parse_failure;
+ }
+
+ return (const GstMpegTSTOT *) section->cached_parsed;
+
+bad_crc:
+ {
+ GST_WARNING ("Bad CRC on section");
+ return NULL;
+ }
+
+parse_failure:
+ {
+ GST_WARNING ("Failure to parse section");
+ return NULL;
+ }
+}
+
+
+/**
+ * gst_mpegts_initialize:
+ *
+ * Initializes the MPEG-TS helper library. Must be called before any
+ * usage.
+ */
+void
+gst_mpegts_initialize (void)
+{
+ if (_gst_mpegts_section_type)
+ return;
+
+ GST_DEBUG_CATEGORY_INIT (gst_mpegts_debug, "mpegts", 0,
+ "MPEG-TS helper library");
+
+ /* FIXME : Temporary hack to initialize section gtype */
+ _gst_mpegts_section_type = gst_mpegts_section_get_type ();
+
+ QUARK_PAT = g_quark_from_string ("pat");
+ QUARK_CAT = g_quark_from_string ("cat");
+ QUARK_PMT = g_quark_from_string ("pmt");
+ QUARK_NIT = g_quark_from_string ("nit");
+ QUARK_BAT = g_quark_from_string ("bat");
+ QUARK_SDT = g_quark_from_string ("sdt");
+ QUARK_EIT = g_quark_from_string ("eit");
+ QUARK_TDT = g_quark_from_string ("tdt");
+ QUARK_TOT = g_quark_from_string ("tot");
+ QUARK_SECTION = g_quark_from_string ("section");
+
+ __initialize_descriptors ();
+}
+
+static GstMpegTSSectionType
+_identify_section (GstMpegTSSectionTableID table_id)
+{
+ switch (table_id) {
+ case GST_MTS_TABLE_ID_PROGRAM_ASSOCIATION:
+ return GST_MPEGTS_SECTION_PAT;
+ case GST_MTS_TABLE_ID_CONDITIONAL_ACCESS:
+ return GST_MPEGTS_SECTION_CAT;
+ case GST_MTS_TABLE_ID_TS_PROGRAM_MAP:
+ return GST_MPEGTS_SECTION_PMT;
+ case GST_MTS_TABLE_ID_BOUQUET_ASSOCIATION:
+ return GST_MPEGTS_SECTION_BAT;
+ case GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK:
+ case GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK:
+ return GST_MPEGTS_SECTION_NIT;
+ case GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_ACTUAL_TS:
+ case GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_OTHER_TS:
+ return GST_MPEGTS_SECTION_SDT;
+ case GST_MTS_TABLE_ID_TIME_DATE:
+ return GST_MPEGTS_SECTION_TDT;
+ case GST_MTS_TABLE_ID_TIME_OFFSET:
+ return GST_MPEGTS_SECTION_TOT;
+ /* FIXME : FILL */
+ default:
+ /* Handle ranges */
+ if (table_id >= GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT &&
+ table_id <= GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_SCHEDULE_N)
+ return GST_MPEGTS_SECTION_EIT;
+ return GST_MPEGTS_SECTION_UNKNOWN;
+ }
+}
+
+/**
+ * gst_mpegts_section_new:
+ * @pid: the PID to which this section belongs
+ * @data: (transfer full): a pointer to the beginning of the section (i.e. the first byte
+ * should contain the table_id field).
+ * @data_size: size of the @data argument.
+ *
+ * Creates a new #GstMpegTSSection from the provided @data.
+ *
+ * Note: Ensuring @data is big enough to contain the full section is the
+ * responsibility of the caller. If it is not big enough, %NULL will be
+ * returned.
+ *
+ * Note: it is the responsibility of the caller to ensure @data does point
+ * to the beginning of the section.
+ *
+ * Returns: (transfer full): A new #GstMpegTSSection if the data was valid,
+ * else %NULL
+ */
+GstMpegTSSection *
+gst_mpegts_section_new (guint16 pid, guint8 * data, gsize data_size)
+{
+ GstMpegTSSection *res = NULL;
+ guint8 tmp;
+ guint16 section_length;
+
+ /* Check for length */
+ section_length = GST_READ_UINT16_BE (data + 1) & 0x0FFF;
+ if (G_UNLIKELY (data_size < section_length + 3))
+ goto short_packet;
+
+ res = g_slice_new0 (GstMpegTSSection);
+ gst_mini_object_init (GST_MINI_OBJECT_CAST (res), 0, MPEG_TYPE_TS_SECTION,
+ (GstMiniObjectCopyFunction) _gst_mpegts_section_copy, NULL,
+ (GstMiniObjectFreeFunction) _gst_mpegts_section_free);
+
+ res->pid = pid;
+ res->data = data;
+ /* table_id : 8 bit */
+ res->table_id = *data++;
+ /* section_syntax_indicator : 1 bit
+ * other_fields (reserved) : 3 bit*/
+ res->short_section = (*data & 0x80) == 0x00;
+ /* section_length (already parsed) : 12 bit */
+ res->section_length = section_length + 3;
+ if (!res->short_section) {
+ /* CRC is after section_length (-4 for the size of the CRC) */
+ res->crc = GST_READ_UINT32_BE (res->data + res->section_length - 4);
+ /* Skip to after section_length */
+ data += 2;
+ /* subtable extension : 16 bit */
+ res->subtable_extension = GST_READ_UINT16_BE (data);
+ data += 2;
+ /* reserved : 2 bit
+ * version_number : 5 bit
+ * current_next_indicator : 1 bit */
+ tmp = *data++;
+ res->version_number = tmp >> 1 & 0x1f;
+ res->current_next_indicator = tmp & 0x01;
+ /* section_number : 8 bit */
+ res->section_number = *data++;
+ /* last_section_number : 8 bit */
+ res->last_section_number = *data;
+ }
+
+ res->section_type = _identify_section (res->table_id);
+
+ return res;
+
+short_packet:
+ {
+ GST_WARNING
+ ("PID 0x%04x section extends past provided data (got:%" G_GSIZE_FORMAT
+ ", need:%d)", pid, data_size, section_length + 3);
+ return NULL;
+ }
+}
--- /dev/null
+/*
+ * mpegtspacketizer.h -
+ * Copyright (C) 2013 Edward Hervey
+ *
+ * Authors:
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_MPEGTS_SECTION_H
+#define GST_MPEGTS_SECTION_H
+
+#include <gst/gst.h>
+#include <gst/mpegts/gstmpegtsdescriptor.h>
+
+typedef struct _GstMpegTSSection GstMpegTSSection;
+
+#define GST_TYPE_MPEGTS_SECTION (gst_mpegts_section_get_type())
+#define GST_MPEGTS_SECTION(section) ((GstMpegTSSection*) section)
+
+#define GST_MPEGTS_SECTION_TYPE(section) (GST_MPEGTS_SECTION (section)->section_type)
+
+GType gst_mpegts_section_get_type (void);
+
+/**
+ * GstMpegTSSectionType:
+ * @GST_MPEGTS_SECTION_UNKNOWN: Unknown section type
+ * @GST_MPEGTS_SECTION_PAT: Program Association Table (ISO/IEC 13818-1)
+ * @GST_MPEGTS_SECTION_PMT: Program Map Table (ISO/IEC 13818-1)
+ * @GST_MPEGTS_SECTION_CAT: Conditional Access Table (ISO/IEC 13818-1)
+ * @GST_MPEGTS_SECTION_TSDT: Transport Stream Description Table (ISO/IEC 13818-1)
+ * @GST_MPEGTS_SECTION_EIT: Event Information Table (EN 300 468)
+ * @GST_MPEGTS_SECTION_NIT: Network Information Table (ISO/IEC 13818-1 / EN 300 468)
+ * @GST_MPEGTS_SECTION_BAT: Bouquet Association Table ((EN 300 468)
+ * @GST_MPEGTS_SECTION_SDT: Service Description Table (EN 300 468)
+ * @GST_MPEGTS_SECTION_TDT: Time and Date Table (EN 300 468)
+ * @GST_MPEGTS_SECTION_TOT: Time Offset Table (EN 300 468)
+ * @GST_MPEGTS_SECTION_LAST:
+ *
+ * Types of #GstMpegTSSection that the library handles.
+ */
+typedef enum {
+ GST_MPEGTS_SECTION_UNKNOWN = 0,
+ GST_MPEGTS_SECTION_PAT,
+ GST_MPEGTS_SECTION_PMT,
+ GST_MPEGTS_SECTION_CAT,
+ GST_MPEGTS_SECTION_TSDT,
+ GST_MPEGTS_SECTION_EIT,
+ GST_MPEGTS_SECTION_NIT,
+ GST_MPEGTS_SECTION_BAT,
+ GST_MPEGTS_SECTION_SDT,
+ GST_MPEGTS_SECTION_TDT,
+ GST_MPEGTS_SECTION_TOT,
+ GST_MPEGTS_SECTION_LAST
+} GstMpegTSSectionType;
+
+/* FIXME : How do we deal with clashing table_id for the various standards:
+ * * ISO/IEC 13818-1 and ITU H.222.0 : Takes precedence over all
+ * * DVB : most used ?
+ * * ATSC
+ * * ISDB (and the brazilian variant)
+ * * DTMB (China)
+ * * DMB (South Korea)
+ *
+ * Do we create a different enum for variants ?
+ */
+/**
+ * GstMpegTSSectionTableID:
+ *
+ * Values for a #GstMpegTSSection table_id
+ */
+typedef enum {
+ /* ITU H.222.0 / IEC 13818-1 */
+ GST_MTS_TABLE_ID_PROGRAM_ASSOCIATION = 0x00,
+ GST_MTS_TABLE_ID_CONDITIONAL_ACCESS = 0x01,
+ GST_MTS_TABLE_ID_TS_PROGRAM_MAP = 0x02,
+ GST_MTS_TABLE_ID_TS_DESCRIPTION = 0x03,
+ GST_MTS_TABLE_ID_14496_SCENE_DESCRIPTION = 0x04,
+ GST_MTS_TABLE_ID_14496_OBJET_DESCRIPTOR = 0x05,
+ GST_MTS_TABLE_ID_METADATA = 0x06,
+ GST_MTS_TABLE_ID_IPMP_CONTROL_INFORMATION = 0x07,
+
+ /* IEC 13818-6 (DSM-CC) */
+ GST_MTS_TABLE_ID_DSM_CC_MULTIPROTO_ENCAPSULATED_DATA = 0x3A,
+ GST_MTS_TABLE_ID_DSM_CC_U_N_MESSAGES = 0x3B,
+ GST_MTS_TABLE_ID_DSM_CC_DOWNLOAD_DATA_MESSAGES = 0x3C,
+ GST_MTS_TABLE_ID_DSM_CC_STREAM_DESCRIPTORS = 0x3D,
+ GST_MTS_TABLE_ID_DSM_CC_PRIVATE_DATA = 0x3E,
+ GST_MTS_TABLE_ID_DSM_CC_ADDRESSABLE_SECTIONS = 0x3F,
+
+ /* EN 300 468 (DVB) v 1.12.1 */
+ GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK = 0x40,
+ GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK = 0x41,
+ GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_ACTUAL_TS = 0x42,
+ GST_MTS_TABLE_ID_SERVICE_DESCRIPTION_OTHER_TS = 0x46,
+ GST_MTS_TABLE_ID_BOUQUET_ASSOCIATION = 0x4A,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT = 0x4E,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_PRESENT = 0x4F,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_SCHEDULE_1 = 0x50,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_SCHEDULE_N = 0x5F,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_SCHEDULE_1 = 0x60,
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_SCHEDULE_N = 0x6F,
+ GST_MTS_TABLE_ID_TIME_DATE = 0x70,
+ GST_MTS_TABLE_ID_RUNNING_STATUS = 0x71,
+ GST_MTS_TABLE_ID_STUFFING = 0x72,
+ GST_MTS_TABLE_ID_TIME_OFFSET = 0x73,
+
+ /* TS 102 812 (MHP v1.1.3) */
+ GST_MTS_TABLE_ID_APPLICATION_INFORMATION_TABLE = 0x74,
+
+ /* TS 102 323 (DVB TV Anytime v1.5.1) */
+ GST_MTS_TABLE_ID_CONTAINER = 0x75,
+ GST_MTS_TABLE_ID_RELATED_CONTENT = 0x76,
+ GST_MTS_TABLE_ID_CONTENT_IDENTIFIER = 0x77,
+
+ /* EN 301 192 (DVB specification for data broadcasting) */
+ GST_MTS_TABLE_ID_MPE_FEC = 0x78,
+
+ /* TS 102 323 (DVB TV Anytime v1.5.1) */
+ GST_MTS_TABLE_ID_RESOLUTION_NOTIFICATION = 0x79,
+
+ /* TS 102 772 (DVB-SH Multi-Protocol Encapsulation) */
+ GST_MTS_TABLE_ID_MPE_IFEC = 0x7A,
+
+ /* EN 300 468 (DVB) v 1.12.1 */
+ GST_MTS_TABLE_ID_DISCONTINUITY_INFORMATION = 0x7E,
+ GST_MTS_TABLE_ID_SELECTION_INFORMATION = 0x7F,
+
+ /* ETR 289 (DVB Support for use of scrambling and CA) */
+ GST_MTS_TABLE_ID_CA_MESSAGE_ECM_0 = 0x80,
+ GST_MTS_TABLE_ID_CA_MESSAGE_ECM_1 = 0x81,
+ GST_MTS_TABLE_ID_CA_MESSAGE_SYSTEM_PRIVATE_1 = 0x82,
+ GST_MTS_TABLE_ID_CA_MESSAGE_SYSTEM_PRIVATE_N = 0x8F,
+
+ /* ... */
+
+ /* EN 301 790 (DVB interaction channel for satellite distribution channels) */
+ GST_MTS_TABLE_ID_SCT = 0xA0,
+ GST_MTS_TABLE_ID_FCT = 0xA1,
+ GST_MTS_TABLE_ID_TCT = 0xA2,
+ GST_MTS_TABLE_ID_SPT = 0xA3,
+ GST_MTS_TABLE_ID_CMT = 0xA4,
+ GST_MTS_TABLE_ID_TBTP = 0xA5,
+ GST_MTS_TABLE_ID_PCR_PACKET_PAYLOAD = 0xA6,
+ GST_MTS_TABLE_ID_TRANSMISSION_MODE_SUPPORT_PAYLOAD = 0xAA,
+ GST_MTS_TABLE_ID_TIM = 0xB0,
+ GST_MTS_TABLE_ID_LL_FEC_PARITY_DATA_TABLE = 0xB1,
+
+ /* ATSC (A/65) */
+ GST_MTS_TABLE_ID_ATSC_MASTER_GUIDE = 0xC7,
+ GST_MTS_TABLE_ID_ATSC_TERRESTRIAL_VIRTUAL_CHANNEL = 0xC8,
+ GST_MTS_TABLE_ID_ATSC_CABLE_VIRTUAL_CHANNEL = 0xC9,
+ GST_MTS_TABLE_ID_ATSC_RATING_REGION = 0xCA,
+ GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION = 0xCB,
+ GST_MTS_TABLE_ID_ATSC_CHANNEL_OR_EVENT_EXTENDED_TEXT = 0xCC,
+ GST_MTS_TABLE_ID_ATSC_SYSTEM_TIME = 0xCD,
+ /* ATSC (A/90) */
+ GST_MTS_TABLE_ID_ATSC_DATA_EVENT = 0xCE,
+ GST_MTS_TABLE_ID_ATSC_DATA_SERVICE = 0xCF,
+ /* 0xD0 ?? */
+ GST_MTS_TABLE_ID_ATSC_NETWORK_RESOURCE = 0xD1,
+ GST_MTS_TABLE_ID_ATSC_LONG_TERM_SERVICE = 0xD2,
+ GST_MTS_TABLE_ID_ATSC_DIRECTED_CHANNEL_CHANGE = 0xD3,
+ GST_MTS_TABLE_ID_ATSC_DIRECTED_CHANNEL_CHANGE_SECTION_CODE = 0xD4,
+ /* 0xD5 ?? */
+ GST_MTS_TABLE_ID_ATSC_AGGREGATE_EVENT_INFORMATION = 0xD6,
+ GST_MTS_TABLE_ID_ATSC_AGGREGATE_EXTENDED_TEXT = 0xD7,
+ /* 0xD8 ?? */
+ GST_MTS_TABLE_ID_ATSC_AGGREGATE_DATA_EVENT = 0xD9,
+ GST_MTS_TABLE_ID_ATSC_SATELLITE_VIRTUAL_CHANNEL = 0xDA,
+
+ /* ISDB (FILLME) Might interfere with ATSC table id */
+
+ /* Unset */
+ GST_MTS_TABLE_ID_UNSET = 0xFF
+
+} GstMpegTSSectionTableID;
+
+/**
+ * GstMpegTSSection:
+ * @section_type: The type of section
+ * @pid: The pid on which this section was found
+ * @table_id: The table id of this section
+ * @subtable_extension: This meaning differs per section. See the documentation
+ * of the parsed section type for the meaning of this field
+ * @version_number: Version of the section.
+ * @current_next_indicator: Applies to current/next stream or not
+ * @section_number: Number of the section (if multiple)
+ * @last_section_number: Number of the last expected section (if multiple)
+ * @crc: CRC
+ *
+ * Mpeg-TS Section Information (SI) (ISO/IEC 13818-1)
+ */
+struct _GstMpegTSSection
+{
+ /*< private >*/
+ GstMiniObject parent;
+
+ /*< public >*/
+ GstMpegTSSectionType section_type;
+
+ guint16 pid;
+ GstMpegTSSectionTableID table_id;
+
+ guint16 subtable_extension;
+ guint8 version_number;
+
+ gboolean current_next_indicator;
+
+ guint8 section_number;
+ guint8 last_section_number;
+
+ guint32 crc;
+
+ /*< private >*/
+ /* data: Points to beginning of section data
+ * i.e. the first byte is the table_id field */
+ guint8 *data;
+ /* section_length: length of data (including final CRC if present) */
+ guint section_length;
+ /* cached_parsed: cached copy of parsed section */
+ gpointer *cached_parsed;
+ /* offset: offset of the section within the container stream */
+ guint64 offset;
+ /* short_section: TRUE if section_syntax_indicator == 0
+ * FIXME : Maybe make public later on when allowing creation of
+ * sections to that people can create private short sections ? */
+ gboolean short_section;
+};
+
+/**
+ * GstMpegTSRunningStatus:
+ *
+ * Running status of a service.
+ *
+ * Corresponds to table 6 of ETSI EN 300 468 (v1.13.0)
+ */
+typedef enum
+{
+ GST_MPEGTS_RUNNING_STATUS_UNDEFINED = 0,
+ GST_MPEGTS_RUNNING_STATUS_NOT_RUNNING,
+ GST_MPEGTS_RUNNING_STATUS_STARTS_IN_FEW_SECONDS,
+ GST_MPEGTS_RUNNING_STATUS_PAUSING,
+ GST_MPEGTS_RUNNING_STATUS_RUNNING,
+ GST_MPEGTS_RUNNING_STATUS_OFF_AIR
+} GstMpegTSRunningStatus;
+
+
+/* PAT */
+typedef struct _GstMpegTSPatProgram GstMpegTSPatProgram;
+/**
+ * GstMpegTSPatProgram:
+ * @program_number: the program number
+ * @network_or_program_map_PID: the network of program map PID
+ *
+ * A program entry from a Program Association Table (ITU H.222.0, ISO/IEC 13818-1).
+ */
+struct _GstMpegTSPatProgram
+{
+ guint16 program_number;
+ guint16 network_or_program_map_PID;
+};
+
+GArray *gst_mpegts_section_get_pat (GstMpegTSSection *section);
+
+/* CAT */
+
+GArray *gst_mpegts_section_get_cat (GstMpegTSSection *section);
+
+/* PMT */
+typedef struct _GstMpegTSPMTStream GstMpegTSPMTStream;
+typedef struct _GstMpegTSPMT GstMpegTSPMT;
+#define GST_TYPE_MPEGTS_PMT (gst_mpegts_pmt_get_type())
+#define GST_TYPE_MPEGTS_PMT_STREAM (gst_mpegts_pmt_stream_get_type())
+
+/**
+ * GstMpegTSPMTStream:
+ * @stream_type: the type of stream
+ * @pid: the PID of the stream
+ * @descriptors: (element-type GstMpegTSDescriptor): the descriptors of the
+ * stream
+ *
+ * An individual stream definition.
+ */
+struct _GstMpegTSPMTStream
+{
+ guint8 stream_type;
+ guint16 pid;
+
+ GArray *descriptors;
+};
+
+/**
+ * GstMpegTSPMT:
+ * @pcr_pid: PID of the stream containing PCR
+ * @descriptors: (element-type GstMpegTSDescriptor): array of #GstMpegTSDescriptor
+ * @streams: (element-type GstMpegTSPMTStream): Array of #GstMpegTSPMTStream
+ *
+ * Program Map Table (ISO/IEC 13818-1).
+ *
+ * The program_number is contained in the subtable_extension field of the
+ * container #GstMpegTSSection.
+ */
+struct _GstMpegTSPMT
+{
+ guint16 pcr_pid;
+
+ GArray *descriptors;
+ GPtrArray *streams;
+};
+
+GType gst_mpegts_pmt_get_type (void);
+GType gst_mpegts_pmt_stream_get_type (void);
+
+const GstMpegTSPMT *gst_mpegts_section_get_pmt (GstMpegTSSection *section);
+
+/* TSDT */
+
+GArray *gst_mpegts_section_get_tsdt (GstMpegTSSection *section);
+
+/* NIT */
+
+typedef struct _GstMpegTSNITStream GstMpegTSNITStream;
+typedef struct _GstMpegTSNIT GstMpegTSNIT;
+
+#define GST_TYPE_MPEGTS_NIT (gst_mpegts_nit_get_type())
+#define GST_TYPE_MPEGTS_NIT_STREAM (gst_mpegts_nit_stream_get_type())
+
+/**
+ * GstMpegTSNITStream:
+ * @transport_stream_id:
+ * @original_network_id:
+ * @descriptors: (element-type GstMpegTSDescriptor)
+ *
+ */
+struct _GstMpegTSNITStream
+{
+ guint16 transport_stream_id;
+ guint16 original_network_id;
+
+ GArray *descriptors;
+};
+
+/**
+ * GstMpegTSNIT:
+ * @actual_network: Whether this NIT corresponds to the actual stream
+ * @descriptors: (element-type GstMpegTSDescriptor) the global descriptors
+ * @streams: (element-type GstMpegTSNITStream) the streams
+ *
+ * Network Information Table (ISO/IEC 13818-1 / EN 300 468)
+ *
+ * The network_id is contained in the subtable_extension field of the
+ * container #GstMpegTSSection.
+ */
+struct _GstMpegTSNIT
+{
+ gboolean actual_network;
+
+ GArray *descriptors;
+
+ GPtrArray *streams;
+};
+
+GType gst_mpegts_nit_get_type (void);
+GType gst_mpegts_nit_stream_get_type (void);
+
+const GstMpegTSNIT *gst_mpegts_section_get_nit (GstMpegTSSection *section);
+
+/* BAT */
+
+typedef struct _GstMpegTSBATStream GstMpegTSBATStream;
+typedef struct _GstMpegTSBAT GstMpegTSBAT;
+
+#define GST_TYPE_MPEGTS_BAT (gst_mpegts_bat_get_type())
+
+struct _GstMpegTSBATStream
+{
+ guint16 transport_stream_id;
+ guint16 original_network_id;
+
+ GArray *descriptors;
+};
+
+/**
+ * GstMpegTSBAT:
+ *
+ * DVB Bouquet Association Table (EN 300 468)
+ */
+struct _GstMpegTSBAT
+{
+ gboolean actual_network;
+
+ GArray *descriptors;
+
+ GPtrArray *streams;
+};
+
+GType gst_mpegts_bat_get_type (void);
+
+/* SDT */
+#define GST_TYPE_MPEGTS_SDT (gst_mpegts_sdt_get_type())
+#define GST_TYPE_MPEGTS_SDT_SERVICE (gst_mpegts_sdt_service_get_type())
+
+typedef struct _GstMpegTSSDTService GstMpegTSSDTService;
+typedef struct _GstMpegTSSDT GstMpegTSSDT;
+
+struct _GstMpegTSSDTService
+{
+ guint16 service_id;
+
+ gboolean EIT_schedule_flag;
+ gboolean EIT_present_following_flag;
+ GstMpegTSRunningStatus running_status;
+ gboolean free_CA_mode;
+
+ GArray *descriptors;
+};
+
+/**
+ * GstMpegTSSDT:
+ *
+ * Service Description Table (EN 300 468)
+ */
+struct _GstMpegTSSDT
+{
+ guint16 original_network_id;
+ gboolean actual_ts;
+
+ GPtrArray *services;
+};
+
+GType gst_mpegts_sdt_get_type (void);
+GType gst_mpegts_sdt_service_get_type (void);
+
+const GstMpegTSSDT *gst_mpegts_section_get_sdt (GstMpegTSSection *section);
+
+/* EIT */
+
+#define GST_TYPE_MPEGTS_EIT (gst_mpegts_eit_get_type())
+#define GST_TYPE_MPEGTS_EIT_EVENT (gst_mpegts_eit_event_get_type())
+
+typedef struct _GstMpegTSEITEvent GstMpegTSEITEvent;
+typedef struct _GstMpegTSEIT GstMpegTSEIT;
+
+/**
+ * GstMpegTSEITEvent:
+ *
+ * Event from a @GstMpegTSEIT
+ */
+struct _GstMpegTSEITEvent
+{
+ guint16 event_id;
+
+ GstDateTime *start_time;
+ guint32 duration;
+
+ GstMpegTSRunningStatus running_status;
+ gboolean free_CA_mode;
+
+ GArray *descriptors;
+};
+
+/**
+ * GstMpegTSEIT:
+ *
+ * Event Information Table (EN 300 468)
+ */
+struct _GstMpegTSEIT
+{
+ guint16 transport_stream_id;
+ guint16 original_network_id;
+ guint8 segment_last_section_number;
+ guint8 last_table_id;
+
+ gboolean actual_stream;
+ gboolean present_following;
+
+ GPtrArray *events;
+};
+
+GType gst_mpegts_eit_get_type (void);
+GType gst_mpegts_eit_event_get_type (void);
+
+const GstMpegTSEIT *gst_mpegts_section_get_eit (GstMpegTSSection *section);
+
+/* TDT */
+GstDateTime *gst_mpegts_section_get_tdt (GstMpegTSSection *section);
+
+/* TOT */
+
+typedef struct _GstMpegTSTOT GstMpegTSTOT;
+#define GST_TYPE_MPEGTS_TOT (gst_mpegts_tot_get_type())
+/**
+ * GstMpegTSTOT:
+ *
+ * Time Offset Table (EN 300 468)
+ */
+struct _GstMpegTSTOT
+{
+ GstDateTime *utc_time;
+
+ GArray *descriptors;
+};
+
+GType gst_mpegts_tot_get_type (void);
+const GstMpegTSTOT *gst_mpegts_section_get_tot (GstMpegTSSection *section);
+
+/* generic */
+
+#define gst_mpegts_section_ref(section) ((GstMpegTSSection*) gst_mini_object_ref (GST_MINI_OBJECT_CAST (section)))
+#define gst_mpegts_section_unref(section) (gst_mini_object_unref (GST_MINI_OBJECT_CAST (section)))
+
+GstMessage *gst_message_new_mpegts_section (GstObject *parent, GstMpegTSSection *section);
+
+GstMpegTSSection *gst_message_parse_mpegts_section (GstMessage *message);
+
+GstMpegTSSection *gst_mpegts_section_new (guint16 pid,
+ guint8 * data,
+ gsize data_size);
+
+#endif /* GST_MPEGTS_SECTION_H */
--- /dev/null
+/*
+ * mpegts.h -
+ * Copyright (C) 2013 Edward Hervey
+ *
+ * Authors:
+ * Edward Hervey <edward@collabora.com>
+ *
+ * This library is free softwagre; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_MPEGTS_H_
+#define _GST_MPEGTS_H_
+
+#include <gst/mpegts/gstmpegtsdescriptor.h>
+#include <gst/mpegts/gstmpegtssection.h>
+#include <gst/mpegts/gstmpegts-enumtypes.h>
+
+void gst_mpegts_initialize (void);
+
+#endif