funnel: Setting the PROXY_CAPS flag on the srcpad does not make much sense
[platform/upstream/gstreamer.git] / plugins / elements / gstfunnel.c
1 /*
2  * GStreamer Funnel element
3  *
4  * Copyright 2007 Collabora Ltd.
5  *  @author: Olivier Crete <olivier.crete@collabora.co.uk>
6  * Copyright 2007 Nokia Corp.
7  *
8  * gstfunnel.c: Simple Funnel element
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
23  */
24
25 /**
26  * SECTION:element-funnel
27  *
28  * Takes packets from various input sinks into one output source.
29  *
30  * funnel always outputs a single, open ended segment from
31  * 0 with in %GST_FORMAT_TIME and outputs the buffers of the
32  * different sinkpads with timestamps that are set to the
33  * running time for that stream. funnel does not synchronize
34  * the different input streams but simply forwards all buffers
35  * immediately when they arrive.
36  *
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include "gstfunnel.h"
44
45 GST_DEBUG_CATEGORY_STATIC (gst_funnel_debug);
46 #define GST_CAT_DEFAULT gst_funnel_debug
47
48 static GstStaticPadTemplate funnel_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink_%u",
50     GST_PAD_SINK,
51     GST_PAD_REQUEST,
52     GST_STATIC_CAPS_ANY);
53
54 static GstStaticPadTemplate funnel_src_template =
55 GST_STATIC_PAD_TEMPLATE ("src",
56     GST_PAD_SRC,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS_ANY);
59
60 #define _do_init \
61   GST_DEBUG_CATEGORY_INIT (gst_funnel_debug, "funnel", 0, "funnel element");
62 #define gst_funnel_parent_class parent_class
63 G_DEFINE_TYPE_WITH_CODE (GstFunnel, gst_funnel, GST_TYPE_ELEMENT, _do_init);
64
65 static GstPad *gst_funnel_request_new_pad (GstElement * element,
66     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
67 static void gst_funnel_release_pad (GstElement * element, GstPad * pad);
68
69 static GstFlowReturn gst_funnel_sink_chain (GstPad * pad, GstObject * parent,
70     GstBuffer * buffer);
71 static gboolean gst_funnel_sink_event (GstPad * pad, GstObject * parent,
72     GstEvent * event);
73
74 static void
75 gst_funnel_dispose (GObject * object)
76 {
77   GstFunnel *funnel = GST_FUNNEL (object);
78   GList *item;
79
80   gst_object_replace ((GstObject **) & funnel->last_sinkpad, NULL);
81
82 restart:
83   for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
84     GstPad *pad = GST_PAD (item->data);
85
86     if (GST_PAD_IS_SINK (pad)) {
87       gst_element_release_request_pad (GST_ELEMENT (object), pad);
88       goto restart;
89     }
90   }
91
92   G_OBJECT_CLASS (parent_class)->dispose (object);
93 }
94
95 static void
96 gst_funnel_class_init (GstFunnelClass * klass)
97 {
98   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
99   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
100
101   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_funnel_dispose);
102
103   gst_element_class_set_static_metadata (gstelement_class,
104       "Funnel pipe fitting", "Generic", "N-to-1 pipe fitting",
105       "Olivier Crete <olivier.crete@collabora.co.uk>");
106
107   gst_element_class_add_pad_template (gstelement_class,
108       gst_static_pad_template_get (&funnel_sink_template));
109   gst_element_class_add_pad_template (gstelement_class,
110       gst_static_pad_template_get (&funnel_src_template));
111
112   gstelement_class->request_new_pad =
113       GST_DEBUG_FUNCPTR (gst_funnel_request_new_pad);
114   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_funnel_release_pad);
115 }
116
117 static void
118 gst_funnel_init (GstFunnel * funnel)
119 {
120   funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template,
121       "src");
122   gst_pad_use_fixed_caps (funnel->srcpad);
123
124   gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad);
125 }
126
127 static GstPad *
128 gst_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
129     const gchar * name, const GstCaps * caps)
130 {
131   GstPad *sinkpad;
132
133   GST_DEBUG_OBJECT (element, "requesting pad");
134
135   sinkpad = gst_pad_new_from_static_template (&funnel_sink_template, name);
136
137   gst_pad_set_chain_function (sinkpad,
138       GST_DEBUG_FUNCPTR (gst_funnel_sink_chain));
139   gst_pad_set_event_function (sinkpad,
140       GST_DEBUG_FUNCPTR (gst_funnel_sink_event));
141
142   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
143   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
144
145   gst_pad_set_active (sinkpad, TRUE);
146
147   gst_element_add_pad (element, sinkpad);
148
149   return sinkpad;
150 }
151
152 static gboolean
153 gst_funnel_all_sinkpads_eos_unlocked (GstFunnel * funnel)
154 {
155   GstElement *element = GST_ELEMENT_CAST (funnel);
156   GList *item;
157
158   if (element->numsinkpads == 0)
159     return FALSE;
160
161   for (item = element->sinkpads; item != NULL; item = g_list_next (item)) {
162     GstPad *sinkpad = item->data;
163     GstEvent *eos;
164
165     eos = gst_pad_get_sticky_event (sinkpad, GST_EVENT_EOS, 0);
166     if (eos)
167       gst_event_unref (eos);
168
169     if (eos == NULL)
170       return FALSE;
171   }
172
173   return TRUE;
174 }
175
176 static void
177 gst_funnel_release_pad (GstElement * element, GstPad * pad)
178 {
179   GstFunnel *funnel = GST_FUNNEL (element);
180   GstEvent *eos;
181   gboolean send_eos = FALSE;
182
183   GST_DEBUG_OBJECT (funnel, "releasing pad");
184
185   gst_pad_set_active (pad, FALSE);
186
187   eos = gst_pad_get_sticky_event (pad, GST_EVENT_EOS, 0);
188   if (eos)
189     gst_event_unref (eos);
190
191   gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad);
192
193   GST_OBJECT_LOCK (funnel);
194   if (eos == NULL && gst_funnel_all_sinkpads_eos_unlocked (funnel)) {
195     GST_DEBUG_OBJECT (funnel, "Pad removed. All others are EOS. Sending EOS");
196     send_eos = TRUE;
197   }
198   GST_OBJECT_UNLOCK (funnel);
199
200   if (send_eos)
201     if (!gst_pad_push_event (funnel->srcpad, gst_event_new_eos ()))
202       GST_WARNING_OBJECT (funnel, "Failure pushing EOS");
203 }
204
205 static gboolean
206 forward_events (GstPad * pad, GstEvent ** event, gpointer user_data)
207 {
208   GstPad *srcpad = user_data;
209
210   if (GST_EVENT_TYPE (*event) != GST_EVENT_EOS)
211     gst_pad_push_event (srcpad, gst_event_ref (*event));
212
213   return TRUE;
214 }
215
216 static GstFlowReturn
217 gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
218 {
219   GstFlowReturn res;
220   GstFunnel *funnel = GST_FUNNEL (parent);
221
222   GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);
223
224   GST_PAD_STREAM_LOCK (funnel->srcpad);
225
226   if (funnel->last_sinkpad != pad) {
227     gst_object_replace ((GstObject **) & funnel->last_sinkpad,
228         GST_OBJECT (pad));
229
230     gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad);
231   }
232
233   res = gst_pad_push (funnel->srcpad, buffer);
234
235   GST_PAD_STREAM_UNLOCK (funnel->srcpad);
236
237   GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));
238
239   return res;
240 }
241
242 static gboolean
243 gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
244 {
245   GstFunnel *funnel = GST_FUNNEL (parent);
246   gboolean forward = TRUE;
247   gboolean res = TRUE;
248   gboolean unlock = FALSE;
249
250   if (GST_EVENT_IS_STICKY (event)) {
251     unlock = TRUE;
252     GST_PAD_STREAM_LOCK (funnel->srcpad);
253
254     if (pad != funnel->last_sinkpad)
255       forward = FALSE;
256   }
257
258   if (forward)
259     res = gst_pad_push_event (funnel->srcpad, event);
260   else
261     gst_event_unref (event);
262
263   if (unlock)
264     GST_PAD_STREAM_UNLOCK (funnel->srcpad);
265
266   return res;
267 }