gst-indent run on core
[platform/upstream/gstreamer.git] / gst / elements / gstaggregator.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstaggregator.c: Aggregator element, N in 1 out
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include "gstaggregator.h"
28
29 GST_DEBUG_CATEGORY_STATIC (gst_aggregator_debug);
30 #define GST_CAT_DEFAULT gst_aggregator_debug
31
32 GstElementDetails gst_aggregator_details =
33 GST_ELEMENT_DETAILS ("Aggregator pipe fitting",
34     "Generic",
35     "N-to-1 pipe fitting",
36     "Wim Taymans <wim.taymans@chello.be>");
37
38 /* Aggregator signals and args */
39 enum
40 {
41   /* FILL ME */
42   LAST_SIGNAL
43 };
44
45 enum
46 {
47   ARG_0,
48   ARG_NUM_PADS,
49   ARG_SILENT,
50   ARG_SCHED,
51   ARG_LAST_MESSAGE,
52   /* FILL ME */
53 };
54
55 GstStaticPadTemplate aggregator_src_template =
56 GST_STATIC_PAD_TEMPLATE ("sink%d",
57     GST_PAD_SINK,
58     GST_PAD_REQUEST,
59     GST_STATIC_CAPS_ANY);
60
61 #define GST_TYPE_AGGREGATOR_SCHED (gst_aggregator_sched_get_type())
62 static GType
63 gst_aggregator_sched_get_type (void)
64 {
65   static GType aggregator_sched_type = 0;
66   static GEnumValue aggregator_sched[] = {
67     {AGGREGATOR_LOOP, "1", "Loop Based"},
68     {AGGREGATOR_LOOP_SELECT, "3", "Loop Based Select"},
69     {AGGREGATOR_CHAIN, "4", "Chain Based"},
70     {0, NULL, NULL},
71   };
72   if (!aggregator_sched_type) {
73     aggregator_sched_type =
74         g_enum_register_static ("GstAggregatorSched", aggregator_sched);
75   }
76   return aggregator_sched_type;
77 }
78
79 #define AGGREGATOR_IS_LOOP_BASED(ag)    ((ag)->sched != AGGREGATOR_CHAIN)
80
81 static GstPad *gst_aggregator_request_new_pad (GstElement * element,
82     GstPadTemplate * temp, const gchar * unused);
83 static void gst_aggregator_update_functions (GstAggregator * aggregator);
84
85 static void gst_aggregator_set_property (GObject * object, guint prop_id,
86     const GValue * value, GParamSpec * pspec);
87 static void gst_aggregator_get_property (GObject * object, guint prop_id,
88     GValue * value, GParamSpec * pspec);
89
90 static void gst_aggregator_chain (GstPad * pad, GstData * _data);
91 static void gst_aggregator_loop (GstElement * element);
92
93 #define _do_init(bla) \
94   GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
95
96 GST_BOILERPLATE_FULL (GstAggregator, gst_aggregator, GstElement,
97     GST_TYPE_ELEMENT, _do_init);
98
99 static void
100 gst_aggregator_base_init (gpointer g_class)
101 {
102   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
103
104   gst_element_class_add_pad_template (gstelement_class,
105       gst_static_pad_template_get (&aggregator_src_template));
106   gst_element_class_set_details (gstelement_class, &gst_aggregator_details);
107 }
108 static void
109 gst_aggregator_class_init (GstAggregatorClass * klass)
110 {
111   GObjectClass *gobject_class;
112   GstElementClass *gstelement_class;
113
114   gobject_class = (GObjectClass *) klass;
115   gstelement_class = (GstElementClass *) klass;
116
117
118   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
119       g_param_spec_int ("num_pads", "Num pads", "The number of source pads",
120           0, G_MAXINT, 0, G_PARAM_READABLE));
121   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
122       g_param_spec_boolean ("silent", "Silent", "Don't produce messages",
123           FALSE, G_PARAM_READWRITE));
124   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
125       g_param_spec_enum ("sched", "Scheduling",
126           "The type of scheduling this element should use",
127           GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE));
128   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
129       g_param_spec_string ("last_message", "Last message",
130           "The current state of the element", NULL, G_PARAM_READABLE));
131
132   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
133   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
134
135   gstelement_class->request_new_pad =
136       GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);
137 }
138
139 static void
140 gst_aggregator_init (GstAggregator * aggregator)
141 {
142   aggregator->srcpad = gst_pad_new ("src", GST_PAD_SRC);
143   gst_pad_set_getcaps_function (aggregator->srcpad, gst_pad_proxy_getcaps);
144   gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
145
146   aggregator->numsinkpads = 0;
147   aggregator->sinkpads = NULL;
148   aggregator->silent = FALSE;
149   aggregator->sched = AGGREGATOR_LOOP;
150
151   gst_aggregator_update_functions (aggregator);
152 }
153
154 static GstPad *
155 gst_aggregator_request_new_pad (GstElement * element, GstPadTemplate * templ,
156     const gchar * unused)
157 {
158   gchar *name;
159   GstPad *sinkpad;
160   GstAggregator *aggregator;
161
162   g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
163
164   if (templ->direction != GST_PAD_SINK) {
165     g_warning ("gstaggregator: request new pad that is not a sink pad\n");
166     return NULL;
167   }
168
169   aggregator = GST_AGGREGATOR (element);
170
171   name = g_strdup_printf ("sink%d", aggregator->numsinkpads);
172
173   sinkpad = gst_pad_new_from_template (templ, name);
174   g_free (name);
175
176   if (!AGGREGATOR_IS_LOOP_BASED (aggregator)) {
177     gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
178   }
179   gst_pad_set_getcaps_function (sinkpad, gst_pad_proxy_getcaps);
180   gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
181
182   aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
183   aggregator->numsinkpads++;
184
185   return sinkpad;
186 }
187
188 static void
189 gst_aggregator_update_functions (GstAggregator * aggregator)
190 {
191   GList *pads;
192
193   if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
194     gst_element_set_loop_function (GST_ELEMENT (aggregator),
195         GST_DEBUG_FUNCPTR (gst_aggregator_loop));
196   } else {
197     gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
198   }
199
200   pads = aggregator->sinkpads;
201   while (pads) {
202     GstPad *pad = GST_PAD (pads->data);
203
204     if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
205       gst_pad_set_get_function (pad, NULL);
206     } else {
207       gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
208     }
209     pads = g_list_next (pads);
210   }
211 }
212
213 static void
214 gst_aggregator_set_property (GObject * object, guint prop_id,
215     const GValue * value, GParamSpec * pspec)
216 {
217   GstAggregator *aggregator;
218
219   /* it's not null if we got it, but it might not be ours */
220   g_return_if_fail (GST_IS_AGGREGATOR (object));
221
222   aggregator = GST_AGGREGATOR (object);
223
224   switch (prop_id) {
225     case ARG_SILENT:
226       aggregator->silent = g_value_get_boolean (value);
227       break;
228     case ARG_SCHED:
229       aggregator->sched = g_value_get_enum (value);
230       gst_aggregator_update_functions (aggregator);
231       break;
232     default:
233       break;
234   }
235 }
236
237 static void
238 gst_aggregator_get_property (GObject * object, guint prop_id, GValue * value,
239     GParamSpec * pspec)
240 {
241   GstAggregator *aggregator;
242
243   /* it's not null if we got it, but it might not be ours */
244   g_return_if_fail (GST_IS_AGGREGATOR (object));
245
246   aggregator = GST_AGGREGATOR (object);
247
248   switch (prop_id) {
249     case ARG_NUM_PADS:
250       g_value_set_int (value, aggregator->numsinkpads);
251       break;
252     case ARG_SILENT:
253       g_value_set_boolean (value, aggregator->silent);
254       break;
255     case ARG_SCHED:
256       g_value_set_enum (value, aggregator->sched);
257       break;
258     case ARG_LAST_MESSAGE:
259       g_value_set_string (value, aggregator->last_message);
260       break;
261     default:
262       break;
263   }
264 }
265
266 static void
267 gst_aggregator_push (GstAggregator * aggregator, GstPad * pad, GstBuffer * buf,
268     guchar * debug)
269 {
270   if (!aggregator->silent) {
271     g_free (aggregator->last_message);
272
273     aggregator->last_message =
274         g_strdup_printf ("%10.10s ******* (%s:%s)a (%d bytes, %"
275         G_GUINT64_FORMAT ")", debug, GST_DEBUG_PAD_NAME (pad),
276         GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
277
278     g_object_notify (G_OBJECT (aggregator), "last_message");
279   }
280
281   gst_pad_push (aggregator->srcpad, GST_DATA (buf));
282 }
283
284 static void
285 gst_aggregator_loop (GstElement * element)
286 {
287   GstAggregator *aggregator;
288   GstBuffer *buf;
289   guchar *debug;
290
291   aggregator = GST_AGGREGATOR (element);
292
293   if (aggregator->sched == AGGREGATOR_LOOP) {
294     GList *pads = aggregator->sinkpads;
295
296     /* we'll loop over all pads and try to pull from all
297      * active ones */
298     while (pads) {
299       GstPad *pad = GST_PAD (pads->data);
300
301       pads = g_list_next (pads);
302
303       /* we need to check is the pad is usable. IS_USABLE will check
304        * if the pad is linked, if it is enabled (the element is
305        * playing and the app didn't gst_pad_set_enabled (pad, FALSE))
306        * and that the peer pad is also enabled.
307        */
308       if (GST_PAD_IS_USABLE (pad)) {
309         buf = GST_BUFFER (gst_pad_pull (pad));
310         debug = "loop";
311
312         /* then push it forward */
313         gst_aggregator_push (aggregator, pad, buf, debug);
314       }
315     }
316   } else {
317     if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
318       GstPad *pad;
319
320       debug = "loop_select";
321
322       pad = gst_pad_selectv (aggregator->sinkpads);
323       buf = GST_BUFFER (gst_pad_pull (pad));
324
325       gst_aggregator_push (aggregator, pad, buf, debug);
326     } else {
327       g_assert_not_reached ();
328     }
329   }
330 }
331
332 /**
333  * gst_aggregator_chain:
334  * @pad: the pad to follow
335  * @buf: the buffer to pass
336  *
337  * Chain a buffer on a pad.
338  */
339 static void
340 gst_aggregator_chain (GstPad * pad, GstData * _data)
341 {
342   GstBuffer *buf = GST_BUFFER (_data);
343   GstAggregator *aggregator;
344
345   g_return_if_fail (pad != NULL);
346   g_return_if_fail (GST_IS_PAD (pad));
347   g_return_if_fail (buf != NULL);
348
349   aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
350 /*  gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
351
352   gst_aggregator_push (aggregator, pad, buf, "chain");
353 }