Port gtk-doc comments to their equivalent markdown syntax
[platform/upstream/gstreamer.git] / plugins / elements / gstfunnel.c
index f5dedcc..a929338 100644 (file)
@@ -24,6 +24,7 @@
 
 /**
  * SECTION:element-funnel
+ * @title: funnel
  *
  * Takes packets from various input sinks into one output source.
  *
@@ -76,6 +77,14 @@ struct _GstFunnelPadClass
 
 G_DEFINE_TYPE (GstFunnelPad, gst_funnel_pad, GST_TYPE_PAD);
 
+#define DEFAULT_FORWARD_STICKY_EVENTS  TRUE
+
+enum
+{
+  PROP_0,
+  PROP_FORWARD_STICKY_EVENTS
+};
+
 static void
 gst_funnel_pad_class_init (GstFunnelPadClass * klass)
 {
@@ -87,14 +96,12 @@ gst_funnel_pad_init (GstFunnelPad * pad)
   pad->got_eos = FALSE;
 }
 
-static GstStaticPadTemplate funnel_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink_%u",
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
     GST_PAD_SINK,
     GST_PAD_REQUEST,
     GST_STATIC_CAPS_ANY);
 
-static GstStaticPadTemplate funnel_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
@@ -112,10 +119,44 @@ static void gst_funnel_release_pad (GstElement * element, GstPad * pad);
 
 static GstFlowReturn gst_funnel_sink_chain (GstPad * pad, GstObject * parent,
     GstBuffer * buffer);
+static GstFlowReturn gst_funnel_sink_chain_list (GstPad * pad,
+    GstObject * parent, GstBufferList * list);
 static gboolean gst_funnel_sink_event (GstPad * pad, GstObject * parent,
     GstEvent * event);
 
 static void
+gst_funnel_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstFunnel *funnel = GST_FUNNEL (object);
+
+  switch (prop_id) {
+    case PROP_FORWARD_STICKY_EVENTS:
+      funnel->forward_sticky_events = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_funnel_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstFunnel *funnel = GST_FUNNEL (object);
+
+  switch (prop_id) {
+    case PROP_FORWARD_STICKY_EVENTS:
+      g_value_set_boolean (value, funnel->forward_sticky_events);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_funnel_dispose (GObject * object)
 {
   GstFunnel *funnel = GST_FUNNEL (object);
@@ -142,16 +183,23 @@ gst_funnel_class_init (GstFunnelClass * klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
 
+  gobject_class->set_property = gst_funnel_set_property;
+  gobject_class->get_property = gst_funnel_get_property;
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_funnel_dispose);
 
+  g_object_class_install_property (gobject_class, PROP_FORWARD_STICKY_EVENTS,
+      g_param_spec_boolean ("forward-sticky-events", "Forward sticky events",
+          "Forward sticky events on stream changes",
+          DEFAULT_FORWARD_STICKY_EVENTS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+
   gst_element_class_set_static_metadata (gstelement_class,
       "Funnel pipe fitting", "Generic", "N-to-1 pipe fitting",
       "Olivier Crete <olivier.crete@collabora.co.uk>");
 
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&funnel_sink_template));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&funnel_src_template));
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
 
   gstelement_class->request_new_pad =
       GST_DEBUG_FUNCPTR (gst_funnel_request_new_pad);
@@ -162,11 +210,12 @@ gst_funnel_class_init (GstFunnelClass * klass)
 static void
 gst_funnel_init (GstFunnel * funnel)
 {
-  funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template,
-      "src");
+  funnel->srcpad = gst_pad_new_from_static_template (&src_template, "src");
   gst_pad_use_fixed_caps (funnel->srcpad);
 
   gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad);
+
+  funnel->forward_sticky_events = DEFAULT_FORWARD_STICKY_EVENTS;
 }
 
 static GstPad *
@@ -183,6 +232,8 @@ gst_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
 
   gst_pad_set_chain_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_funnel_sink_chain));
+  gst_pad_set_chain_list_function (sinkpad,
+      GST_DEBUG_FUNCPTR (gst_funnel_sink_chain_list));
   gst_pad_set_event_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_funnel_sink_event));
 
@@ -193,6 +244,9 @@ gst_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
 
   gst_element_add_pad (element, sinkpad);
 
+  GST_DEBUG_OBJECT (element, "requested pad %s:%s",
+      GST_DEBUG_PAD_NAME (sinkpad));
+
   return sinkpad;
 }
 
@@ -229,7 +283,7 @@ gst_funnel_release_pad (GstElement * element, GstPad * pad)
   gboolean got_eos;
   gboolean send_eos = FALSE;
 
-  GST_DEBUG_OBJECT (funnel, "releasing pad");
+  GST_DEBUG_OBJECT (funnel, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
   gst_pad_set_active (pad, FALSE);
 
@@ -261,31 +315,56 @@ forward_events (GstPad * pad, GstEvent ** event, gpointer user_data)
 }
 
 static GstFlowReturn
-gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel,
+    gboolean is_list, GstMiniObject * obj)
 {
   GstFlowReturn res;
-  GstFunnel *funnel = GST_FUNNEL (parent);
 
-  GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);
+  GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj);
 
   GST_PAD_STREAM_LOCK (funnel->srcpad);
 
-  if (funnel->last_sinkpad != pad) {
+  if ((funnel->last_sinkpad == NULL) || (funnel->forward_sticky_events
+          && (funnel->last_sinkpad != pad))) {
     gst_object_replace ((GstObject **) & funnel->last_sinkpad,
         GST_OBJECT (pad));
 
+    GST_DEBUG_OBJECT (pad, "Forwarding sticky events");
     gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad);
   }
 
-  res = gst_pad_push (funnel->srcpad, buffer);
+  if (is_list)
+    res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj));
+  else
+    res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj));
 
   GST_PAD_STREAM_UNLOCK (funnel->srcpad);
 
-  GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));
+  GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""),
+      gst_flow_get_name (res));
 
   return res;
 }
 
+static GstFlowReturn
+gst_funnel_sink_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * list)
+{
+  GstFunnel *funnel = GST_FUNNEL (parent);
+
+  return gst_funnel_sink_chain_object (pad, funnel, TRUE,
+      GST_MINI_OBJECT_CAST (list));
+}
+
+static GstFlowReturn
+gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstFunnel *funnel = GST_FUNNEL (parent);
+
+  return gst_funnel_sink_chain_object (pad, funnel, FALSE,
+      GST_MINI_OBJECT_CAST (buffer));
+}
+
 static gboolean
 gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
@@ -295,6 +374,8 @@ gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   gboolean res = TRUE;
   gboolean unlock = FALSE;
 
+  GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event);
+
   if (GST_EVENT_IS_STICKY (event)) {
     unlock = TRUE;
     GST_PAD_STREAM_LOCK (funnel->srcpad);
@@ -319,6 +400,23 @@ gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
     GST_OBJECT_UNLOCK (funnel);
   }
 
+  if (forward && GST_EVENT_IS_SERIALIZED (event)) {
+    /* If no data is coming and we receive serialized event, need to forward all sticky events.
+     * Otherwise downstream has an inconsistent set of sticky events when
+     * handling the new event. */
+    if (!unlock) {
+      unlock = TRUE;
+      GST_PAD_STREAM_LOCK (funnel->srcpad);
+    }
+
+    if ((funnel->last_sinkpad == NULL) || (funnel->forward_sticky_events
+            && (funnel->last_sinkpad != pad))) {
+      gst_object_replace ((GstObject **) & funnel->last_sinkpad,
+          GST_OBJECT (pad));
+      gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad);
+    }
+  }
+
   if (forward)
     res = gst_pad_push_event (funnel->srcpad, event);
   else
@@ -335,10 +433,11 @@ reset_pad (const GValue * data, gpointer user_data)
 {
   GstPad *pad = g_value_get_object (data);
   GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad);
+  GstFunnel *funnel = user_data;
 
-  GST_OBJECT_LOCK (pad);
+  GST_OBJECT_LOCK (funnel);
   fpad->got_eos = FALSE;
-  GST_OBJECT_UNLOCK (pad);
+  GST_OBJECT_UNLOCK (funnel);
 }
 
 static GstStateChangeReturn
@@ -357,9 +456,10 @@ gst_funnel_change_state (GstElement * element, GstStateChange transition)
       GstIteratorResult res;
 
       do {
-        res = gst_iterator_foreach (iter, reset_pad, NULL);
+        res = gst_iterator_foreach (iter, reset_pad, element);
+        if (res == GST_ITERATOR_RESYNC)
+          gst_iterator_resync (iter);
       } while (res == GST_ITERATOR_RESYNC);
-
       gst_iterator_free (iter);
 
       if (res == GST_ITERATOR_ERROR)