diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index 90bb27c686..ef24ce7b5f 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -169,110 +169,126 @@ gst_mpeg4_parse_video_packet_header
gstmpegtsdescriptor -GstMpegTSDescriptor -GstMpegTSDescriptorType +GstMpegTsDescriptor +GstMpegTsDescriptorType +GstMpegTsATSCDescriptorType +GstMpegTsDVBDescriptorType +GstMpegTsISDBDescriptorType +GstMpegTsMiscDescriptorType gst_mpegts_find_descriptor gst_mpegts_parse_descriptors -GstMpegTSComponentDescriptor +GstMpegTsComponentDescriptor gst_mpegts_descriptor_parse_dvb_component -GstMpegTSExtendedEventItem -GstMpegTSExtendedEventDescriptor +GstMpegTsExtendedEventItem +GstMpegTsExtendedEventDescriptor gst_mpegts_descriptor_parse_dvb_extended_event -GstMpegTSSatelliteDeliverySystemDescriptor -GstMpegTSDVBCodeRate -GstMpegTSModulationType -GstMpegTSSatellitePolarizationType -GstMpegTSSatelliteRolloff +GstMpegTsSatelliteDeliverySystemDescriptor +GstMpegTsDVBCodeRate +GstMpegTsModulationType +GstMpegTsSatellitePolarizationType +GstMpegTsSatelliteRolloff gst_mpegts_descriptor_parse_satellite_delivery_system -GstMpegTSCableDeliverySystemDescriptor -GstMpegTSCableOuterFECScheme +GstMpegTsCableDeliverySystemDescriptor +GstMpegTsCableOuterFECScheme gst_mpegts_descriptor_parse_cable_delivery_system gst_mpegts_descriptor_parse_dvb_short_event gst_mpegts_descriptor_parse_dvb_network_name -GstMpegTSDVBServiceType +GstMpegTsDVBServiceType gst_mpegts_descriptor_parse_dvb_service -GstMpegTSISO639LanguageDescriptor -GstMpegTSIso639AudioType +GstMpegTsISO639LanguageDescriptor +GstMpegTsIso639AudioType gst_mpegts_descriptor_parse_iso_639_language gst_mpegts_descriptor_parse_dvb_stream_identifier -GstMpegTSLogicalChannel -GstMpegTSLogicalChannelDescriptor +GstMpegTsLogicalChannel +GstMpegTsLogicalChannelDescriptor gst_mpegts_descriptor_parse_logical_channel -GST_TYPE_MPEG_TSDVB_CODE_RATE +GST_TYPE_MPEG_TS_DVB_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_DVB_SERVICE_TYPE GST_TYPE_MPEG_TS_DESCRIPTOR_TYPE GST_TYPE_MPEG_TS_ISO639_AUDIO_TYPE GST_TYPE_MPEG_TS_RUNNING_STATUS +GST_TYPE_MPEG_TS_ATSC_DESCRIPTOR_TYPE +GST_TYPE_MPEG_TS_DVB_DESCRIPTOR_TYPE +GST_TYPE_MPEG_TS_ISDB_DESCRIPTOR_TYPE +GST_TYPE_MPEG_TS_MISC_DESCRIPTOR_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_dvb_code_rate_get_type gst_mpeg_ts_descriptor_type_get_type +gst_mpeg_ts_atsc_descriptor_type_get_type +gst_mpeg_ts_dvb_descriptor_type_get_type +gst_mpeg_ts_isdb_descriptor_type_get_type +gst_mpeg_ts_misc_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_mpeg_ts_dvb_service_type_get_type
gstmpegtssection GST_MPEGTS_SECTION_TYPE -GstMpegTSSection -GstMpegTSSectionTableID -GstMpegTSSectionType +GstMpegTsSection +GstMpegTsSectionTableID +GstMpegTsSectionATSCTableID +GstMpegTsSectionDVBTableID +GstMpegTsSectionType gst_message_new_mpegts_section gst_message_parse_mpegts_section gst_mpegts_section_new gst_mpegts_section_ref gst_mpegts_section_unref -GstMpegTSPatProgram +GstMpegTsPatProgram gst_mpegts_section_get_pat -GstMpegTSPMT -GstMpegTSPMTStream +GstMpegTsPMT +GstMpegTsPMTStream gst_mpegts_section_get_pmt -GstMpegTSBAT -GstMpegTSBATStream +GstMpegTsBAT +GstMpegTsBATStream gst_mpegts_section_get_cat -GstMpegTSEIT -GstMpegTSEITEvent -GstMpegTSRunningStatus +GstMpegTsEIT +GstMpegTsEITEvent +GstMpegTsRunningStatus gst_mpegts_section_get_eit -GstMpegTSNIT -GstMpegTSNITStream +GstMpegTsNIT +GstMpegTsNITStream gst_mpegts_section_get_nit -GstMpegTSSDT -GstMpegTSSDTService +GstMpegTsSDT +GstMpegTsSDTService gst_mpegts_section_get_sdt -GstMpegTSTOT +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_TYPE_MPEG_TS_SECTION_ATSC_TABLE_ID +GST_TYPE_MPEG_TS_SECTION_DVB_TABLE_ID GST_MPEGTS_SECTION GST_TYPE_MPEGTS_BAT GST_TYPE_MPEGTS_EIT @@ -286,6 +302,8 @@ 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_atsc_table_id_get_type +gst_mpeg_ts_section_dvb_table_id_get_type gst_mpeg_ts_section_type_get_type gst_mpegts_bat_get_type gst_mpegts_eit_event_get_type diff --git a/gst-libs/gst/mpegts/Makefile.am b/gst-libs/gst/mpegts/Makefile.am index d84402aae6..e3832f3d1c 100644 --- a/gst-libs/gst/mpegts/Makefile.am +++ b/gst-libs/gst/mpegts/Makefile.am @@ -2,7 +2,8 @@ lib_LTLIBRARIES = libgstmpegts-@GST_API_VERSION@.la libgstmpegts_@GST_API_VERSION@_la_SOURCES = \ gstmpegtssection.c \ - gstmpegtsdescriptor.c + gstmpegtsdescriptor.c \ + gst-dvb-section.c libgstmpegts_@GST_API_VERSION@includedir = \ $(includedir)/gstreamer-@GST_API_VERSION@/gst/mpegts @@ -10,8 +11,11 @@ libgstmpegts_@GST_API_VERSION@includedir = \ noinst_HEADERS = gstmpegts-private.h libgstmpegts_@GST_API_VERSION@include_HEADERS = \ - gstmpegtssection.h \ - gstmpegtsdescriptor.h mpegts.h + gstmpegtssection.h \ + gst-atsc-section.h \ + gst-dvb-section.h \ + gstmpegtsdescriptor.h \ + mpegts.h libgstmpegts_@GST_API_VERSION@_la_CFLAGS = \ @@ -28,7 +32,10 @@ libgstmpegts_@GST_API_VERSION@_la_LDFLAGS = \ $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) -glib_enum_headers=gstmpegtssection.h gstmpegtsdescriptor.h +glib_enum_headers=gstmpegtssection.h \ + gstmpegtsdescriptor.h \ + gst-atsc-section.h \ + gst-dvb-section.h glib_enum_define=GST_MPEGTS glib_gen_prefix=gst_mpegts glib_gen_basename=gstmpegts diff --git a/gst-libs/gst/mpegts/gst-atsc-section.h b/gst-libs/gst/mpegts/gst-atsc-section.h new file mode 100644 index 0000000000..5d4d1786b9 --- /dev/null +++ b/gst-libs/gst/mpegts/gst-atsc-section.h @@ -0,0 +1,67 @@ +/* + * 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_ATSC_SECTION_H +#define GST_ATSC_SECTION_H + +#include +#include +#include + +/** + * GstMpegTsSectionATSCTableID: + * + * Values for a #GstMpegTsSection table_id. + * + * These are the registered ATSC table_id variants. + * + * see also: #GstMpegTsSectionTableID + */ +typedef enum { + + + /* 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, +} GstMpegTsSectionATSCTableID; + +#endif /* GST_MPEGTS_SECTION_H */ diff --git a/gst-libs/gst/mpegts/gst-dvb-section.c b/gst-libs/gst/mpegts/gst-dvb-section.c new file mode 100644 index 0000000000..7626caf253 --- /dev/null +++ b/gst-libs/gst/mpegts/gst-dvb-section.c @@ -0,0 +1,785 @@ +/* + * 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" + +/* + * TODO + * + * * Check minimum size for section parsing in the various + * gst_mpegts_section_get_() methods + * + * * Implement parsing code for + * * BAT + * * CAT + * * TSDT + */ + +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); +} + +/* Event Information Table */ +static GstMpegTsEITEvent * +_gst_mpegts_eit_event_copy (GstMpegTsEITEvent * eit) +{ + /* FIXME : IMPLEMENT */ + return NULL; +} + +static void +_gst_mpegts_eit_event_free (GstMpegTsEITEvent * eit) +{ + gst_date_time_unref (eit->start_time); + g_array_unref (eit->descriptors); + g_slice_free (GstMpegTsEITEvent, eit); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsEITEvent, gst_mpegts_eit_event, + (GBoxedCopyFunc) _gst_mpegts_eit_event_copy, + (GFreeFunc) _gst_mpegts_eit_event_free); + +static GstMpegTsEIT * +_gst_mpegts_eit_copy (GstMpegTsEIT * eit) +{ + /* FIXME : IMPLEMENT */ + return NULL; +} + +static void +_gst_mpegts_eit_free (GstMpegTsEIT * eit) +{ + g_ptr_array_unref (eit->events); + g_slice_free (GstMpegTsEIT, eit); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsEIT, gst_mpegts_eit, + (GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_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); + section->destroy_parsed = (GDestroyNotify) _gst_mpegts_eit_free; + 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 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 * +_gst_mpegts_nit_copy (GstMpegTsNIT * nit) +{ + /* FIXME : IMPLEMENT */ + return NULL; +} + +static void +_gst_mpegts_nit_free (GstMpegTsNIT * nit) +{ + g_array_unref (nit->descriptors); + g_ptr_array_unref (nit->streams); + g_slice_free (GstMpegTsNIT, nit); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsNIT, gst_mpegts_nit, + (GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_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); + section->destroy_parsed = (GDestroyNotify) _gst_mpegts_nit_free; + 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 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 * +_gst_mpegts_sdt_copy (GstMpegTsSDT * sdt) +{ + /* FIXME : IMPLEMENT */ + return NULL; +} + +static void +_gst_mpegts_sdt_free (GstMpegTsSDT * sdt) +{ + g_ptr_array_unref (sdt->services); + g_slice_free (GstMpegTsSDT, sdt); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsSDT, gst_mpegts_sdt, + (GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_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); + section->destroy_parsed = (GDestroyNotify) _gst_mpegts_sdt_free; + 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); + section->destroy_parsed = (GDestroyNotify) gst_date_time_unref; + 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) +{ + gst_date_time_unref (tot->utc_time); + g_array_unref (tot->descriptors); + g_slice_free (GstMpegTsTOT, tot); +} + +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); + section->destroy_parsed = (GDestroyNotify) _gst_mpegts_tot_free; + 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; + } +} diff --git a/gst-libs/gst/mpegts/gst-dvb-section.h b/gst-libs/gst/mpegts/gst-dvb-section.h new file mode 100644 index 0000000000..465d614ca2 --- /dev/null +++ b/gst-libs/gst/mpegts/gst-dvb-section.h @@ -0,0 +1,307 @@ +/* + * 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_DVB_SECTION_H +#define GST_DVB_SECTION_H + +#include +#include +#include + +/** + * GstMpegTsSectionDVBTableID: + * + * Values for a #GstMpegTsSection table_id. + * + * These are the registered DVB table_id variants. + * + * see also: #GstMpegTsSectionTableID + */ +typedef enum { + /* 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 + +} GstMpegTsSectionDVBTableID; + +/** + * 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; + + + +/* 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); + +#endif /* GST_MPEGTS_SECTION_H */ diff --git a/gst-libs/gst/mpegts/gstmpegts-private.h b/gst-libs/gst/mpegts/gstmpegts-private.h index a2496cdbb0..03d6de335e 100644 --- a/gst-libs/gst/mpegts/gstmpegts-private.h +++ b/gst-libs/gst/mpegts/gstmpegts-private.h @@ -27,6 +27,7 @@ GST_DEBUG_CATEGORY_EXTERN (gst_mpegts_debug); #define GST_CAT_DEFAULT gst_mpegts_debug -void __initialize_descriptors (void); +G_GNUC_INTERNAL void __initialize_descriptors (void); +G_GNUC_INTERNAL guint32 _calc_crc32 (const guint8 *data, guint datalen); #endif /* _GST_MPEGTS_PRIVATE_H_ */ diff --git a/gst-libs/gst/mpegts/gstmpegtsdescriptor.c b/gst-libs/gst/mpegts/gstmpegtsdescriptor.c index 58a80954ad..956b44d147 100644 --- a/gst-libs/gst/mpegts/gstmpegtsdescriptor.c +++ b/gst-libs/gst/mpegts/gstmpegtsdescriptor.c @@ -810,10 +810,10 @@ gst_mpegts_descriptor_parse_dvb_service (const GstMpegTsDescriptor * if (service_type) *service_type = *data; data += 1; - if (*provider_name) + if (provider_name) *provider_name = get_encoding_and_convert ((const gchar *) data + 1, *data); data += *data + 1; - if (*service_name) + if (service_name) *service_name = get_encoding_and_convert ((const gchar *) data + 1, *data); return TRUE; @@ -843,15 +843,15 @@ gst_mpegts_descriptor_parse_dvb_short_event (const GstMpegTsDescriptor * data = (guint8 *) descriptor->descriptor_data + 2; - if (*language_code) { + if (language_code) { *language_code = g_malloc0 (4); memcpy (*language_code, data, 3); } data += 3; - if (*event_name) + if (event_name) *event_name = get_encoding_and_convert ((const gchar *) data + 1, *data); data += *data + 1; - if (*text) + if (text) *text = get_encoding_and_convert ((const gchar *) data + 1, *data); return TRUE; } diff --git a/gst-libs/gst/mpegts/gstmpegtssection.c b/gst-libs/gst/mpegts/gstmpegtssection.c index fa52b19d27..339444b056 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.c +++ b/gst-libs/gst/mpegts/gstmpegtssection.c @@ -119,7 +119,7 @@ static const guint32 crc_tab[256] = { }; /* _calc_crc32 relicenced to LGPL from fluendo ts demuxer */ -static guint32 +guint32 _calc_crc32 (const guint8 * data, guint datalen) { gint i; @@ -132,40 +132,6 @@ _calc_crc32 (const guint8 * data, guint datalen) } -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 @@ -175,58 +141,12 @@ _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; + if (section->cached_parsed && section->destroy_parsed) + section->destroy_parsed (section->cached_parsed); - g_ptr_array_unref (sdt->services); - break; - } - default: - break; - } - } if (section->data) g_free (section->data); + g_slice_free (GstMpegTsSection, section); } @@ -417,6 +337,7 @@ gst_mpegts_section_get_pat (GstMpegTsSection * section) goto bad_crc; section->cached_parsed = (gpointer) _parse_pat (section); + section->destroy_parsed = (GDestroyNotify) g_array_unref; if (section->cached_parsed == NULL) goto parse_failure; } @@ -467,7 +388,9 @@ _gst_mpegts_pmt_copy (GstMpegTsPMT * pmt) static void _gst_mpegts_pmt_free (GstMpegTsPMT * pmt) { - /* FIXME: IMPLEMENT */ + g_array_unref (pmt->descriptors); + g_ptr_array_unref (pmt->streams); + g_slice_free (GstMpegTsPMT, pmt); } G_DEFINE_BOXED_TYPE (GstMpegTsPMT, gst_mpegts_pmt, @@ -584,6 +507,7 @@ gst_mpegts_section_get_pmt (GstMpegTsSection * section) goto bad_crc; section->cached_parsed = (gpointer) _parse_pmt (section); + section->destroy_parsed = (GDestroyNotify) _gst_mpegts_pmt_free; if (section->cached_parsed == NULL) goto parse_failure; } @@ -638,6 +562,7 @@ gst_mpegts_section_get_cat (GstMpegTsSection * section) if (!section->cached_parsed) { section->cached_parsed = (gpointer) _parse_cat (section); + section->destroy_parsed = (GDestroyNotify) g_array_unref; if (section->cached_parsed == NULL) goto parse_failure; } @@ -676,694 +601,6 @@ gst_mpegts_section_get_tsdt (GstMpegTsSection * section) } -/* 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: * @@ -1396,8 +633,10 @@ gst_mpegts_initialize (void) __initialize_descriptors (); } +/* FIXME : Later on we might need to use more than just the table_id + * to figure out which type of section this is. */ static GstMpegTsSectionType -_identify_section (GstMpegTsSectionTableID table_id) +_identify_section (guint8 table_id) { switch (table_id) { case GST_MTS_TABLE_ID_PROGRAM_ASSOCIATION: diff --git a/gst-libs/gst/mpegts/gstmpegtssection.h b/gst-libs/gst/mpegts/gstmpegtssection.h index cea3962b51..875ad7df08 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.h +++ b/gst-libs/gst/mpegts/gstmpegtssection.h @@ -49,7 +49,6 @@ GType gst_mpegts_section_get_type (void); * @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. */ @@ -64,24 +63,17 @@ typedef enum { GST_MPEGTS_SECTION_BAT, GST_MPEGTS_SECTION_SDT, GST_MPEGTS_SECTION_TDT, - GST_MPEGTS_SECTION_TOT, - GST_MPEGTS_SECTION_LAST + GST_MPEGTS_SECTION_TOT } 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 + * + * These are the registered ITU H.222.0 | ISO/IEC 13818-1 table_id variants. + * + * see also #GstMpegTsSectionATSCTableID and #GstMpegTsSectionDVBTableID. */ typedef enum { /* ITU H.222.0 / IEC 13818-1 */ @@ -93,7 +85,9 @@ typedef enum { GST_MTS_TABLE_ID_14496_OBJET_DESCRIPTOR = 0x05, GST_MTS_TABLE_ID_METADATA = 0x06, GST_MTS_TABLE_ID_IPMP_CONTROL_INFORMATION = 0x07, - + + /* 0x08 - 0x39 : ITU H.222.0 | ISO/IEC 13818-1 reserved */ + /* 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, @@ -102,89 +96,6 @@ typedef enum { 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 @@ -214,7 +125,7 @@ struct _GstMpegTsSection GstMpegTsSectionType section_type; guint16 pid; - GstMpegTsSectionTableID table_id; + guint8 table_id; guint16 subtable_extension; guint8 version_number; @@ -234,6 +145,8 @@ struct _GstMpegTsSection guint section_length; /* cached_parsed: cached copy of parsed section */ gpointer *cached_parsed; + /* destroy_parsed: function to clear cached_parsed */ + GDestroyNotify destroy_parsed; /* offset: offset of the section within the container stream */ guint64 offset; /* short_section: TRUE if section_syntax_indicator == 0 @@ -242,23 +155,6 @@ struct _GstMpegTsSection 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; @@ -332,192 +228,6 @@ const GstMpegTsPMT *gst_mpegts_section_get_pmt (GstMpegTsSection *section); 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 */ diff --git a/gst-libs/gst/mpegts/mpegts.h b/gst-libs/gst/mpegts/mpegts.h index 5b3e42ac1d..63cfe0a73b 100644 --- a/gst-libs/gst/mpegts/mpegts.h +++ b/gst-libs/gst/mpegts/mpegts.h @@ -26,6 +26,8 @@ #include #include +#include +#include #include void gst_mpegts_initialize (void);