more of the popular // fixes
[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 #include "gstaggregator.h"
24
25
26 GstElementDetails gst_aggregator_details = {
27   "Aggregator pipe fitting",
28   "Aggregator",
29   "N-to-1 pipe fitting",
30   VERSION,
31   "Wim Taymans <wim.taymans@chello.be>",
32   "(C) 2001",
33 };
34
35 /* Aggregator signals and args */
36 enum {
37   /* FILL ME */
38   LAST_SIGNAL
39 };
40
41 enum {
42   ARG_0,
43   ARG_NUM_PADS,
44   ARG_SILENT,
45   ARG_SCHED,
46   /* FILL ME */
47 };
48
49 GST_PADTEMPLATE_FACTORY (aggregator_src_factory,
50   "sink%d",
51   GST_PAD_SINK,
52   GST_PAD_REQUEST,
53   NULL                  /* no caps */
54 );
55
56 #define GST_TYPE_AGGREGATOR_SCHED (gst_aggregator_sched_get_type())
57 static GType
58 gst_aggregator_sched_get_type (void)
59 {
60   static GType aggregator_sched_type = 0;
61   static GEnumValue aggregator_sched[] = {
62     { AGGREGATOR_LOOP,          "1", "Loop Based"},
63     { AGGREGATOR_LOOP_PEEK,     "2", "Loop Based Peek"},
64     { AGGREGATOR_LOOP_SELECT,   "3", "Loop Based Select"},
65     { AGGREGATOR_CHAIN,         "4", "Chain Based"},
66     {0, NULL, NULL},
67   };
68   if (!aggregator_sched_type) {
69     aggregator_sched_type = g_enum_register_static ("GstAggregatorSched", aggregator_sched);
70   }
71   return aggregator_sched_type;
72 }
73
74 #define AGGREGATOR_IS_LOOP_BASED(ag)    ((ag)->sched != AGGREGATOR_CHAIN)
75
76 static void     gst_aggregator_class_init       (GstAggregatorClass *klass);
77 static void     gst_aggregator_init             (GstAggregator *aggregator);
78
79 static GstPad*  gst_aggregator_request_new_pad  (GstElement *element, GstPadTemplate *temp, const
80                                                  gchar *unused);
81
82 static void     gst_aggregator_set_property     (GObject *object, guint prop_id, 
83                                                  const GValue *value, GParamSpec *pspec);
84 static void     gst_aggregator_get_property     (GObject *object, guint prop_id, 
85                                                  GValue *value, GParamSpec *pspec);
86
87 static void     gst_aggregator_chain            (GstPad *pad, GstBuffer *buf);
88 static void     gst_aggregator_loop             (GstElement *element);
89
90 static GstElementClass *parent_class = NULL;
91 /*static guint gst_aggregator_signals[LAST_SIGNAL] = { 0 };*/
92
93 GType
94 gst_aggregator_get_type (void) 
95 {
96   static GType aggregator_type = 0;
97
98   if (!aggregator_type) {
99     static const GTypeInfo aggregator_info = {
100       sizeof(GstAggregatorClass),      
101       NULL,
102       NULL,
103       (GClassInitFunc)gst_aggregator_class_init,
104       NULL,
105       NULL,
106       sizeof(GstAggregator),
107       0,
108       (GInstanceInitFunc)gst_aggregator_init,
109     };
110     aggregator_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAggregator", &aggregator_info, 0);
111   }
112   return aggregator_type;
113 }
114
115 static void
116 gst_aggregator_class_init (GstAggregatorClass *klass) 
117 {
118   GObjectClass *gobject_class;
119   GstElementClass *gstelement_class;
120
121   gobject_class = (GObjectClass*) klass;
122   gstelement_class = (GstElementClass*) klass;
123
124   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
125
126   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
127     g_param_spec_int ("num_pads", "num_pads", "num_pads",
128                       0, G_MAXINT, 0, G_PARAM_READABLE)); 
129   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
130     g_param_spec_boolean ("silent", "silent", "silent",
131                       FALSE, G_PARAM_READWRITE)); 
132   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
133     g_param_spec_enum ("sched", "sched", "sched",
134                       GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE)); 
135
136   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_aggregator_set_property);
137   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_aggregator_get_property);
138
139   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_aggregator_request_new_pad);
140 }
141
142 static void 
143 gst_aggregator_init (GstAggregator *aggregator) 
144 {
145   aggregator->srcpad = gst_pad_new ("src", GST_PAD_SRC);
146   gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
147
148   aggregator->numsinkpads = 0;
149   aggregator->sinkpads = NULL;
150   aggregator->silent = FALSE;
151   aggregator->sched = AGGREGATOR_LOOP;
152 }
153
154 static GstPad*
155 gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) 
156 {
157   gchar *name;
158   GstPad *sinkpad;
159   GstAggregator *aggregator;
160
161   g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
162
163   if (templ->direction != GST_PAD_SINK) {
164     g_warning ("gstaggregator: request new pad that is not a SRC pad\n");
165     return NULL;
166   }
167
168   aggregator = GST_AGGREGATOR (element);
169
170   name = g_strdup_printf ("sink%d",aggregator->numsinkpads);
171   
172   sinkpad = gst_pad_new_from_template (templ, name);
173   gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
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     default:
252       break;
253   }
254 }
255
256 static void 
257 gst_aggregator_push (GstAggregator *aggregator, GstPad *pad, GstBuffer *buf, guchar *debug) 
258 {
259   if (!aggregator->silent)
260     g_print("aggregator: %10.10s ******* (%s:%s)a (%d bytes, %llu) \n",
261             debug, GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
262
263   gst_pad_push (aggregator->srcpad, buf);
264 }
265
266 static void 
267 gst_aggregator_loop (GstElement *element) 
268 {
269   GstAggregator *aggregator;
270   GstBuffer *buf;
271   guchar *debug;
272
273   aggregator = GST_AGGREGATOR (element);
274
275   do {
276     if (aggregator->sched == AGGREGATOR_LOOP ||
277         aggregator->sched == AGGREGATOR_LOOP_PEEK) {
278       GList *pads = aggregator->sinkpads;
279
280       while (pads) {
281         GstPad *pad = GST_PAD (pads->data);
282         pads = g_list_next (pads);
283
284         if (aggregator->sched == AGGREGATOR_LOOP_PEEK) {
285           buf = gst_pad_peek (pad);
286           if (buf == NULL)
287             continue;
288
289           g_assert (buf == gst_pad_pull (pad));
290           debug = "loop_peek";
291         }
292         else {
293           buf = gst_pad_pull (pad);
294           debug = "loop";
295         }
296         gst_aggregator_push (aggregator, pad, buf, debug);
297       }
298     }
299     else {
300       if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
301         GstPad *pad;
302
303         debug = "loop_select";
304
305         pad = gst_pad_select (aggregator->sinkpads);
306         buf = gst_pad_pull (pad);
307
308         gst_aggregator_push (aggregator, pad, buf, debug);
309       }
310       else {
311         g_assert_not_reached ();
312       }
313     }
314   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
315 }
316
317 /**
318  * gst_aggregator_chain:
319  * @pad: the pad to follow
320  * @buf: the buffer to pass
321  *
322  * Chain a buffer on a pad.
323  */
324 static void 
325 gst_aggregator_chain (GstPad *pad, GstBuffer *buf) 
326 {
327   GstAggregator *aggregator;
328
329   g_return_if_fail (pad != NULL);
330   g_return_if_fail (GST_IS_PAD (pad));
331   g_return_if_fail (buf != NULL);
332
333   aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
334 /*  gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
335
336   gst_aggregator_push (aggregator, pad, buf, "chain");
337 }
338
339 gboolean
340 gst_aggregator_factory_init (GstElementFactory *factory)
341 {
342   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (aggregator_src_factory));
343
344   return TRUE;
345 }
346