merge from EVENTS1 on 20011016
[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 }
152
153 static GstPad*
154 gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) 
155 {
156   gchar *name;
157   GstPad *sinkpad;
158   GstAggregator *aggregator;
159
160   g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
161
162   if (templ->direction != GST_PAD_SINK) {
163     g_warning ("gstaggregator: request new pad that is not a SRC pad\n");
164     return NULL;
165   }
166
167   aggregator = GST_AGGREGATOR (element);
168
169   name = g_strdup_printf ("sink%d",aggregator->numsinkpads);
170   
171   sinkpad = gst_pad_new_from_template (templ, name);
172   gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
173   gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
174   
175   aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
176   aggregator->numsinkpads++;
177   
178   return sinkpad;
179 }
180
181 static void
182 gst_aggregator_update_functions (GstAggregator *aggregator)
183 {
184   GList *pads;
185
186   if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
187     gst_element_set_loop_function (GST_ELEMENT (aggregator), GST_DEBUG_FUNCPTR (gst_aggregator_loop));
188   }
189   else {
190     gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
191   }
192
193   pads = aggregator->sinkpads;
194   while (pads) {
195     GstPad *pad = GST_PAD (pads->data);
196                           
197     if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
198       gst_pad_set_get_function (pad, NULL);
199     }
200     else {
201       gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
202     }
203     pads = g_list_next (pads);
204   }
205 }
206
207 static void
208 gst_aggregator_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
209 {
210   GstAggregator *aggregator;
211
212   /* it's not null if we got it, but it might not be ours */
213   g_return_if_fail (GST_IS_AGGREGATOR (object));
214
215   aggregator = GST_AGGREGATOR (object);
216
217   switch (prop_id) {
218     case ARG_SILENT:
219       aggregator->silent = g_value_get_boolean (value);
220       break;
221     case ARG_SCHED:
222       aggregator->sched = g_value_get_enum (value);
223       gst_aggregator_update_functions (aggregator);
224       break;
225     default:
226       break;
227   }
228 }
229
230 static void
231 gst_aggregator_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
232 {
233   GstAggregator *aggregator;
234
235   /* it's not null if we got it, but it might not be ours */
236   g_return_if_fail (GST_IS_AGGREGATOR (object));
237
238   aggregator = GST_AGGREGATOR (object);
239
240   switch (prop_id) {
241     case ARG_NUM_PADS:
242       g_value_set_int (value, aggregator->numsinkpads);
243       break;
244     case ARG_SILENT:
245       g_value_set_boolean (value, aggregator->silent);
246       break;
247     case ARG_SCHED:
248       g_value_set_enum (value, aggregator->sched);
249       break;
250     default:
251       break;
252   }
253 }
254
255 static void 
256 gst_aggregator_push (GstAggregator *aggregator, GstPad *pad, GstBuffer *buf, guchar *debug) 
257 {
258   if (!aggregator->silent)
259     g_print("aggregator: %10.10s ******* (%s:%s)a (%d bytes, %llu) \n",
260             debug, GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
261
262   gst_pad_push (aggregator->srcpad, buf);
263 }
264
265 static void 
266 gst_aggregator_loop (GstElement *element) 
267 {
268   GstAggregator *aggregator;
269   GstBuffer *buf;
270   guchar *debug;
271
272   aggregator = GST_AGGREGATOR (element);
273
274   do {
275     if (aggregator->sched == AGGREGATOR_LOOP ||
276         aggregator->sched == AGGREGATOR_LOOP_PEEK) {
277       GList *pads = aggregator->sinkpads;
278
279       while (pads) {
280         GstPad *pad = GST_PAD (pads->data);
281         pads = g_list_next (pads);
282
283         if (aggregator->sched == AGGREGATOR_LOOP_PEEK) {
284           buf = gst_pad_peek (pad);
285           if (buf == NULL)
286             continue;
287
288           g_assert (buf == gst_pad_pull (pad));
289           debug = "loop_peek";
290         }
291         else {
292           buf = gst_pad_pull (pad);
293           debug = "loop";
294         }
295         gst_aggregator_push (aggregator, pad, buf, debug);
296       }
297     }
298     else {
299       if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
300         GstPad *pad;
301
302         debug = "loop_select";
303
304         pad = gst_pad_select (aggregator->sinkpads);
305         buf = gst_pad_pull (pad);
306
307         gst_aggregator_push (aggregator, pad, buf, debug);
308       }
309       else {
310         g_assert_not_reached ();
311       }
312     }
313   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
314 }
315
316 /**
317  * gst_aggregator_chain:
318  * @pad: the pad to follow
319  * @buf: the buffer to pass
320  *
321  * Chain a buffer on a pad.
322  */
323 static void 
324 gst_aggregator_chain (GstPad *pad, GstBuffer *buf) 
325 {
326   GstAggregator *aggregator;
327
328   g_return_if_fail (pad != NULL);
329   g_return_if_fail (GST_IS_PAD (pad));
330   g_return_if_fail (buf != NULL);
331
332   aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
333 //  gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");
334
335   gst_aggregator_push (aggregator, pad, buf, "chain");
336 }
337
338 gboolean
339 gst_aggregator_factory_init (GstElementFactory *factory)
340 {
341   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (aggregator_src_factory));
342
343   return TRUE;
344 }
345