scte-section: add support for parsing splice components
authorMathieu Duponchelle <mathieu@centricular.com>
Tue, 13 Apr 2021 21:38:16 +0000 (23:38 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Sat, 25 Sep 2021 01:29:38 +0000 (01:29 +0000)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/913>

subprojects/gst-plugins-bad/gst-libs/gst/mpegts/gst-scte-section.c
subprojects/gst-plugins-bad/gst-libs/gst/mpegts/gst-scte-section.h

index 88e99aa..e711f2d 100644 (file)
 static GstMpegtsSCTESpliceEvent *
 _gst_mpegts_scte_splice_event_copy (GstMpegtsSCTESpliceEvent * event)
 {
-  return g_slice_dup (GstMpegtsSCTESpliceEvent, event);
+  GstMpegtsSCTESpliceEvent *copy =
+      g_slice_dup (GstMpegtsSCTESpliceEvent, event);
+
+  copy->components = g_ptr_array_ref (event->components);
+
+  return copy;
 }
 
 static void
 _gst_mpegts_scte_splice_event_free (GstMpegtsSCTESpliceEvent * event)
 {
+  g_ptr_array_unref (event->components);
   g_slice_free (GstMpegtsSCTESpliceEvent, event);
 }
 
@@ -56,6 +62,71 @@ G_DEFINE_BOXED_TYPE (GstMpegtsSCTESpliceEvent, gst_mpegts_scte_splice_event,
     (GBoxedCopyFunc) _gst_mpegts_scte_splice_event_copy,
     (GFreeFunc) _gst_mpegts_scte_splice_event_free);
 
+static GstMpegtsSCTESpliceComponent *
+_gst_mpegts_scte_splice_component_copy (GstMpegtsSCTESpliceComponent *
+    component)
+{
+  return g_slice_dup (GstMpegtsSCTESpliceComponent, component);
+}
+
+static void
+_gst_mpegts_scte_splice_component_free (GstMpegtsSCTESpliceComponent *
+    component)
+{
+  g_slice_free (GstMpegtsSCTESpliceComponent, component);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsSCTESpliceComponent,
+    gst_mpegts_scte_splice_component,
+    (GBoxedCopyFunc) _gst_mpegts_scte_splice_component_copy,
+    (GFreeFunc) _gst_mpegts_scte_splice_component_free);
+
+static GstMpegtsSCTESpliceComponent *
+_parse_splice_component (GstMpegtsSCTESpliceEvent * event, guint8 ** orig_data,
+    guint8 * end)
+{
+  GstMpegtsSCTESpliceComponent *component =
+      g_slice_new0 (GstMpegtsSCTESpliceComponent);
+  guint8 *data = *orig_data;
+
+  if (data + 1 + 6 > end)
+    goto error;
+
+  component->tag = *data;
+  data += 1;
+
+  if (event->insert_event && event->splice_immediate_flag == 0) {
+    component->splice_time_specified = *data >> 7;
+    if (component->splice_time_specified) {
+      component->splice_time = ((guint64) (*data & 0x01)) << 32;
+      data += 1;
+      component->splice_time += GST_READ_UINT32_BE (data);
+      data += 4;
+      GST_LOG ("component %u splice_time %" G_GUINT64_FORMAT " (%"
+          GST_TIME_FORMAT ")", component->tag, component->splice_time,
+          GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (component->splice_time)));
+    } else {
+      data += 1;
+    }
+  } else if (!event->insert_event) {
+    component->utc_splice_time = GST_READ_UINT32_BE (data);
+    GST_LOG ("component %u utc_splice_time %u", component->tag,
+        component->utc_splice_time);
+    data += 4;
+  }
+
+  *orig_data = data;
+
+  return component;
+
+error:
+  {
+    if (event)
+      _gst_mpegts_scte_splice_event_free (event);
+    return NULL;
+  }
+}
+
 static GstMpegtsSCTESpliceEvent *
 _parse_splice_event (guint8 ** orig_data, guint8 * end, gboolean insert_event)
 {
@@ -66,6 +137,9 @@ _parse_splice_event (guint8 ** orig_data, guint8 * end, gboolean insert_event)
   if (data + 5 + 6 > end)
     goto error;
 
+  event->components = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      _gst_mpegts_scte_splice_component_free);
+
   event->insert_event = insert_event;
   event->splice_event_id = GST_READ_UINT32_BE (data);
   GST_LOG ("splice_event_id: 0x%08x", event->splice_event_id);
@@ -97,26 +171,36 @@ _parse_splice_event (guint8 ** orig_data, guint8 * end, gboolean insert_event)
     data += 1;
 
     if (event->program_splice_flag == 0) {
-      GST_ERROR ("Component splice flag not supported !");
-      goto error;
-    }
+      guint component_count = *data;
+      guint i;
 
-    if (insert_event && event->splice_immediate_flag == 0) {
-      event->program_splice_time_specified = *data >> 7;
-      if (event->program_splice_time_specified) {
-        event->program_splice_time = ((guint64) (*data & 0x01)) << 32;
-        data += 1;
-        event->program_splice_time += GST_READ_UINT32_BE (data);
+      data += 1;
+
+      for (i = 0; i < component_count; i++) {
+        GstMpegtsSCTESpliceComponent *component =
+            _parse_splice_component (event, &data, end);
+        if (component == NULL)
+          goto error;
+        g_ptr_array_add (event->components, component);
+      }
+    } else {
+      if (insert_event && event->splice_immediate_flag == 0) {
+        event->program_splice_time_specified = *data >> 7;
+        if (event->program_splice_time_specified) {
+          event->program_splice_time = ((guint64) (*data & 0x01)) << 32;
+          data += 1;
+          event->program_splice_time += GST_READ_UINT32_BE (data);
+          data += 4;
+          GST_LOG ("program_splice_time %" G_GUINT64_FORMAT " (%"
+              GST_TIME_FORMAT ")", event->program_splice_time,
+              GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (event->program_splice_time)));
+        } else
+          data += 1;
+      } else if (!insert_event) {
+        event->utc_splice_time = GST_READ_UINT32_BE (data);
+        GST_LOG ("utc_splice_time %u", event->utc_splice_time);
         data += 4;
-        GST_LOG ("program_splice_time %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT
-            ")", event->program_splice_time,
-            GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (event->program_splice_time)));
-      } else
-        data += 1;
-    } else if (!insert_event) {
-      event->utc_splice_time = GST_READ_UINT32_BE (data);
-      GST_LOG ("utc_splice_time %u", event->utc_splice_time);
-      data += 4;
+      }
     }
 
     if (event->duration_flag) {
@@ -513,10 +597,33 @@ gst_mpegts_scte_splice_event_new (void)
 
   /* Non-0 Default values */
   event->program_splice_flag = TRUE;
+  event->components = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      _gst_mpegts_scte_splice_component_free);
+
 
   return event;
 }
 
+/**
+ * gst_mpegts_scte_splice_component_new:
+ * tag: the elementary PID stream identifier
+ *
+ * Allocates and initializes a #GstMpegtsSCTESpliceComponent.
+ *
+ * Returns: (transfer full): A newly allocated #GstMpegtsSCTESpliceComponent
+ * Since: 1.20
+ */
+GstMpegtsSCTESpliceComponent *
+gst_mpegts_scte_splice_component_new (guint8 tag)
+{
+  GstMpegtsSCTESpliceComponent *component =
+      g_slice_new0 (GstMpegtsSCTESpliceComponent);
+
+  component->tag = tag;
+
+  return component;
+}
+
 static gboolean
 _packetize_sit (GstMpegtsSection * section)
 {
index 2694626..498df34 100644 (file)
@@ -103,6 +103,18 @@ typedef enum {
 
 } GstMpegtsSectionSCTETableID;
 
+#define GST_TYPE_MPEGTS_SCTE_SPLICE_COMPONENT (gst_mpegts_scte_splice_component_get_type())
+typedef struct _GstMpegtsSCTESpliceComponent GstMpegtsSCTESpliceComponent;
+
+struct _GstMpegtsSCTESpliceComponent {
+  guint8 tag;
+
+  gboolean splice_time_specified; /* Only valid for insert_event */
+  guint64 splice_time; /* Only valid for insert_event */
+
+  guint32 utc_splice_time; /* Only valid for !insert_event (schedule) */
+};
+
 /* Splice Information Table (SIT) */
 #define GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT (gst_mpegts_scte_splice_event_get_type())
 typedef struct _GstMpegtsSCTESpliceEvent GstMpegtsSCTESpliceEvent;
@@ -116,14 +128,17 @@ struct _GstMpegtsSCTESpliceEvent {
 
   /* If splice_event_cancel_indicator == 0 */
   gboolean out_of_network_indicator;
-  gboolean program_splice_flag;          /* NOTE: Only program splice are supported */
+  gboolean program_splice_flag;
   gboolean duration_flag;
 
   gboolean splice_immediate_flag; /* Only valid for insert_event */
-  gboolean program_splice_time_specified; /* Only valid for insert_event */
-  guint64 program_splice_time; /* Only valid for insert_event */
 
-  guint32 utc_splice_time; /* Only valid for !insert_event (schedule) */
+  gboolean program_splice_time_specified; /* Only valid for insert_event && program_splice */
+  guint64 program_splice_time; /* Only valid for insert_event && program_splice */
+
+  guint32 utc_splice_time; /* Only valid for !insert_event (schedule) && program_splice */
+
+  GPtrArray *components; /* Only valid for !program_splice */
 
   gboolean break_duration_auto_return;
   guint64 break_duration;
@@ -219,6 +234,12 @@ const GstMpegtsSCTESIT *gst_mpegts_section_get_scte_sit (GstMpegtsSection *secti
 GST_MPEGTS_API
 GstMpegtsSection *gst_mpegts_section_from_scte_sit (GstMpegtsSCTESIT * sit, guint16 pid);
 
+GST_MPEGTS_API
+GType gst_mpegts_scte_splice_component_get_type (void);
+
+GST_MPEGTS_API
+GstMpegtsSCTESpliceComponent *gst_mpegts_scte_splice_component_new (guint8 tag);
+
 
 G_END_DECLS