diff --git a/gst-libs/gst/mpegts/gst-atsc-section.c b/gst-libs/gst/mpegts/gst-atsc-section.c index 553c65fe32..c77d0f8a11 100644 --- a/gst-libs/gst/mpegts/gst-atsc-section.c +++ b/gst-libs/gst/mpegts/gst-atsc-section.c @@ -250,3 +250,149 @@ gst_mpegts_section_get_atsc_cvct (GstMpegTsSection * section) 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: + if (mgt) + _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; +} diff --git a/gst-libs/gst/mpegts/gst-atsc-section.h b/gst-libs/gst/mpegts/gst-atsc-section.h index b7a5796d7f..caa612ef3e 100644 --- a/gst-libs/gst/mpegts/gst-atsc-section.h +++ b/gst-libs/gst/mpegts/gst-atsc-section.h @@ -122,6 +122,53 @@ GType gst_mpegts_atsc_vct_source_get_type (void); const GstMpegTsAtscVCT * gst_mpegts_section_get_atsc_tvct (GstMpegTsSection * section); const GstMpegTsAtscVCT * gst_mpegts_section_get_atsc_cvct (GstMpegTsSection * section); +/* MGT */ +#define GST_TYPE_MPEGTS_ATSC_MGT (gst_mpegts_atsc_mgt_get_type ()) +#define GST_TYPE_MPEGTS_ATSC_MGT_TABLE (gst_mpegts_atsc_mgt_table_get_type ()) + +typedef struct _GstMpegTsAtscMGTTable GstMpegTsAtscMGTTable; +typedef struct _GstMpegTsAtscMGT GstMpegTsAtscMGT; + +typedef enum { + GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_EIT0 = 0x0100, + GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_EIT127 = 0x017F, + GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_ETT0 = 0x0200, + GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_ETT127 = 0x027F +} GstMpegTsAtscMGTTableType; + +/** + * GstMpegTsAtscMGTTable: + * + * Source from a @GstMpegTsAtscMGT + */ +struct _GstMpegTsAtscMGTTable +{ + guint16 table_type; + guint16 pid; + guint8 version_number; + guint32 number_bytes; + GPtrArray *descriptors; +}; + +/** + * GstMpegTsAtscMGT: + * + * Terrestrial Virtual Channel Table (A65) + * + */ +struct _GstMpegTsAtscMGT +{ + guint8 protocol_version; + guint16 tables_defined; + GPtrArray *tables; + GPtrArray *descriptors; +}; + +GType gst_mpegts_atsc_mgt_get_type (void); +GType gst_mpegts_atsc_mgt_table_get_type (void); + +const GstMpegTsAtscMGT * gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section); + 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 70035c7622..d294d16d6b 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.c +++ b/gst-libs/gst/mpegts/gstmpegtssection.c @@ -1056,6 +1056,13 @@ _identify_section (guint16 pid, guint8 table_id) if (pid == 0x1ffb) return GST_MPEGTS_SECTION_ATSC_CVCT; break; + case GST_MTS_TABLE_ID_ATSC_MASTER_GUIDE: + if (pid == 0x1ffb) + return GST_MPEGTS_SECTION_ATSC_MGT; + break; + case GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION: + /* FIXME check pids reported on the MGT to confirm expectations */ + return GST_MPEGTS_SECTION_EIT; /* FIXME : FILL */ default: /* Handle ranges */ diff --git a/gst-libs/gst/mpegts/gstmpegtssection.h b/gst-libs/gst/mpegts/gstmpegtssection.h index 2fd9df6a27..536dce3865 100644 --- a/gst-libs/gst/mpegts/gstmpegtssection.h +++ b/gst-libs/gst/mpegts/gstmpegtssection.h @@ -53,6 +53,7 @@ GType gst_mpegts_section_get_type (void); * @GST_MPEGTS_SECTION_TOT: Time Offset Table (EN 300 468) * @GST_MPEGTS_SECTION_ATSC_TVCT: ATSC Terrestrial Virtual Channel Table (A65) * @GST_MPEGTS_SECTION_ATSC_CVCT: ATSC Cable Virtual Channel Table (A65) + * @GST_MPEGTS_SECTION_ATSC_MGT: ATSC Master Guide Table (A65) * * Types of #GstMpegTsSection that the library handles. */ @@ -69,7 +70,8 @@ typedef enum { GST_MPEGTS_SECTION_TDT, GST_MPEGTS_SECTION_TOT, GST_MPEGTS_SECTION_ATSC_TVCT, - GST_MPEGTS_SECTION_ATSC_CVCT + GST_MPEGTS_SECTION_ATSC_CVCT, + GST_MPEGTS_SECTION_ATSC_MGT } GstMpegTsSectionType; /** diff --git a/tests/examples/mpegts/ts-parser.c b/tests/examples/mpegts/ts-parser.c index c510e169a7..f10f403f5f 100644 --- a/tests/examples/mpegts/ts-parser.c +++ b/tests/examples/mpegts/ts-parser.c @@ -702,6 +702,26 @@ dump_tot (GstMpegTsSection * section) g_free (str); } +static void +dump_mgt (GstMpegTsSection * section) +{ + const GstMpegTsAtscMGT *mgt = gst_mpegts_section_get_atsc_mgt (section); + gint i; + + g_printf (" protocol_version : %u\n", mgt->protocol_version); + g_printf (" tables number : %d\n", mgt->tables->len); + for (i = 0; i < mgt->tables->len; i++) { + GstMpegTsAtscMGTTable *table = g_ptr_array_index (mgt->tables, i); + g_printf (" table %d)\n", i); + g_printf (" table_type : %u\n", table->table_type); + g_printf (" pid : 0x%x\n", table->pid); + g_printf (" version_number: %u\n", table->version_number); + g_printf (" number_bytes : %u\n", table->number_bytes); + dump_descriptors (table->descriptors, 9); + } + dump_descriptors (mgt->descriptors, 7); +} + static void dump_vct (GstMpegTsSection * section) { @@ -773,6 +793,9 @@ dump_section (GstMpegTsSection * section) case GST_MPEGTS_SECTION_EIT: dump_eit (section); break; + case GST_MPEGTS_SECTION_ATSC_MGT: + dump_mgt (section); + break; case GST_MPEGTS_SECTION_ATSC_CVCT: case GST_MPEGTS_SECTION_ATSC_TVCT: dump_vct (section);