diff options
Diffstat (limited to 'gst-libs/gst/mpegts/gst-atsc-section.c')
-rw-r--r-- | gst-libs/gst/mpegts/gst-atsc-section.c | 821 |
1 files changed, 770 insertions, 51 deletions
diff --git a/gst-libs/gst/mpegts/gst-atsc-section.c b/gst-libs/gst/mpegts/gst-atsc-section.c index a56be15d..87565470 100644 --- a/gst-libs/gst/mpegts/gst-atsc-section.c +++ b/gst-libs/gst/mpegts/gst-atsc-section.c @@ -34,101 +34,108 @@ * */ -/* Terrestrial Virtual Channel Table TVCT */ -static GstMpegTsAtscTVCTSource * -_gst_mpegts_atsc_tvct_source_copy (GstMpegTsAtscTVCTSource * source) +/* Terrestrial/Cable Virtual Channel Table TVCT/CVCT */ +static GstMpegTsAtscVCTSource * +_gst_mpegts_atsc_vct_source_copy (GstMpegTsAtscVCTSource * source) { - GstMpegTsAtscTVCTSource *copy; + GstMpegTsAtscVCTSource *copy; - copy = g_slice_dup (GstMpegTsAtscTVCTSource, source); + copy = g_slice_dup (GstMpegTsAtscVCTSource, source); copy->descriptors = g_ptr_array_ref (source->descriptors); return copy; } static void -_gst_mpegts_atsc_tvct_source_free (GstMpegTsAtscTVCTSource * source) +_gst_mpegts_atsc_vct_source_free (GstMpegTsAtscVCTSource * source) { if (source->descriptors) g_ptr_array_unref (source->descriptors); - g_slice_free (GstMpegTsAtscTVCTSource, source); + g_slice_free (GstMpegTsAtscVCTSource, source); } -G_DEFINE_BOXED_TYPE (GstMpegTsAtscTVCTSource, gst_mpegts_atsc_tvct_source, - (GBoxedCopyFunc) _gst_mpegts_atsc_tvct_source_copy, - (GFreeFunc) _gst_mpegts_atsc_tvct_source_free); +G_DEFINE_BOXED_TYPE (GstMpegTsAtscVCTSource, gst_mpegts_atsc_vct_source, + (GBoxedCopyFunc) _gst_mpegts_atsc_vct_source_copy, + (GFreeFunc) _gst_mpegts_atsc_vct_source_free); -static GstMpegTsAtscTVCT * -_gst_mpegts_atsc_tvct_copy (GstMpegTsAtscTVCT * tvct) +static GstMpegTsAtscVCT * +_gst_mpegts_atsc_vct_copy (GstMpegTsAtscVCT * vct) { - GstMpegTsAtscTVCT *copy; + GstMpegTsAtscVCT *copy; - copy = g_slice_dup (GstMpegTsAtscTVCT, tvct); - copy->sources = g_ptr_array_ref (tvct->sources); - copy->descriptors = g_ptr_array_ref (tvct->descriptors); + copy = g_slice_dup (GstMpegTsAtscVCT, vct); + copy->sources = g_ptr_array_ref (vct->sources); + copy->descriptors = g_ptr_array_ref (vct->descriptors); return copy; } static void -_gst_mpegts_atsc_tvct_free (GstMpegTsAtscTVCT * tvct) +_gst_mpegts_atsc_vct_free (GstMpegTsAtscVCT * vct) { - g_ptr_array_unref (tvct->sources); - if (tvct->descriptors) - g_ptr_array_unref (tvct->descriptors); - g_slice_free (GstMpegTsAtscTVCT, tvct); + if (vct->sources) + g_ptr_array_unref (vct->sources); + if (vct->descriptors) + g_ptr_array_unref (vct->descriptors); + g_slice_free (GstMpegTsAtscVCT, vct); } -G_DEFINE_BOXED_TYPE (GstMpegTsAtscTVCT, gst_mpegts_atsc_tvct, - (GBoxedCopyFunc) _gst_mpegts_atsc_tvct_copy, - (GFreeFunc) _gst_mpegts_atsc_tvct_free); +G_DEFINE_BOXED_TYPE (GstMpegTsAtscVCT, gst_mpegts_atsc_vct, + (GBoxedCopyFunc) _gst_mpegts_atsc_vct_copy, + (GFreeFunc) _gst_mpegts_atsc_vct_free); static gpointer -_parse_atsc_tvct (GstMpegTsSection * section) +_parse_atsc_vct (GstMpegTsSection * section) { - GstMpegTsAtscTVCT *tvct = NULL; + GstMpegTsAtscVCT *vct = NULL; guint8 *data, *end, source_nb; guint32 tmp32; guint16 descriptors_loop_length, tmp16; guint i; + GError *err = NULL; - tvct = g_slice_new0 (GstMpegTsAtscTVCT); + vct = g_slice_new0 (GstMpegTsAtscVCT); data = section->data; end = data + section->section_length; - tvct->transport_stream_id = section->subtable_extension; + vct->transport_stream_id = section->subtable_extension; /* Skip already parsed data */ data += 8; /* minimum size */ - if (data - end < 2 + 2 + 4) + if (end - data < 2 + 2 + 4) goto error; - tvct->protocol_version = *data; + vct->protocol_version = *data; data += 1; source_nb = *data; data += 1; - tvct->sources = g_ptr_array_new_full (source_nb, - (GDestroyNotify) _gst_mpegts_atsc_tvct_source_free); + vct->sources = g_ptr_array_new_full (source_nb, + (GDestroyNotify) _gst_mpegts_atsc_vct_source_free); for (i = 0; i < source_nb; i++) { - GstMpegTsAtscTVCTSource *source; + GstMpegTsAtscVCTSource *source; /* minimum 32 bytes for a entry, 2 bytes second descriptor loop-length, 4 bytes crc */ if (end - data < 32 + 2 + 4) goto error; - source = g_slice_new0 (GstMpegTsAtscTVCTSource); - g_ptr_array_add (tvct->sources, source); - - /* FIXME: 7 utf16 charater - GST_READ_UINT16_BE x 7 or extern method ? */ - source->short_name = g_memdup (data, 14); + source = g_slice_new0 (GstMpegTsAtscVCTSource); + g_ptr_array_add (vct->sources, source); + + source->short_name = + g_convert ((gchar *) data, 14, "utf-8", "utf-16be", NULL, NULL, &err); + if (err) { + GST_WARNING ("Failed to convert VCT Source short_name to utf-8: %d %s", + err->code, err->message); + GST_MEMDUMP ("UTF-16 string", data, 14); + g_error_free (err); + } data += 14; tmp32 = GST_READ_UINT32_BE (data); @@ -150,7 +157,12 @@ _parse_atsc_tvct (GstMpegTsSection * section) source->ETM_location = (tmp16 >> 14) & 0x3; source->access_controlled = (tmp16 >> 13) & 0x1; source->hidden = (tmp16 >> 12) & 0x1; - source->hide_guide = (tmp16 >> 10) & 0x1; + + /* only used in CVCT */ + source->path_select = (tmp16 >> 11) & 0x1; + source->out_of_band = (tmp16 >> 10) & 0x1; + + source->hide_guide = (tmp16 >> 9) & 0x1; source->service_type = tmp16 & 0x3f; data += 2; @@ -176,17 +188,16 @@ _parse_atsc_tvct (GstMpegTsSection * section) if (end - data < descriptors_loop_length + 4) goto error; - tvct->descriptors = + vct->descriptors = gst_mpegts_parse_descriptors (data, descriptors_loop_length); - if (tvct->descriptors == NULL) + if (vct->descriptors == NULL) goto error; data += descriptors_loop_length; - return (gpointer) tvct; + return (gpointer) vct; error: - if (tvct) - _gst_mpegts_atsc_tvct_free (tvct); + _gst_mpegts_atsc_vct_free (vct); return NULL; } @@ -195,12 +206,12 @@ error: * gst_mpegts_section_get_atsc_tvct: * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_TVCT * - * Returns the #GstMpegTsAtscTVCT contained in the @section + * Returns the #GstMpegTsAtscVCT contained in the @section * - * Returns: The #GstMpegTsAtscTVCT contained in the section, or %NULL if an error + * Returns: The #GstMpegTsAtscVCT contained in the section, or %NULL if an error * happened. */ -const GstMpegTsAtscTVCT * +const GstMpegTsAtscVCT * gst_mpegts_section_get_atsc_tvct (GstMpegTsSection * section) { g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_TVCT, @@ -209,8 +220,716 @@ gst_mpegts_section_get_atsc_tvct (GstMpegTsSection * section) if (!section->cached_parsed) section->cached_parsed = - __common_section_checks (section, 16, _parse_atsc_tvct, - (GDestroyNotify) _gst_mpegts_atsc_tvct_free); + __common_section_checks (section, 16, _parse_atsc_vct, + (GDestroyNotify) _gst_mpegts_atsc_vct_free); + + return (const GstMpegTsAtscVCT *) section->cached_parsed; +} + +/** + * gst_mpegts_section_get_atsc_cvct: + * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_CVCT + * + * Returns the #GstMpegTsAtscVCT contained in the @section + * + * Returns: The #GstMpegTsAtscVCT contained in the section, or %NULL if an error + * happened. + */ +const GstMpegTsAtscVCT * +gst_mpegts_section_get_atsc_cvct (GstMpegTsSection * section) +{ + g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_CVCT, + NULL); + g_return_val_if_fail (section->cached_parsed || section->data, NULL); + + if (!section->cached_parsed) + section->cached_parsed = + __common_section_checks (section, 16, _parse_atsc_vct, + (GDestroyNotify) _gst_mpegts_atsc_vct_free); + + return (const GstMpegTsAtscVCT *) section->cached_parsed; +} + +/* MGT */ + +static GstMpegTsAtscMGTTable * +_gst_mpegts_atsc_mgt_table_copy (GstMpegTsAtscMGTTable * mgt_table) +{ + GstMpegTsAtscMGTTable *copy; + + copy = g_slice_dup (GstMpegTsAtscMGTTable, mgt_table); + copy->descriptors = g_ptr_array_ref (mgt_table->descriptors); + + return copy; +} + +static void +_gst_mpegts_atsc_mgt_table_free (GstMpegTsAtscMGTTable * mgt_table) +{ + g_ptr_array_unref (mgt_table->descriptors); + g_slice_free (GstMpegTsAtscMGTTable, mgt_table); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscMGTTable, gst_mpegts_atsc_mgt_table, + (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_table_copy, + (GFreeFunc) _gst_mpegts_atsc_mgt_table_free); + +static GstMpegTsAtscMGT * +_gst_mpegts_atsc_mgt_copy (GstMpegTsAtscMGT * mgt) +{ + GstMpegTsAtscMGT *copy; + + copy = g_slice_dup (GstMpegTsAtscMGT, mgt); + copy->tables = g_ptr_array_ref (mgt->tables); + copy->descriptors = g_ptr_array_ref (mgt->descriptors); + + return copy; +} + +static void +_gst_mpegts_atsc_mgt_free (GstMpegTsAtscMGT * mgt) +{ + g_ptr_array_unref (mgt->tables); + g_ptr_array_unref (mgt->descriptors); + g_slice_free (GstMpegTsAtscMGT, mgt); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscMGT, gst_mpegts_atsc_mgt, + (GBoxedCopyFunc) _gst_mpegts_atsc_mgt_copy, + (GFreeFunc) _gst_mpegts_atsc_mgt_free); + +static gpointer +_parse_atsc_mgt (GstMpegTsSection * section) +{ + GstMpegTsAtscMGT *mgt = NULL; + guint i = 0; + guint8 *data, *end; + guint16 descriptors_loop_length; + + mgt = g_slice_new0 (GstMpegTsAtscMGT); + + data = section->data; + end = data + section->section_length; + + /* Skip already parsed data */ + data += 8; + + mgt->protocol_version = GST_READ_UINT8 (data); + data += 1; + mgt->tables_defined = GST_READ_UINT16_BE (data); + data += 2; + mgt->tables = g_ptr_array_new_full (mgt->tables_defined, + (GDestroyNotify) _gst_mpegts_atsc_mgt_table_free); + for (i = 0; i < mgt->tables_defined && data + 11 < end; i++) { + GstMpegTsAtscMGTTable *mgt_table; + + if (data + 11 >= end) { + GST_WARNING ("MGT data too short to parse inner table num %d", i); + goto error; + } + + mgt_table = g_slice_new0 (GstMpegTsAtscMGTTable); + g_ptr_array_add (mgt->tables, mgt_table); + + mgt_table->table_type = GST_READ_UINT16_BE (data); + data += 2; + mgt_table->pid = GST_READ_UINT16_BE (data) & 0x1FFF; + data += 2; + mgt_table->version_number = GST_READ_UINT8 (data) & 0x1F; + data += 1; + mgt_table->number_bytes = GST_READ_UINT32_BE (data); + data += 4; + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + descriptors_loop_length >= end) { + GST_WARNING ("MGT data too short to parse inner table descriptors (table " + "num %d", i); + goto error; + } + mgt_table->descriptors = + gst_mpegts_parse_descriptors (data, descriptors_loop_length); + data += descriptors_loop_length; + } + + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0xFFF; + data += 2; + if (data + descriptors_loop_length >= end) { + GST_WARNING ("MGT data too short to parse descriptors"); + goto error; + } + mgt->descriptors = + gst_mpegts_parse_descriptors (data, descriptors_loop_length); + data += descriptors_loop_length; + + return (gpointer) mgt; + +error: + _gst_mpegts_atsc_mgt_free (mgt); + + return NULL; +} + + +/** + * gst_mpegts_section_get_atsc_mgt: + * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_MGT + * + * Returns the #GstMpegTsAtscMGT contained in the @section. + * + * Returns: The #GstMpegTsAtscMGT contained in the section, or %NULL if an error + * happened. + */ +const GstMpegTsAtscMGT * +gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section) +{ + g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_MGT, + NULL); + g_return_val_if_fail (section->cached_parsed || section->data, NULL); + + if (!section->cached_parsed) + section->cached_parsed = + __common_section_checks (section, 17, _parse_atsc_mgt, + (GDestroyNotify) _gst_mpegts_atsc_mgt_free); + + return (const GstMpegTsAtscMGT *) section->cached_parsed; +} + +/* Multi string structure */ + +static GstMpegTsAtscStringSegment * +_gst_mpegts_atsc_string_segment_copy (GstMpegTsAtscStringSegment * seg) +{ + GstMpegTsAtscStringSegment *copy; + + copy = g_slice_dup (GstMpegTsAtscStringSegment, seg); + + return copy; +} + +static void +_gst_mpegts_atsc_string_segment_free (GstMpegTsAtscStringSegment * seg) +{ + if (seg->cached_string) + g_free (seg->cached_string); + g_slice_free (GstMpegTsAtscStringSegment, seg); +} + +static void +_gst_mpegts_atsc_string_segment_decode_string (GstMpegTsAtscStringSegment * seg) +{ + const gchar *from_encoding; + + g_return_if_fail (seg->cached_string == NULL); + + if (seg->compression_type != 0) { + GST_FIXME ("Compressed strings not yet supported"); + return; + } + + /* FIXME add more encodings */ + switch (seg->mode) { + case 0x3F: + from_encoding = "UTF-16BE"; + break; + default: + from_encoding = NULL; + break; + } + + if (from_encoding != NULL) { + GError *err = NULL; + + seg->cached_string = + g_convert ((gchar *) seg->compressed_data, + (gssize) seg->compressed_data_size, "UTF-8", from_encoding, NULL, NULL, + &err); + + if (err) { + GST_WARNING ("Failed to convert input string from codeset %s", + from_encoding); + g_error_free (err); + } + } else { + seg->cached_string = + g_strndup ((gchar *) seg->compressed_data, seg->compressed_data_size); + } +} + +const gchar * +gst_mpegts_atsc_string_segment_get_string (GstMpegTsAtscStringSegment * seg) +{ + if (!seg->cached_string) + _gst_mpegts_atsc_string_segment_decode_string (seg); + + return seg->cached_string; +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscStringSegment, gst_mpegts_atsc_string_segment, + (GBoxedCopyFunc) _gst_mpegts_atsc_string_segment_copy, + (GFreeFunc) _gst_mpegts_atsc_string_segment_free); + +static GstMpegTsAtscMultString * +_gst_mpegts_atsc_mult_string_copy (GstMpegTsAtscMultString * mstring) +{ + GstMpegTsAtscMultString *copy; + + copy = g_slice_dup (GstMpegTsAtscMultString, mstring); + copy->segments = g_ptr_array_ref (mstring->segments); + + return copy; +} + +static void +_gst_mpegts_atsc_mult_string_free (GstMpegTsAtscMultString * mstring) +{ + g_ptr_array_unref (mstring->segments); + g_slice_free (GstMpegTsAtscMultString, mstring); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscMultString, gst_mpegts_atsc_mult_string, + (GBoxedCopyFunc) _gst_mpegts_atsc_mult_string_copy, + (GFreeFunc) _gst_mpegts_atsc_mult_string_free); + +static GPtrArray * +_parse_atsc_mult_string (guint8 * data, guint datasize) +{ + guint8 num_strings; + GPtrArray *res = NULL; + guint8 *end = data + datasize; + gint i; + + if (datasize > 0) { + /* 1 is the minimum entry size, so no need to check here */ + num_strings = GST_READ_UINT8 (data); + data += 1; + + res = + g_ptr_array_new_full (num_strings, + (GDestroyNotify) _gst_mpegts_atsc_mult_string_free); + + for (i = 0; i < num_strings; i++) { + GstMpegTsAtscMultString *mstring; + guint8 num_segments; + gint j; + + mstring = g_slice_new0 (GstMpegTsAtscMultString); + g_ptr_array_add (res, mstring); + mstring->segments = + g_ptr_array_new_full (num_strings, + (GDestroyNotify) _gst_mpegts_atsc_string_segment_free); + + /* each entry needs at least 4 bytes (lang code and segments number) */ + if (end - data < 4) { + GST_WARNING ("Data too short for multstring parsing %d", + (gint) (end - data)); + goto error; + } + + mstring->iso_639_langcode[0] = GST_READ_UINT8 (data); + data += 1; + mstring->iso_639_langcode[1] = GST_READ_UINT8 (data); + data += 1; + mstring->iso_639_langcode[2] = GST_READ_UINT8 (data); + data += 1; + num_segments = GST_READ_UINT8 (data); + data += 1; + + for (j = 0; j < num_segments; j++) { + GstMpegTsAtscStringSegment *seg; + + seg = g_slice_new0 (GstMpegTsAtscStringSegment); + g_ptr_array_add (mstring->segments, seg); + + /* each entry needs at least 3 bytes */ + if (end - data < 3) { + GST_WARNING ("Data too short for multstring parsing %d", datasize); + goto error; + } + + seg->compression_type = GST_READ_UINT8 (data); + data += 1; + seg->mode = GST_READ_UINT8 (data); + data += 1; + seg->compressed_data_size = GST_READ_UINT8 (data); + data += 1; + + if (end - data < seg->compressed_data_size) { + GST_WARNING ("Data too short for multstring parsing %d", datasize); + goto error; + } + + if (seg->compressed_data_size) + seg->compressed_data = data; + data += seg->compressed_data_size; + } + + } + } + return res; + +error: + if (res) + g_ptr_array_unref (res); + return NULL; +} + +/* EIT */ + +static GstMpegTsAtscEITEvent * +_gst_mpegts_atsc_eit_event_copy (GstMpegTsAtscEITEvent * event) +{ + GstMpegTsAtscEITEvent *copy; + + copy = g_slice_dup (GstMpegTsAtscEITEvent, event); + copy->titles = g_ptr_array_ref (event->titles); + copy->descriptors = g_ptr_array_ref (event->descriptors); + + return copy; +} + +static void +_gst_mpegts_atsc_eit_event_free (GstMpegTsAtscEITEvent * event) +{ + if (event->titles) + g_ptr_array_unref (event->titles); + if (event->descriptors) + g_ptr_array_unref (event->descriptors); + g_slice_free (GstMpegTsAtscEITEvent, event); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscEITEvent, gst_mpegts_atsc_eit_event, + (GBoxedCopyFunc) _gst_mpegts_atsc_eit_event_copy, + (GFreeFunc) _gst_mpegts_atsc_eit_event_free); + +static GstMpegTsAtscEIT * +_gst_mpegts_atsc_eit_copy (GstMpegTsAtscEIT * eit) +{ + GstMpegTsAtscEIT *copy; + + copy = g_slice_dup (GstMpegTsAtscEIT, eit); + copy->events = g_ptr_array_ref (eit->events); + + return copy; +} + +static void +_gst_mpegts_atsc_eit_free (GstMpegTsAtscEIT * eit) +{ + if (eit->events) + g_ptr_array_unref (eit->events); + g_slice_free (GstMpegTsAtscEIT, eit); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscEIT, gst_mpegts_atsc_eit, + (GBoxedCopyFunc) _gst_mpegts_atsc_eit_copy, + (GFreeFunc) _gst_mpegts_atsc_eit_free); + +static gpointer +_parse_atsc_eit (GstMpegTsSection * section) +{ + GstMpegTsAtscEIT *eit = NULL; + guint i = 0; + guint8 *data, *end; + guint8 num_events; + + eit = g_slice_new0 (GstMpegTsAtscEIT); + + data = section->data; + end = data + section->section_length; + + eit->source_id = section->subtable_extension; + + /* Skip already parsed data */ + data += 8; + + eit->protocol_version = GST_READ_UINT8 (data); + data += 1; + num_events = GST_READ_UINT8 (data); + data += 1; + + eit->events = g_ptr_array_new_with_free_func ((GDestroyNotify) + _gst_mpegts_atsc_eit_event_free); + + for (i = 0; i < num_events; i++) { + GstMpegTsAtscEITEvent *event; + guint32 tmp; + guint8 text_length; + guint16 descriptors_loop_length; + + if (end - data < 12) { + GST_WARNING ("PID %d invalid EIT entry length %d with %u events", + section->pid, (gint) (end - 4 - data), num_events); + goto error; + } + + event = g_slice_new0 (GstMpegTsAtscEITEvent); + g_ptr_array_add (eit->events, event); + + event->event_id = GST_READ_UINT16_BE (data) & 0x3FFF; + data += 2; + event->start_time = GST_READ_UINT32_BE (data); + data += 4; + + tmp = GST_READ_UINT32_BE (data); + data += 4; + event->etm_location = (tmp >> 28) & 0x3; + event->length_in_seconds = (tmp >> 8) & 0x0FFFFF; + text_length = tmp & 0xFF; + + if (text_length > end - data - 4 - 2) { + GST_WARNING ("PID %d invalid EIT entry length %d with %u events", + section->pid, (gint) (end - 4 - data), num_events); + goto error; + } + event->titles = _parse_atsc_mult_string (data, text_length); + data += text_length; + + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (end - data - 4 < descriptors_loop_length) { + GST_WARNING ("PID %d invalid EIT entry length %d with %u events", + section->pid, (gint) (end - 4 - data), num_events); + goto error; + } + + event->descriptors = + gst_mpegts_parse_descriptors (data, descriptors_loop_length); + data += descriptors_loop_length; + } + + 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 (gpointer) eit; + +error: + _gst_mpegts_atsc_eit_free (eit); + + return NULL; + +} + +/** + * gst_mpegts_section_get_atsc_eit: + * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_EIT + * + * Returns the #GstMpegTsAtscEIT contained in the @section. + * + * Returns: The #GstMpegTsAtscEIT contained in the section, or %NULL if an error + * happened. + */ +const GstMpegTsAtscEIT * +gst_mpegts_section_get_atsc_eit (GstMpegTsSection * section) +{ + g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_EIT, + NULL); + g_return_val_if_fail (section->cached_parsed || section->data, NULL); + + if (!section->cached_parsed) + section->cached_parsed = + __common_section_checks (section, 14, _parse_atsc_eit, + (GDestroyNotify) _gst_mpegts_atsc_eit_free); + + return (const GstMpegTsAtscEIT *) section->cached_parsed; +} + + +static GstMpegTsAtscETT * +_gst_mpegts_atsc_ett_copy (GstMpegTsAtscETT * ett) +{ + GstMpegTsAtscETT *copy; + + copy = g_slice_dup (GstMpegTsAtscETT, ett); + copy->messages = g_ptr_array_ref (ett->messages); - return (const GstMpegTsAtscTVCT *) section->cached_parsed; + return copy; +} + +static void +_gst_mpegts_atsc_ett_free (GstMpegTsAtscETT * ett) +{ + if (ett->messages) + g_ptr_array_unref (ett->messages); + g_slice_free (GstMpegTsAtscETT, ett); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscETT, gst_mpegts_atsc_ett, + (GBoxedCopyFunc) _gst_mpegts_atsc_ett_copy, + (GFreeFunc) _gst_mpegts_atsc_ett_free); + +static gpointer +_parse_ett (GstMpegTsSection * section) +{ + GstMpegTsAtscETT *ett = NULL; + guint8 *data, *end; + + ett = g_slice_new0 (GstMpegTsAtscETT); + + data = section->data; + end = data + section->section_length; + + ett->ett_table_id_extension = section->subtable_extension; + + /* Skip already parsed data */ + data += 8; + + ett->protocol_version = GST_READ_UINT8 (data); + data += 1; + ett->etm_id = GST_READ_UINT32_BE (data); + data += 4; + + ett->messages = _parse_atsc_mult_string (data, end - data - 4); + data += end - data - 4; + + if (data != end - 4) { + GST_WARNING ("PID %d invalid ETT parsed %d length %d", + section->pid, (gint) (data - section->data), section->section_length); + goto error; + } + + return (gpointer) ett; + +error: + _gst_mpegts_atsc_ett_free (ett); + + return NULL; + +} + +/** + * gst_mpegts_section_get_atsc_ett: + * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_ETT + * + * Returns the #GstMpegTsAtscETT contained in the @section. + * + * Returns: The #GstMpegTsAtscETT contained in the section, or %NULL if an error + * happened. + */ +const GstMpegTsAtscETT * +gst_mpegts_section_get_atsc_ett (GstMpegTsSection * section) +{ + g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_ETT, + NULL); + g_return_val_if_fail (section->cached_parsed || section->data, NULL); + + if (!section->cached_parsed) + section->cached_parsed = __common_section_checks (section, 17, _parse_ett, + (GDestroyNotify) _gst_mpegts_atsc_ett_free); + + return (const GstMpegTsAtscETT *) section->cached_parsed; +} + +/* STT */ + +static GstMpegTsAtscSTT * +_gst_mpegts_atsc_stt_copy (GstMpegTsAtscSTT * stt) +{ + GstMpegTsAtscSTT *copy; + + copy = g_slice_dup (GstMpegTsAtscSTT, stt); + copy->descriptors = g_ptr_array_ref (stt->descriptors); + + return copy; +} + +static void +_gst_mpegts_atsc_stt_free (GstMpegTsAtscSTT * stt) +{ + if (stt->descriptors) + g_ptr_array_unref (stt->descriptors); + g_slice_free (GstMpegTsAtscSTT, stt); +} + +G_DEFINE_BOXED_TYPE (GstMpegTsAtscSTT, gst_mpegts_atsc_stt, + (GBoxedCopyFunc) _gst_mpegts_atsc_stt_copy, + (GFreeFunc) _gst_mpegts_atsc_stt_free); + +static gpointer +_parse_atsc_stt (GstMpegTsSection * section) +{ + GstMpegTsAtscSTT *stt = NULL; + guint8 *data, *end; + guint16 daylight_saving; + + stt = g_slice_new0 (GstMpegTsAtscSTT); + + data = section->data; + end = data + section->section_length; + + /* Skip already parsed data */ + data += 8; + + stt->protocol_version = GST_READ_UINT8 (data); + data += 1; + stt->system_time = GST_READ_UINT32_BE (data); + data += 4; + stt->gps_utc_offset = GST_READ_UINT8 (data); + data += 1; + + daylight_saving = GST_READ_UINT16_BE (data); + data += 2; + stt->ds_status = daylight_saving >> 15; + stt->ds_dayofmonth = (daylight_saving >> 8) & 0x1F; + stt->ds_hour = daylight_saving & 0xFF; + + stt->descriptors = gst_mpegts_parse_descriptors (data, end - data - 4); + if (stt->descriptors == NULL) + goto error; + + return (gpointer) stt; + +error: + _gst_mpegts_atsc_stt_free (stt); + + return NULL; +} + + +/** + * gst_mpegts_section_get_atsc_stt: + * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_STT + * + * Returns the #GstMpegTsAtscSTT contained in the @section. + * + * Returns: The #GstMpegTsAtscSTT contained in the section, or %NULL if an error + * happened. + */ +const GstMpegTsAtscSTT * +gst_mpegts_section_get_atsc_stt (GstMpegTsSection * section) +{ + g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_STT, + NULL); + g_return_val_if_fail (section->cached_parsed || section->data, NULL); + + if (!section->cached_parsed) + section->cached_parsed = + __common_section_checks (section, 20, _parse_atsc_stt, + (GDestroyNotify) _gst_mpegts_atsc_stt_free); + + return (const GstMpegTsAtscSTT *) section->cached_parsed; +} + +#define GPS_TO_UTC_TICKS G_GINT64_CONSTANT(315964800) +static GstDateTime * +_gst_mpegts_atsc_gps_time_to_datetime (guint32 systemtime, guint8 gps_offset) +{ + return gst_date_time_new_from_unix_epoch_utc (systemtime - gps_offset + + GPS_TO_UTC_TICKS); +} + +GstDateTime * +gst_mpegts_atsc_stt_get_datetime_utc (GstMpegTsAtscSTT * stt) +{ + if (stt->utc_datetime == NULL) + stt->utc_datetime = _gst_mpegts_atsc_gps_time_to_datetime (stt->system_time, + stt->gps_utc_offset); + + if (stt->utc_datetime) + return gst_date_time_ref (stt->utc_datetime); + return NULL; } |