From 3665e8543a7be01060db834501d99750bda1cec0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 23 Jun 2013 08:41:12 +0200 Subject: [PATCH] gst-libs: New Mpeg-TS support library Exposes various MPEG-TS (ISO/IEC 13818-1) and DVB (EN 300 468) Section Information as well as descriptors for usage by plugins and applications. This replaces entirely the old GstStructure-based system for conveying mpeg-ts information to applications and other plugins. Parsing and validation is done on a "when-needed" basis. This ensures the minimal overhead for elements and applications creating and using sections and descriptors. Since all information is made available, this also allows applications to parse custom sections and descriptors. Right now the library is targeted towards parsing, but the structures could be used in the future to allow applications to create and inject sections and descriptors (for usage by various mpeg-ts elements). https://bugzilla.gnome.org/show_bug.cgi?id=702724 --- configure.ac | 1 + docs/libs/Makefile.am | 3 +- docs/libs/gst-plugins-bad-libs-docs.sgml | 13 +- docs/libs/gst-plugins-bad-libs-sections.txt | 134 +++ docs/libs/gst-plugins-bad-libs.types | 17 + gst-libs/gst/Makefile.am | 4 +- gst-libs/gst/mpegts/Makefile.am | 112 ++ gst-libs/gst/mpegts/gstmpegts-private.h | 32 + gst-libs/gst/mpegts/gstmpegtsdescriptor.c | 892 ++++++++++++++++ gst-libs/gst/mpegts/gstmpegtsdescriptor.h | 589 +++++++++++ gst-libs/gst/mpegts/gstmpegtssection.c | 1507 +++++++++++++++++++++++++++ gst-libs/gst/mpegts/gstmpegtssection.h | 535 ++++++++++ gst-libs/gst/mpegts/mpegts.h | 33 + 13 files changed, 3868 insertions(+), 4 deletions(-) create mode 100644 gst-libs/gst/mpegts/Makefile.am create mode 100644 gst-libs/gst/mpegts/gstmpegts-private.h create mode 100644 gst-libs/gst/mpegts/gstmpegtsdescriptor.c create mode 100644 gst-libs/gst/mpegts/gstmpegtsdescriptor.h create mode 100644 gst-libs/gst/mpegts/gstmpegtssection.c create mode 100644 gst-libs/gst/mpegts/gstmpegtssection.h create mode 100644 gst-libs/gst/mpegts/mpegts.h diff --git a/configure.ac b/configure.ac index a179364..9dbcc8f 100644 --- a/configure.ac +++ b/configure.ac @@ -2422,6 +2422,7 @@ gst-libs/gst/egl/Makefile 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 diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index bf60c29..390886e 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -36,7 +36,7 @@ HFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.h 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 = @@ -56,6 +56,7 @@ GTKDOC_LIBS = \ $(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) diff --git a/docs/libs/gst-plugins-bad-libs-docs.sgml b/docs/libs/gst-plugins-bad-libs-docs.sgml index adf6ce6..3a8d994 100644 --- a/docs/libs/gst-plugins-bad-libs-docs.sgml +++ b/docs/libs/gst-plugins-bad-libs-docs.sgml @@ -26,7 +26,7 @@ This library should be linked to by getting cflags and libs from gstreamer-plugins-bad-&GST_API_VERSION;.pc and adding - -lgscodeparsers-&GST_API_VERSION; to the library flags. + -lgstcodeparsers-&GST_API_VERSION; to the library flags. @@ -35,6 +35,17 @@ + + Mpeg TS helper library + + This library should be linked to by getting cflags and libs from + gstreamer-plugins-bad-&GST_API_VERSION;.pc and adding + -lgstmpegts-&GST_API_VERSION; to the library flags. + + + + + Useful elements diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index 9804aae..90bb27c 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -167,6 +167,140 @@ gst_mpeg4_parse_video_packet_header
+gstmpegtsdescriptor + +GstMpegTSDescriptor +GstMpegTSDescriptorType +gst_mpegts_find_descriptor +gst_mpegts_parse_descriptors + +GstMpegTSComponentDescriptor +gst_mpegts_descriptor_parse_dvb_component + +GstMpegTSExtendedEventItem +GstMpegTSExtendedEventDescriptor +gst_mpegts_descriptor_parse_dvb_extended_event + +GstMpegTSSatelliteDeliverySystemDescriptor +GstMpegTSDVBCodeRate +GstMpegTSModulationType +GstMpegTSSatellitePolarizationType +GstMpegTSSatelliteRolloff +gst_mpegts_descriptor_parse_satellite_delivery_system + +GstMpegTSCableDeliverySystemDescriptor +GstMpegTSCableOuterFECScheme +gst_mpegts_descriptor_parse_cable_delivery_system + +gst_mpegts_descriptor_parse_dvb_short_event +gst_mpegts_descriptor_parse_dvb_network_name + +GstMpegTSDVBServiceType +gst_mpegts_descriptor_parse_dvb_service + +GstMpegTSISO639LanguageDescriptor +GstMpegTSIso639AudioType +gst_mpegts_descriptor_parse_iso_639_language +gst_mpegts_descriptor_parse_dvb_stream_identifier + +GstMpegTSLogicalChannel +GstMpegTSLogicalChannelDescriptor +gst_mpegts_descriptor_parse_logical_channel + +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 +
+ +
+gstmpegtssection + +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 + +GstMpegTSPatProgram +gst_mpegts_section_get_pat + +GstMpegTSPMT +GstMpegTSPMTStream +gst_mpegts_section_get_pmt + +GstMpegTSBAT +GstMpegTSBATStream + +gst_mpegts_section_get_cat + +GstMpegTSEIT +GstMpegTSEITEvent +GstMpegTSRunningStatus +gst_mpegts_section_get_eit + +GstMpegTSNIT +GstMpegTSNITStream +gst_mpegts_section_get_nit + +GstMpegTSSDT +GstMpegTSSDTService +gst_mpegts_section_get_sdt +GstMpegTSTOT +gst_mpegts_section_get_tdt +gst_mpegts_section_get_tot +gst_mpegts_section_get_tsdt + +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 +
+ +
gstphotography GST_PHOTOGRAPHY_AUTOFOCUS_DONE GST_PHOTOGRAPHY_SHAKE_RISK diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types index caa3918..bc3e605 100644 --- a/docs/libs/gst-plugins-bad-libs.types +++ b/docs/libs/gst-plugins-bad-libs.types @@ -3,5 +3,22 @@ #include #include #include +#include + +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 diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index 372444e..1d6cc35 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -3,8 +3,8 @@ EGL_DIR = egl 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 diff --git a/gst-libs/gst/mpegts/Makefile.am b/gst-libs/gst/mpegts/Makefile.am new file mode 100644 index 0000000..2ba2dee --- /dev/null +++ b/gst-libs/gst/mpegts/Makefile.am @@ -0,0 +1,112 @@ +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 diff --git a/gst-libs/gst/mpegts/gstmpegts-private.h b/gst-libs/gst/mpegts/gstmpegts-private.h new file mode 100644 index 0000000..a2496cd --- /dev/null +++ b/gst-libs/gst/mpegts/gstmpegts-private.h @@ -0,0 +1,32 @@ +/* + * mpegts.h - + * Copyright (C) 2013 Edward Hervey + * + * Authors: + * Edward Hervey + * + * 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_ */ diff --git a/gst-libs/gst/mpegts/gstmpegtsdescriptor.c b/gst-libs/gst/mpegts/gstmpegtsdescriptor.c new file mode 100644 index 0000000..92df3dd --- /dev/null +++ b/gst-libs/gst/mpegts/gstmpegtsdescriptor.c @@ -0,0 +1,892 @@ +/* + * gstmpegtsdescriptor.c - + * Copyright (C) 2013 Edward Hervey + * + * Authors: + * Edward Hervey + * + * 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 +#include + +#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 ( and ) + * @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; +} diff --git a/gst-libs/gst/mpegts/gstmpegtsdescriptor.h b/gst-libs/gst/mpegts/gstmpegtsdescriptor.h new file mode 100644 index 0000000..1c706be --- /dev/null +++ b/gst-libs/gst/mpegts/gstmpegtsdescriptor.h @@ -0,0 +1,589 @@ +/* + * gstmpegtsdescriptor.h - + * Copyright (C) 2013 Edward Hervey + * + * Authors: + * Edward Hervey + * + * 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 + */ + +#ifndef GST_MPEGTS_DESCRIPTOR_H +#define GST_MPEGTS_DESCRIPTOR_H + +#include + +/* + * 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 */ diff --git a/gst-libs/gst/mpegts/gstmpegtssection.c b/gst-libs/gst/mpegts/gstmpegtssection.c new file mode 100644 index 0000000..e7a1f7a --- /dev/null +++ b/gst-libs/gst/mpegts/gstmpegtssection.c @@ -0,0 +1,1507 @@ +/* + * 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 , Collabora Ltd. + * Author: Sebastian Dröge , Collabora Ltd. + * Author: Edward Hervey , Collabora Ltd. + * + * Authors: + * Alessandro Decina + * Zaheer Abbas Merali + * Edward Hervey + * + * 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 +#include + +#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_() 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; + } +} diff --git a/gst-libs/gst/mpegts/gstmpegtssection.h b/gst-libs/gst/mpegts/gstmpegtssection.h new file mode 100644 index 0000000..f71aa03 --- /dev/null +++ b/gst-libs/gst/mpegts/gstmpegtssection.h @@ -0,0 +1,535 @@ +/* + * mpegtspacketizer.h - + * Copyright (C) 2013 Edward Hervey + * + * Authors: + * Edward Hervey + * + * 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 +#include + +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 */ diff --git a/gst-libs/gst/mpegts/mpegts.h b/gst-libs/gst/mpegts/mpegts.h new file mode 100644 index 0000000..5b3e42a --- /dev/null +++ b/gst-libs/gst/mpegts/mpegts.h @@ -0,0 +1,33 @@ +/* + * mpegts.h - + * Copyright (C) 2013 Edward Hervey + * + * Authors: + * Edward Hervey + * + * 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 +#include +#include + +void gst_mpegts_initialize (void); + +#endif -- 2.7.4