GST_DEBUG reorganization containing loads of stuff:
[platform/upstream/gstreamer.git] / gst / elements / gsttee.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gsttee.c: Tee element, one in N 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 "gsttee.h"
28
29 GST_DEBUG_CATEGORY (gst_tee_debug);
30 #define GST_CAT_DEFAULT gst_tee_debug
31
32 GstElementDetails gst_tee_details = {
33   "Tee pipe fitting",
34   "Generic",
35   "LGPL",
36   "1-to-N pipe fitting",
37   VERSION,
38   "Erik Walthinsen <omega@cse.ogi.edu>\n"
39   "Wim Taymans <wim.taymans@chello.be>",
40   "(C) 1999, 2000",
41 };
42
43 /* Tee signals and args */
44 enum {
45   /* FILL ME */
46   LAST_SIGNAL
47 };
48
49 enum {
50   ARG_0,
51   ARG_SILENT,
52   ARG_NUM_PADS,
53   ARG_LAST_MESSAGE,
54   /* FILL ME */
55 };
56
57 GST_PAD_TEMPLATE_FACTORY (tee_src_factory,
58   "src%d",
59   GST_PAD_SRC,
60   GST_PAD_REQUEST,
61   NULL                  /* no caps */
62 );
63
64 static void     gst_tee_class_init      (GstTeeClass *klass);
65 static void     gst_tee_init            (GstTee *tee);
66
67 static GstPad*  gst_tee_request_new_pad (GstElement *element, GstPadTemplate *temp, const gchar *unused);
68
69 static void     gst_tee_set_property    (GObject *object, guint prop_id, 
70                                          const GValue *value, GParamSpec *pspec);
71 static void     gst_tee_get_property    (GObject *object, guint prop_id, 
72                                          GValue *value, GParamSpec *pspec);
73
74 static void     gst_tee_chain           (GstPad *pad, GstBuffer *buf);
75
76
77 static GstElementClass *parent_class = NULL;
78 /*static guint gst_tee_signals[LAST_SIGNAL] = { 0 };*/
79
80 GType
81 gst_tee_get_type(void) {
82   static GType tee_type = 0;
83
84   if (!tee_type) {
85     static const GTypeInfo tee_info = {
86       sizeof(GstTeeClass),      NULL,
87       NULL,
88       (GClassInitFunc)gst_tee_class_init,
89       NULL,
90       NULL,
91       sizeof(GstTee),
92       0,
93       (GInstanceInitFunc)gst_tee_init,
94     };
95     tee_type = g_type_register_static (GST_TYPE_ELEMENT, "GstTee", &tee_info, 0);
96   }
97   return tee_type;
98 }
99
100 static void
101 gst_tee_class_init (GstTeeClass *klass) 
102 {
103   GObjectClass *gobject_class;
104   GstElementClass *gstelement_class;
105
106   gobject_class = (GObjectClass*)klass;
107   gstelement_class = (GstElementClass*)klass;
108
109   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
110
111   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
112     g_param_spec_int ("num_pads", "num_pads", "num_pads",
113                       0, G_MAXINT, 0, G_PARAM_READABLE)); 
114   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
115     g_param_spec_boolean ("silent", "silent", "silent",
116                       FALSE, G_PARAM_READWRITE));
117   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
118     g_param_spec_string ("last_message", "last_message", "last_message",
119                          NULL, G_PARAM_READABLE));
120   
121
122   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_tee_set_property);
123   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_tee_get_property);
124
125   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_tee_request_new_pad);
126 }
127
128 static GstPadLinkReturn 
129 gst_tee_sinklink (GstPad *pad, GstCaps *caps) 
130 {
131   GstTee *tee;
132   const GList *pads;
133   GstPadLinkReturn set_retval;
134   GstCaps *caps1;
135   
136   GST_DEBUG ( "gst_tee_sinklink caps=%s", gst_caps_to_string(caps));
137
138   tee = GST_TEE (gst_pad_get_parent (pad));
139
140   if (!GST_CAPS_IS_FIXED (caps)) {
141     return GST_PAD_LINK_DELAYED;
142   }
143
144   if (GST_CAPS_IS_CHAINED (caps)) {
145     caps1 = gst_caps_copy_1(caps);
146     caps = caps1;
147   }
148
149   /* go through all the src pads */
150   pads = gst_element_get_pad_list (GST_ELEMENT (tee));
151
152   while (pads) {
153     GstPad *outpad = GST_PAD (pads->data);
154     pads = g_list_next (pads);
155                      
156     if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC || !GST_PAD_IS_LINKED (outpad))
157       continue;
158
159     if ((set_retval = gst_pad_try_set_caps (outpad, caps)) <= 0) {
160       return set_retval;
161     }
162   }
163   return GST_PAD_LINK_OK;
164 }
165
166 static GstPadLinkReturn 
167 gst_tee_srclink (GstPad *pad, GstCaps *caps) 
168 {
169   GstTee *tee;
170
171   GST_DEBUG ( "gst_tee_srclink caps=%s", gst_caps_to_string(caps));
172
173   tee = GST_TEE (gst_pad_get_parent (pad));
174
175   return gst_pad_proxy_link (tee->sinkpad, caps);
176 }
177
178 static GstCaps* 
179 gst_tee_getcaps (GstPad *pad, GstCaps *filter) 
180 {
181   GstCaps *caps = NULL;
182   GstTee *tee;
183   const GList *pads;
184
185   GST_DEBUG ( "gst_tee_getcaps");
186
187   tee = GST_TEE (gst_pad_get_parent (pad));
188
189   pads = gst_element_get_pad_list (GST_ELEMENT (tee));
190
191   while (pads) {
192     GstPad *srcpad = GST_PAD_CAST (pads->data);
193     GstPad *peer;
194     GstCaps *peercaps;
195     GstCaps *newcaps;
196
197     pads = g_list_next (pads);
198
199     peer = gst_pad_get_peer(srcpad);
200     if(!peer){
201       continue;
202     }
203
204     peercaps = gst_pad_get_caps (peer);
205     newcaps = gst_caps_intersect (caps, peercaps);
206     gst_caps_unref (caps);
207     gst_caps_sink (peercaps);
208     caps = newcaps;
209   }
210
211   return caps;
212 }
213
214 static void 
215 gst_tee_init (GstTee *tee) 
216 {
217   tee->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
218   gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
219   gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
220   gst_pad_set_link_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_sinklink));
221   gst_pad_set_getcaps_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_getcaps));
222
223   tee->silent = FALSE;
224   tee->last_message = NULL;
225 }
226
227 /* helper compare function */
228 gint name_pad_compare (gconstpointer a, gconstpointer b)
229 {
230   GstPad* pad = (GstPad*) a;
231   gchar *name = (gchar *) b;
232   
233   g_assert (GST_IS_PAD (pad));
234
235   return g_strcasecmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
236 }
237
238 static GstPad*
239 gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) 
240 {
241   gchar *name;
242   GstPad *srcpad;
243   GstTee *tee;
244   gint i = 0;
245   const GList *pads;
246
247   g_return_val_if_fail (GST_IS_TEE (element), NULL);
248   
249   if (templ->direction != GST_PAD_SRC) {
250     g_warning ("gsttee: request new pad that is not a SRC pad\n");
251     return NULL;
252   }
253
254   tee = GST_TEE (element);
255
256   /* try names in order and find one that's not in use atm */
257   pads = gst_element_get_pad_list (element);
258     
259   name = NULL;
260   while (!name)
261   {
262     name = g_strdup_printf ("src%d", i);
263     if (g_list_find_custom ((GList *)pads, (gconstpointer) name, name_pad_compare) != NULL)
264     {
265       /* this name is taken, use the next one */
266       ++i;
267       g_free (name);
268       name = NULL;
269     }
270   }
271   if (!tee->silent) {
272     g_free (tee->last_message);
273     tee->last_message = g_strdup_printf ("new pad %s", name);
274     g_object_notify (G_OBJECT (tee), "last_message");
275   }
276   
277   srcpad = gst_pad_new_from_template (templ, name);
278   g_free (name);
279   gst_pad_set_link_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_srclink));
280   gst_pad_set_getcaps_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_getcaps));
281   gst_element_add_pad (GST_ELEMENT (tee), srcpad);
282   GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
283
284   if (GST_PAD_CAPS (tee->sinkpad)) {
285     gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
286   }
287
288   return srcpad;
289 }
290
291 static void
292 gst_tee_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
293 {
294   GstTee *tee;
295
296   /* it's not null if we got it, but it might not be ours */
297   g_return_if_fail (GST_IS_TEE (object));
298
299   tee = GST_TEE (object);
300
301   switch (prop_id) {
302     case ARG_SILENT:
303       tee->silent = g_value_get_boolean (value);
304       break;
305     default:
306       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307       break;
308   }
309 }
310
311 static void
312 gst_tee_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
313 {
314   GstTee *tee;
315
316   /* it's not null if we got it, but it might not be ours */
317   g_return_if_fail (GST_IS_TEE (object));
318
319   tee = GST_TEE (object);
320
321   switch (prop_id) {
322     case ARG_NUM_PADS:
323       g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
324       break;
325     case ARG_SILENT:
326       g_value_set_boolean (value, tee->silent);
327       break;
328     case ARG_LAST_MESSAGE:
329       g_value_set_string ((GValue *) value, tee->last_message);
330       break;
331     default:
332       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333       break;
334   }
335 }
336
337 /**
338  * gst_tee_chain:
339  * @pad: the pad to follow
340  * @buf: the buffer to pass
341  *
342  * Chain a buffer on a pad.
343  */
344 static void 
345 gst_tee_chain (GstPad *pad, GstBuffer *buf) 
346 {
347   GstTee *tee;
348   const GList *pads;
349
350   g_return_if_fail (pad != NULL);
351   g_return_if_fail (GST_IS_PAD (pad));
352   g_return_if_fail (buf != NULL);
353
354   tee = GST_TEE (gst_pad_get_parent (pad));
355
356   gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
357   
358   pads = gst_element_get_pad_list (GST_ELEMENT (tee));
359
360   while (pads) {
361     GstPad *outpad = GST_PAD (pads->data);
362     pads = g_list_next (pads);
363
364     if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
365       continue;
366
367     if (!tee->silent) {
368       g_free (tee->last_message);
369       tee->last_message = g_strdup_printf ("chain        ******* (%s:%s)t (%d bytes, %"
370                                            G_GUINT64_FORMAT ") %p",
371               GST_DEBUG_PAD_NAME (outpad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
372       g_object_notify (G_OBJECT (tee), "last_message");
373     }
374
375     if (GST_PAD_IS_USABLE (outpad))
376       gst_pad_push (outpad, buf);
377     else
378       gst_buffer_unref (buf);
379   }
380 }
381
382 gboolean
383 gst_tee_factory_init (GstElementFactory *factory)
384 {
385   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (tee_src_factory));
386
387   return TRUE;
388 }