ccextractor: Always forward all sticky events to the caption pad
authorSebastian Dröge <sebastian@centricular.com>
Mon, 28 Oct 2019 09:22:06 +0000 (11:22 +0200)
committerTim-Philipp Müller <tim@centricular.com>
Tue, 29 Oct 2019 09:08:42 +0000 (09:08 +0000)
And only update the caps and stream-start event accordingly. This
ensures that we'll always forward sticky events that arrive after the
caption pad was created, and especially updates to existing sticky
events like the segment event.

Also create a proper stream id based on the upstream stream id for the
stream-start event, and make sure that all the sticky events we know are
already on the caption pad at the time it is added to the element.

ext/closedcaption/gstccextractor.c

index 0dda4bd..e8164a3 100644 (file)
@@ -212,6 +212,25 @@ gst_cc_extractor_get_property (GObject * object, guint prop_id,
   }
 }
 
+static GstEvent *
+create_stream_start_event_from_stream_start_event (GstEvent * event)
+{
+  GstEvent *new_event;
+  const gchar *stream_id;
+  gchar *new_stream_id;
+  guint group_id;
+
+  gst_event_parse_stream_start (event, &stream_id);
+  new_stream_id = g_strdup_printf ("%s/caption", stream_id);
+
+  new_event = gst_event_new_stream_start (new_stream_id);
+  g_free (new_stream_id);
+  if (gst_event_parse_group_id (event, &group_id))
+    gst_event_set_group_id (new_event, group_id);
+
+  return new_event;
+}
+
 static gboolean
 gst_cc_extractor_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
@@ -231,17 +250,21 @@ gst_cc_extractor_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       }
       break;
     }
-    case GST_EVENT_EOS:
-    case GST_EVENT_FLUSH_START:
-    case GST_EVENT_FLUSH_STOP:
-      /* Also forward to the caption pad if present */
-      if (filter->captionpad)
-        gst_pad_push_event (filter->captionpad, gst_event_ref (event));
+    case GST_EVENT_STREAM_START:
+      if (filter->captionpad) {
+        GstEvent *new_event =
+            create_stream_start_event_from_stream_start_event (event);
+        gst_pad_push_event (filter->captionpad, new_event);
+      }
       break;
     default:
+      /* Also forward all other events to the caption pad if present */
+      if (filter->captionpad)
+        gst_pad_push_event (filter->captionpad, gst_event_ref (event));
       break;
   }
 
+  /* This only forwards to the non-caption source pad */
   return gst_pad_event_default (pad, parent, event);
 }
 
@@ -289,28 +312,55 @@ create_caps_from_caption_type (GstVideoCaptionType caption_type,
   return caption_caps;
 }
 
+static gboolean
+forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  GstCCExtractor *filter = user_data;
+
+  switch (GST_EVENT_TYPE (*event)) {
+    case GST_EVENT_CAPS:{
+      GstCaps *caption_caps =
+          create_caps_from_caption_type (filter->caption_type,
+          &filter->video_info);
+
+      if (caption_caps) {
+        GstEvent *new_event = gst_event_new_caps (caption_caps);
+        gst_event_set_seqnum (new_event, gst_event_get_seqnum (*event));
+        gst_pad_store_sticky_event (filter->captionpad, new_event);
+        gst_event_unref (new_event);
+        gst_caps_unref (caption_caps);
+      }
+
+      break;
+    }
+    case GST_EVENT_STREAM_START:{
+      GstEvent *new_event =
+          create_stream_start_event_from_stream_start_event (*event);
+      gst_pad_store_sticky_event (filter->captionpad, new_event);
+      gst_event_unref (new_event);
+
+      break;
+    }
+    default:
+      gst_pad_store_sticky_event (filter->captionpad, *event);
+      break;
+  }
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_cc_extractor_handle_meta (GstCCExtractor * filter, GstBuffer * buf,
     GstVideoCaptionMeta * meta, GstVideoTimeCodeMeta * tc_meta)
 {
   GstBuffer *outbuf = NULL;
-  GstEvent *event;
-  gchar *captionid;
   GstFlowReturn flow;
 
   GST_DEBUG_OBJECT (filter, "Handling meta");
 
   /* Check if the meta type matches the configured one */
   if (filter->captionpad == NULL) {
-    GstCaps *caption_caps =
-        create_caps_from_caption_type (meta->caption_type, &filter->video_info);
-    GstEvent *stream_event;
-
     GST_DEBUG_OBJECT (filter, "Creating new caption pad");
-    if (caption_caps == NULL) {
-      GST_ERROR_OBJECT (filter, "Unknown/invalid caption type");
-      return GST_FLOW_NOT_NEGOTIATED;
-    }
 
     /* Create the caption pad and set the caps */
     filter->captionpad =
@@ -318,36 +368,19 @@ gst_cc_extractor_handle_meta (GstCCExtractor * filter, GstBuffer * buf,
     gst_pad_set_iterate_internal_links_function (filter->sinkpad,
         GST_DEBUG_FUNCPTR (gst_cc_extractor_iterate_internal_links));
     gst_pad_set_active (filter->captionpad, TRUE);
-    gst_element_add_pad (GST_ELEMENT (filter), filter->captionpad);
-    gst_flow_combiner_add_pad (filter->combiner, filter->captionpad);
 
-    captionid =
-        gst_pad_create_stream_id (filter->captionpad, (GstElement *) filter,
-        "caption");
-    stream_event = gst_event_new_stream_start (captionid);
-    g_free (captionid);
-
-    /* FIXME : Create a proper stream-id */
-    if ((event =
-            gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_STREAM_START,
-                0))) {
-      guint group_id;
-      if (gst_event_parse_group_id (event, &group_id))
-        gst_event_set_group_id (stream_event, group_id);
-      gst_event_unref (event);
-    }
-    gst_pad_push_event (filter->captionpad, stream_event);
-    gst_pad_set_caps (filter->captionpad, caption_caps);
-    gst_caps_unref (caption_caps);
+    filter->caption_type = meta->caption_type;
 
-    /* Carry over sticky events */
-    if ((event =
-            gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_SEGMENT, 0)))
-      gst_pad_push_event (filter->captionpad, event);
-    if ((event = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_TAG, 0)))
-      gst_pad_push_event (filter->captionpad, event);
+    gst_pad_sticky_events_foreach (filter->sinkpad, forward_sticky_events,
+        filter);
 
-    filter->caption_type = meta->caption_type;
+    if (!gst_pad_has_current_caps (filter->captionpad)) {
+      GST_ERROR_OBJECT (filter, "Unknown/invalid caption type");
+      return GST_FLOW_NOT_NEGOTIATED;
+    }
+
+    gst_element_add_pad (GST_ELEMENT (filter), filter->captionpad);
+    gst_flow_combiner_add_pad (filter->combiner, filter->captionpad);
   } else if (meta->caption_type != filter->caption_type) {
     GstCaps *caption_caps =
         create_caps_from_caption_type (meta->caption_type, &filter->video_info);
@@ -359,7 +392,7 @@ gst_cc_extractor_handle_meta (GstCCExtractor * filter, GstBuffer * buf,
       return GST_FLOW_NOT_NEGOTIATED;
     }
 
-    gst_pad_set_caps (filter->captionpad, caption_caps);
+    gst_pad_push_event (filter->captionpad, gst_event_new_caps (caption_caps));
     gst_caps_unref (caption_caps);
 
     filter->caption_type = meta->caption_type;