diff --git a/gst-libs/gst/mpegts/gst-atsc-section.c b/gst-libs/gst/mpegts/gst-atsc-section.c index 9b5a55e05e..5d02dbdb7f 100644 --- a/gst-libs/gst/mpegts/gst-atsc-section.c +++ b/gst-libs/gst/mpegts/gst-atsc-section.c @@ -641,3 +641,114 @@ gst_mpegts_section_get_atsc_ett (GstMpegTsSection * section) 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: + if (stt) + _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; +} diff --git a/gst-libs/gst/mpegts/gst-atsc-section.h b/gst-libs/gst/mpegts/gst-atsc-section.h index 91fb265862..185479b8e8 100644 --- a/gst-libs/gst/mpegts/gst-atsc-section.h +++ b/gst-libs/gst/mpegts/gst-atsc-section.h @@ -216,6 +216,36 @@ GType gst_mpegts_atsc_ett_get_type (void); const GstMpegTsAtscETT *gst_mpegts_section_get_atsc_ett (GstMpegTsSection *section); +/* STT */ +#define GST_TYPE_MPEGTS_ATSC_STT (gst_mpegts_atsc_stt_get_type ()) + +typedef struct _GstMpegTsAtscSTT GstMpegTsAtscSTT; + +/** + * GstMpegTsAtscSTT: + * + * System Time Table (A65) + * + */ +struct _GstMpegTsAtscSTT +{ + guint8 protocol_version; + guint32 system_time; + guint8 gps_utc_offset; + gboolean ds_status; + guint8 ds_dayofmonth; + guint8 ds_hour; + GPtrArray *descriptors; + + GstDateTime *utc_datetime; +}; + +GType gst_mpegts_atsc_stt_get_type (void); + +const GstMpegTsAtscSTT * gst_mpegts_section_get_atsc_stt (GstMpegTsSection * section); +/* FIXME receive a non-const parameter but we only provide a const getter */ +GstDateTime * gst_mpegts_atsc_stt_get_datetime_utc (GstMpegTsAtscSTT * stt); + G_END_DECLS #endif /* GST_MPEGTS_SECTION_H */ diff --git a/gst-libs/gst/mpegts/gstmpegtssection.c b/gst-libs/gst/mpegts/gstmpegtssection.c index 97118f0e5d..71191b581c 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.c +++ b/gst-libs/gst/mpegts/gstmpegtssection.c @@ -1067,6 +1067,10 @@ _identify_section (guint16 pid, guint8 table_id) /* FIXME check pids reported on the MGT to confirm expectations */ return GST_MPEGTS_SECTION_ATSC_ETT; /* FIXME : FILL */ + case GST_MTS_TABLE_ID_ATSC_SYSTEM_TIME: + if (pid == 0x1ffb) + return GST_MPEGTS_SECTION_ATSC_STT; + break; default: /* Handle ranges */ if (table_id >= GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT && diff --git a/gst-libs/gst/mpegts/gstmpegtssection.h b/gst-libs/gst/mpegts/gstmpegtssection.h index 2ee8f39273..640b0cdbf3 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.h +++ b/gst-libs/gst/mpegts/gstmpegtssection.h @@ -55,6 +55,7 @@ GType gst_mpegts_section_get_type (void); * @GST_MPEGTS_SECTION_ATSC_CVCT: ATSC Cable Virtual Channel Table (A65) * @GST_MPEGTS_SECTION_ATSC_MGT: ATSC Master Guide Table (A65) * @GST_MPEGTS_SECTION_ATSC_ETT: ATSC Extended Text Table (A65) + * @GST_MPEGTS_SECTION_ATSC_STT: ATSC System Time Table (A65) * * Types of #GstMpegTsSection that the library handles. */ @@ -73,7 +74,8 @@ typedef enum { GST_MPEGTS_SECTION_ATSC_TVCT, GST_MPEGTS_SECTION_ATSC_CVCT, GST_MPEGTS_SECTION_ATSC_MGT, - GST_MPEGTS_SECTION_ATSC_ETT + GST_MPEGTS_SECTION_ATSC_ETT, + GST_MPEGTS_SECTION_ATSC_STT } GstMpegTsSectionType; /** diff --git a/tests/examples/mpegts/ts-parser.c b/tests/examples/mpegts/ts-parser.c index 029a27439d..617e8207fc 100644 --- a/tests/examples/mpegts/ts-parser.c +++ b/tests/examples/mpegts/ts-parser.c @@ -639,6 +639,30 @@ dump_ett (GstMpegTsSection * section) } } +static void +dump_stt (GstMpegTsSection * section) +{ + const GstMpegTsAtscSTT *stt = gst_mpegts_section_get_atsc_stt (section); + GstDateTime *dt; + gchar *dt_str = NULL; + + g_assert (stt); + + dt = gst_mpegts_atsc_stt_get_datetime_utc ((GstMpegTsAtscSTT *) stt); + if (dt) + dt_str = gst_date_time_to_iso8601_string (dt); + + g_printf (" protocol_version : 0x%04x\n", stt->protocol_version); + g_printf (" system_time : 0x%08x\n", stt->system_time); + g_printf (" gps_utc_offset : %d\n", stt->gps_utc_offset); + g_printf (" daylight saving : %d day:%d hour:%d\n", stt->ds_status, + stt->ds_dayofmonth, stt->ds_hour); + g_printf (" utc datetime : %s", dt_str); + + g_free (dt_str); + gst_date_time_unref (dt); +} + static void dump_nit (GstMpegTsSection * section) { @@ -839,6 +863,9 @@ dump_section (GstMpegTsSection * section) case GST_MPEGTS_SECTION_ATSC_ETT: dump_ett (section); break; + case GST_MPEGTS_SECTION_ATSC_STT: + dump_stt (section); + break; default: g_printf (" Unknown section type\n"); break;