mpegts: add atsc MGT section parsing
authorThiago Santos <ts.santos@sisa.samsung.com>
Thu, 15 May 2014 15:31:05 +0000 (12:31 -0300)
committerEdward Hervey <bilboed@bilboed.com>
Thu, 29 May 2014 08:37:59 +0000 (10:37 +0200)
Add a parsing function for MGT and also detect the EIT tables
for ATSC, the EIT pids are reported inside the MGT and we are still
only relying only on the table id for detecting it. In the future we
would want to also check the pid and compare with whatever the MGT
previously reported to confirm that it is indeed the EIT.

https://bugzilla.gnome.org/show_bug.cgi?id=730435

gst-libs/gst/mpegts/gst-atsc-section.c
gst-libs/gst/mpegts/gst-atsc-section.h
gst-libs/gst/mpegts/gstmpegtssection.c
gst-libs/gst/mpegts/gstmpegtssection.h
tests/examples/mpegts/ts-parser.c

index 553c65f..c77d0f8 100644 (file)
@@ -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;
+}
index b7a5796..caa612e 100644 (file)
@@ -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 */
index 70035c7..d294d16 100644 (file)
@@ -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 */
index 2fd9df6..536dce3 100644 (file)
@@ -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;
 
 /**
index c510e16..f10f403 100644 (file)
@@ -703,6 +703,26 @@ dump_tot (GstMpegTsSection * section)
 }
 
 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)
 {
   const GstMpegTsAtscVCT *vct;
@@ -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);