mpegts: Add support for SIT sections
authorEdward Hervey <edward@centricular.com>
Sun, 22 Nov 2020 17:48:08 +0000 (18:48 +0100)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 14 Dec 2020 15:37:29 +0000 (16:37 +0100)
Selection Information Tables (EN 300 468)

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1852>

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

index e41047e..d88de84 100644 (file)
@@ -86,6 +86,13 @@ typedef enum {
   GST_MTS_DESC_DVB_SERVICE_MOVE                 = 0x60,
   GST_MTS_DESC_DVB_SHORT_SMOOTHING_BUFFER       = 0x61,
   GST_MTS_DESC_DVB_FREQUENCY_LIST               = 0x62,
+  /**
+   * GST_MTS_DESC_DVB_PARTIAL_TRANSPORT_STREAM:
+   *
+   * Partial Transport Stream descriptor. Only present in SIT Sections.
+   *
+   * See also: %GST_MPEGTS_SECTION_SIT, %GstMpegtsSIT
+   */
   GST_MTS_DESC_DVB_PARTIAL_TRANSPORT_STREAM     = 0x63,
   GST_MTS_DESC_DVB_DATA_BROADCAST               = 0x64,
   GST_MTS_DESC_DVB_SCRAMBLING                   = 0x65,
index 6b9eb49..d41723f 100644 (file)
  * * gst_mpegts_section_get_tot()
  * * %GstMpegtsTOT
  *
+ * ## Selection Information Table (SIT)
+ * See:
+ * * gst_mpegts_section_get_sit()
+ * * %GstMpegtsSIT
+ * * %GstMpegtsSITService
+ *
  * # API
  */
 
@@ -1252,3 +1258,160 @@ gst_mpegts_section_get_tot (GstMpegtsSection * section)
 
   return (const GstMpegtsTOT *) section->cached_parsed;
 }
+
+
+/* Selection Information Table (SIT) */
+
+static GstMpegtsSITService *
+_gst_mpegts_sit_service_copy (GstMpegtsSITService * sit)
+{
+  GstMpegtsSITService *copy = g_slice_dup (GstMpegtsSITService, sit);
+
+  copy->service_id = sit->service_id;
+  copy->running_status = sit->running_status;
+  copy->descriptors = g_ptr_array_ref (sit->descriptors);
+
+  return copy;
+}
+
+static void
+_gst_mpegts_sit_service_free (GstMpegtsSITService * sit)
+{
+  if (sit->descriptors)
+    g_ptr_array_unref (sit->descriptors);
+  g_slice_free (GstMpegtsSITService, sit);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsSITService, gst_mpegts_sit_service,
+    (GBoxedCopyFunc) _gst_mpegts_sit_service_copy,
+    (GFreeFunc) _gst_mpegts_sit_service_free);
+
+static GstMpegtsSIT *
+_gst_mpegts_sit_copy (GstMpegtsSIT * sit)
+{
+  GstMpegtsSIT *copy = g_slice_dup (GstMpegtsSIT, sit);
+
+  copy->services = g_ptr_array_ref (sit->services);
+  copy->descriptors = g_ptr_array_ref (sit->descriptors);
+
+  return copy;
+}
+
+static void
+_gst_mpegts_sit_free (GstMpegtsSIT * sit)
+{
+  g_ptr_array_unref (sit->services);
+  g_ptr_array_unref (sit->descriptors);
+  g_slice_free (GstMpegtsSIT, sit);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsSIT, gst_mpegts_sit,
+    (GBoxedCopyFunc) _gst_mpegts_sit_copy, (GFreeFunc) _gst_mpegts_sit_free);
+
+
+static gpointer
+_parse_sit (GstMpegtsSection * section)
+{
+  GstMpegtsSIT *sit = NULL;
+  guint i = 0, allocated_services = 8;
+  guint8 *data, *end, *entry_begin;
+  guint sit_info_length;
+  guint descriptors_loop_length;
+
+  GST_DEBUG ("SIT");
+
+  sit = g_slice_new0 (GstMpegtsSIT);
+
+  data = section->data;
+  end = data + section->section_length;
+
+  /* Skip common fields */
+  data += 8;
+
+  descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
+  data += 2;
+  sit->descriptors =
+      gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+  if (sit->descriptors == NULL)
+    goto error;
+  data += descriptors_loop_length;
+
+  sit_info_length = end - data;;
+  sit->services = g_ptr_array_new_full (allocated_services,
+      (GDestroyNotify) _gst_mpegts_sit_service_free);
+
+  /* read up to the CRC */
+  while (sit_info_length - 4 > 0) {
+    GstMpegtsSITService *service = g_slice_new0 (GstMpegtsSITService);
+    g_ptr_array_add (sit->services, service);
+
+    entry_begin = data;
+
+    if (sit_info_length - 4 < 4) {
+      /* each entry must be at least 4 bytes (+4 bytes for the CRC) */
+      GST_WARNING ("PID %d invalid SIT entry size %d",
+          section->pid, sit_info_length);
+      goto error;
+    }
+
+    service->service_id = GST_READ_UINT16_BE (data);
+    data += 2;
+
+    service->running_status = (*data >> 5) & 0x07;
+    descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
+    data += 2;
+
+    if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
+      GST_WARNING ("PID %d invalid SIT 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;
+
+    sit_info_length -= data - entry_begin;
+    i += 1;
+  }
+
+  if (data != end - 4) {
+    GST_WARNING ("PID %d invalid SIT parsed %d length %d",
+        section->pid, (gint) (data - section->data), section->section_length);
+    goto error;
+  }
+
+  return sit;
+
+error:
+  if (sit)
+    _gst_mpegts_sit_free (sit);
+
+  return NULL;
+}
+
+/**
+ * gst_mpegts_section_get_sit:
+ * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SIT
+ *
+ * Returns the #GstMpegtsSIT contained in the @section.
+ *
+ * Returns: The #GstMpegtsSIT contained in the section, or %NULL if an error
+ * happened.
+ *
+ * Since: 1.20
+ */
+const GstMpegtsSIT *
+gst_mpegts_section_get_sit (GstMpegtsSection * section)
+{
+  g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SIT, NULL);
+  g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+  if (!section->cached_parsed)
+    section->cached_parsed =
+        __common_section_checks (section, 18, _parse_sit,
+        (GDestroyNotify) _gst_mpegts_sit_free);
+
+  return (const GstMpegtsSIT *) section->cached_parsed;
+}
index 2fa2a9a..665bb5d 100644 (file)
@@ -433,6 +433,68 @@ GType gst_mpegts_tot_get_type (void);
 GST_MPEGTS_API
 const GstMpegtsTOT *gst_mpegts_section_get_tot (GstMpegtsSection *section);
 
+/* SIT */
+
+typedef struct _GstMpegtsSITService GstMpegtsSITService;
+/**
+ * GST_TYPE_MPEGTS_SIT_SERVICE:
+ *
+ * Since: 1.20
+ */
+#define GST_TYPE_MPEGTS_SIT_SERVICE (gst_mpegts_sit_service_get_type())
+
+typedef struct _GstMpegtsSIT GstMpegtsSIT;
+/**
+ * GST_TYPE_MPEGTS_SIT:
+ *
+ * Since: 1.20
+ */
+#define GST_TYPE_MPEGTS_SIT (gst_mpegts_sit_get_type())
+
+/**
+ * GstMpegtsSITService:
+ * @service_id: The Program number this table belongs to
+ * @running_status: Status of this service
+ * @descriptors: (element-type GstMpegtsDescriptor): List of descriptors
+ *
+ * SIT Service entry
+ *
+ * Since: 1.20
+ */
+struct _GstMpegtsSITService
+{
+  guint16        service_id;
+  GstMpegtsRunningStatus running_status;
+
+  GPtrArray     *descriptors;
+};
+
+/**
+ * GstMpegtsSIT:
+ * @descriptors: (element-type GstMpegtsDescriptor): List of descriptors
+ * @services: (element-type GstMpegtsSITService): List of services
+ *
+ * Selection Information Table (EN 300 468)
+ *
+ * Since: 1.20
+ */
+struct _GstMpegtsSIT
+{
+  GPtrArray     *descriptors;
+  GPtrArray     *services;
+};
+
+
+GST_MPEGTS_API
+GType gst_mpegts_sit_get_type (void);
+
+GST_MPEGTS_API
+GType gst_mpegts_sit_service_get_type (void);
+
+GST_MPEGTS_API
+const GstMpegtsSIT *gst_mpegts_section_get_sit (GstMpegtsSection *section);
+
+
 G_END_DECLS
 
 #endif                         /* GST_MPEGTS_SECTION_H */
index 2f2a96f..d93253f 100644 (file)
@@ -1086,6 +1086,9 @@ _identify_section (guint16 pid, guint8 table_id)
     case GST_MTS_TABLE_ID_SCTE_SPLICE:
       return GST_MPEGTS_SECTION_SCTE_SIT;
       break;
+    case GST_MTS_TABLE_ID_SELECTION_INFORMATION:
+      if (pid == 0x001f)
+        return GST_MPEGTS_SECTION_SIT;
     default:
       /* Handle ranges */
       if (table_id >= GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT &&
index 95a7208..18f0e7f 100644 (file)
@@ -77,6 +77,14 @@ typedef enum {
   GST_MPEGTS_SECTION_SDT,
   GST_MPEGTS_SECTION_TDT,
   GST_MPEGTS_SECTION_TOT,
+  /**
+   * GST_MPEGTS_SECTION_SIT:
+   *
+   * Selection Information Table (EN 300 468)
+   *
+   * Since: 1.20
+   */
+  GST_MPEGTS_SECTION_SIT,
   GST_MPEGTS_SECTION_ATSC_TVCT,
   GST_MPEGTS_SECTION_ATSC_CVCT,
   GST_MPEGTS_SECTION_ATSC_MGT,
index ad667f6..32dab35 100644 (file)
@@ -1035,6 +1035,29 @@ dump_sdt (GstMpegtsSection * section)
   }
 }
 
+
+static void
+dump_sit (GstMpegtsSection * section)
+{
+  const GstMpegtsSIT *sit = gst_mpegts_section_get_sit (section);
+  guint i, len;
+
+  g_assert (sit);
+
+  dump_descriptors (sit->descriptors, 7);
+  len = sit->services->len;
+  g_printf ("     %d Services:\n", len);
+  for (i = 0; i < len; i++) {
+    GstMpegtsSITService *service = g_ptr_array_index (sit->services, i);
+    g_print
+        ("       service_id:0x%04x, running_status:0x%02x (%s)\n",
+        service->service_id, service->running_status,
+        enum_name (GST_TYPE_MPEGTS_RUNNING_STATUS, service->running_status));
+    dump_descriptors (service->descriptors, 9);
+  }
+}
+
+
 static void
 dump_tdt (GstMpegtsSection * section)
 {
@@ -1256,6 +1279,9 @@ dump_section (GstMpegtsSection * section)
     case GST_MPEGTS_SECTION_EIT:
       dump_eit (section);
       break;
+    case GST_MPEGTS_SECTION_SIT:
+      dump_sit (section);
+      break;
     case GST_MPEGTS_SECTION_ATSC_MGT:
       dump_mgt (section);
       break;