diff -r 9b2c3c7a1a9c -r 567bb019e3e3 gstreamer_core/gst/gstutils.c --- a/gstreamer_core/gst/gstutils.c Wed Mar 31 22:03:18 2010 +0300 +++ b/gstreamer_core/gst/gstutils.c Tue Aug 31 15:30:33 2010 +0300 @@ -3,7 +3,7 @@ * 2000 Wim Taymans * 2002 Thomas Vander Stichele * - * gstutils.c: Utility functions: gtk_get_property stuff, etc. + * gstutils.c: Utility functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -37,8 +37,16 @@ #include "gsterror.h" #include "gstinfo.h" #include "gstparse.h" +#include "gstvalue.h" #include "gst-i18n-lib.h" +/** + * gst_util_dump_mem: + * @mem: a pointer to the memory to dump + * @size: the size of the memory block to dump + * + * Dumps the memory block into a hex representation. Useful for debugging. + */ #ifdef __SYMBIAN32__ #include #include @@ -95,6 +103,9 @@ * * Converts the string to the type of the value and * sets the value with it. + * + * Note that this function is dangerous as it does not return any indication + * if the conversion worked or not. */ #ifdef __SYMBIAN32__ EXPORT_C @@ -103,7 +114,7 @@ void gst_util_set_value_from_string (GValue * value, const gchar * value_str) { - gint sscanf_ret; + gboolean res; g_return_if_fail (value != NULL); g_return_if_fail (value_str != NULL); @@ -111,86 +122,13 @@ GST_CAT_DEBUG (GST_CAT_PARAMS, "parsing '%s' to type %s", value_str, g_type_name (G_VALUE_TYPE (value))); - switch (G_VALUE_TYPE (value)) { - case G_TYPE_STRING: - g_value_set_string (value, value_str); - break; - case G_TYPE_ENUM: - case G_TYPE_INT:{ - gint i; - - sscanf_ret = sscanf (value_str, "%d", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_int (value, i); - break; - } - case G_TYPE_UINT:{ - guint i; - - sscanf_ret = sscanf (value_str, "%u", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_uint (value, i); - break; - } - case G_TYPE_LONG:{ - glong i; - - sscanf_ret = sscanf (value_str, "%ld", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_long (value, i); - break; - } - case G_TYPE_ULONG:{ - gulong i; - - sscanf_ret = sscanf (value_str, "%lu", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_ulong (value, i); - break; - } - case G_TYPE_BOOLEAN:{ - gboolean i = FALSE; - - if (!g_ascii_strncasecmp ("true", value_str, 4)) - i = TRUE; - g_value_set_boolean (value, i); - break; - } - case G_TYPE_CHAR:{ - gchar i; - - sscanf_ret = sscanf (value_str, "%c", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_char (value, i); - break; - } - case G_TYPE_UCHAR:{ - guchar i; - - sscanf_ret = sscanf (value_str, "%c", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_uchar (value, i); - break; - } - case G_TYPE_FLOAT:{ - gfloat i; - - sscanf_ret = sscanf (value_str, "%f", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_float (value, i); - break; - } - case G_TYPE_DOUBLE:{ - gfloat i; - - sscanf_ret = sscanf (value_str, "%g", &i); - g_return_if_fail (sscanf_ret == 1); - g_value_set_double (value, (gdouble) i); - break; - } - default: - break; + res = gst_value_deserialize (value, value_str); + if (!res && G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) { + /* backwards compat, all booleans that fail to parse are false */ + g_value_set_boolean (value, FALSE); + res = TRUE; } + g_return_if_fail (res); } /** @@ -201,6 +139,9 @@ * * Convertes the string value to the type of the objects argument and * sets the argument with it. + * + * Note that this function silently returns if @object has no property named + * @name or when @value cannot be converted to the type of the property. */ #ifdef __SYMBIAN32__ EXPORT_C @@ -210,111 +151,41 @@ gst_util_set_object_arg (GObject * object, const gchar * name, const gchar * value) { - gboolean sscanf_ret; - - if (name && value) { - GParamSpec *paramspec; - - paramspec = - g_object_class_find_property (G_OBJECT_GET_CLASS (object), name); - - if (!paramspec) { - return; - } - - GST_DEBUG ("paramspec->flags is %d, paramspec->value_type is %d", - paramspec->flags, (gint) paramspec->value_type); - - if (paramspec->flags & G_PARAM_WRITABLE) { - switch (paramspec->value_type) { - case G_TYPE_STRING: - g_object_set (G_OBJECT (object), name, value, NULL); - break; - case G_TYPE_ENUM: - case G_TYPE_INT:{ - gint i; - - sscanf_ret = sscanf (value, "%d", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_UINT:{ - guint i; - - sscanf_ret = sscanf (value, "%u", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_LONG:{ - glong i; - - sscanf_ret = sscanf (value, "%ld", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_ULONG:{ - gulong i; - - sscanf_ret = sscanf (value, "%lu", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_BOOLEAN:{ - gboolean i = FALSE; - - if (!g_ascii_strncasecmp ("true", value, 4)) - i = TRUE; - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_CHAR:{ - gchar i; - - sscanf_ret = sscanf (value, "%c", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_UCHAR:{ - guchar i; - - sscanf_ret = sscanf (value, "%c", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_FLOAT:{ - gfloat i; - - sscanf_ret = sscanf (value, "%f", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - break; - } - case G_TYPE_DOUBLE:{ - gfloat i; - - sscanf_ret = sscanf (value, "%g", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, (gdouble) i, NULL); - break; - } - default: - if (G_IS_PARAM_SPEC_ENUM (paramspec)) { - gint i; - - sscanf_ret = sscanf (value, "%d", &i); - g_return_if_fail (sscanf_ret == 1); - g_object_set (G_OBJECT (object), name, i, NULL); - } - break; - } - } + GParamSpec *pspec; + GType value_type; + GValue v = { 0, }; + + g_return_if_fail (G_IS_OBJECT (object)); + g_return_if_fail (name != NULL); + g_return_if_fail (value != NULL); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name); + if (!pspec) + return; + + value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); + + GST_DEBUG ("pspec->flags is %d, pspec->value_type is %s", + pspec->flags, g_type_name (value_type)); + + if (!(pspec->flags & G_PARAM_WRITABLE)) + return; + + g_value_init (&v, value_type); + + /* special case for element <-> xml (de)serialisation */ + if (GST_VALUE_HOLDS_STRUCTURE (&v) && strcmp (value, "NULL") == 0) { + g_value_set_boxed (&v, NULL); + goto done; } + + if (!gst_value_deserialize (&v, value)) + return; + +done: + + g_object_set_property (object, pspec->name, &v); + g_value_unset (&v); } /* work around error C2520: conversion from unsigned __int64 to double @@ -435,7 +306,7 @@ } static guint64 -gst_util_uint64_scale_int64 (guint64 val, guint64 num, guint64 denom) +gst_util_uint64_scale_int64_unchecked (guint64 val, guint64 num, guint64 denom) { GstUInt64 a0, a1, b0, b1, c0, ct, c1, result; GstUInt64 v, n; @@ -467,7 +338,7 @@ c1.ll = (guint64) a1.l.high + b0.l.high + ct.l.high + b1.ll; /* if high bits bigger than denom, we overflow */ - if (c1.ll >= denom) + if (G_UNLIKELY (c1.ll >= denom)) goto overflow; /* shortcut for division by 1, c1.ll should be 0 because of the @@ -497,6 +368,36 @@ } } +static inline guint64 +gst_util_uint64_scale_int_unchecked (guint64 val, gint num, gint denom) +{ + GstUInt64 result; + GstUInt64 low, high; + + /* do 96 bits mult/div */ + low.ll = val; + result.ll = ((guint64) low.l.low) * num; + high.ll = ((guint64) low.l.high) * num + (result.l.high); + + low.ll = high.ll / denom; + result.l.high = high.ll % denom; + result.ll /= denom; + + /* avoid overflow */ + if (G_UNLIKELY (low.ll + result.l.high > G_MAXUINT32)) + goto overflow; + + result.l.high += low.l.low; + + return result.ll; + +overflow: + { + return G_MAXUINT64; + } +} + + /** * gst_util_uint64_scale: * @val: the number to scale @@ -519,33 +420,33 @@ { g_return_val_if_fail (denom != 0, G_MAXUINT64); - if (num == 0) + if (G_UNLIKELY (num == 0)) return 0; - if (num == 1 && denom == 1) + if (G_UNLIKELY (num == denom)) return val; /* if the denom is high, we need to do a 64 muldiv */ - if (denom > G_MAXINT32) + if (G_UNLIKELY (denom > G_MAXINT32)) goto do_int64; /* if num and denom are low we can do a 32 bit muldiv */ - if (num <= G_MAXINT32) + if (G_LIKELY (num <= G_MAXINT32)) goto do_int32; /* val and num are high, we need 64 muldiv */ - if (val > G_MAXINT32) + if (G_UNLIKELY (val > G_MAXINT32)) goto do_int64; /* val is low and num is high, we can swap them and do 32 muldiv */ - return gst_util_uint64_scale_int (num, (gint) val, (gint) denom); + return gst_util_uint64_scale_int_unchecked (num, (gint) val, (gint) denom); do_int32: - return gst_util_uint64_scale_int (val, (gint) num, (gint) denom); + return gst_util_uint64_scale_int_unchecked (val, (gint) num, (gint) denom); do_int64: /* to the more heavy implementations... */ - return gst_util_uint64_scale_int64 (val, num, denom); + return gst_util_uint64_scale_int64_unchecked (val, num, denom); } /** @@ -569,43 +470,71 @@ guint64 gst_util_uint64_scale_int (guint64 val, gint num, gint denom) { - GstUInt64 result; - GstUInt64 low, high; - g_return_val_if_fail (denom > 0, G_MAXUINT64); g_return_val_if_fail (num >= 0, G_MAXUINT64); - if (num == 0) + if (G_UNLIKELY (num == 0)) return 0; - if (num == 1 && denom == 1) + if (G_UNLIKELY (num == denom)) return val; if (val <= G_MAXUINT32) /* simple case */ return val * num / denom; - /* do 96 bits mult/div */ - low.ll = val; - result.ll = ((guint64) low.l.low) * num; - high.ll = ((guint64) low.l.high) * num + (result.l.high); - - low.ll = high.ll / denom; - result.l.high = high.ll % denom; - result.ll /= denom; - - /* avoid overflow */ - if (low.ll + result.l.high > G_MAXUINT32) - goto overflow; - - result.l.high += low.l.low; - - return result.ll; - -overflow: - { - return G_MAXUINT64; - } + return gst_util_uint64_scale_int_unchecked (val, num, denom); +} + +/** + * gst_util_seqnum_next: + * + * Return a constantly incrementing sequence number. + * + * This function is used internally to GStreamer to be able to determine which + * events and messages are "the same". For example, elements may set the seqnum + * on a segment-done message to be the same as that of the last seek event, to + * indicate that event and the message correspond to the same segment. + * + * Returns: A constantly incrementing 32-bit unsigned integer, which might + * overflow back to 0 at some point. Use gst_util_seqnum_compare() to make sure + * you handle wraparound correctly. + * + * Since: 0.10.22 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +guint32 +gst_util_seqnum_next (void) +{ + static gint counter = 0; + return g_atomic_int_exchange_and_add (&counter, 1); +} + +/** + * gst_util_seqnum_compare: + * @s1: A sequence number. + * @s2: Another sequence number. + * + * Compare two sequence numbers, handling wraparound. + * + * The current implementation just returns (gint32)(@s1 - @s2). + * + * Returns: A negative number if @s1 is before @s2, 0 if they are equal, or a + * positive number if @s1 is after @s2. + * + * Since: 0.10.22 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gint32 +gst_util_seqnum_compare (guint32 s1, guint32 s2) +{ + return (gint32) (s1 - s2); } /* ----------------------------------------------------- @@ -928,6 +857,60 @@ return pad; } +/* + * Checks if the source pad and the sink pad can be linked. + * Both @srcpad and @sinkpad must be unlinked and have a parent. + */ +static gboolean +gst_pad_check_link (GstPad * srcpad, GstPad * sinkpad) +{ + /* FIXME This function is gross. It's almost a direct copy of + * gst_pad_link_filtered(). Any decent programmer would attempt + * to merge the two functions, which I will do some day. --ds + */ + + /* generic checks */ + g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE); + g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE); + + GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s", + GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); + + /* FIXME: shouldn't we convert this to g_return_val_if_fail? */ + if (GST_PAD_PEER (srcpad) != NULL) { + GST_CAT_INFO (GST_CAT_PADS, "Source pad %s:%s has a peer, failed", + GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + if (GST_PAD_PEER (sinkpad) != NULL) { + GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has a peer, failed", + GST_DEBUG_PAD_NAME (sinkpad)); + return FALSE; + } + if (!GST_PAD_IS_SRC (srcpad)) { + GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s is not source pad, failed", + GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + if (!GST_PAD_IS_SINK (sinkpad)) { + GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s is not sink pad, failed", + GST_DEBUG_PAD_NAME (sinkpad)); + return FALSE; + } + if (GST_PAD_PARENT (srcpad) == NULL) { + GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s has no parent, failed", + GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + if (GST_PAD_PARENT (sinkpad) == NULL) { + GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has no parent, failed", + GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + + return TRUE; +} + /** * gst_element_get_compatible_pad: * @element: a #GstElement in which the pad should be found. @@ -955,8 +938,6 @@ GstPad *foundpad = NULL; gboolean done; - /* FIXME check for caps compatibility */ - g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL); @@ -985,22 +966,47 @@ peer = gst_pad_get_peer (current); - if (peer == NULL && gst_pad_can_link (pad, current)) { - + if (peer == NULL && gst_pad_check_link (pad, current)) { + GstCaps *temp, *temp2, *intersection; + + /* Now check if the two pads' caps are compatible */ + temp = gst_pad_get_caps (pad); + if (caps) { + intersection = gst_caps_intersect (temp, caps); + gst_caps_unref (temp); + } else { + intersection = temp; + } + + temp = gst_pad_get_caps (current); + temp2 = gst_caps_intersect (temp, intersection); + gst_caps_unref (temp); + gst_caps_unref (intersection); + + intersection = temp2; + + if (!gst_caps_is_empty (intersection)) { + gst_caps_unref (intersection); + + GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, + "found existing unlinked compatible pad %s:%s", + GST_DEBUG_PAD_NAME (current)); + gst_iterator_free (pads); + + return current; + } else { + GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "incompatible pads"); + } + gst_caps_unref (intersection); + } else { GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, - "found existing unlinked pad %s:%s", - GST_DEBUG_PAD_NAME (current)); - - gst_iterator_free (pads); - - return current; - } else { - GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads"); - - gst_object_unref (current); - if (peer) - gst_object_unref (peer); + "already linked or cannot be linked (peer = %p)", peer); } + GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads"); + + gst_object_unref (current); + if (peer) + gst_object_unref (peer); break; } case GST_ITERATOR_DONE: @@ -1016,12 +1022,18 @@ } gst_iterator_free (pads); + GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, + "Could not find a compatible unlinked always pad to link to %s:%s, now checking request pads", + GST_DEBUG_PAD_NAME (pad)); + /* try to create a new one */ /* requesting is a little crazy, we need a template. Let's create one */ + /* FIXME: why not gst_pad_get_pad_template (pad); */ templcaps = gst_pad_get_caps (pad); templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps); + foundpad = gst_element_request_compatible_pad (element, templ); gst_object_unref (templ); @@ -1160,8 +1172,8 @@ GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data; if (template->direction == GST_PAD_SRC) { - if (gst_caps_is_always_compatible (gst_static_caps_get (&template-> - static_caps), caps)) + if (gst_caps_is_always_compatible (gst_static_caps_get + (&template->static_caps), caps)) return TRUE; } templates = g_list_next (templates); @@ -1437,7 +1449,8 @@ /* get a src pad */ if (srcpadname) { /* name specified, look it up */ - srcpad = gst_element_get_pad (src, srcpadname); + if (!(srcpad = gst_element_get_static_pad (src, srcpadname))) + srcpad = gst_element_get_request_pad (src, srcpadname); if (!srcpad) { GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (src), srcpadname); @@ -1470,7 +1483,8 @@ /* get a destination pad */ if (destpadname) { /* name specified, look it up */ - destpad = gst_element_get_pad (dest, destpadname); + if (!(destpad = gst_element_get_static_pad (dest, destpadname))) + destpad = gst_element_get_request_pad (dest, destpadname); if (!destpad) { GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (dest), destpadname); @@ -1775,6 +1789,7 @@ gboolean gst_element_link_many (GstElement * element_1, GstElement * element_2, ...) { + gboolean res = TRUE; va_list args; g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE); @@ -1783,8 +1798,10 @@ va_start (args, element_2); while (element_2) { - if (!gst_element_link (element_1, element_2)) - return FALSE; + if (!gst_element_link (element_1, element_2)) { + res = FALSE; + break; + } element_1 = element_2; element_2 = va_arg (args, GstElement *); @@ -1792,7 +1809,7 @@ va_end (args); - return TRUE; + return res; } /** @@ -1841,6 +1858,9 @@ GstElement * dest, const gchar * destpadname) { GstPad *srcpad, *destpad; + gboolean srcrequest, destrequest; + + srcrequest = destrequest = FALSE; g_return_if_fail (src != NULL); g_return_if_fail (GST_IS_ELEMENT (src)); @@ -1850,23 +1870,33 @@ g_return_if_fail (destpadname != NULL); /* obtain the pads requested */ - srcpad = gst_element_get_pad (src, srcpadname); + if (!(srcpad = gst_element_get_static_pad (src, srcpadname))) + if ((srcpad = gst_element_get_request_pad (src, srcpadname))) + srcrequest = TRUE; if (srcpad == NULL) { GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname); return; } - destpad = gst_element_get_pad (dest, destpadname); + if (!(destpad = gst_element_get_static_pad (dest, destpadname))) + if ((destpad = gst_element_get_request_pad (dest, destpadname))) + destrequest = TRUE; if (destpad == NULL) { GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"", destpadname); - gst_object_unref (srcpad); - return; + goto free_src; } /* we're satisified they can be unlinked, let's do it */ gst_pad_unlink (srcpad, destpad); + + if (destrequest) + gst_element_release_request_pad (dest, destpad); + gst_object_unref (destpad); + +free_src: + if (srcrequest) + gst_element_release_request_pad (src, srcpad); gst_object_unref (srcpad); - gst_object_unref (destpad); } /** @@ -1940,8 +1970,7 @@ if (GST_PAD_IS_SRC (pad)) { GstPad *peerpad = gst_pad_get_peer (pad); - /* see if the pad is connected and is really a pad - * of dest */ + /* see if the pad is linked and is really a pad of dest */ if (peerpad) { GstElement *peerelem; @@ -2135,70 +2164,6 @@ } /** - * gst_pad_can_link: - * @srcpad: the source #GstPad to link. - * @sinkpad: the sink #GstPad to link. - * - * Checks if the source pad and the sink pad can be linked. - * Both @srcpad and @sinkpad must be unlinked. - * - * Returns: TRUE if the pads can be linked, FALSE otherwise. - */ -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - -gboolean -gst_pad_can_link (GstPad * srcpad, GstPad * sinkpad) -{ - /* FIXME This function is gross. It's almost a direct copy of - * gst_pad_link_filtered(). Any decent programmer would attempt - * to merge the two functions, which I will do some day. --ds - */ - - /* generic checks */ - g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE); - g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE); - - GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - - /* FIXME: shouldn't we convert this to g_return_val_if_fail? */ - if (GST_PAD_PEER (srcpad) != NULL) { - GST_CAT_INFO (GST_CAT_PADS, "Source pad %s:%s has a peer, failed", - GST_DEBUG_PAD_NAME (srcpad)); - return FALSE; - } - if (GST_PAD_PEER (sinkpad) != NULL) { - GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has a peer, failed", - GST_DEBUG_PAD_NAME (sinkpad)); - return FALSE; - } - if (!GST_PAD_IS_SRC (srcpad)) { - GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s is not source pad, failed", - GST_DEBUG_PAD_NAME (srcpad)); - return FALSE; - } - if (!GST_PAD_IS_SINK (sinkpad)) { - GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s is not sink pad, failed", - GST_DEBUG_PAD_NAME (sinkpad)); - return FALSE; - } - if (GST_PAD_PARENT (srcpad) == NULL) { - GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s has no parent, failed", - GST_DEBUG_PAD_NAME (srcpad)); - return FALSE; - } - if (GST_PAD_PARENT (sinkpad) == NULL) { - GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has no parent, failed", - GST_DEBUG_PAD_NAME (srcpad)); - return FALSE; - } - - return TRUE; -} - -/** * gst_pad_use_fixed_caps: * @pad: the pad to use * @@ -2249,9 +2214,7 @@ "using pad caps %p %" GST_PTR_FORMAT, result, result); result = gst_caps_ref (result); - goto done; - } - if (GST_PAD_PAD_TEMPLATE (pad)) { + } else if (GST_PAD_PAD_TEMPLATE (pad)) { GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad); result = GST_PAD_TEMPLATE_CAPS (templ); @@ -2260,12 +2223,10 @@ result); result = gst_caps_ref (result); - goto done; + } else { + GST_CAT_DEBUG (GST_CAT_CAPS, "pad has no caps"); + result = gst_caps_new_empty (); } - GST_CAT_DEBUG (GST_CAT_CAPS, "pad has no caps"); - result = gst_caps_new_empty (); - -done: GST_OBJECT_UNLOCK (pad); return result; @@ -2559,6 +2520,11 @@ * If the buffers point to contiguous areas of memory, the buffer * is created without copying the data. * + * This is a convenience function for C programmers. See also + * gst_buffer_merge(), which does the same thing without + * unreffing the input parameters. Language bindings without + * explicit reference counting should not wrap this function. + * * Returns: the new #GstBuffer which is the concatenation of the source buffers. */ #ifdef __SYMBIAN32__ @@ -2606,6 +2572,7 @@ static gboolean intersect_caps_func (GstPad * pad, GValue * ret, GstPad * orig) { + /* skip the pad, the request came from */ if (pad != orig) { GstCaps *peercaps, *existing; @@ -2649,7 +2616,8 @@ g_return_val_if_fail (GST_IS_PAD (pad), NULL); - GST_DEBUG ("proxying getcaps for %s:%s", GST_DEBUG_PAD_NAME (pad)); + GST_CAT_DEBUG (GST_CAT_PADS, "proxying getcaps for %s:%s", + GST_DEBUG_PAD_NAME (pad)); element = gst_pad_get_parent_element (pad); if (element == NULL) @@ -2757,7 +2725,8 @@ g_return_val_if_fail (GST_IS_PAD (pad), FALSE); g_return_val_if_fail (caps != NULL, FALSE); - GST_DEBUG ("proxying pad link for %s:%s", GST_DEBUG_PAD_NAME (pad)); + GST_CAT_DEBUG (GST_CAT_PADS, "proxying pad link for %s:%s", + GST_DEBUG_PAD_NAME (pad)); element = gst_pad_get_parent_element (pad); if (element == NULL) @@ -2957,7 +2926,6 @@ gboolean ret; g_return_val_if_fail (GST_IS_PAD (pad), FALSE); - g_return_val_if_fail (src_val >= 0, FALSE); g_return_val_if_fail (dest_format != NULL, FALSE); g_return_val_if_fail (dest_val != NULL, FALSE); @@ -3024,7 +2992,11 @@ * @value: value to set * * Unconditionally sets the atomic integer to @value. + * + * Deprecated: Use g_atomic_int_set(). + * */ +#ifndef GST_REMOVE_DEPRECATED #ifdef __SYMBIAN32__ EXPORT_C #endif @@ -3032,12 +3004,9 @@ void gst_atomic_int_set (gint * atomic_int, gint value) { - int ignore; - - *atomic_int = value; - /* read acts as a memory barrier */ - ignore = g_atomic_int_get (atomic_int); + g_atomic_int_set (atomic_int, value); } +#endif /** * gst_pad_add_data_probe: @@ -3076,17 +3045,68 @@ gulong gst_pad_add_data_probe (GstPad * pad, GCallback handler, gpointer data) { + return gst_pad_add_data_probe_full (pad, handler, data, NULL); +} + +/** + * gst_pad_add_data_probe_full: + * @pad: pad to add the data probe handler to + * @handler: function to call when data is passed over pad + * @data: data to pass along with the handler + * @notify: function to call when the probe is disconnected, or NULL + * + * Adds a "data probe" to a pad. This function will be called whenever data + * passes through a pad. In this case data means both events and buffers. The + * probe will be called with the data as an argument, meaning @handler should + * have the same callback signature as the #GstPad::have-data signal. + * Note that the data will have a reference count greater than 1, so it will + * be immutable -- you must not change it. + * + * For source pads, the probe will be called after the blocking function, if any + * (see gst_pad_set_blocked_async()), but before looking up the peer to chain + * to. For sink pads, the probe function will be called before configuring the + * sink with new caps, if any, and before calling the pad's chain function. + * + * Your data probe should return TRUE to let the data continue to flow, or FALSE + * to drop it. Dropping data is rarely useful, but occasionally comes in handy + * with events. + * + * Although probes are implemented internally by connecting @handler to the + * have-data signal on the pad, if you want to remove a probe it is insufficient + * to only call g_signal_handler_disconnect on the returned handler id. To + * remove a probe, use the appropriate function, such as + * gst_pad_remove_data_probe(). + * + * The @notify function is called when the probe is disconnected and usually + * used to free @data. + * + * Returns: The handler id. + * + * Since: 0.10.20 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gulong +gst_pad_add_data_probe_full (GstPad * pad, GCallback handler, + gpointer data, GDestroyNotify notify) +{ gulong sigid; g_return_val_if_fail (GST_IS_PAD (pad), 0); g_return_val_if_fail (handler != NULL, 0); GST_OBJECT_LOCK (pad); - sigid = g_signal_connect (pad, "have-data", handler, data); + + /* we only expose a GDestroyNotify in our API because that's less confusing */ + sigid = g_signal_connect_data (pad, "have-data", handler, data, + (GClosureNotify) notify, 0); + GST_PAD_DO_EVENT_SIGNALS (pad)++; GST_PAD_DO_BUFFER_SIGNALS (pad)++; - GST_DEBUG ("adding data probe to pad %s:%s, now %d data, %d event probes", - GST_DEBUG_PAD_NAME (pad), + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, + "adding data probe, now %d data, %d event probes", GST_PAD_DO_BUFFER_SIGNALS (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); @@ -3111,16 +3131,48 @@ gulong gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data) { + return gst_pad_add_event_probe_full (pad, handler, data, NULL); +} + +/** + * gst_pad_add_event_probe_full: + * @pad: pad to add the event probe handler to + * @handler: function to call when events are passed over pad + * @data: data to pass along with the handler, or NULL + * @notify: function to call when probe is disconnected, or NULL + * + * Adds a probe that will be called for all events passing through a pad. See + * gst_pad_add_data_probe() for more information. + * + * The @notify function is called when the probe is disconnected and usually + * used to free @data. + * + * Returns: The handler id + * + * Since: 0.10.20 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gulong +gst_pad_add_event_probe_full (GstPad * pad, GCallback handler, + gpointer data, GDestroyNotify notify) +{ gulong sigid; g_return_val_if_fail (GST_IS_PAD (pad), 0); g_return_val_if_fail (handler != NULL, 0); GST_OBJECT_LOCK (pad); - sigid = g_signal_connect (pad, "have-data::event", handler, data); + + /* we only expose a GDestroyNotify in our API because that's less confusing */ + sigid = g_signal_connect_data (pad, "have-data::event", handler, data, + (GClosureNotify) notify, 0); + GST_PAD_DO_EVENT_SIGNALS (pad)++; - GST_DEBUG ("adding event probe to pad %s:%s, now %d probes", - GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "adding event probe, now %d probes", + GST_PAD_DO_EVENT_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); return sigid; @@ -3144,16 +3196,48 @@ gulong gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data) { + return gst_pad_add_buffer_probe_full (pad, handler, data, NULL); +} + +/** + * gst_pad_add_buffer_probe_full: + * @pad: pad to add the buffer probe handler to + * @handler: function to call when buffer are passed over pad + * @data: data to pass along with the handler + * @notify: function to call when the probe is disconnected, or NULL + * + * Adds a probe that will be called for all buffers passing through a pad. See + * gst_pad_add_data_probe() for more information. + * + * The @notify function is called when the probe is disconnected and usually + * used to free @data. + * + * Returns: The handler id + * + * Since: 0.10.20 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gulong +gst_pad_add_buffer_probe_full (GstPad * pad, GCallback handler, + gpointer data, GDestroyNotify notify) +{ gulong sigid; g_return_val_if_fail (GST_IS_PAD (pad), 0); g_return_val_if_fail (handler != NULL, 0); GST_OBJECT_LOCK (pad); - sigid = g_signal_connect (pad, "have-data::buffer", handler, data); + + /* we only expose a GDestroyNotify in our API because that's less confusing */ + sigid = g_signal_connect_data (pad, "have-data::buffer", handler, data, + (GClosureNotify) notify, 0); + GST_PAD_DO_BUFFER_SIGNALS (pad)++; - GST_DEBUG ("adding buffer probe to pad %s:%s, now %d probes", - GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "adding buffer probe, now %d probes", + GST_PAD_DO_BUFFER_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); return sigid; @@ -3180,10 +3264,9 @@ g_signal_handler_disconnect (pad, handler_id); GST_PAD_DO_BUFFER_SIGNALS (pad)--; GST_PAD_DO_EVENT_SIGNALS (pad)--; - GST_DEBUG - ("removed data probe from pad %s:%s, now %d event, %d buffer probes", - GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad), - GST_PAD_DO_BUFFER_SIGNALS (pad)); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, + "removed data probe, now %d event, %d buffer probes", + GST_PAD_DO_EVENT_SIGNALS (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); } @@ -3208,8 +3291,9 @@ GST_OBJECT_LOCK (pad); g_signal_handler_disconnect (pad, handler_id); GST_PAD_DO_EVENT_SIGNALS (pad)--; - GST_DEBUG ("removed event probe from pad %s:%s, now %d event probes", - GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, + "removed event probe, now %d event probes", + GST_PAD_DO_EVENT_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); } @@ -3233,8 +3317,9 @@ GST_OBJECT_LOCK (pad); g_signal_handler_disconnect (pad, handler_id); GST_PAD_DO_BUFFER_SIGNALS (pad)--; - GST_DEBUG ("removed buffer probe from pad %s:%s, now %d buffer probes", - GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, + "removed buffer probe, now %d buffer probes", + GST_PAD_DO_BUFFER_SIGNALS (pad)); GST_OBJECT_UNLOCK (pad); } @@ -3264,8 +3349,9 @@ g_return_if_fail (list != NULL); gst_pad_push_event (pad, gst_event_new_tag (gst_tag_list_copy (list))); + /* FIXME 0.11: Set the pad as source. */ gst_element_post_message (element, - gst_message_new_tag (GST_OBJECT (element), list)); + gst_message_new_tag_full (GST_OBJECT (element), pad, list)); } static void @@ -3311,10 +3397,10 @@ } static GstPad * -element_find_unconnected_pad (GstElement * element, GstPadDirection direction) +element_find_unlinked_pad (GstElement * element, GstPadDirection direction) { GstIterator *iter; - GstPad *unconnected_pad = NULL; + GstPad *unlinked_pad = NULL; gboolean done; switch (direction) { @@ -3341,11 +3427,11 @@ peer = gst_pad_get_peer (GST_PAD (pad)); if (peer == NULL) { - unconnected_pad = pad; + unlinked_pad = pad; done = TRUE; GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "found existing unlinked pad %s:%s", - GST_DEBUG_PAD_NAME (unconnected_pad)); + GST_DEBUG_PAD_NAME (unlinked_pad)); } else { gst_object_unref (pad); gst_object_unref (peer); @@ -3366,30 +3452,30 @@ gst_iterator_free (iter); - return unconnected_pad; + return unlinked_pad; } /** - * gst_bin_find_unconnected_pad: - * @bin: bin in which to look for elements with unconnected pads - * @direction: whether to look for an unconnected source or sink pad + * gst_bin_find_unlinked_pad: + * @bin: bin in which to look for elements with unlinked pads + * @direction: whether to look for an unlinked source or sink pad * - * Recursively looks for elements with an unconnected pad of the given - * direction within the specified bin and returns an unconnected pad + * Recursively looks for elements with an unlinked pad of the given + * direction within the specified bin and returns an unlinked pad * if one is found, or NULL otherwise. If a pad is found, the caller * owns a reference to it and should use gst_object_unref() on the * pad when it is not needed any longer. * - * Returns: unconnected pad of the given direction, or NULL. + * Returns: unlinked pad of the given direction, or NULL. * - * Since: 0.10.3 + * Since: 0.10.20 */ #ifdef __SYMBIAN32__ EXPORT_C #endif GstPad * -gst_bin_find_unconnected_pad (GstBin * bin, GstPadDirection direction) +gst_bin_find_unlinked_pad (GstBin * bin, GstPadDirection direction) { GstIterator *iter; gboolean done; @@ -3405,7 +3491,7 @@ switch (gst_iterator_next (iter, &element)) { case GST_ITERATOR_OK: - pad = element_find_unconnected_pad (GST_ELEMENT (element), direction); + pad = element_find_unlinked_pad (GST_ELEMENT (element), direction); gst_object_unref (element); if (pad != NULL) done = TRUE; @@ -3428,20 +3514,48 @@ } /** + * gst_bin_find_unconnected_pad: + * @bin: bin in which to look for elements with unlinked pads + * @direction: whether to look for an unlinked source or sink pad + * + * Recursively looks for elements with an unlinked pad of the given + * direction within the specified bin and returns an unlinked pad + * if one is found, or NULL otherwise. If a pad is found, the caller + * owns a reference to it and should use gst_object_unref() on the + * pad when it is not needed any longer. + * + * Returns: unlinked pad of the given direction, or NULL. + * + * Since: 0.10.3 + * + * Deprecated: use gst_bin_find_unlinked_pad() instead. + */ +#ifndef GST_REMOVE_DEPRECATED + +#ifdef __SYMBIAN32__ +EXPORT_C +#endif +GstPad * +gst_bin_find_unconnected_pad (GstBin * bin, GstPadDirection direction) +{ + return gst_bin_find_unlinked_pad (bin, direction); +} +#endif + +/** * gst_parse_bin_from_description: * @bin_description: command line describing the bin - * @ghost_unconnected_pads: whether to automatically create ghost pads - * for unconnected source or sink pads within - * the bin + * @ghost_unlinked_pads: whether to automatically create ghost pads + * for unlinked source or sink pads within the bin * @err: where to store the error message in case of an error, or NULL * * This is a convenience wrapper around gst_parse_launch() to create a * #GstBin from a gst-launch-style pipeline description. See * gst_parse_launch() and the gst-launch man page for details about the - * syntax. Ghost pads on the bin for unconnected source or sink pads + * syntax. Ghost pads on the bin for unlinked source or sink pads * within the bin can automatically be created (but only a maximum of * one ghost pad for each direction will be created; if you expect - * multiple unconnected source pads or multiple unconnected sink pads + * multiple unlinked source pads or multiple unlinked sink pads * and want them all ghosted, you will have to create the ghost pads * yourself). * @@ -3455,7 +3569,43 @@ GstElement * gst_parse_bin_from_description (const gchar * bin_description, - gboolean ghost_unconnected_pads, GError ** err) + gboolean ghost_unlinked_pads, GError ** err) +{ + return gst_parse_bin_from_description_full (bin_description, + ghost_unlinked_pads, NULL, 0, err); +} + +/** + * gst_parse_bin_from_description_full: + * @bin_description: command line describing the bin + * @ghost_unlinked_pads: whether to automatically create ghost pads + * for unlinked source or sink pads within the bin + * @context: a parse context allocated with gst_parse_context_new(), or %NULL + * @flags: parsing options, or #GST_PARSE_FLAG_NONE + * @err: where to store the error message in case of an error, or NULL + * + * This is a convenience wrapper around gst_parse_launch() to create a + * #GstBin from a gst-launch-style pipeline description. See + * gst_parse_launch() and the gst-launch man page for details about the + * syntax. Ghost pads on the bin for unlinked source or sink pads + * within the bin can automatically be created (but only a maximum of + * one ghost pad for each direction will be created; if you expect + * multiple unlinked source pads or multiple unlinked sink pads + * and want them all ghosted, you will have to create the ghost pads + * yourself). + * + * Returns: a newly-created bin, or NULL if an error occurred. + * + * Since: 0.10.20 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +GstElement * +gst_parse_bin_from_description_full (const gchar * bin_description, + gboolean ghost_unlinked_pads, GstParseContext * context, + GstParseFlags flags, GError ** err) { #ifndef GST_DISABLE_PARSE GstPad *pad = NULL; @@ -3469,7 +3619,7 @@ /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s )", bin_description); - bin = (GstBin *) gst_parse_launch (desc, err); + bin = (GstBin *) gst_parse_launch_full (desc, context, flags, err); g_free (desc); if (bin == NULL || (err && *err != NULL)) { @@ -3479,12 +3629,12 @@ } /* find pads and ghost them if necessary */ - if (ghost_unconnected_pads) { - if ((pad = gst_bin_find_unconnected_pad (bin, GST_PAD_SRC))) { + if (ghost_unlinked_pads) { + if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad)); gst_object_unref (pad); } - if ((pad = gst_bin_find_unconnected_pad (bin, GST_PAD_SINK))) { + if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad)); gst_object_unref (pad); } @@ -3494,7 +3644,7 @@ #else gchar *msg; - GST_WARNING ("Disabled API called: gst_parse_bin_from_description()"); + GST_WARNING ("Disabled API called"); msg = gst_error_get_message (GST_CORE_ERROR, GST_CORE_ERROR_DISABLED); g_set_error (err, GST_CORE_ERROR, GST_CORE_ERROR_DISABLED, "%s", msg); @@ -3607,3 +3757,95 @@ return GST_TIMEVAL_TO_TIME (now); #endif } + +/** + * gst_util_array_binary_search: + * @array: the sorted input array + * @num_elements: number of elements in the array + * @element_size: size of every element in bytes + * @search_func: function to compare two elements, @search_data will always be passed as second argument + * @mode: search mode that should be used + * @search_data: element that should be found + * @user_data: data to pass to @search_func + * + * Searches inside @array for @search_data by using the comparison function + * @search_func. @array must be sorted ascending. + * + * As @search_data is always passed as second argument to @search_func it's + * not required that @search_data has the same type as the array elements. + * + * The complexity of this search function is O(log (num_elements)). + * + * Returns: The address of the found element or %NULL if nothing was found + * + * Since: 0.10.23 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gpointer +gst_util_array_binary_search (gpointer array, guint num_elements, + gsize element_size, GCompareDataFunc search_func, GstSearchMode mode, + gconstpointer search_data, gpointer user_data) +{ + glong left = 0, right = num_elements - 1, m; + gint ret; + guint8 *data = (guint8 *) array; + + g_return_val_if_fail (array != NULL, NULL); + g_return_val_if_fail (element_size > 0, NULL); + g_return_val_if_fail (search_func != NULL, NULL); + + /* 0. No elements => return NULL */ + if (num_elements == 0) + return NULL; + + /* 1. If search_data is before the 0th element return the 0th element */ + ret = search_func (data, search_data, user_data); + if ((ret >= 0 && mode == GST_SEARCH_MODE_AFTER) || ret == 0) + return data; + else if (ret > 0) + return NULL; + + /* 2. If search_data is after the last element return the last element */ + ret = + search_func (data + (num_elements - 1) * element_size, search_data, + user_data); + if ((ret <= 0 && mode == GST_SEARCH_MODE_BEFORE) || ret == 0) + return data + (num_elements - 1) * element_size; + else if (ret < 0) + return NULL; + + /* 3. else binary search */ + while (TRUE) { + m = left + (right - left) / 2; + + ret = search_func (data + m * element_size, search_data, user_data); + + if (ret == 0) { + return data + m * element_size; + } else if (ret < 0) { + left = m + 1; + } else { + right = m - 1; + } + + /* No exact match found */ + if (right < left) { + if (mode == GST_SEARCH_MODE_EXACT) { + return NULL; + } else if (mode == GST_SEARCH_MODE_AFTER) { + if (ret < 0) + return (m < num_elements) ? data + (m + 1) * element_size : NULL; + else + return data + m * element_size; + } else { + if (ret < 0) + return data + m * element_size; + else + return (m > 0) ? data + (m - 1) * element_size : NULL; + } + } + } +}