srtpdec: Make sure that stream-id/caps/segment are sent before buffers
authorOlivier Crête <olivier.crete@collabora.com>
Wed, 20 Nov 2013 01:12:54 +0000 (20:12 -0500)
committerOlivier Crête <olivier.crete@collabora.com>
Wed, 20 Nov 2013 01:12:54 +0000 (20:12 -0500)
It may be possible that only one of the two sink pads is linked in that case,
the events need to be created from the other pad.

ext/srtp/gstsrtpdec.c
ext/srtp/gstsrtpdec.h

index ae64109..a47b205 100644 (file)
@@ -685,31 +685,50 @@ gst_srtp_dec_sink_setcaps (GstPad * pad, GstObject * parent,
 }
 
 static gboolean
-gst_srtp_dec_sink_event (GstPad * pad, GstObject * parent,
-    GstEvent * event, gboolean is_rtcp)
+gst_srtp_dec_sink_event_rtp (GstPad * pad, GstObject * parent, GstEvent * event)
 {
   GstCaps *caps;
+  GstSrtpDec *filter = GST_SRTP_DEC (parent);
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_CAPS:
       gst_event_parse_caps (event, &caps);
-      return gst_srtp_dec_sink_setcaps (pad, parent, caps, is_rtcp);
+      return gst_srtp_dec_sink_setcaps (pad, parent, caps, FALSE);
+    case GST_EVENT_SEGMENT:
+      filter->rtp_has_segment = TRUE;
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      filter->rtp_has_segment = FALSE;
+      break;
     default:
-      return gst_pad_event_default (pad, parent, event);
+      break;
   }
-}
 
-static gboolean
-gst_srtp_dec_sink_event_rtp (GstPad * pad, GstObject * parent, GstEvent * event)
-{
-  return gst_srtp_dec_sink_event (pad, parent, event, FALSE);
+  return gst_pad_event_default (pad, parent, event);
 }
 
 static gboolean
 gst_srtp_dec_sink_event_rtcp (GstPad * pad, GstObject * parent,
     GstEvent * event)
 {
-  return gst_srtp_dec_sink_event (pad, parent, event, TRUE);
+  GstCaps *caps;
+  GstSrtpDec *filter = GST_SRTP_DEC (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+      gst_event_parse_caps (event, &caps);
+      return gst_srtp_dec_sink_setcaps (pad, parent, caps, TRUE);
+    case GST_EVENT_SEGMENT:
+      filter->rtcp_has_segment = TRUE;
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      filter->rtcp_has_segment = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
 }
 
 static gboolean
@@ -842,6 +861,71 @@ gst_srtp_dec_iterate_internal_links_rtcp (GstPad * pad, GstObject * parent)
   return gst_srtp_dec_iterate_internal_links (pad, parent, TRUE);
 }
 
+static void
+gst_srtp_dec_push_early_events (GstSrtpDec * filter, GstPad * pad,
+    GstPad * otherpad, gboolean is_rtcp)
+{
+  GstEvent *otherev, *ev;
+
+  ev = gst_pad_get_sticky_event (pad, GST_EVENT_STREAM_START, 0);
+  if (ev) {
+    gst_event_unref (ev);
+  } else {
+    gchar *new_stream_id;
+
+    otherev = gst_pad_get_sticky_event (otherpad, GST_EVENT_STREAM_START, 0);
+
+    if (otherev) {
+      const gchar *other_stream_id;
+
+      gst_event_parse_stream_start (otherev, &other_stream_id);
+
+      new_stream_id = g_strdup_printf ("%s/%s", other_stream_id,
+          is_rtcp ? "rtcp" : "rtp");
+      gst_event_unref (otherev);
+    } else {
+      new_stream_id = gst_pad_create_stream_id (pad, GST_ELEMENT (filter),
+          is_rtcp ? "rtcp" : "rtp");
+    }
+
+    ev = gst_event_new_stream_start (new_stream_id);
+    g_free (new_stream_id);
+
+    gst_pad_push_event (pad, ev);
+  }
+
+  ev = gst_pad_get_sticky_event (pad, GST_EVENT_CAPS, 0);
+  if (ev) {
+    gst_event_unref (ev);
+  } else {
+    GstCaps *caps;
+
+    if (is_rtcp)
+      caps = gst_caps_new_empty_simple ("application/x-rtcp");
+    else
+      caps = gst_caps_new_empty_simple ("application/x-rtp");
+
+    gst_pad_set_caps (pad, caps);
+    gst_caps_unref (caps);
+  }
+
+  ev = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0);
+  if (ev) {
+    gst_event_unref (ev);
+  } else {
+    ev = gst_pad_get_sticky_event (otherpad, GST_EVENT_SEGMENT, 0);
+
+    if (ev)
+      gst_pad_push_event (pad, ev);
+  }
+
+  if (is_rtcp)
+    filter->rtcp_has_segment = TRUE;
+  else
+    filter->rtp_has_segment = TRUE;
+
+}
+
 static GstFlowReturn
 gst_srtp_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf,
     gboolean is_rtcp)
@@ -939,10 +1023,17 @@ unprotect:
 
 push_out:
   /* Push buffer to source pad */
-  if (is_rtcp)
+  if (is_rtcp) {
     otherpad = filter->rtcp_srcpad;
-  else
+    if (!filter->rtcp_has_segment)
+      gst_srtp_dec_push_early_events (filter, filter->rtcp_srcpad,
+          filter->rtp_srcpad, TRUE);
+  } else {
     otherpad = filter->rtp_srcpad;
+    if (!filter->rtp_has_segment)
+      gst_srtp_dec_push_early_events (filter, filter->rtp_srcpad,
+          filter->rtcp_srcpad, FALSE);
+  }
   ret = gst_pad_push (otherpad, buf);
 
   return ret;
@@ -980,6 +1071,8 @@ gst_srtp_dec_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       filter->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
           NULL, (GDestroyNotify) clear_stream);
+      filter->rtp_has_segment = FALSE;
+      filter->rtcp_has_segment = FALSE;
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
index 633818b..9d210fa 100644 (file)
@@ -78,6 +78,9 @@ struct _GstSrtpDec
   srtp_t session;
   gboolean first_session;
   GHashTable *streams;
+
+  gboolean rtp_has_segment;
+  gboolean rtcp_has_segment;
 };
 
 struct _GstSrtpDecClass