First THREADED backport attempt, focusing on adding locks and making sure the API...
[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_get_compatible_pad_template:
375  * @element: a #GstElement to get a compatible pad template for.
376  * @compattempl: the #GstPadTemplate to find a compatible template for.
377  *
378  * Retrieves a pad template from @element that is compatible with @compattempl.
379  * Pads from compatible templates can be linked together.
380  *
381  * Returns: a compatible #GstPadTemplate, or NULL if none was found. No
382  * unreferencing is necessary.
383  */
384 GstPadTemplate *
385 gst_element_get_compatible_pad_template (GstElement * element,
386     GstPadTemplate * compattempl)
387 {
388   GstPadTemplate *newtempl = NULL;
389   GList *padlist;
390   GstElementClass *class;
391
392   g_return_val_if_fail (element != NULL, NULL);
393   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
394   g_return_val_if_fail (compattempl != NULL, NULL);
395
396   class = GST_ELEMENT_GET_CLASS (element);
397
398   padlist = gst_element_class_get_pad_template_list (class);
399
400   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
401       "Looking for a suitable pad template in %s out of %d templates...",
402       GST_ELEMENT_NAME (element), g_list_length (padlist));
403
404   while (padlist) {
405     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
406     GstCaps *intersection;
407
408     /* Ignore name
409      * Ignore presence
410      * Check direction (must be opposite)
411      * Check caps
412      */
413     GST_CAT_LOG (GST_CAT_CAPS,
414         "checking pad template %s", padtempl->name_template);
415     if (padtempl->direction != compattempl->direction) {
416       GST_CAT_DEBUG (GST_CAT_CAPS,
417           "compatible direction: found %s pad template \"%s\"",
418           padtempl->direction == GST_PAD_SRC ? "src" : "sink",
419           padtempl->name_template);
420
421       intersection = gst_caps_intersect (GST_PAD_TEMPLATE_CAPS (compattempl),
422           GST_PAD_TEMPLATE_CAPS (padtempl));
423
424       GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible",
425           (intersection ? "" : "not "));
426
427       if (!gst_caps_is_empty (intersection))
428         newtempl = padtempl;
429       gst_caps_unref (intersection);
430       if (newtempl)
431         break;
432     }
433
434     padlist = g_list_next (padlist);
435   }
436   if (newtempl)
437     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
438         "Returning new pad template %p", newtempl);
439   else
440     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "No compatible pad template found");
441
442   return newtempl;
443 }
444
445 static GstPad *
446 gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
447     const gchar * name)
448 {
449   GstPad *newpad = NULL;
450   GstElementClass *oclass;
451
452   oclass = GST_ELEMENT_GET_CLASS (element);
453
454   if (oclass->request_new_pad)
455     newpad = (oclass->request_new_pad) (element, templ, name);
456
457   return newpad;
458 }
459
460
461
462 /**
463  * gst_element_get_pad_from_template:
464  * @element: a #GstElement.
465  * @templ: a #GstPadTemplate belonging to @element.
466  *
467  * Gets a pad from @element described by @templ. If the presence of @templ is
468  * #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES
469  * templates.
470  *
471  * Returns: the #GstPad, or NULL if one could not be found or created.
472  */
473 static GstPad *
474 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
475 {
476   GstPad *ret = NULL;
477   GstPadPresence presence;
478
479   /* If this function is ever exported, we need check the validity of `element'
480    * and `templ', and to make sure the template actually belongs to the
481    * element. */
482
483   presence = GST_PAD_TEMPLATE_PRESENCE (templ);
484
485   switch (presence) {
486     case GST_PAD_ALWAYS:
487     case GST_PAD_SOMETIMES:
488       ret = gst_element_get_static_pad (element, templ->name_template);
489       if (!ret && presence == GST_PAD_ALWAYS)
490         g_warning
491             ("Element %s has an ALWAYS template %s, but no pad of the same name",
492             GST_OBJECT_NAME (element), templ->name_template);
493       break;
494
495     case GST_PAD_REQUEST:
496       ret = gst_element_request_pad (element, templ, NULL);
497       break;
498   }
499
500   return ret;
501 }
502
503 /**
504  * gst_element_request_compatible_pad:
505  * @element: a #GstElement.
506  * @templ: the #GstPadTemplate to which the new pad should be able to link.
507  *
508  * Requests a pad from @element. The returned pad should be unlinked and
509  * compatible with @templ. Might return an existing pad, or request a new one.
510  *
511  * Returns: a #GstPad, or %NULL if one could not be found or created.
512  */
513 GstPad *
514 gst_element_request_compatible_pad (GstElement * element,
515     GstPadTemplate * templ)
516 {
517   GstPadTemplate *templ_new;
518   GstPad *pad = NULL;
519
520   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
521   g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
522
523   /* FIXME: should really loop through the templates, testing each for
524    *      compatibility and pad availability. */
525   templ_new = gst_element_get_compatible_pad_template (element, templ);
526   if (templ_new)
527     pad = gst_element_get_pad_from_template (element, templ_new);
528
529   /* This can happen for non-request pads. No need to unref. */
530   if (pad && GST_PAD_PEER (pad))
531     pad = NULL;
532
533   return pad;
534 }
535
536 /**
537  * gst_element_get_compatible_pad_filtered:
538  * @element: a #GstElement in which the pad should be found.
539  * @pad: the #GstPad to find a compatible one for.
540  * @filtercaps: the #GstCaps to use as a filter.
541  *
542  * Looks for an unlinked pad to which the given pad can link. It is not
543  * guaranteed that linking the pads will work, though it should work in most
544  * cases.
545  *
546  * Returns: the #GstPad to which a link can be made, or %NULL if one cannot be
547  * found.
548  */
549 GstPad *
550 gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
551     const GstCaps * filtercaps)
552 {
553   GstIterator *pads;
554   GstPadTemplate *templ;
555   GstCaps *templcaps;
556   GstPad *foundpad = NULL;
557   gboolean done;
558
559   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
560   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
561
562   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
563       "finding pad in %s compatible with %s:%s and filter %" GST_PTR_FORMAT,
564       GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad), filtercaps);
565
566   /* let's use the real pad */
567   pad = (GstPad *) GST_PAD_REALIZE (pad);
568   g_return_val_if_fail (pad != NULL, NULL);
569   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
570
571   done = FALSE;
572   /* try to get an existing unlinked pad */
573   pads = gst_element_iterate_pads (element);
574   while (!done) {
575     gpointer padptr;
576
577     switch (gst_iterator_next (pads, &padptr)) {
578       case GST_ITERATOR_OK:
579       {
580         GstPad *peer;
581         GstPad *current;
582
583         current = GST_PAD (padptr);
584
585         GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s",
586             GST_DEBUG_PAD_NAME (current));
587
588         peer = gst_pad_get_peer (current);
589
590         if (peer == NULL &&
591             gst_pad_can_link_filtered (pad, current, filtercaps)) {
592
593           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
594               "found existing unlinked pad %s:%s",
595               GST_DEBUG_PAD_NAME (current));
596
597           gst_iterator_free (pads);
598
599           return current;
600         } else {
601           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");
602
603           gst_object_unref (GST_OBJECT (current));
604           if (peer)
605             gst_object_unref (GST_OBJECT (peer));
606         }
607         break;
608       }
609       case GST_ITERATOR_DONE:
610         done = TRUE;
611         break;
612       case GST_ITERATOR_RESYNC:
613         gst_iterator_resync (pads);
614         break;
615       case GST_ITERATOR_ERROR:
616         g_assert_not_reached ();
617         break;
618     }
619   }
620   gst_iterator_free (pads);
621
622   /* try to create a new one */
623   /* requesting is a little crazy, we need a template. Let's create one */
624   templcaps = gst_pad_get_caps (pad);
625   if (filtercaps != NULL) {
626     GstCaps *temp;
627
628     temp = gst_caps_intersect (filtercaps, templcaps);
629     gst_caps_unref (templcaps);
630     templcaps = temp;
631   }
632
633   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
634       GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
635   foundpad = gst_element_request_compatible_pad (element, templ);
636   gst_object_unref (GST_OBJECT (templ));
637
638   if (foundpad) {
639     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
640         "found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad));
641     return foundpad;
642   }
643
644   GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element,
645       "Could not find a compatible pad to link to %s:%s",
646       GST_DEBUG_PAD_NAME (pad));
647   return NULL;
648 }
649
650
651
652 /**
653  * gst_element_get_compatible_pad:
654  * @element: a #GstElement in which the pad should be found.
655  * @pad: the #GstPad to find a compatible one for.
656  *
657  * Looks for an unlinked pad to which the given pad can link to.
658  * It is not guaranteed that linking the pads will work, though
659  * it should work in most cases.
660  *
661  * Returns: the #GstPad to which a link can be made, or %NULL if one
662  * could not be found.
663  */
664 GstPad *
665 gst_element_get_compatible_pad (GstElement * element, GstPad * pad)
666 {
667   return gst_element_get_compatible_pad_filtered (element, pad, NULL);
668 }
669
670 /**
671  * gst_element_state_get_name:
672  * @state: a #GstElementState to get the name of.
673  *
674  * Gets a string representing the given state.
675  *
676  * Returns: a string with the name of the state.
677  */
678 const gchar *
679 gst_element_state_get_name (GstElementState state)
680 {
681   switch (state) {
682 #ifdef GST_DEBUG_COLOR
683     case GST_STATE_VOID_PENDING:
684       return "NONE_PENDING";
685       break;
686     case GST_STATE_NULL:
687       return "\033[01;34mNULL\033[00m";
688       break;
689     case GST_STATE_READY:
690       return "\033[01;31mREADY\033[00m";
691       break;
692     case GST_STATE_PLAYING:
693       return "\033[01;32mPLAYING\033[00m";
694       break;
695     case GST_STATE_PAUSED:
696       return "\033[01;33mPAUSED\033[00m";
697       break;
698     default:
699       /* This is a memory leak */
700       return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
701 #else
702     case GST_STATE_VOID_PENDING:
703       return "NONE_PENDING";
704       break;
705     case GST_STATE_NULL:
706       return "NULL";
707       break;
708     case GST_STATE_READY:
709       return "READY";
710       break;
711     case GST_STATE_PLAYING:
712       return "PLAYING";
713       break;
714     case GST_STATE_PAUSED:
715       return "PAUSED";
716       break;
717     default:
718       return g_strdup_printf ("UNKNOWN!(%d)", state);
719 #endif
720   }
721   return "";
722 }
723
724 /**
725  * gst_element_link_pads_filtered:
726  * @src: a #GstElement containing the source pad.
727  * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
728  * @dest: the #GstElement containing the destination pad.
729  * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
730  * @filtercaps: the #GstCaps to use as a filter.
731  *
732  * Links the two named pads of the source and destination elements.
733  * Side effect is that if one of the pads has no parent, it becomes a
734  * child of the parent of the other element.  If they have different
735  * parents, the link fails.
736  *
737  * Returns: TRUE if the pads could be linked, FALSE otherwise.
738  */
739 gboolean
740 gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
741     GstElement * dest, const gchar * destpadname, const GstCaps * filtercaps)
742 {
743   const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
744   GstPad *srcpad, *destpad;
745   GstPadTemplate *srctempl, *desttempl;
746   GstElementClass *srcclass, *destclass;
747
748   /* checks */
749   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
750   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
751
752   srcclass = GST_ELEMENT_GET_CLASS (src);
753   destclass = GST_ELEMENT_GET_CLASS (dest);
754
755   GST_CAT_INFO (GST_CAT_ELEMENT_PADS,
756       "trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),
757       srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),
758       destpadname ? destpadname : "(any)");
759
760   /* now get the pads we're trying to link and a list of all remaining pads */
761   if (srcpadname) {
762     srcpad = gst_element_get_pad (src, srcpadname);
763     if (!srcpad) {
764       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
765           GST_ELEMENT_NAME (src), srcpadname);
766       return FALSE;
767     } else {
768       if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
769         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
770             GST_DEBUG_PAD_NAME (srcpad));
771         gst_object_unref (GST_OBJECT (srcpad));
772         return FALSE;
773       }
774       if (GST_PAD_PEER (srcpad) != NULL) {
775         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
776             GST_DEBUG_PAD_NAME (srcpad));
777         gst_object_unref (GST_OBJECT (srcpad));
778         return FALSE;
779       }
780     }
781     srcpads = NULL;
782   } else {
783     GST_LOCK (src);
784     srcpads = GST_ELEMENT_PADS (src);
785     srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
786     if (srcpad)
787       gst_object_ref (GST_OBJECT (srcpad));
788     GST_UNLOCK (src);
789   }
790   if (destpadname) {
791     destpad = gst_element_get_pad (dest, destpadname);
792     if (!destpad) {
793       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
794           GST_ELEMENT_NAME (dest), destpadname);
795       return FALSE;
796     } else {
797       if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
798         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
799             GST_DEBUG_PAD_NAME (destpad));
800         gst_object_unref (GST_OBJECT (destpad));
801         return FALSE;
802       }
803       if (GST_PAD_PEER (destpad) != NULL) {
804         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
805             GST_DEBUG_PAD_NAME (destpad));
806         gst_object_unref (GST_OBJECT (destpad));
807         return FALSE;
808       }
809     }
810     destpads = NULL;
811   } else {
812     GST_LOCK (dest);
813     destpads = GST_ELEMENT_PADS (dest);
814     destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
815     if (destpad)
816       gst_object_ref (GST_OBJECT (destpad));
817     GST_UNLOCK (dest);
818   }
819
820   if (srcpadname && destpadname) {
821     gboolean result;
822
823     /* two explicitly specified pads */
824     result = gst_pad_link_filtered (srcpad, destpad, filtercaps);
825
826     gst_object_unref (GST_OBJECT (srcpad));
827     gst_object_unref (GST_OBJECT (destpad));
828
829     return result;
830   }
831   if (srcpad) {
832     /* loop through the allowed pads in the source, trying to find a
833      * compatible destination pad */
834     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
835         "looping through allowed src and dest pads");
836     do {
837       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
838           GST_DEBUG_PAD_NAME (srcpad));
839       if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
840           (GST_PAD_PEER (srcpad) == NULL)) {
841         GstPad *temp = destpadname ? destpad :
842             gst_element_get_compatible_pad_filtered (dest, srcpad,
843             filtercaps);
844
845         if (temp
846             && gst_pad_link_filtered (srcpad, temp,
847                 filtercaps) == GST_PAD_LINK_OK) {
848           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
849               GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
850           if (destpad)
851             gst_object_unref (GST_OBJECT (destpad));
852           gst_object_unref (GST_OBJECT (srcpad));
853           gst_object_unref (GST_OBJECT (temp));
854           return TRUE;
855         }
856       }
857       /* find a better way for this mess */
858       if (srcpads) {
859         srcpads = g_list_next (srcpads);
860         if (srcpads) {
861           gst_object_unref (GST_OBJECT (srcpad));
862           srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
863           gst_object_ref (GST_OBJECT (srcpad));
864         }
865       }
866     } while (srcpads);
867   }
868   if (srcpadname) {
869     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
870         GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
871     gst_object_unref (GST_OBJECT (srcpad));
872     if (destpad)
873       gst_object_unref (GST_OBJECT (destpad));
874     return FALSE;
875   } else {
876     gst_object_unref (GST_OBJECT (srcpad));
877     srcpad = NULL;
878   }
879   if (destpad) {
880     /* loop through the existing pads in the destination */
881     do {
882       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
883           GST_DEBUG_PAD_NAME (destpad));
884       if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
885           (GST_PAD_PEER (destpad) == NULL)) {
886         GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad,
887             filtercaps);
888
889         if (temp
890             && gst_pad_link_filtered (temp, destpad,
891                 filtercaps) == GST_PAD_LINK_OK) {
892           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
893               GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
894           gst_object_unref (GST_OBJECT (temp));
895           gst_object_unref (GST_OBJECT (destpad));
896           if (srcpad)
897             gst_object_unref (GST_OBJECT (srcpad));
898           return TRUE;
899         }
900       }
901       if (destpads) {
902         destpads = g_list_next (destpads);
903         if (destpads) {
904           gst_object_unref (GST_OBJECT (destpad));
905           destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
906           gst_object_ref (GST_OBJECT (destpad));
907         }
908       }
909     } while (destpads);
910   }
911   if (destpadname) {
912     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
913         GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
914     gst_object_unref (GST_OBJECT (destpad));
915     if (srcpad)
916       gst_object_unref (GST_OBJECT (srcpad));
917     return FALSE;
918   } else {
919     gst_object_unref (GST_OBJECT (destpad));
920     if (srcpad)
921       gst_object_unref (GST_OBJECT (srcpad));
922     srcpad = NULL;
923     destpad = NULL;
924   }
925
926   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
927       "we might have request pads on both sides, checking...");
928   srctempls = gst_element_class_get_pad_template_list (srcclass);
929   desttempls = gst_element_class_get_pad_template_list (destclass);
930
931   if (srctempls && desttempls) {
932     while (srctempls) {
933       srctempl = (GstPadTemplate *) srctempls->data;
934       if (srctempl->presence == GST_PAD_REQUEST) {
935         for (l = desttempls; l; l = l->next) {
936           desttempl = (GstPadTemplate *) l->data;
937           if (desttempl->presence == GST_PAD_REQUEST &&
938               desttempl->direction != srctempl->direction) {
939             if (gst_caps_is_always_compatible (gst_pad_template_get_caps
940                     (srctempl), gst_pad_template_get_caps (desttempl))) {
941               srcpad =
942                   gst_element_get_request_pad (src, srctempl->name_template);
943               destpad =
944                   gst_element_get_request_pad (dest, desttempl->name_template);
945               if (gst_pad_link_filtered (srcpad, destpad,
946                       filtercaps) == GST_PAD_LINK_OK) {
947                 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
948                     "linked pad %s:%s to pad %s:%s",
949                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
950                 gst_object_unref (GST_OBJECT (srcpad));
951                 gst_object_unref (GST_OBJECT (destpad));
952                 return TRUE;
953               }
954               /* it failed, so we release the request pads */
955               gst_element_release_request_pad (src, srcpad);
956               gst_element_release_request_pad (dest, destpad);
957             }
958           }
959         }
960       }
961       srctempls = srctempls->next;
962     }
963   }
964
965   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
966       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
967   return FALSE;
968 }
969
970 /**
971  * gst_element_link_filtered:
972  * @src: a #GstElement containing the source pad.
973  * @dest: the #GstElement containing the destination pad.
974  * @filtercaps: the #GstCaps to use as a filter.
975  *
976  * Links @src to @dest, filtered by @filtercaps. The link must be from source to
977  * destination; the other direction will not be tried. The function looks for
978  * existing pads that aren't linked yet. It will request new pads if necessary.
979  * If multiple links are possible, only one is established.
980  *
981  * Returns: TRUE if the elements could be linked, FALSE otherwise.
982  */
983 gboolean
984 gst_element_link_filtered (GstElement * src, GstElement * dest,
985     const GstCaps * filtercaps)
986 {
987   return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
988 }
989
990 /**
991  * gst_element_link_many:
992  * @element_1: the first #GstElement in the link chain.
993  * @element_2: the second #GstElement in the link chain.
994  * @...: the NULL-terminated list of elements to link in order.
995  *
996  * Chain together a series of elements. Uses gst_element_link().
997  *
998  * Returns: TRUE on success, FALSE otherwise.
999  */
1000 gboolean
1001 gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
1002 {
1003   va_list args;
1004
1005   g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE);
1006   g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE);
1007
1008   va_start (args, element_2);
1009
1010   while (element_2) {
1011     if (!gst_element_link (element_1, element_2))
1012       return FALSE;
1013
1014     element_1 = element_2;
1015     element_2 = va_arg (args, GstElement *);
1016   }
1017
1018   va_end (args);
1019
1020   return TRUE;
1021 }
1022
1023 /**
1024  * gst_element_link:
1025  * @src: a #GstElement containing the source pad.
1026  * @dest: the #GstElement containing the destination pad.
1027  *
1028  * Links @src to @dest with no filter caps. See gst_element_link_filtered() for
1029  * more information.
1030  *
1031  * Returns: TRUE if the elements could be linked, FALSE otherwise.
1032  */
1033 gboolean
1034 gst_element_link (GstElement * src, GstElement * dest)
1035 {
1036   return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
1037 }
1038
1039 /**
1040  * gst_element_link_pads:
1041  * @src: a #GstElement containing the source pad.
1042  * @srcpadname: the name of the #GstPad in the source element.
1043  * @dest: the #GstElement containing the destination pad.
1044  * @destpadname: the name of the #GstPad in destination element.
1045  *
1046  * Links the two named pads of the source and destination elements.
1047  * Side effect is that if one of the pads has no parent, it becomes a
1048  * child of the parent of the other element.  If they have different
1049  * parents, the link fails.
1050  *
1051  * Returns: TRUE if the pads could be linked, FALSE otherwise.
1052  */
1053 gboolean
1054 gst_element_link_pads (GstElement * src, const gchar * srcpadname,
1055     GstElement * dest, const gchar * destpadname)
1056 {
1057   return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname,
1058       NULL);
1059 }
1060
1061 /**
1062  * gst_element_unlink_pads:
1063  * @src: a #GstElement containing the source pad.
1064  * @srcpadname: the name of the #GstPad in source element.
1065  * @dest: a #GstElement containing the destination pad.
1066  * @destpadname: the name of the #GstPad in destination element.
1067  *
1068  * Unlinks the two named pads of the source and destination elements.
1069  */
1070 void
1071 gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
1072     GstElement * dest, const gchar * destpadname)
1073 {
1074   GstPad *srcpad, *destpad;
1075
1076   g_return_if_fail (src != NULL);
1077   g_return_if_fail (GST_IS_ELEMENT (src));
1078   g_return_if_fail (srcpadname != NULL);
1079   g_return_if_fail (dest != NULL);
1080   g_return_if_fail (GST_IS_ELEMENT (dest));
1081   g_return_if_fail (destpadname != NULL);
1082
1083   /* obtain the pads requested */
1084   srcpad = gst_element_get_pad (src, srcpadname);
1085   if (srcpad == NULL) {
1086     GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
1087     return;
1088   }
1089   destpad = gst_element_get_pad (dest, destpadname);
1090   if (srcpad == NULL) {
1091     GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
1092         destpadname);
1093     return;
1094   }
1095
1096   /* we're satisified they can be unlinked, let's do it */
1097   gst_pad_unlink (srcpad, destpad);
1098 }
1099
1100 /**
1101  * gst_element_unlink_many:
1102  * @element_1: the first #GstElement in the link chain.
1103  * @element_2: the second #GstElement in the link chain.
1104  * @...: the NULL-terminated list of elements to unlink in order.
1105  *
1106  * Unlinks a series of elements. Uses gst_element_unlink().
1107  */
1108 void
1109 gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
1110 {
1111   va_list args;
1112
1113   g_return_if_fail (element_1 != NULL && element_2 != NULL);
1114   g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1115
1116   va_start (args, element_2);
1117
1118   while (element_2) {
1119     gst_element_unlink (element_1, element_2);
1120
1121     element_1 = element_2;
1122     element_2 = va_arg (args, GstElement *);
1123   }
1124
1125   va_end (args);
1126 }
1127
1128 /**
1129  * gst_element_unlink:
1130  * @src: the source #GstElement to unlink.
1131  * @dest: the sink #GstElement to unlink.
1132  *
1133  * Unlinks all source pads of the source element with all sink pads
1134  * of the sink element to which they are linked.
1135  */
1136 void
1137 gst_element_unlink (GstElement * src, GstElement * dest)
1138 {
1139   GstIterator *pads;
1140   gboolean done = FALSE;
1141
1142   g_return_if_fail (GST_IS_ELEMENT (src));
1143   g_return_if_fail (GST_IS_ELEMENT (dest));
1144
1145   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
1146       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1147
1148   pads = gst_element_iterate_pads (src);
1149   while (!done) {
1150     gpointer data;
1151
1152     switch (gst_iterator_next (pads, &data)) {
1153       case GST_ITERATOR_OK:
1154       {
1155         GstPad *pad = GST_PAD_CAST (data);
1156
1157         /* we only care about real src pads */
1158         if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
1159           GstPad *peerpad = gst_pad_get_peer (pad);
1160
1161           /* see if the pad is connected and is really a pad
1162            * of dest */
1163           if (peerpad) {
1164             GstElement *peerelem = gst_pad_get_parent (peerpad);
1165
1166             if (peerelem == dest) {
1167               gst_pad_unlink (pad, peerpad);
1168             }
1169             if (peerelem)
1170               gst_object_unref (GST_OBJECT (peerelem));
1171
1172             gst_object_unref (GST_OBJECT (peerpad));
1173           }
1174         }
1175         gst_object_unref (GST_OBJECT (pad));
1176         break;
1177       }
1178       case GST_ITERATOR_RESYNC:
1179         gst_iterator_resync (pads);
1180         break;
1181       case GST_ITERATOR_DONE:
1182         done = TRUE;
1183         break;
1184       default:
1185         g_assert_not_reached ();
1186         break;
1187     }
1188   }
1189 }
1190
1191 /**
1192  * gst_pad_can_link_filtered:
1193  * @srcpad: the source #GstPad to link.
1194  * @sinkpad: the sink #GstPad to link.
1195  * @filtercaps: the filter #GstCaps.
1196  *
1197  * Checks if the source pad and the sink pad can be linked when constrained
1198  * by the given filter caps. Both @srcpad and @sinkpad must be unlinked.
1199  *
1200  * Returns: TRUE if the pads can be linked, FALSE otherwise.
1201  */
1202 gboolean
1203 gst_pad_can_link_filtered (GstPad * srcpad, GstPad * sinkpad,
1204     const GstCaps * filtercaps)
1205 {
1206   GstRealPad *realsrc, *realsink;
1207
1208   /* FIXME This function is gross.  It's almost a direct copy of
1209    * gst_pad_link_filtered().  Any decent programmer would attempt
1210    * to merge the two functions, which I will do some day. --ds
1211    */
1212
1213   /* generic checks */
1214   g_return_val_if_fail (srcpad != NULL, FALSE);
1215   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
1216   g_return_val_if_fail (sinkpad != NULL, FALSE);
1217   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
1218
1219   GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
1220       GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1221
1222   /* now we need to deal with the real/ghost stuff */
1223   realsrc = GST_PAD_REALIZE (srcpad);
1224   realsink = GST_PAD_REALIZE (sinkpad);
1225
1226   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
1227     GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
1228         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1229   }
1230   /* FIXME: shouldn't we convert this to g_return_val_if_fail? */
1231   if (GST_RPAD_PEER (realsrc) != NULL) {
1232     GST_CAT_INFO (GST_CAT_PADS, "Real source pad %s:%s has a peer, failed",
1233         GST_DEBUG_PAD_NAME (realsrc));
1234     return FALSE;
1235   }
1236   if (GST_RPAD_PEER (realsink) != NULL) {
1237     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has a peer, failed",
1238         GST_DEBUG_PAD_NAME (realsink));
1239     return FALSE;
1240   }
1241   if (!GST_PAD_IS_SRC (realsrc)) {
1242     GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s is not source pad, failed",
1243         GST_DEBUG_PAD_NAME (realsrc));
1244     return FALSE;
1245   }
1246   if (!GST_PAD_IS_SINK (realsink)) {
1247     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s is not sink pad, failed",
1248         GST_DEBUG_PAD_NAME (realsink));
1249     return FALSE;
1250   }
1251   if (GST_PAD_PARENT (realsrc) == NULL) {
1252     GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s has no parent, failed",
1253         GST_DEBUG_PAD_NAME (realsrc));
1254     return FALSE;
1255   }
1256   if (GST_PAD_PARENT (realsink) == NULL) {
1257     GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has no parent, failed",
1258         GST_DEBUG_PAD_NAME (realsrc));
1259     return FALSE;
1260   }
1261
1262   g_return_val_if_fail (realsrc != NULL, GST_PAD_LINK_REFUSED);
1263   g_return_val_if_fail (realsink != NULL, GST_PAD_LINK_REFUSED);
1264
1265   return TRUE;
1266 }
1267
1268 /**
1269  * gst_pad_can_link:
1270  * @srcpad: the source #GstPad to link.
1271  * @sinkpad: the sink #GstPad to link.
1272  *
1273  * Checks if the source pad and the sink pad can be linked.
1274  *
1275  * Returns: TRUE if the pads can be linked, FALSE otherwise.
1276  */
1277 gboolean
1278 gst_pad_can_link (GstPad * srcpad, GstPad * sinkpad)
1279 {
1280   return gst_pad_can_link_filtered (srcpad, sinkpad, NULL);
1281 }
1282
1283 /**
1284  * gst_pad_use_fixed_caps:
1285  * @pad: the pad to use
1286  *
1287  * A helper function you can use that sets the 
1288  * @gst_pad_get_fixed_caps_func as the gstcaps function for the
1289  * pad. This way the function will always return the negotiated caps
1290  * or in case the pad is not negotiated, the padtemplate caps.
1291  */
1292 void
1293 gst_pad_use_fixed_caps (GstPad * pad)
1294 {
1295   gst_pad_set_getcaps_function (pad, gst_pad_get_fixed_caps_func);
1296 }
1297
1298 /**
1299  * gst_pad_get_fixed_caps_func:
1300  * @pad: the pad to use
1301  *
1302  * A helper function you can use as a GetCaps function that
1303  * will return the currently negotiated caps or the padtemplate
1304  * when NULL.
1305  *
1306  * Returns: The currently negotiated caps or the padtemplate.
1307  */
1308 GstCaps *
1309 gst_pad_get_fixed_caps_func (GstPad * pad)
1310 {
1311   GstCaps *result;
1312   GstRealPad *realpad;
1313
1314   g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
1315
1316   realpad = GST_REAL_PAD_CAST (pad);
1317
1318   if (GST_RPAD_CAPS (realpad)) {
1319     result = GST_RPAD_CAPS (realpad);
1320
1321     GST_CAT_DEBUG (GST_CAT_CAPS,
1322         "using pad caps %p %" GST_PTR_FORMAT, result, result);
1323
1324     result = gst_caps_ref (result);
1325     goto done;
1326   }
1327   if (GST_PAD_PAD_TEMPLATE (realpad)) {
1328     GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (realpad);
1329
1330     result = GST_PAD_TEMPLATE_CAPS (templ);
1331     GST_CAT_DEBUG (GST_CAT_CAPS,
1332         "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
1333         result);
1334
1335     result = gst_caps_ref (result);
1336     goto done;
1337   }
1338   GST_CAT_DEBUG (GST_CAT_CAPS, "pad has no caps");
1339   result = gst_caps_new_empty ();
1340
1341 done:
1342   return result;
1343 }
1344
1345 /**
1346  * gst_object_default_error:
1347  * @object: a #GObject that signalled the error.
1348  * @orig: the #GstObject that initiated the error.
1349  * @error: the GError.
1350  * @debug: an additional debug information string, or NULL.
1351  *
1352  * A default error function.
1353  *
1354  * The default handler will simply print the error string using g_print.
1355  */
1356 void
1357 gst_object_default_error (GstObject * source, GError * error, gchar * debug)
1358 {
1359   gchar *name = gst_object_get_path_string (source);
1360
1361   g_print (_("ERROR: from element %s: %s\n"), name, error->message);
1362   if (debug)
1363     g_print (_("Additional debug info:\n%s\n"), debug);
1364
1365   g_free (name);
1366 }
1367
1368 /**
1369  * gst_bin_add_many:
1370  * @bin: the bin to add the elements to
1371  * @element_1: the first element to add to the bin
1372  * @...: additional elements to add to the bin
1373  *
1374  * Adds a NULL-terminated list of elements to a bin.  This function is
1375  * equivalent to calling #gst_bin_add() for each member of the list.
1376  */
1377 void
1378 gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
1379 {
1380   va_list args;
1381
1382   g_return_if_fail (GST_IS_BIN (bin));
1383   g_return_if_fail (GST_IS_ELEMENT (element_1));
1384
1385   va_start (args, element_1);
1386
1387   while (element_1) {
1388     gst_bin_add (bin, element_1);
1389
1390     element_1 = va_arg (args, GstElement *);
1391   }
1392
1393   va_end (args);
1394 }
1395
1396 /**
1397  * gst_bin_remove_many:
1398  * @bin: the bin to remove the elements from
1399  * @element_1: the first element to remove from the bin
1400  * @...: NULL-terminated list of elements to remove from the bin
1401  *
1402  * Remove a list of elements from a bin. This function is equivalent
1403  * to calling #gst_bin_remove with each member of the list.
1404  */
1405 void
1406 gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
1407 {
1408   va_list args;
1409
1410   g_return_if_fail (GST_IS_BIN (bin));
1411   g_return_if_fail (GST_IS_ELEMENT (element_1));
1412
1413   va_start (args, element_1);
1414
1415   while (element_1) {
1416     gst_bin_remove (bin, element_1);
1417
1418     element_1 = va_arg (args, GstElement *);
1419   }
1420
1421   va_end (args);
1422 }
1423
1424 static void
1425 gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name,
1426     guint arg_id, GParamFlags flags)
1427 {
1428   GQuark prop_id = g_quark_from_string (prop_name);
1429   GParamSpec *pspec;
1430
1431   static GQuark fd_id = 0;
1432   static GQuark blocksize_id;
1433   static GQuark bytesperread_id;
1434   static GQuark dump_id;
1435   static GQuark filesize_id;
1436   static GQuark mmapsize_id;
1437   static GQuark location_id;
1438   static GQuark offset_id;
1439   static GQuark silent_id;
1440   static GQuark touch_id;
1441
1442   if (!fd_id) {
1443     fd_id = g_quark_from_static_string ("fd");
1444     blocksize_id = g_quark_from_static_string ("blocksize");
1445     bytesperread_id = g_quark_from_static_string ("bytesperread");
1446     dump_id = g_quark_from_static_string ("dump");
1447     filesize_id = g_quark_from_static_string ("filesize");
1448     mmapsize_id = g_quark_from_static_string ("mmapsize");
1449     location_id = g_quark_from_static_string ("location");
1450     offset_id = g_quark_from_static_string ("offset");
1451     silent_id = g_quark_from_static_string ("silent");
1452     touch_id = g_quark_from_static_string ("touch");
1453   }
1454
1455   if (prop_id == fd_id) {
1456     pspec = g_param_spec_int ("fd", "File-descriptor",
1457         "File-descriptor for the file being read", 0, G_MAXINT, 0, flags);
1458   } else if (prop_id == blocksize_id) {
1459     pspec = g_param_spec_ulong ("blocksize", "Block Size",
1460         "Block size to read per buffer", 0, G_MAXULONG, 4096, flags);
1461
1462   } else if (prop_id == bytesperread_id) {
1463     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
1464         "Number of bytes to read per buffer", G_MININT, G_MAXINT, 0, flags);
1465
1466   } else if (prop_id == dump_id) {
1467     pspec = g_param_spec_boolean ("dump", "Dump",
1468         "Dump bytes to stdout", FALSE, flags);
1469
1470   } else if (prop_id == filesize_id) {
1471     pspec = g_param_spec_int64 ("filesize", "File Size",
1472         "Size of the file being read", 0, G_MAXINT64, 0, flags);
1473
1474   } else if (prop_id == mmapsize_id) {
1475     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
1476         "Size in bytes of mmap()d regions", 0, G_MAXULONG, 4 * 1048576, flags);
1477
1478   } else if (prop_id == location_id) {
1479     pspec = g_param_spec_string ("location", "File Location",
1480         "Location of the file to read", NULL, flags);
1481
1482   } else if (prop_id == offset_id) {
1483     pspec = g_param_spec_int64 ("offset", "File Offset",
1484         "Byte offset of current read pointer", 0, G_MAXINT64, 0, flags);
1485
1486   } else if (prop_id == silent_id) {
1487     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
1488         FALSE, flags);
1489
1490   } else if (prop_id == touch_id) {
1491     pspec = g_param_spec_boolean ("touch", "Touch read data",
1492         "Touch data to force disk read before " "push ()", TRUE, flags);
1493   } else {
1494     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
1495         prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
1496     pspec = NULL;
1497   }
1498
1499   if (pspec) {
1500     g_object_class_install_property (klass, arg_id, pspec);
1501   }
1502 }
1503
1504 /**
1505  * gst_element_class_install_std_props:
1506  * @klass: the #GstElementClass to add the properties to.
1507  * @first_name: the name of the first property.
1508  * in a NULL terminated
1509  * @...: the id and flags of the first property, followed by
1510  * further 'name', 'id', 'flags' triplets and terminated by NULL.
1511  *
1512  * Adds a list of standardized properties with types to the @klass.
1513  * the id is for the property switch in your get_prop method, and
1514  * the flags determine readability / writeability.
1515  **/
1516 void
1517 gst_element_class_install_std_props (GstElementClass * klass,
1518     const gchar * first_name, ...)
1519 {
1520   const char *name;
1521
1522   va_list args;
1523
1524   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1525
1526   va_start (args, first_name);
1527
1528   name = first_name;
1529
1530   while (name) {
1531     int arg_id = va_arg (args, int);
1532     int flags = va_arg (args, int);
1533
1534     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id,
1535         flags);
1536
1537     name = va_arg (args, char *);
1538   }
1539
1540   va_end (args);
1541 }
1542
1543
1544 /**
1545  * gst_buffer_merge:
1546  * @buf1: a first source #GstBuffer to merge.
1547  * @buf2: the second source #GstBuffer to merge.
1548  *
1549  * Create a new buffer that is the concatenation of the two source
1550  * buffers.  The original source buffers will not be modified or
1551  * unref'd.  Make sure you unref the source buffers if they are not used
1552  * anymore afterwards.
1553  *
1554  * If the buffers point to contiguous areas of memory, the buffer
1555  * is created without copying the data.
1556  *
1557  * Returns: the new #GstBuffer that's the concatenation of the source buffers.
1558  */
1559 GstBuffer *
1560 gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
1561 {
1562   GstBuffer *result;
1563
1564   /* we're just a specific case of the more general gst_buffer_span() */
1565   result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
1566
1567   return result;
1568 }
1569
1570 /**
1571  * gst_buffer_stamp:
1572  * @dest: buffer to stamp
1573  * @src: buffer to stamp from
1574  *
1575  * Copies additional information (timestamps and offsets) from one buffer to
1576  * the other.
1577  */
1578 void
1579 gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
1580 {
1581   g_return_if_fail (dest != NULL);
1582   g_return_if_fail (src != NULL);
1583
1584   GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
1585   GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
1586   GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
1587   GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
1588 }
1589
1590 static gboolean
1591 intersect_caps_func (GstPad * pad, GValue * ret, GstPad * orig)
1592 {
1593   if (pad != orig) {
1594     GstCaps *peercaps, *existing;
1595
1596     existing = g_value_get_pointer (ret);
1597     peercaps = gst_pad_peer_get_caps (pad);
1598     g_value_set_pointer (ret, gst_caps_intersect (existing, peercaps));
1599     gst_caps_unref (existing);
1600     gst_caps_unref (peercaps);
1601   }
1602   return TRUE;
1603 }
1604
1605 /**
1606  * gst_pad_proxy_getcaps:
1607  * @pad: a #GstPad to proxy.
1608  *
1609  * Calls gst_pad_get_allowed_caps() for every other pad belonging to the
1610  * same element as @pad, and returns the intersection of the results.
1611  *
1612  * This function is useful as a default getcaps function for an element
1613  * that can handle any stream format, but requires all its pads to have
1614  * the same caps.  Two such elements are tee and aggregator.
1615  *
1616  * Returns: the intersection of the other pads' allowed caps.
1617  */
1618 GstCaps *
1619 gst_pad_proxy_getcaps (GstPad * pad)
1620 {
1621   GstElement *element;
1622   GstCaps *caps, *intersected;
1623   GstIterator *iter;
1624   GstIteratorResult res;
1625   GValue ret = { 0, };
1626
1627   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1628
1629   GST_DEBUG ("proxying getcaps for %s:%s", GST_DEBUG_PAD_NAME (pad));
1630
1631   element = gst_pad_get_parent (pad);
1632
1633   iter = gst_element_iterate_pads (element);
1634
1635   g_value_init (&ret, G_TYPE_POINTER);
1636   g_value_set_pointer (&ret, gst_caps_new_any ());
1637
1638   res = gst_iterator_fold (iter, (GstIteratorFoldFunction) intersect_caps_func,
1639       &ret, pad);
1640   gst_iterator_free (iter);
1641
1642   if (res != GST_ITERATOR_DONE) {
1643     g_warning ("Pad list changed during capsnego for element %s",
1644         GST_ELEMENT_NAME (element));
1645     return NULL;
1646   }
1647
1648   caps = g_value_get_pointer (&ret);
1649   g_value_unset (&ret);
1650
1651   intersected = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
1652   gst_caps_unref (caps);
1653
1654   return intersected;
1655 }
1656
1657 typedef struct
1658 {
1659   GstPad *orig;
1660   GstCaps *caps;
1661 } LinkData;
1662
1663 static gboolean
1664 link_fold_func (GstPad * pad, GValue * ret, LinkData * data)
1665 {
1666   gboolean success = TRUE;
1667
1668   if (pad != data->orig) {
1669     success = gst_pad_set_caps (pad, data->caps);
1670     g_value_set_boolean (ret, success);
1671   }
1672
1673   return success;
1674 }
1675
1676 /**
1677  * gst_pad_proxy_setcaps
1678  * @pad: a #GstPad to proxy from
1679  * @caps: the #GstCaps to link with
1680  *
1681  * Calls gst_pad_set_caps() for every other pad belonging to the
1682  * same element as @pad.  If gst_pad_set_caps() fails on any pad,
1683  * the proxy setcaps fails. May be used only during negotiation.
1684  *
1685  * Returns: TRUE if sucessful
1686  */
1687 gboolean
1688 gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps)
1689 {
1690   GstElement *element;
1691   GstIterator *iter;
1692   GstIteratorResult res;
1693   GValue ret = { 0, };
1694   LinkData data;
1695
1696   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
1697   g_return_val_if_fail (caps != NULL, FALSE);
1698
1699   GST_DEBUG ("proxying pad link for %s:%s", GST_DEBUG_PAD_NAME (pad));
1700
1701   element = gst_pad_get_parent (pad);
1702
1703   iter = gst_element_iterate_pads (element);
1704
1705   g_value_init (&ret, G_TYPE_BOOLEAN);
1706   g_value_set_boolean (&ret, TRUE);
1707   data.orig = pad;
1708   data.caps = caps;
1709
1710   res = gst_iterator_fold (iter, (GstIteratorFoldFunction) link_fold_func,
1711       &ret, &data);
1712   gst_iterator_free (iter);
1713
1714   if (res != GST_ITERATOR_DONE) {
1715     g_warning ("Pad list changed during proxy_pad_link for element %s",
1716         GST_ELEMENT_NAME (element));
1717     return FALSE;
1718   }
1719
1720   /* ok not to unset the gvalue */
1721   return g_value_get_boolean (&ret);
1722 }