/**
* SECTION:element-funnel
+ * @title: funnel
*
* Takes packets from various input sinks into one output source.
*
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)
{
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);
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);
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);
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 *
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));
gst_element_add_pad (element, sinkpad);
+ GST_DEBUG_OBJECT (element, "requested pad %s:%s",
+ GST_DEBUG_PAD_NAME (sinkpad));
+
return sinkpad;
}
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);
}
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)
{
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);
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
{
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
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)