gst/gstutils.h: GST_PARENT_CALL and
[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 = GST_ELEMENT_DETAILS (
33   "Aggregator pipe fitting",
34   "Generic",
35   "N-to-1 pipe fitting",
36   "Wim Taymans <wim.taymans@chello.be>"
37 );
38
39 /* Aggregator signals and args */
40 enum {
41   /* FILL ME */
42   LAST_SIGNAL
43 };
44
45 enum {
46   ARG_0,
47   ARG_NUM_PADS,
48   ARG_SILENT,
49   ARG_SCHED,
50   ARG_LAST_MESSAGE,
51   /* FILL ME */
52 };
53
54 GstStaticPadTemplate aggregator_src_template = GST_STATIC_PAD_TEMPLATE (
55   "sink%d",
56   GST_PAD_SINK,
57   GST_PAD_REQUEST,
58   GST_STATIC_CAPS_ANY
59 );
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 = g_enum_register_static ("GstAggregatorSched", aggregator_sched);
74   }
75   return aggregator_sched_type;
76 }
77
78 #define AGGREGATOR_IS_LOOP_BASED(ag)    ((ag)->sched != AGGREGATOR_CHAIN)
79
80 static GstPad*  gst_aggregator_request_new_pad  (GstElement *element, GstPadTemplate *temp, const
81                                                  gchar *unused);
82 static void     gst_aggregator_update_functions (GstAggregator *aggregator);
83
84 static void     gst_aggregator_set_property     (GObject *object, guint prop_id, 
85                                                  const GValue *value, GParamSpec *pspec);
86 static void     gst_aggregator_get_property     (GObject *object, guint prop_id, 
87                                                  GValue *value, GParamSpec *pspec);
88
89 static void     gst_aggregator_chain            (GstPad *pad, GstData *_data);
90 static void     gst_aggregator_loop             (GstElement *element);
91
92 #define _do_init(bla) \
93   GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
94
95 GST_BOILERPLATE_FULL (GstAggregator, gst_aggregator, GstElement, GST_TYPE_ELEMENT, _do_init);
96
97 static void
98 gst_aggregator_base_init (gpointer g_class)
99 {
100   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); 
101   gst_element_class_add_pad_template (gstelement_class,
102       gst_static_pad_template_get (&aggregator_src_template));
103   gst_element_class_set_details (gstelement_class, &gst_aggregator_details);
104 }
105 static void
106 gst_aggregator_class_init (GstAggregatorClass *klass) 
107 {
108   GObjectClass *gobject_class;
109   GstElementClass *gstelement_class;
110
111   gobject_class = (GObjectClass*) klass;
112   gstelement_class = (GstElementClass*) klass;
113
114
115   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
116     g_param_spec_int ("num_pads", "Num pads", "The number of source pads",
117                       0, G_MAXINT, 0, G_PARAM_READABLE)); 
118   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
119     g_param_spec_boolean ("silent", "Silent", "Don't produce messages",
120                       FALSE, G_PARAM_READWRITE)); 
121   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
122     g_param_spec_enum ("sched", "Scheduling", "The type of scheduling this element should use",
123                       GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE)); 
124   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
125     g_param_spec_string ("last_message", "Last message", "The current state of the element",
126                          NULL, G_PARAM_READABLE));
127
128   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_aggregator_set_property);
129   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_aggregator_get_property);
130
131   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_aggregator_request_new_pad);
132 }
133
134 static void 
135 gst_aggregator_init (GstAggregator *aggregator) 
136 {
137   aggregator->srcpad = gst_pad_new ("src", GST_PAD_SRC);
138   gst_pad_set_getcaps_function (aggregator->srcpad, gst_pad_proxy_getcaps);
139   gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
140
141   aggregator->numsinkpads = 0;
142   aggregator->sinkpads = NULL;
143   aggregator->silent = FALSE;
144   aggregator->sched = AGGREGATOR_LOOP;
145
146   gst_aggregator_update_functions (aggregator);
147 }
148
149 static GstPad*
150 gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) 
151 {
152   gchar *name;
153   GstPad *sinkpad;
154   GstAggregator *aggregator;
155
156   g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
157
158   if (templ->direction != GST_PAD_SINK) {
159     g_warning ("gstaggregator: request new pad that is not a sink pad\n");
160     return NULL;
161   }
162
163   aggregator = GST_AGGREGATOR (element);
164
165   name = g_strdup_printf ("sink%d",aggregator->numsinkpads);
166   
167   sinkpad = gst_pad_new_from_template (templ, name);
168   g_free (name);
169   
170   if (!AGGREGATOR_IS_LOOP_BASED (aggregator)) {
171     gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
172   }
173   gst_pad_set_getcaps_function (sinkpad, gst_pad_proxy_getcaps);
174   gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
175   
176   aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
177   aggregator->numsinkpads++;
178   
179   return sinkpad;
180 }
181
182 static void
183 gst_aggregator_update_functions (GstAggregator *aggregator)
184 {
185   GList *pads;
186
187   if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
188     gst_element_set_loop_function (GST_ELEMENT (aggregator), GST_DEBUG_FUNCPTR (gst_aggregator_loop));
189   }
190   else {
191     gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
192   }
193
194   pads = aggregator->sinkpads;
195   while (pads) {
196     GstPad *pad = GST_PAD (pads->data);
197                           
198     if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
199       gst_pad_set_get_function (pad, NULL);
200     }
201     else {
202       gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
203     }
204     pads = g_list_next (pads);
205   }
206 }
207
208 static void
209 gst_aggregator_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
210 {
211   GstAggregator *aggregator;
212
213   /* it's not null if we got it, but it might not be ours */
214   g_return_if_fail (GST_IS_AGGREGATOR (object));
215
216   aggregator = GST_AGGREGATOR (object);
217
218   switch (prop_id) {
219     case ARG_SILENT:
220       aggregator->silent = g_value_get_boolean (value);
221       break;
222     case ARG_SCHED:
223       aggregator->sched = g_value_get_enum (value);
224       gst_aggregator_update_functions (aggregator);
225       break;
226     default:
227       break;
228   }
229 }
230
231 static void
232 gst_aggregator_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
233 {
234   GstAggregator *aggregator;
235
236   /* it's not null if we got it, but it might not be ours */
237   g_return_if_fail (GST_IS_AGGREGATOR (object));
238
239   aggregator = GST_AGGREGATOR (object);
240
241   switch (prop_id) {
242     case ARG_NUM_PADS:
243       g_value_set_int (value, aggregator->numsinkpads);
244       break;
245     case ARG_SILENT:
246       g_value_set_boolean (value, aggregator->silent);
247       break;
248     case ARG_SCHED:
249       g_value_set_enum (value, aggregator->sched);
250       break;
251     case ARG_LAST_MESSAGE:
252       g_value_set_string (value, aggregator->last_message);
253       break;
254     default:
255       break;
256   }
257 }
258
259 static void 
260 gst_aggregator_push (GstAggregator *aggregator, GstPad *pad, GstBuffer *buf, guchar *debug) 
261 {
262   if (!aggregator->silent) {
263     g_free (aggregator->last_message);
264
265     aggregator->last_message = g_strdup_printf ("%10.10s ******* (%s:%s)a (%d bytes, %"
266                                                 G_GUINT64_FORMAT ")",
267             debug, GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
268
269     g_object_notify (G_OBJECT (aggregator), "last_message");
270   }
271
272   gst_pad_push (aggregator->srcpad, GST_DATA (buf));
273 }
274
275 static void 
276 gst_aggregator_loop (GstElement *element) 
277 {
278   GstAggregator *aggregator;
279   GstBuffer *buf;
280   guchar *debug;
281
282   aggregator = GST_AGGREGATOR (element);
283
284   if (aggregator->sched == AGGREGATOR_LOOP) {
285     GList *pads = aggregator->sinkpads;
286
287     /* we'll loop over all pads and try to pull from all
288      * active ones */
289     while (pads) {
290       GstPad *pad = GST_PAD (pads->data);
291       pads = g_list_next (pads);
292
293       /* we need to check is the pad is usable. IS_USABLE will check
294        * if the pad is linked, if it is enabled (the element is
295        * playing and the app didn't gst_pad_set_enabled (pad, FALSE))
296        * and that the peer pad is also enabled.
297        */
298       if (GST_PAD_IS_USABLE (pad)) {
299         buf = GST_BUFFER (gst_pad_pull (pad));
300         debug = "loop";
301
302         /* then push it forward */
303         gst_aggregator_push (aggregator, pad, buf, debug);
304       }
305     }
306   }
307   else {
308     if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
309       GstPad *pad;
310
311       debug = "loop_select";
312
313       pad = gst_pad_selectv (aggregator->sinkpads);
314       buf = GST_BUFFER (gst_pad_pull (pad));
315
316       gst_aggregator_push (aggregator, pad, buf, debug);
317     }
318     else {
319       g_assert_not_reached ();
320     }
321   }
322 }
323
324 /**
325  * gst_aggregator_chain:
326  * @pad: the pad to follow
327  * @buf: the buffer to pass
328  *
329  * Chain a buffer on a pad.
330  */
331 static void 
332 gst_aggregator_chain (GstPad *pad, GstData *_data) 
333 {
334   GstBuffer *buf = GST_BUFFER (_data);
335   GstAggregator *aggregator;
336
337   g_return_if_fail (pad != NULL);
338   g_return_if_fail (GST_IS_PAD (pad));
339   g_return_if_fail (buf != NULL);
340
341   aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
342 /*  gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
343
344   gst_aggregator_push (aggregator, pad, buf, "chain");
345 }
346