gst/: Fix name lookup in GstBin.
[platform/upstream/gstreamer.git] / gst / gstutils.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstutils.c: Utility functions: gtk_get_property stuff, etc.
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 <stdio.h>
24 #include <string.h>
25
26 #include "gst_private.h"
27 #include "gstutils.h"
28 #include "gsturitype.h"
29 #include "gstinfo.h"
30 #include "gst-i18n-lib.h"
31
32
33 /**
34  * gst_util_dump_mem:
35  * @mem: a pointer to the memory to dump
36  * @size: the size of the memory block to dump
37  *
38  * Dumps the memory block into a hex representation. Useful for debugging.
39  */
40 void
41 gst_util_dump_mem (const guchar * mem, guint size)
42 {
43   guint i, j;
44   GString *string = g_string_sized_new (50);
45   GString *chars = g_string_sized_new (18);
46
47   i = j = 0;
48   while (i < size) {
49     if (g_ascii_isprint (mem[i]))
50       g_string_append_printf (chars, "%c", mem[i]);
51     else
52       g_string_append_printf (chars, ".");
53
54     g_string_append_printf (string, "%02x ", mem[i]);
55
56     j++;
57     i++;
58
59     if (j == 16 || i == size) {
60       g_print ("%08x (%p): %-48.48s %-16.16s\n", i - j, mem + i - j,
61           string->str, chars->str);
62       g_string_set_size (string, 0);
63       g_string_set_size (chars, 0);
64       j = 0;
65     }
66   }
67   g_string_free (string, TRUE);
68   g_string_free (chars, TRUE);
69 }
70
71
72 /**
73  * gst_util_set_value_from_string:
74  * @value: the value to set
75  * @value_str: the string to get the value from
76  *
77  * Converts the string to the type of the value and
78  * sets the value with it.
79  */
80 void
81 gst_util_set_value_from_string (GValue * value, const gchar * value_str)
82 {
83
84   g_return_if_fail (value != NULL);
85   g_return_if_fail (value_str != NULL);
86
87   GST_CAT_DEBUG (GST_CAT_PARAMS, "parsing '%s' to type %s", value_str,
88       g_type_name (G_VALUE_TYPE (value)));
89
90   switch (G_VALUE_TYPE (value)) {
91     case G_TYPE_STRING:
92       g_value_set_string (value, g_strdup (value_str));
93       break;
94     case G_TYPE_ENUM:
95     case G_TYPE_INT:{
96       gint i;
97
98       sscanf (value_str, "%d", &i);
99       g_value_set_int (value, i);
100       break;
101     }
102     case G_TYPE_UINT:{
103       guint i;
104
105       sscanf (value_str, "%u", &i);
106       g_value_set_uint (value, i);
107       break;
108     }
109     case G_TYPE_LONG:{
110       glong i;
111
112       sscanf (value_str, "%ld", &i);
113       g_value_set_long (value, i);
114       break;
115     }
116     case G_TYPE_ULONG:{
117       gulong i;
118
119       sscanf (value_str, "%lu", &i);
120       g_value_set_ulong (value, i);
121       break;
122     }
123     case G_TYPE_BOOLEAN:{
124       gboolean i = FALSE;
125
126       if (!strncmp ("true", value_str, 4))
127         i = TRUE;
128       g_value_set_boolean (value, i);
129       break;
130     }
131     case G_TYPE_CHAR:{
132       gchar i;
133
134       sscanf (value_str, "%c", &i);
135       g_value_set_char (value, i);
136       break;
137     }
138     case G_TYPE_UCHAR:{
139       guchar i;
140
141       sscanf (value_str, "%c", &i);
142       g_value_set_uchar (value, i);
143       break;
144     }
145     case G_TYPE_FLOAT:{
146       gfloat i;
147
148       sscanf (value_str, "%f", &i);
149       g_value_set_float (value, i);
150       break;
151     }
152     case G_TYPE_DOUBLE:{
153       gfloat i;
154
155       sscanf (value_str, "%g", &i);
156       g_value_set_double (value, (gdouble) i);
157       break;
158     }
159     default:
160       break;
161   }
162 }
163
164 /**
165  * gst_util_set_object_arg:
166  * @object: the object to set the argument of
167  * @name: the name of the argument to set
168  * @value: the string value to set
169  *
170  * Convertes the string value to the type of the objects argument and
171  * sets the argument with it.
172  */
173 void
174 gst_util_set_object_arg (GObject * object, const gchar * name,
175     const gchar * value)
176 {
177   if (name && value) {
178     GParamSpec *paramspec;
179
180     paramspec =
181         g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
182
183     if (!paramspec) {
184       return;
185     }
186
187     GST_DEBUG ("paramspec->flags is %d, paramspec->value_type is %d",
188         paramspec->flags, (gint) paramspec->value_type);
189
190     if (paramspec->flags & G_PARAM_WRITABLE) {
191       switch (paramspec->value_type) {
192         case G_TYPE_STRING:
193           g_object_set (G_OBJECT (object), name, value, NULL);
194           break;
195         case G_TYPE_ENUM:
196         case G_TYPE_INT:{
197           gint i;
198
199           sscanf (value, "%d", &i);
200           g_object_set (G_OBJECT (object), name, i, NULL);
201           break;
202         }
203         case G_TYPE_UINT:{
204           guint i;
205
206           sscanf (value, "%u", &i);
207           g_object_set (G_OBJECT (object), name, i, NULL);
208           break;
209         }
210         case G_TYPE_LONG:{
211           glong i;
212
213           sscanf (value, "%ld", &i);
214           g_object_set (G_OBJECT (object), name, i, NULL);
215           break;
216         }
217         case G_TYPE_ULONG:{
218           gulong i;
219
220           sscanf (value, "%lu", &i);
221           g_object_set (G_OBJECT (object), name, i, NULL);
222           break;
223         }
224         case G_TYPE_BOOLEAN:{
225           gboolean i = FALSE;
226
227           if (!g_ascii_strncasecmp ("true", value, 4))
228             i = TRUE;
229           g_object_set (G_OBJECT (object), name, i, NULL);
230           break;
231         }
232         case G_TYPE_CHAR:{
233           gchar i;
234
235           sscanf (value, "%c", &i);
236           g_object_set (G_OBJECT (object), name, i, NULL);
237           break;
238         }
239         case G_TYPE_UCHAR:{
240           guchar i;
241
242           sscanf (value, "%c", &i);
243           g_object_set (G_OBJECT (object), name, i, NULL);
244           break;
245         }
246         case G_TYPE_FLOAT:{
247           gfloat i;
248
249           sscanf (value, "%f", &i);
250           g_object_set (G_OBJECT (object), name, i, NULL);
251           break;
252         }
253         case G_TYPE_DOUBLE:{
254           gfloat i;
255
256           sscanf (value, "%g", &i);
257           g_object_set (G_OBJECT (object), name, (gdouble) i, NULL);
258           break;
259         }
260         default:
261           if (G_IS_PARAM_SPEC_ENUM (paramspec)) {
262             gint i;
263
264             sscanf (value, "%d", &i);
265             g_object_set (G_OBJECT (object), name, i, NULL);
266           } else if (paramspec->value_type == GST_TYPE_URI) {
267             g_object_set (G_OBJECT (object), name, value, NULL);
268           }
269           break;
270       }
271     }
272   }
273 }
274
275 /* -----------------------------------------------------
276  *
277  *  The following code will be moved out of the main
278  * gstreamer library someday.
279  */
280
281 #include "gstpad.h"
282
283 static void
284 string_append_indent (GString * str, gint count)
285 {
286   gint xx;
287
288   for (xx = 0; xx < count; xx++)
289     g_string_append_c (str, ' ');
290 }
291
292 /**
293  * gst_print_pad_caps:
294  * @buf: the buffer to print the caps in
295  * @indent: initial indentation
296  * @pad: the pad to print the caps from
297  *
298  * Write the pad capabilities in a human readable format into
299  * the given GString.
300  */
301 void
302 gst_print_pad_caps (GString * buf, gint indent, GstPad * pad)
303 {
304   GstRealPad *realpad;
305   GstCaps *caps;
306
307   realpad = GST_PAD_REALIZE (pad);
308   caps = realpad->caps;
309
310   if (!caps) {
311     string_append_indent (buf, indent);
312     g_string_printf (buf, "%s:%s has no capabilities",
313         GST_DEBUG_PAD_NAME (pad));
314   } else {
315     char *s;
316
317     s = gst_caps_to_string (caps);
318     g_string_append (buf, s);
319     g_free (s);
320   }
321 }
322
323 /**
324  * gst_print_element_args:
325  * @buf: the buffer to print the args in
326  * @indent: initial indentation
327  * @element: the element to print the args of
328  *
329  * Print the element argument in a human readable format in the given
330  * GString.
331  */
332 void
333 gst_print_element_args (GString * buf, gint indent, GstElement * element)
334 {
335   guint width;
336   GValue value = { 0, };        /* the important thing is that value.type = 0 */
337   gchar *str = NULL;
338   GParamSpec *spec, **specs, **walk;
339
340   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element), NULL);
341
342   width = 0;
343   for (walk = specs; *walk; walk++) {
344     spec = *walk;
345     if (width < strlen (spec->name))
346       width = strlen (spec->name);
347   }
348
349   for (walk = specs; *walk; walk++) {
350     spec = *walk;
351
352     if (spec->flags & G_PARAM_READABLE) {
353       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec));
354       g_object_get_property (G_OBJECT (element), spec->name, &value);
355       str = g_strdup_value_contents (&value);
356       g_value_unset (&value);
357     } else {
358       str = g_strdup ("Parameter not readable.");
359     }
360
361     string_append_indent (buf, indent);
362     g_string_append (buf, spec->name);
363     string_append_indent (buf, 2 + width - strlen (spec->name));
364     g_string_append (buf, str);
365     g_string_append_c (buf, '\n');
366
367     g_free (str);
368   }
369
370   g_free (specs);
371 }
372
373 /**
374  * gst_element_create_all_pads:
375  * @element: a #GstElement to create pads for
376  *
377  * Creates a pad for each pad template that is always available.
378  * This function is only useful during object intialization of
379  * subclasses of #GstElement.
380  */
381 void
382 gst_element_create_all_pads (GstElement * element)
383 {
384   GList *padlist;
385
386   /* FIXME: lock element */
387
388   padlist =
389       gst_element_class_get_pad_template_list (GST_ELEMENT_CLASS
390       (G_OBJECT_GET_CLASS (element)));
391
392   while (padlist) {
393     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
394
395     if (padtempl->presence == GST_PAD_ALWAYS) {
396       GstPad *pad;
397
398       pad = gst_pad_new_from_template (padtempl, padtempl->name_template);
399
400       gst_element_add_pad (element, pad);
401     }
402     padlist = padlist->next;
403   }
404 }
405
406 /**
407  * gst_element_get_compatible_pad_template:
408  * @element: a #GstElement to get a compatible pad template for.
409  * @compattempl: the #GstPadTemplate to find a compatible template for.
410  *
411  * Retrieves a pad template from @element that is compatible with @compattempl.
412  * Pads from compatible templates can be linked together.
413  *
414  * Returns: a compatible #GstPadTemplate, or NULL if none was found. No
415  * unreferencing is necessary.
416  */
417 GstPadTemplate *
418 gst_element_get_compatible_pad_template (GstElement * element,
419     GstPadTemplate * compattempl)
420 {
421   GstPadTemplate *newtempl = NULL;
422   GList *padlist;
423   GstElementClass *class;
424
425   g_return_val_if_fail (element != NULL, NULL);
426   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
427   g_return_val_if_fail (compattempl != NULL, NULL);
428
429   class = GST_ELEMENT_GET_CLASS (element);
430
431   padlist = gst_element_class_get_pad_template_list (class);
432
433   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
434       "Looking for a suitable pad template in %s out of %d templates...",
435       GST_ELEMENT_NAME (element), g_list_length (padlist));
436
437   while (padlist) {
438     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
439     GstCaps *intersection;
440
441     /* Ignore name
442      * Ignore presence
443      * Check direction (must be opposite)
444      * Check caps
445      */
446     GST_CAT_LOG (GST_CAT_CAPS,
447         "checking pad template %s", padtempl->name_template);
448     if (padtempl->direction != compattempl->direction) {
449       GST_CAT_DEBUG (GST_CAT_CAPS,
450           "compatible direction: found %s pad template \"%s\"",
451           padtempl->direction == GST_PAD_SRC ? "src" : "sink",
452           padtempl->name_template);
453
454       GST_CAT_DEBUG (GST_CAT_CAPS,
455           "intersecting %" GST_PTR_FORMAT, GST_PAD_TEMPLATE_CAPS (compattempl));
456       GST_CAT_DEBUG (GST_CAT_CAPS,
457           "..and %" GST_PTR_FORMAT, GST_PAD_TEMPLATE_CAPS (padtempl));
458
459       intersection = gst_caps_intersect (GST_PAD_TEMPLATE_CAPS (compattempl),
460           GST_PAD_TEMPLATE_CAPS (padtempl));
461
462       GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible %" GST_PTR_FORMAT,
463           (intersection ? "" : "not "), intersection);
464
465       if (!gst_caps_is_empty (intersection))
466         newtempl = padtempl;
467       gst_caps_unref (intersection);
468       if (newtempl)
469         break;
470     }
471
472     padlist = g_list_next (padlist);
473   }
474   if (newtempl)
475     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
476         "Returning new pad template %p", newtempl);
477   else
478     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "No compatible pad template found");
479
480   return newtempl;
481 }
482
483 static GstPad *
484 gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
485     const gchar * name)
486 {
487   GstPad *newpad = NULL;
488   GstElementClass *oclass;
489
490   oclass = GST_ELEMENT_GET_CLASS (element);
491
492   if (oclass->request_new_pad)
493     newpad = (oclass->request_new_pad) (element, templ, name);
494
495   if (newpad)
496     gst_object_ref (GST_OBJECT (newpad));
497
498   return newpad;
499 }
500
501
502
503 /**
504  * gst_element_get_pad_from_template:
505  * @element: a #GstElement.
506  * @templ: a #GstPadTemplate belonging to @element.
507  *
508  * Gets a pad from @element described by @templ. If the presence of @templ is
509  * #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES
510  * templates.
511  *
512  * Returns: the #GstPad, or NULL if one could not be found or created.
513  */
514 static GstPad *
515 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
516 {
517   GstPad *ret = NULL;
518   GstPadPresence presence;
519
520   /* If this function is ever exported, we need check the validity of `element'
521    * and `templ', and to make sure the template actually belongs to the
522    * element. */
523
524   presence = GST_PAD_TEMPLATE_PRESENCE (templ);
525
526   switch (presence) {
527     case GST_PAD_ALWAYS:
528     case GST_PAD_SOMETIMES:
529       ret = gst_element_get_static_pad (element, templ->name_template);
530       if (!ret && presence == GST_PAD_ALWAYS)
531         g_warning
532             ("Element %s has an ALWAYS template %s, but no pad of the same name",
533             GST_OBJECT_NAME (element), templ->name_template);
534       break;
535
536     case GST_PAD_REQUEST:
537       ret = gst_element_request_pad (element, templ, NULL);
538       break;
539   }
540
541   return ret;
542 }
543
544 /**
545  * gst_element_request_compatible_pad:
546  * @element: a #GstElement.
547  * @templ: the #GstPadTemplate to which the new pad should be able to link.
548  *
549  * Requests a pad from @element. The returned pad should be unlinked and
550  * compatible with @templ. Might return an existing pad, or request a new one.
551  *
552  * Returns: a #GstPad, or %NULL if one could not be found or created.
553  */
554 GstPad *
555 gst_element_request_compatible_pad (GstElement * element,
556     GstPadTemplate * templ)
557 {
558   GstPadTemplate *templ_new;
559   GstPad *pad = NULL;
560
561   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
562   g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
563
564   /* FIXME: should really loop through the templates, testing each for
565    *      compatibility and pad availability. */
566   templ_new = gst_element_get_compatible_pad_template (element, templ);
567   if (templ_new)
568     pad = gst_element_get_pad_from_template (element, templ_new);
569
570   /* This can happen for non-request pads. No need to unref. */
571   if (pad && GST_PAD_PEER (pad))
572     pad = NULL;
573
574   return pad;
575 }
576
577 /**
578  * gst_element_get_compatible_pad:
579  * @element: a #GstElement in which the pad should be found.
580  * @pad: the #GstPad to find a compatible one for.
581  * @filtercaps: the #GstCaps to use as a filter.
582  *
583  * Looks for an unlinked pad to which the given pad can link. It is not
584  * guaranteed that linking the pads will work, though it should work in most
585  * cases.
586  *
587  * Returns: the #GstPad to which a link can be made, or %NULL if one cannot be
588  * found.
589  */
590 GstPad *
591 gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
592     const GstCaps * caps)
593 {
594   GstIterator *pads;
595   GstPadTemplate *templ;
596   GstCaps *templcaps;
597   GstPad *foundpad = NULL;
598   gboolean done;
599
600   /* FIXME check for caps compatibility */
601
602   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
603   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
604
605   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
606       "finding pad in %s compatible with %s:%s",
607       GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
608
609   /* let's use the real pad */
610   pad = (GstPad *) GST_PAD_REALIZE (pad);
611   g_return_val_if_fail (pad != NULL, NULL);
612   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
613
614   done = FALSE;
615   /* try to get an existing unlinked pad */
616   pads = gst_element_iterate_pads (element);
617   while (!done) {
618     gpointer padptr;
619
620     switch (gst_iterator_next (pads, &padptr)) {
621       case GST_ITERATOR_OK:
622       {
623         GstPad *peer;
624         GstPad *current;
625
626         current = GST_PAD (padptr);
627
628         GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s",
629             GST_DEBUG_PAD_NAME (current));
630
631         peer = gst_pad_get_peer (current);
632
633         if (peer == NULL && gst_pad_can_link (pad, current)) {
634
635           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
636               "found existing unlinked pad %s:%s",
637               GST_DEBUG_PAD_NAME (current));
638
639           gst_iterator_free (pads);
640
641           return current;
642         } else {
643           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");
644
645           gst_object_unref (GST_OBJECT (current));
646           if (peer)
647             gst_object_unref (GST_OBJECT (peer));
648         }
649         break;
650       }
651       case GST_ITERATOR_DONE:
652         done = TRUE;
653         break;
654       case GST_ITERATOR_RESYNC:
655         gst_iterator_resync (pads);
656         break;
657       case GST_ITERATOR_ERROR:
658         g_assert_not_reached ();
659         break;
660     }
661   }
662   gst_iterator_free (pads);
663
664   /* try to create a new one */
665   /* requesting is a little crazy, we need a template. Let's create one */
666   templcaps = gst_pad_get_caps (pad);
667
668   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
669       GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
670   foundpad = gst_element_request_compatible_pad (element, templ);
671   gst_object_unref (GST_OBJECT (templ));
672
673   if (foundpad) {
674     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
675         "found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad));
676     return foundpad;
677   }
678
679   GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element,
680       "Could not find a compatible pad to link to %s:%s",
681       GST_DEBUG_PAD_NAME (pad));
682   return NULL;
683 }
684
685 /**
686  * gst_element_state_get_name:
687  * @state: a #GstElementState to get the name of.
688  *
689  * Gets a string representing the given state.
690  *
691  * Returns: a string with the name of the state.
692  */
693 const gchar *
694 gst_element_state_get_name (GstElementState state)
695 {
696   switch (state) {
697 #ifdef GST_DEBUG_COLOR
698     case GST_STATE_VOID_PENDING:
699       return "NONE_PENDING";
700       break;
701     case GST_STATE_NULL:
702       return "\033[01;34mNULL\033[00m";
703       break;
704     case GST_STATE_READY:
705       return "\033[01;31mREADY\033[00m";
706       break;
707     case GST_STATE_PLAYING:
708       return "\033[01;32mPLAYING\033[00m";
709       break;
710     case GST_STATE_PAUSED:
711       return "\033[01;33mPAUSED\033[00m";
712       break;
713     default:
714       /* This is a memory leak */
715       return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
716 #else
717     case GST_STATE_VOID_PENDING:
718       return "NONE_PENDING";
719       break;
720     case GST_STATE_NULL:
721       return "NULL";
722       break;
723     case GST_STATE_READY:
724       return "READY";
725       break;
726     case GST_STATE_PLAYING:
727       return "PLAYING";
728       break;
729     case GST_STATE_PAUSED:
730       return "PAUSED";
731       break;
732     default:
733       return g_strdup_printf ("UNKNOWN!(%d)", state);
734 #endif
735   }
736   return "";
737 }
738
739 /**
740  * gst_element_link_pads:
741  * @src: a #GstElement containing the source pad.
742  * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
743  * @dest: the #GstElement containing the destination pad.
744  * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
745  *
746  * Links the two named pads of the source and destination elements.
747  * Side effect is that if one of the pads has no parent, it becomes a
748  * child of the parent of the other element.  If they have different
749  * parents, the link fails.
750  *
751  * Returns: TRUE if the pads could be linked, FALSE otherwise.
752  */
753 gboolean
754 gst_element_link_pads (GstElement * src, const gchar * srcpadname,
755     GstElement * dest, const gchar * destpadname)
756 {
757   const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
758   GstPad *srcpad, *destpad;
759   GstPadTemplate *srctempl, *desttempl;
760   GstElementClass *srcclass, *destclass;
761
762   /* checks */
763   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
764   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
765
766   srcclass = GST_ELEMENT_GET_CLASS (src);
767   destclass = GST_ELEMENT_GET_CLASS (dest);
768
769   GST_CAT_INFO (GST_CAT_ELEMENT_PADS,
770       "trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),
771       srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),
772       destpadname ? destpadname : "(any)");
773
774   /* now get the pads we're trying to link and a list of all remaining pads */
775   if (srcpadname) {
776     srcpad = gst_element_get_pad (src, srcpadname);
777     if (!srcpad) {
778       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
779           GST_ELEMENT_NAME (src), srcpadname);
780       return FALSE;
781     } else {
782       if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
783         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
784             GST_DEBUG_PAD_NAME (srcpad));
785         gst_object_unref (GST_OBJECT (srcpad));
786         return FALSE;
787       }
788       if (GST_PAD_PEER (srcpad) != NULL) {
789         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
790             GST_DEBUG_PAD_NAME (srcpad));
791         gst_object_unref (GST_OBJECT (srcpad));
792         return FALSE;
793       }
794     }
795     srcpads = NULL;
796   } else {
797     GST_LOCK (src);
798     srcpads = GST_ELEMENT_PADS (src);
799     srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
800     if (srcpad)
801       gst_object_ref (GST_OBJECT (srcpad));
802     GST_UNLOCK (src);
803   }
804   if (destpadname) {
805     destpad = gst_element_get_pad (dest, destpadname);
806     if (!destpad) {
807       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
808           GST_ELEMENT_NAME (dest), destpadname);
809       return FALSE;
810     } else {
811       if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
812         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
813             GST_DEBUG_PAD_NAME (destpad));
814         gst_object_unref (GST_OBJECT (destpad));
815         return FALSE;
816       }
817       if (GST_PAD_PEER (destpad) != NULL) {
818         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
819             GST_DEBUG_PAD_NAME (destpad));
820         gst_object_unref (GST_OBJECT (destpad));
821         return FALSE;
822       }
823     }
824     destpads = NULL;
825   } else {
826     GST_LOCK (dest);
827     destpads = GST_ELEMENT_PADS (dest);
828     destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
829     if (destpad)
830       gst_object_ref (GST_OBJECT (destpad));
831     GST_UNLOCK (dest);
832   }
833
834   if (srcpadname && destpadname) {
835     gboolean result;
836
837     /* two explicitly specified pads */
838     result = gst_pad_link (srcpad, destpad);
839
840     gst_object_unref (GST_OBJECT (srcpad));
841     gst_object_unref (GST_OBJECT (destpad));
842
843     return result;
844   }
845   if (srcpad) {
846     /* loop through the allowed pads in the source, trying to find a
847      * compatible destination pad */
848     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
849         "looping through allowed src and dest pads");
850     do {
851       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
852           GST_DEBUG_PAD_NAME (srcpad));
853       if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
854           (GST_PAD_PEER (srcpad) == NULL)) {
855         GstPad *temp = destpadname ? destpad :
856             gst_element_get_compatible_pad (dest, srcpad, NULL);
857
858         if (temp && gst_pad_link (srcpad, temp) == GST_PAD_LINK_OK) {
859           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
860               GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
861           if (destpad)
862             gst_object_unref (GST_OBJECT (destpad));
863           gst_object_unref (GST_OBJECT (srcpad));
864           gst_object_unref (GST_OBJECT (temp));
865           return TRUE;
866         }
867       }
868       /* find a better way for this mess */
869       if (srcpads) {
870         srcpads = g_list_next (srcpads);
871         if (srcpads) {
872           gst_object_unref (GST_OBJECT (srcpad));
873           srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
874           gst_object_ref (GST_OBJECT (srcpad));
875         }
876       }
877     } while (srcpads);
878   }
879   if (srcpadname) {
880     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
881         GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
882     gst_object_unref (GST_OBJECT (srcpad));
883     if (destpad)
884       gst_object_unref (GST_OBJECT (destpad));
885     return FALSE;
886   } else {
887     gst_object_unref (GST_OBJECT (srcpad));
888     srcpad = NULL;
889   }
890   if (destpad) {
891     /* loop through the existing pads in the destination */
892     do {
893       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
894           GST_DEBUG_PAD_NAME (destpad));
895       if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
896           (GST_PAD_PEER (destpad) == NULL)) {
897         GstPad *temp = gst_element_get_compatible_pad (src, destpad, NULL);
898
899         if (temp && gst_pad_link (temp, destpad) == GST_PAD_LINK_OK) {
900           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
901               GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
902           gst_object_unref (GST_OBJECT (temp));
903           gst_object_unref (GST_OBJECT (destpad));
904           if (srcpad)
905             gst_object_unref (GST_OBJECT (srcpad));
906           return TRUE;
907         }
908       }
909       if (destpads) {
910         destpads = g_list_next (destpads);
911         if (destpads) {
912           gst_object_unref (GST_OBJECT (destpad));
913           destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
914           gst_object_ref (GST_OBJECT (destpad));
915         }
916       }
917     } while (destpads);
918   }
919   if (destpadname) {
920     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
921         GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
922     gst_object_unref (GST_OBJECT (destpad));
923     if (srcpad)
924       gst_object_unref (GST_OBJECT (srcpad));
925     return FALSE;
926   } else {
927     gst_object_unref (GST_OBJECT (destpad));
928     if (srcpad)
929       gst_object_unref (GST_OBJECT (srcpad));
930     srcpad = NULL;
931     destpad = NULL;
932   }
933
934   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
935       "we might have request pads on both sides, checking...");
936   srctempls = gst_element_class_get_pad_template_list (srcclass);
937   desttempls = gst_element_class_get_pad_template_list (destclass);
938
939   if (srctempls && desttempls) {
940     while (srctempls) {
941       srctempl = (GstPadTemplate *) srctempls->data;
942       if (srctempl->presence == GST_PAD_REQUEST) {
943         for (l = desttempls; l; l = l->next) {
944           desttempl = (GstPadTemplate *) l->data;
945           if (desttempl->presence == GST_PAD_REQUEST &&
946               desttempl->direction != srctempl->direction) {
947             if (gst_caps_is_always_compatible (gst_pad_template_get_caps
948                     (srctempl), gst_pad_template_get_caps (desttempl))) {
949               srcpad =
950                   gst_element_get_request_pad (src, srctempl->name_template);
951               destpad =
952                   gst_element_get_request_pad (dest, desttempl->name_template);
953               if (gst_pad_link (srcpad, destpad) == GST_PAD_LINK_OK) {
954                 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
955                     "linked pad %s:%s to pad %s:%s",
956                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
957                 gst_object_unref (GST_OBJECT (srcpad));
958                 gst_object_unref (GST_OBJECT (destpad));
959                 return TRUE;
960               }
961               /* it failed, so we release the request pads */
962               gst_element_release_request_pad (src, srcpad);
963               gst_element_release_request_pad (dest, destpad);
964             }
965           }
966         }
967       }
968       srctempls = srctempls->next;
969     }
970   }
971
972   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
973       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
974   return FALSE;
975 }
976
977 /**
978  * gst_element_link:
979  * @src: a #GstElement containing the source pad.
980  * @dest: the #GstElement containing the destination pad.
981  *
982  * Links @src to @dest. The link must be from source to
983  * destination; the other direction will not be tried. The function looks for
984  * existing pads that aren't linked yet. It will request new pads if necessary.
985  * If multiple links are possible, only one is established.
986  *
987  * Returns: TRUE if the elements could be linked, FALSE otherwise.
988  */
989 gboolean
990 gst_element_link (GstElement * src, GstElement * dest)
991 {
992   return gst_element_link_pads (src, NULL, dest, NULL);
993 }
994
995 /**
996  * gst_element_link_many:
997  * @element_1: the first #GstElement in the link chain.
998  * @element_2: the second #GstElement in the link chain.
999  * @...: the NULL-terminated list of elements to link in order.
1000  *
1001  * Chain together a series of elements. Uses gst_element_link().
1002  *
1003  * Returns: TRUE on success, FALSE otherwise.
1004  */
1005 gboolean
1006 gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
1007 {
1008   va_list args;
1009
1010   g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE);
1011   g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE);
1012
1013   va_start (args, element_2);
1014
1015   while (element_2) {
1016     if (!gst_element_link (element_1, element_2))
1017       return FALSE;
1018
1019     element_1 = element_2;
1020     element_2 = va_arg (args, GstElement *);
1021   }
1022
1023   va_end (args);
1024
1025   return TRUE;
1026 }
1027
1028 /**
1029  * gst_element_unlink_pads:
1030  * @src: a #GstElement containing the source pad.
1031  * @srcpadname: the name of the #GstPad in source element.
1032  * @dest: a #GstElement containing the destination pad.
1033  * @destpadname: the name of the #GstPad in destination element.
1034  *
1035  * Unlinks the two named pads of the source and destination elements.
1036  */
1037 void
1038 gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
1039     GstElement * dest, const gchar * destpadname)
1040 {
1041   GstPad *srcpad, *destpad;
1042
1043   g_return_if_fail (src != NULL);
1044   g_return_if_fail (GST_IS_ELEMENT (src));
1045   g_return_if_fail (srcpadname != NULL);
1046   g_return_if_fail (dest != NULL);
1047   g_return_if_fail (GST_IS_ELEMENT (dest));
1048   g_return_if_fail (destpadname != NULL);
1049
1050   /* obtain the pads requested */
1051   srcpad = gst_element_get_pad (src, srcpadname);
1052   if (srcpad == NULL) {
1053     GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
1054     return;
1055   }
1056   destpad = gst_element_get_pad (dest, destpadname);
1057   if (srcpad == NULL) {
1058     GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
1059         destpadname);
1060     return;
1061   }
1062
1063   /* we're satisified they can be unlinked, let's do it */
1064   gst_pad_unlink (srcpad, destpad);
1065 }
1066
1067 /**
1068  * gst_element_unlink_many:
1069  * @element_1: the first #GstElement in the link chain.
1070  * @element_2: the second #GstElement in the link chain.
1071  * @...: the NULL-terminated list of elements to unlink in order.
1072  *
1073  * Unlinks a series of elements. Uses gst_element_unlink().
1074  */
1075 void
1076 gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
1077 {
1078   va_list args;
1079
1080   g_return_if_fail (element_1 != NULL && element_2 != NULL);
1081   g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1082
1083   va_start (args, element_2);
1084
1085   while (element_2) {
1086     gst_element_unlink (element_1, element_2);
1087
1088     element_1 = element_2;
1089     element_2 = va_arg (args, GstElement *);
1090   }
1091
1092   va_end (args);
1093 }
1094
1095 /**
1096  * gst_element_unlink:
1097  * @src: the source #GstElement to unlink.
1098  * @dest: the sink #GstElement to unlink.
1099  *
1100  * Unlinks all source pads of the source element with all sink pads
1101  * of the sink element to which they are linked.
1102  */
1103 void
1104 gst_element_unlink (GstElement * src, GstElement * dest)
1105 {
1106   GstIterator *pads;
1107   gboolean done = FALSE;
1108
1109   g_return_if_fail (GST_IS_ELEMENT (src));
1110   g_return_if_fail (GST_IS_ELEMENT (dest));
1111
1112   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
1113       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1114
1115   pads = gst_element_iterate_pads (src);
1116   while (!done) {
1117     gpointer data;
1118
1119     switch (gst_iterator_next (pads, &data)) {
1120       case GST_ITERATOR_OK:
1121       {
1122         GstPad *pad = GST_PAD_CAST (data);
1123
1124         /* we only care about real src pads */
1125         if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
1126           GstPad *peerpad = gst_pad_get_peer (pad);
1127
1128           /* see if the pad is connected and is really a pad
1129            * of dest */
1130           if (peerpad) {
1131             GstElement *peerelem = gst_pad_get_parent (peerpad);
1132
1133             if (peerelem == dest) {
1134               gst_pad_unlink (pad, peerpad);
1135             }
1136             if (peerelem)
1137               gst_object_unref (GST_OBJECT (peerelem));
1138
1139             gst_object_unref (GST_OBJECT (peerpad));
1140           }
1141         }
1142         gst_object_unref (GST_OBJECT (pad));
1143         break;
1144       }
1145       case GST_ITERATOR_RESYNC:
1146         gst_iterator_resync (pads);
1147         break;
1148       case GST_ITERATOR_DONE:
1149         done = TRUE;
1150         break;
1151       default:
1152         g_assert_not_reached ();
1153         break;
1154     }
1155   }
1156 }
1157
1158 /**
1159  * gst_pad_can_link:
1160  * @srcpad: the source #GstPad to link.
1161  * @sinkpad: the sink #GstPad to link.
1162  *
1163  * Checks if the source pad and the sink pad can be linked.
1164  * Both @srcpad and @sinkpad must be unlinked.
1165  *
1166  * Returns: TRUE if the pads can be linked, FALSE otherwise.
1167  */
1168 gboolean
1169 gst_pad_can_link (GstPad * srcpad, GstPad * sinkpad)
1170 {
1171   GstRealPad *realsrc, *realsink;
1172
1173   /* FIXME This function is gross.  It's almost a direct copy of
1174    * gst_pad_link_filtered().  Any decent programmer would attempt
1175    * to merge the two functions, which I will do some day. --ds
1176    */
1177
1178   /* generic checks */
1179   g_return_val_if_fail (srcpad != NULL, FALSE);
1180   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
1181   g_return_val_if_fail (sinkpad != NULL, FALSE);
1182   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
1183
1184   GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
1185       GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1186
1187   /* now we need to deal with the real/ghost stuff */
1188   realsrc = GST_PAD_REALIZE (srcpad);
1189   realsink = GST_PAD_REALIZE (sinkpad);
1190
1191   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
1192     GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
1193         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1194   }
1195   /* FIXME: shouldn't we convert this to g_return_val_if_fail? */
1196   if (GST_RPAD_PEER (realsrc) != NULL) {
1197     GST_CAT_INFO (GST_CAT_PADS, "Real source pad %s:%s has a peer, failed",
1198         GST_DEBUG_PAD_NAME (realsrc));
1199     return FALSE;
1200   }
1201   if (GST_RPAD_PEER (realsink) != NULL) {
1202     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has a peer, failed",
1203         GST_DEBUG_PAD_NAME (realsink));
1204     return FALSE;
1205   }
1206   if (!GST_PAD_IS_SRC (realsrc)) {
1207     GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s is not source pad, failed",
1208         GST_DEBUG_PAD_NAME (realsrc));
1209     return FALSE;
1210   }
1211   if (!GST_PAD_IS_SINK (realsink)) {
1212     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s is not sink pad, failed",
1213         GST_DEBUG_PAD_NAME (realsink));
1214     return FALSE;
1215   }
1216   if (GST_PAD_PARENT (realsrc) == NULL) {
1217     GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s has no parent, failed",
1218         GST_DEBUG_PAD_NAME (realsrc));
1219     return FALSE;
1220   }
1221   if (GST_PAD_PARENT (realsink) == NULL) {
1222     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has no parent, failed",
1223         GST_DEBUG_PAD_NAME (realsrc));
1224     return FALSE;
1225   }
1226
1227   g_return_val_if_fail (realsrc != NULL, GST_PAD_LINK_REFUSED);
1228   g_return_val_if_fail (realsink != NULL, GST_PAD_LINK_REFUSED);
1229
1230   return TRUE;
1231 }
1232
1233 /**
1234  * gst_pad_use_fixed_caps:
1235  * @pad: the pad to use
1236  *
1237  * A helper function you can use that sets the 
1238  * @gst_pad_get_fixed_caps_func as the gstcaps function for the
1239  * pad. This way the function will always return the negotiated caps
1240  * or in case the pad is not negotiated, the padtemplate caps.
1241  */
1242 void
1243 gst_pad_use_fixed_caps (GstPad * pad)
1244 {
1245   gst_pad_set_getcaps_function (pad, gst_pad_get_fixed_caps_func);
1246 }
1247
1248 /**
1249  * gst_pad_get_fixed_caps_func:
1250  * @pad: the pad to use
1251  *
1252  * A helper function you can use as a GetCaps function that
1253  * will return the currently negotiated caps or the padtemplate
1254  * when NULL.
1255  *
1256  * Returns: The currently negotiated caps or the padtemplate.
1257  */
1258 GstCaps *
1259 gst_pad_get_fixed_caps_func (GstPad * pad)
1260 {
1261   GstCaps *result;
1262   GstRealPad *realpad;
1263
1264   g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
1265
1266   realpad = GST_REAL_PAD_CAST (pad);
1267
1268   if (GST_RPAD_CAPS (realpad)) {
1269     result = GST_RPAD_CAPS (realpad);
1270
1271     GST_CAT_DEBUG (GST_CAT_CAPS,
1272         "using pad caps %p %" GST_PTR_FORMAT, result, result);
1273
1274     result = gst_caps_ref (result);
1275     goto done;
1276   }
1277   if (GST_PAD_PAD_TEMPLATE (realpad)) {
1278     GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (realpad);
1279
1280     result = GST_PAD_TEMPLATE_CAPS (templ);
1281     GST_CAT_DEBUG (GST_CAT_CAPS,
1282         "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
1283         result);
1284
1285     result = gst_caps_ref (result);
1286     goto done;
1287   }
1288   GST_CAT_DEBUG (GST_CAT_CAPS, "pad has no caps");
1289   result = gst_caps_new_empty ();
1290
1291 done:
1292   return result;
1293 }
1294
1295 /**
1296  * gst_object_default_error:
1297  * @object: a #GObject that signalled the error.
1298  * @orig: the #GstObject that initiated the error.
1299  * @error: the GError.
1300  * @debug: an additional debug information string, or NULL.
1301  *
1302  * A default error function.
1303  *
1304  * The default handler will simply print the error string using g_print.
1305  */
1306 void
1307 gst_object_default_error (GstObject * source, GError * error, gchar * debug)
1308 {
1309   gchar *name = gst_object_get_path_string (source);
1310
1311   g_print (_("ERROR: from element %s: %s\n"), name, error->message);
1312   if (debug)
1313     g_print (_("Additional debug info:\n%s\n"), debug);
1314
1315   g_free (name);
1316 }
1317
1318 /**
1319  * gst_bin_add_many:
1320  * @bin: the bin to add the elements to
1321  * @element_1: the first element to add to the bin
1322  * @...: additional elements to add to the bin
1323  *
1324  * Adds a NULL-terminated list of elements to a bin.  This function is
1325  * equivalent to calling #gst_bin_add() for each member of the list.
1326  */
1327 void
1328 gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
1329 {
1330   va_list args;
1331
1332   g_return_if_fail (GST_IS_BIN (bin));
1333   g_return_if_fail (GST_IS_ELEMENT (element_1));
1334
1335   va_start (args, element_1);
1336
1337   while (element_1) {
1338     gst_bin_add (bin, element_1);
1339
1340     element_1 = va_arg (args, GstElement *);
1341   }
1342
1343   va_end (args);
1344 }
1345
1346 /**
1347  * gst_bin_remove_many:
1348  * @bin: the bin to remove the elements from
1349  * @element_1: the first element to remove from the bin
1350  * @...: NULL-terminated list of elements to remove from the bin
1351  *
1352  * Remove a list of elements from a bin. This function is equivalent
1353  * to calling #gst_bin_remove with each member of the list.
1354  */
1355 void
1356 gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
1357 {
1358   va_list args;
1359
1360   g_return_if_fail (GST_IS_BIN (bin));
1361   g_return_if_fail (GST_IS_ELEMENT (element_1));
1362
1363   va_start (args, element_1);
1364
1365   while (element_1) {
1366     gst_bin_remove (bin, element_1);
1367
1368     element_1 = va_arg (args, GstElement *);
1369   }
1370
1371   va_end (args);
1372 }
1373
1374 static void
1375 gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name,
1376     guint arg_id, GParamFlags flags)
1377 {
1378   GQuark prop_id = g_quark_from_string (prop_name);
1379   GParamSpec *pspec;
1380
1381   static GQuark fd_id = 0;
1382   static GQuark blocksize_id;
1383   static GQuark bytesperread_id;
1384   static GQuark dump_id;
1385   static GQuark filesize_id;
1386   static GQuark mmapsize_id;
1387   static GQuark location_id;
1388   static GQuark offset_id;
1389   static GQuark silent_id;
1390   static GQuark touch_id;
1391
1392   if (!fd_id) {
1393     fd_id = g_quark_from_static_string ("fd");
1394     blocksize_id = g_quark_from_static_string ("blocksize");
1395     bytesperread_id = g_quark_from_static_string ("bytesperread");
1396     dump_id = g_quark_from_static_string ("dump");
1397     filesize_id = g_quark_from_static_string ("filesize");
1398     mmapsize_id = g_quark_from_static_string ("mmapsize");
1399     location_id = g_quark_from_static_string ("location");
1400     offset_id = g_quark_from_static_string ("offset");
1401     silent_id = g_quark_from_static_string ("silent");
1402     touch_id = g_quark_from_static_string ("touch");
1403   }
1404
1405   if (prop_id == fd_id) {
1406     pspec = g_param_spec_int ("fd", "File-descriptor",
1407         "File-descriptor for the file being read", 0, G_MAXINT, 0, flags);
1408   } else if (prop_id == blocksize_id) {
1409     pspec = g_param_spec_ulong ("blocksize", "Block Size",
1410         "Block size to read per buffer", 0, G_MAXULONG, 4096, flags);
1411
1412   } else if (prop_id == bytesperread_id) {
1413     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
1414         "Number of bytes to read per buffer", G_MININT, G_MAXINT, 0, flags);
1415
1416   } else if (prop_id == dump_id) {
1417     pspec = g_param_spec_boolean ("dump", "Dump",
1418         "Dump bytes to stdout", FALSE, flags);
1419
1420   } else if (prop_id == filesize_id) {
1421     pspec = g_param_spec_int64 ("filesize", "File Size",
1422         "Size of the file being read", 0, G_MAXINT64, 0, flags);
1423
1424   } else if (prop_id == mmapsize_id) {
1425     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
1426         "Size in bytes of mmap()d regions", 0, G_MAXULONG, 4 * 1048576, flags);
1427
1428   } else if (prop_id == location_id) {
1429     pspec = g_param_spec_string ("location", "File Location",
1430         "Location of the file to read", NULL, flags);
1431
1432   } else if (prop_id == offset_id) {
1433     pspec = g_param_spec_int64 ("offset", "File Offset",
1434         "Byte offset of current read pointer", 0, G_MAXINT64, 0, flags);
1435
1436   } else if (prop_id == silent_id) {
1437     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
1438         FALSE, flags);
1439
1440   } else if (prop_id == touch_id) {
1441     pspec = g_param_spec_boolean ("touch", "Touch read data",
1442         "Touch data to force disk read before " "push ()", TRUE, flags);
1443   } else {
1444     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
1445         prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
1446     pspec = NULL;
1447   }
1448
1449   if (pspec) {
1450     g_object_class_install_property (klass, arg_id, pspec);
1451   }
1452 }
1453
1454 /**
1455  * gst_element_class_install_std_props:
1456  * @klass: the #GstElementClass to add the properties to.
1457  * @first_name: the name of the first property.
1458  * in a NULL terminated
1459  * @...: the id and flags of the first property, followed by
1460  * further 'name', 'id', 'flags' triplets and terminated by NULL.
1461  *
1462  * Adds a list of standardized properties with types to the @klass.
1463  * the id is for the property switch in your get_prop method, and
1464  * the flags determine readability / writeability.
1465  **/
1466 void
1467 gst_element_class_install_std_props (GstElementClass * klass,
1468     const gchar * first_name, ...)
1469 {
1470   const char *name;
1471
1472   va_list args;
1473
1474   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1475
1476   va_start (args, first_name);
1477
1478   name = first_name;
1479
1480   while (name) {
1481     int arg_id = va_arg (args, int);
1482     int flags = va_arg (args, int);
1483
1484     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id,
1485         flags);
1486
1487     name = va_arg (args, char *);
1488   }
1489
1490   va_end (args);
1491 }
1492
1493
1494 /**
1495  * gst_buffer_merge:
1496  * @buf1: a first source #GstBuffer to merge.
1497  * @buf2: the second source #GstBuffer to merge.
1498  *
1499  * Create a new buffer that is the concatenation of the two source
1500  * buffers.  The original source buffers will not be modified or
1501  * unref'd.  Make sure you unref the source buffers if they are not used
1502  * anymore afterwards.
1503  *
1504  * If the buffers point to contiguous areas of memory, the buffer
1505  * is created without copying the data.
1506  *
1507  * Returns: the new #GstBuffer that's the concatenation of the source buffers.
1508  */
1509 GstBuffer *
1510 gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
1511 {
1512   GstBuffer *result;
1513
1514   /* we're just a specific case of the more general gst_buffer_span() */
1515   result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
1516
1517   return result;
1518 }
1519
1520 /**
1521  * gst_buffer_stamp:
1522  * @dest: buffer to stamp
1523  * @src: buffer to stamp from
1524  *
1525  * Copies additional information (timestamps and offsets) from one buffer to
1526  * the other.
1527  */
1528 void
1529 gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
1530 {
1531   g_return_if_fail (dest != NULL);
1532   g_return_if_fail (src != NULL);
1533
1534   GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
1535   GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
1536   GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
1537   GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
1538 }
1539
1540 static gboolean
1541 intersect_caps_func (GstPad * pad, GValue * ret, GstPad * orig)
1542 {
1543   if (pad != orig) {
1544     GstCaps *peercaps, *existing;
1545
1546     existing = g_value_get_pointer (ret);
1547     peercaps = gst_pad_peer_get_caps (pad);
1548     g_value_set_pointer (ret, gst_caps_intersect (existing, peercaps));
1549     gst_caps_unref (existing);
1550     gst_caps_unref (peercaps);
1551   }
1552   return TRUE;
1553 }
1554
1555 /**
1556  * gst_pad_proxy_getcaps:
1557  * @pad: a #GstPad to proxy.
1558  *
1559  * Calls gst_pad_get_allowed_caps() for every other pad belonging to the
1560  * same element as @pad, and returns the intersection of the results.
1561  *
1562  * This function is useful as a default getcaps function for an element
1563  * that can handle any stream format, but requires all its pads to have
1564  * the same caps.  Two such elements are tee and aggregator.
1565  *
1566  * Returns: the intersection of the other pads' allowed caps.
1567  */
1568 GstCaps *
1569 gst_pad_proxy_getcaps (GstPad * pad)
1570 {
1571   GstElement *element;
1572   GstCaps *caps, *intersected;
1573   GstIterator *iter;
1574   GstIteratorResult res;
1575   GValue ret = { 0, };
1576
1577   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1578
1579   GST_DEBUG ("proxying getcaps for %s:%s", GST_DEBUG_PAD_NAME (pad));
1580
1581   element = gst_pad_get_parent (pad);
1582   if (element == NULL)
1583     return NULL;
1584
1585   iter = gst_element_iterate_pads (element);
1586
1587   g_value_init (&ret, G_TYPE_POINTER);
1588   g_value_set_pointer (&ret, gst_caps_new_any ());
1589
1590   res = gst_iterator_fold (iter, (GstIteratorFoldFunction) intersect_caps_func,
1591       &ret, pad);
1592   gst_iterator_free (iter);
1593
1594   if (res != GST_ITERATOR_DONE) {
1595     g_warning ("Pad list changed during capsnego for element %s",
1596         GST_ELEMENT_NAME (element));
1597     return NULL;
1598   }
1599
1600   caps = g_value_get_pointer (&ret);
1601   g_value_unset (&ret);
1602
1603   intersected = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
1604   gst_caps_unref (caps);
1605
1606   return intersected;
1607 }
1608
1609 typedef struct
1610 {
1611   GstPad *orig;
1612   GstCaps *caps;
1613 } LinkData;
1614
1615 static gboolean
1616 link_fold_func (GstPad * pad, GValue * ret, LinkData * data)
1617 {
1618   gboolean success = TRUE;
1619
1620   if (pad != data->orig) {
1621     success = gst_pad_set_caps (pad, data->caps);
1622     g_value_set_boolean (ret, success);
1623   }
1624
1625   return success;
1626 }
1627
1628 /**
1629  * gst_pad_proxy_setcaps
1630  * @pad: a #GstPad to proxy from
1631  * @caps: the #GstCaps to link with
1632  *
1633  * Calls gst_pad_set_caps() for every other pad belonging to the
1634  * same element as @pad.  If gst_pad_set_caps() fails on any pad,
1635  * the proxy setcaps fails. May be used only during negotiation.
1636  *
1637  * Returns: TRUE if sucessful
1638  */
1639 gboolean
1640 gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps)
1641 {
1642   GstElement *element;
1643   GstIterator *iter;
1644   GstIteratorResult res;
1645   GValue ret = { 0, };
1646   LinkData data;
1647
1648   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
1649   g_return_val_if_fail (caps != NULL, FALSE);
1650
1651   GST_DEBUG ("proxying pad link for %s:%s", GST_DEBUG_PAD_NAME (pad));
1652
1653   element = gst_pad_get_parent (pad);
1654
1655   iter = gst_element_iterate_pads (element);
1656
1657   g_value_init (&ret, G_TYPE_BOOLEAN);
1658   g_value_set_boolean (&ret, TRUE);
1659   data.orig = pad;
1660   data.caps = caps;
1661
1662   res = gst_iterator_fold (iter, (GstIteratorFoldFunction) link_fold_func,
1663       &ret, &data);
1664   gst_iterator_free (iter);
1665
1666   if (res != GST_ITERATOR_DONE) {
1667     g_warning ("Pad list changed during proxy_pad_link for element %s",
1668         GST_ELEMENT_NAME (element));
1669     return FALSE;
1670   }
1671
1672   /* ok not to unset the gvalue */
1673   return g_value_get_boolean (&ret);
1674 }
1675
1676
1677 /**
1678  * gst_atomic_int_set:
1679  * @atomic_int: pointer to an atomic integer
1680  * @value: value to set
1681  *
1682  * Unconditionally sets the atomic integer to @value.
1683  */
1684 void
1685 gst_atomic_int_set (gint * atomic_int, gint value)
1686 {
1687   int ignore;
1688
1689   *atomic_int = value;
1690   ignore = g_atomic_int_get (atomic_int);
1691 }