gstobject.c 39.5 KB
Newer Older
1 2 3
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
4
 *                    2005 Wim Taymans <wim@fluendo.com>
5 6
 *
 * gstobject.c: Fundamental class used for all of GStreamer
Erik Walthinsen's avatar
Erik Walthinsen committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
23

24 25 26 27
/**
 * SECTION:gstobject
 * @short_description: Base class for the GStreamer object hierarchy
 *
28 29
 * #GstObject provides a root for the object hierarchy tree filed in by the
 * GStreamer library.  It is currently a thin wrapper on top of
Wim Taymans's avatar
Wim Taymans committed
30
 * #GInitiallyUnowned. It is an abstract class that is not very usable on its own.
31
 *
32 33 34
 * #GstObject gives us basic refcounting, parenting functionality and locking.
 * Most of the function are just extended for special GStreamer needs and can be
 * found under the same name in the base class of #GstObject which is #GObject
35 36
 * (e.g. g_object_ref() becomes gst_object_ref()).
 *
Wim Taymans's avatar
Wim Taymans committed
37 38 39
 * Since #GstObject dereives from #GInitiallyUnowned, it also inherits the
 * floating reference. Be aware that functions such as gst_bin_add() and
 * gst_element_add_pad() take ownership of the floating reference.
40 41
 *
 * In contrast to #GObject instances, #GstObject adds a name property. The functions
42 43
 * gst_object_set_name() and gst_object_get_name() are used to set/get the name
 * of the object.
44
 *
45 46
 * <refsect2>
 * <title>controlled properties</title>
Stefan Sauer's avatar
Stefan Sauer committed
47
 * <para>
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
 * Controlled properties offers a lightweight way to adjust gobject
 * properties over stream-time. It works by using time-stamped value pairs that
 * are queued for element-properties. At run-time the elements continously pull
 * values changes for the current stream-time.
 *
 * What needs to be changed in a #GstElement?
 * Very little - it is just two steps to make a plugin controllable!
 * <orderedlist>
 *   <listitem><para>
 *     mark gobject-properties paramspecs that make sense to be controlled,
 *     by GST_PARAM_CONTROLLABLE.
 *   </para></listitem>
 *   <listitem><para>
 *     when processing data (get, chain, loop function) at the beginning call
 *     gst_object_sync_values(element,timestamp).
 *     This will made the controller to update all gobject properties that are under
 *     control with the current values based on timestamp.
 *   </para></listitem>
 * </orderedlist>
 *
 * What needs to be done in applications?
 * Again its not a lot to change.
 * <orderedlist>
 *   <listitem><para>
 *     first put some properties under control, by calling
 *     gst_object_control_properties (object, "prop1", "prop2",...);
 *   </para></listitem>
 *   <listitem><para>
 *     create a #GstControlSource.
 *     csource = gst_interpolation_control_source_new ();
78
 *     g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
79 80 81
 *   </para></listitem>
 *   <listitem><para>
 *     Attach the #GstControlSource on the controller to a property.
82
 *     gst_object_add_control_binding (object, gst_direct_control_binding_new (objetct, "prop1", csource));
83 84 85
 *   </para></listitem>
 *   <listitem><para>
 *     Set the control values
86 87
 *     gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,0 * GST_SECOND, value1);
 *     gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,1 * GST_SECOND, value2);
88 89 90 91 92
 *   </para></listitem>
 *   <listitem><para>
 *     start your pipeline
 *   </para></listitem>
 * </orderedlist>
Stefan Sauer's avatar
Stefan Sauer committed
93
 * </para>
94 95
 * </refsect2>
 *
Wim Taymans's avatar
Wim Taymans committed
96
 * Last reviewed on 2012-03-29 (0.11.3)
97
 */
Erik Walthinsen's avatar
Erik Walthinsen committed
98

99
#include "gst_private.h"
100
#include "glib-compat-private.h"
101

102
#include "gstobject.h"
103
#include "gstclock.h"
104
#include "gstcontrolbinding.h"
105
#include "gstcontrolsource.h"
106
#include "gstinfo.h"
107
#include "gstparamspecs.h"
108
#include "gstutils.h"
109

110 111
#ifndef GST_DISABLE_TRACE
#include "gsttrace.h"
112
static GstAllocTrace *_gst_object_trace;
113
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
114

115 116
#define DEBUG_REFCOUNT

Erik Walthinsen's avatar
Erik Walthinsen committed
117
/* Object signals and args */
118 119
enum
{
Wim Taymans's avatar
Wim Taymans committed
120
  DEEP_NOTIFY,
Erik Walthinsen's avatar
Erik Walthinsen committed
121 122 123
  LAST_SIGNAL
};

124 125
enum
{
126 127 128 129
  PROP_0,
  PROP_NAME,
  PROP_PARENT,
  PROP_LAST
Erik Walthinsen's avatar
Erik Walthinsen committed
130 131
};

132 133
enum
{
134 135 136 137
  SO_OBJECT_LOADED,
  SO_LAST_SIGNAL
};

138 139
/* maps type name quark => count */
static GData *object_name_counts = NULL;
140

141
G_LOCK_DEFINE_STATIC (object_name_mutex);
142

143 144 145 146
static void gst_object_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_object_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
147

148 149
static void gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs);
Wim Taymans's avatar
Wim Taymans committed
150

151 152
static void gst_object_dispose (GObject * object);
static void gst_object_finalize (GObject * object);
153

154
static gboolean gst_object_set_name_default (GstObject * object);
155

Erik Walthinsen's avatar
Erik Walthinsen committed
156 157
static guint gst_object_signals[LAST_SIGNAL] = { 0 };

158 159 160
static GParamSpec *properties[PROP_LAST];

G_DEFINE_ABSTRACT_TYPE (GstObject, gst_object, G_TYPE_INITIALLY_UNOWNED);
Erik Walthinsen's avatar
Erik Walthinsen committed
161

162
static void
163
gst_object_class_init (GstObjectClass * klass)
164
{
165
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Erik Walthinsen's avatar
Erik Walthinsen committed
166

167
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
168
  _gst_object_trace =
169
      _gst_alloc_trace_register (g_type_name (GST_TYPE_OBJECT), -2);
170 171
#endif

172 173
  gobject_class->set_property = gst_object_set_property;
  gobject_class->get_property = gst_object_get_property;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
174

175 176 177
  properties[PROP_NAME] =
      g_param_spec_string ("name", "Name", "The name of the object", NULL,
      G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
Wim Taymans's avatar
Wim Taymans committed
178

179 180 181
  properties[PROP_PARENT] =
      g_param_spec_object ("parent", "Parent", "The parent of the object",
      GST_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
182 183

  g_object_class_install_properties (gobject_class, PROP_LAST, properties);
184 185 186

  /**
   * GstObject::deep-notify:
187
   * @gstobject: a #GstObject
188 189 190 191 192 193 194
   * @prop_object: the object that originated the signal
   * @prop: the property that changed
   *
   * The deep notify signal is used to be notified of property changes. It is
   * typically attached to the toplevel bin to receive notifications from all
   * the elements contained in that bin.
   */
Wim Taymans's avatar
Wim Taymans committed
195
  gst_object_signals[DEEP_NOTIFY] =
196 197 198
      g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
      G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (GstObjectClass, deep_notify), NULL,
199
      NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_OBJECT,
200
      G_TYPE_PARAM);
201 202

  klass->path_string_separator = "/";
Wim Taymans's avatar
Wim Taymans committed
203

204
  /* see the comments at gst_object_dispatch_properties_changed */
Wim Taymans's avatar
Wim Taymans committed
205
  gobject_class->dispatch_properties_changed
206
      = GST_DEBUG_FUNCPTR (gst_object_dispatch_properties_changed);
207

208
  gobject_class->dispose = gst_object_dispose;
209
  gobject_class->finalize = gst_object_finalize;
Erik Walthinsen's avatar
Erik Walthinsen committed
210 211
}

212
static void
213
gst_object_init (GstObject * object)
214
{
Wim Taymans's avatar
Wim Taymans committed
215
  g_mutex_init (&object->lock);
Erik Walthinsen's avatar
Erik Walthinsen committed
216
  object->parent = NULL;
Wim Taymans's avatar
Wim Taymans committed
217
  object->name = NULL;
218
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p new", object);
219

220
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
221
  _gst_alloc_trace_new (_gst_object_trace, object);
222 223
#endif

224
  object->flags = 0;
225 226 227

  object->control_rate = 100 * GST_MSECOND;
  object->last_sync = GST_CLOCK_TIME_NONE;
Erik Walthinsen's avatar
Erik Walthinsen committed
228 229
}

230 231
/**
 * gst_object_ref:
232
 * @object: a #GstObject to reference
233
 *
234
 * Increments the reference count on @object. This function
235
 * does not take the lock on @object because it relies on
236 237 238 239 240
 * atomic refcounting.
 *
 * This object returns the input parameter to ease writing
 * constructs like :
 *  result = gst_object_ref (object->parent);
Wim Taymans's avatar
Wim Taymans committed
241
 *
242
 * Returns: (transfer full): A pointer to @object
243
 */
244 245
gpointer
gst_object_ref (gpointer object)
246
{
247
  g_return_val_if_fail (object != NULL, NULL);
248

249
#ifdef DEBUG_REFCOUNT
250
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p ref %d->%d", object,
251 252
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1);
#endif
253
  g_object_ref (object);
254 255 256 257 258 259

  return object;
}

/**
 * gst_object_unref:
260
 * @object: a #GstObject to unreference
261
 *
262
 * Decrements the reference count on @object.  If reference count hits
263 264
 * zero, destroy @object. This function does not take the lock
 * on @object as it relies on atomic refcounting.
265 266 267
 *
 * The unref method should never be called with the LOCK held since
 * this might deadlock the dispose function.
268
 */
269 270
void
gst_object_unref (gpointer object)
271
{
272
  g_return_if_fail (object != NULL);
273
  g_return_if_fail (((GObject *) object)->ref_count > 0);
274 275

#ifdef DEBUG_REFCOUNT
276
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p unref %d->%d", object,
277 278
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1);
#endif
279
  g_object_unref (object);
280 281
}

282
/**
283
 * gst_object_ref_sink: (skip)
284 285 286 287 288 289 290 291 292 293 294
 * @object: a #GstObject to sink
 *
 * Increase the reference count of @object, and possibly remove the floating
 * reference, if @object has a floating reference.
 *
 * In other words, if the object is floating, then this call "assumes ownership"
 * of the floating reference, converting it to a normal reference by clearing
 * the floating flag while leaving the reference count unchanged. If the object
 * is not floating, then this call adds a new normal reference increasing the
 * reference count by one.
 */
295
gpointer
296 297
gst_object_ref_sink (gpointer object)
{
298
  g_return_val_if_fail (object != NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
299

300 301 302 303 304 305
#ifdef DEBUG_REFCOUNT
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p ref_sink %d->%d",
      object, ((GObject *) object)->ref_count,
      ((GObject *) object)->ref_count + 1);
#endif
  return g_object_ref_sink (object);
306 307
}

308
/**
309
 * gst_object_replace:
310 311 312
 * @oldobj: (inout) (transfer full): pointer to a place of a #GstObject to
 *     replace
 * @newobj: (transfer none): a new #GstObject
313
 *
314 315 316
 * Atomically modifies a pointer to point to a new object.
 * The reference count of @oldobj is decreased and the reference count of
 * @newobj is increased.
317
 *
318
 * Either @newobj and the value pointed to by @oldobj may be NULL.
319
 *
320
 * Returns: TRUE if @newobj was different from @oldobj
321
 */
322
gboolean
323
gst_object_replace (GstObject ** oldobj, GstObject * newobj)
324
{
325 326
  GstObject *oldptr;

327
  g_return_val_if_fail (oldobj != NULL, FALSE);
328

329
#ifdef DEBUG_REFCOUNT
330
  GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p %s (%d) with %p %s (%d)",
331
      *oldobj, *oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
332
      *oldobj ? G_OBJECT (*oldobj)->ref_count : 0,
333
      newobj, newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
334
      newobj ? G_OBJECT (newobj)->ref_count : 0);
335
#endif
Wim Taymans's avatar
Wim Taymans committed
336

337 338 339 340 341
  oldptr = g_atomic_pointer_get ((gpointer *) oldobj);

  if (G_UNLIKELY (oldptr == newobj))
    return FALSE;

342 343
  if (newobj)
    g_object_ref (newobj);
344 345 346 347 348 349 350 351

  while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
              oldobj, oldptr, newobj))) {
    oldptr = g_atomic_pointer_get ((gpointer *) oldobj);
    if (G_UNLIKELY (oldptr == newobj))
      break;
  }

352 353
  if (oldptr)
    g_object_unref (oldptr);
354 355

  return oldptr != newobj;
356 357
}

358 359
/* dispose is called when the object has to release all links
 * to other objects */
360
static void
361
gst_object_dispose (GObject * object)
362
{
363
  GstObject *self = (GstObject *) object;
364 365
  GstObject *parent;

366
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
367

368
  GST_OBJECT_LOCK (object);
369 370
  if ((parent = GST_OBJECT_PARENT (object)))
    goto have_parent;
371
  GST_OBJECT_PARENT (object) = NULL;
372
  GST_OBJECT_UNLOCK (object);
373

374
  if (self->control_bindings) {
375 376
    GList *node;

377 378
    for (node = self->control_bindings; node; node = g_list_next (node)) {
      g_object_unref (node->data);
379
    }
380 381
    g_list_free (self->control_bindings);
    self->control_bindings = NULL;
382 383
  }

384
  ((GObjectClass *) gst_object_parent_class)->dispose (object);
385 386 387 388 389 390 391 392 393 394 395

  return;

  /* ERRORS */
have_parent:
  {
    g_critical ("\nTrying to dispose object \"%s\", but it still has a "
        "parent \"%s\".\nYou need to let the parent manage the "
        "object instead of unreffing the object directly.\n",
        GST_OBJECT_NAME (object), GST_OBJECT_NAME (parent));
    GST_OBJECT_UNLOCK (object);
396
    /* ref the object again to revive it in this error case */
397
    gst_object_ref (object);
398 399
    return;
  }
400 401
}

402
/* finalize is called when the object has to free its resources */
403
static void
404
gst_object_finalize (GObject * object)
405
{
Wim Taymans's avatar
Wim Taymans committed
406
  GstObject *gstobject = GST_OBJECT_CAST (object);
407

408
  GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "finalize");
409

410 411
  g_signal_handlers_destroy (object);

412
  g_free (gstobject->name);
Wim Taymans's avatar
Wim Taymans committed
413
  g_mutex_clear (&gstobject->lock);
414

415
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
416
  _gst_alloc_trace_free (_gst_object_trace, object);
417 418
#endif

419
  ((GObjectClass *) gst_object_parent_class)->finalize (object);
420 421
}

422
/* Changing a GObject property of a GstObject will result in "deep-notify"
423 424
 * signals being emitted by the object itself, as well as in each parent
 * object. This is so that an application can connect a listener to the
Wim Taymans's avatar
Wim Taymans committed
425
 * top-level bin to catch property-change notifications for all contained
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
426
 * elements.
427 428 429
 *
 * MT safe.
 */
Wim Taymans's avatar
Wim Taymans committed
430
static void
431 432
gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs)
Wim Taymans's avatar
Wim Taymans committed
433
{
434
  GstObject *gst_object, *parent, *old_parent;
Wim Taymans's avatar
Wim Taymans committed
435
  guint i;
436 437
#ifndef GST_DISABLE_GST_DEBUG
  gchar *name = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
438
  const gchar *debug_name;
439
#endif
440

Wim Taymans's avatar
Wim Taymans committed
441
  /* do the standard dispatching */
442 443 444
  ((GObjectClass *)
      gst_object_parent_class)->dispatch_properties_changed (object, n_pspecs,
      pspecs);
445 446

  gst_object = GST_OBJECT_CAST (object);
447
#ifndef GST_DISABLE_GST_DEBUG
448
  if (G_UNLIKELY (_gst_debug_min >= GST_LEVEL_LOG)) {
449 450 451 452 453
    name = gst_object_get_name (gst_object);
    debug_name = GST_STR_NULL (name);
  } else
    debug_name = "";
#endif
Wim Taymans's avatar
Wim Taymans committed
454 455

  /* now let the parent dispatch those, too */
456 457
  parent = gst_object_get_parent (gst_object);
  while (parent) {
Wim Taymans's avatar
Wim Taymans committed
458
    for (i = 0; i < n_pspecs; i++) {
459 460
      GST_CAT_LOG_OBJECT (GST_CAT_PROPERTIES, parent,
          "deep notification from %s (%s)", debug_name, pspecs[i]->name);
461 462

      g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
Wim Taymans's avatar
Wim Taymans committed
463
          g_quark_from_string (pspecs[i]->name), gst_object, pspecs[i]);
Wim Taymans's avatar
Wim Taymans committed
464 465
    }

466 467 468
    old_parent = parent;
    parent = gst_object_get_parent (old_parent);
    gst_object_unref (old_parent);
Wim Taymans's avatar
Wim Taymans committed
469
  }
470
#ifndef GST_DISABLE_GST_DEBUG
471
  g_free (name);
472
#endif
Wim Taymans's avatar
Wim Taymans committed
473 474
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
475
/**
Wim Taymans's avatar
Wim Taymans committed
476 477 478 479
 * gst_object_default_deep_notify:
 * @object: the #GObject that signalled the notify.
 * @orig: a #GstObject that initiated the notify.
 * @pspec: a #GParamSpec of the property.
480 481 482
 * @excluded_props: (array zero-terminated=1) (element-type gchar*)
 *     (allow-none):a set of user-specified properties to exclude or
 *     NULL to show all changes.
Wim Taymans's avatar
Wim Taymans committed
483
 *
484
 * A default deep_notify signal callback for an object. The user data
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
485 486
 * should contain a pointer to an array of strings that should be excluded
 * from the notify. The default handler will print the new value of the property
Wim Taymans's avatar
Wim Taymans committed
487
 * using g_print.
488
 *
489 490
 * MT safe. This function grabs and releases @object's LOCK for getting its
 *          path string.
Wim Taymans's avatar
Wim Taymans committed
491 492
 */
void
493 494
gst_object_default_deep_notify (GObject * object, GstObject * orig,
    GParamSpec * pspec, gchar ** excluded_props)
Wim Taymans's avatar
Wim Taymans committed
495
{
496
  GValue value = { 0, };        /* the important thing is that value.type = 0 */
497
  gchar *str = NULL;
498
  gchar *name = NULL;
Wim Taymans's avatar
Wim Taymans committed
499 500 501 502 503

  if (pspec->flags & G_PARAM_READABLE) {
    /* let's not print these out for excluded properties... */
    while (excluded_props != NULL && *excluded_props != NULL) {
      if (strcmp (pspec->name, *excluded_props) == 0)
504
        return;
Wim Taymans's avatar
Wim Taymans committed
505 506
      excluded_props++;
    }
507
    g_value_init (&value, pspec->value_type);
Wim Taymans's avatar
Wim Taymans committed
508 509
    g_object_get_property (G_OBJECT (orig), pspec->name, &value);

510
    /* FIXME: handle flags */
Wim Taymans's avatar
Wim Taymans committed
511 512
    if (G_IS_PARAM_SPEC_ENUM (pspec)) {
      GEnumValue *enum_value;
513
      GEnumClass *klass = G_ENUM_CLASS (g_type_class_ref (pspec->value_type));
514

515
      enum_value = g_enum_get_value (klass, g_value_get_enum (&value));
Wim Taymans's avatar
Wim Taymans committed
516 517

      str = g_strdup_printf ("%s (%d)", enum_value->value_nick,
518
          enum_value->value);
519
      g_type_class_unref (klass);
520
    } else {
Wim Taymans's avatar
Wim Taymans committed
521 522
      str = g_strdup_value_contents (&value);
    }
523 524 525
    name = gst_object_get_path_string (orig);
    g_print ("%s: %s = %s\n", name, pspec->name, str);
    g_free (name);
Wim Taymans's avatar
Wim Taymans committed
526 527 528
    g_free (str);
    g_value_unset (&value);
  } else {
529
    name = gst_object_get_path_string (orig);
530
    g_warning ("Parameter %s not readable in %s.", pspec->name, name);
531
    g_free (name);
Wim Taymans's avatar
Wim Taymans committed
532 533 534
  }
}

535
static gboolean
536
gst_object_set_name_default (GstObject * object)
537
{
538
  const gchar *type_name;
539
  gint count;
540
  gchar *name;
541
  GQuark q;
542
  guint i, l;
543

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
544 545
  /* to ensure guaranteed uniqueness across threads, only one thread
   * may ever assign a name */
546 547
  G_LOCK (object_name_mutex);

548
  if (!object_name_counts) {
549
    g_datalist_init (&object_name_counts);
550
  }
551

552 553 554
  q = g_type_qname (G_OBJECT_TYPE (object));
  count = GPOINTER_TO_INT (g_datalist_id_get_data (&object_name_counts, q));
  g_datalist_id_set_data (&object_name_counts, q, GINT_TO_POINTER (count + 1));
555

556 557
  G_UNLOCK (object_name_mutex);

558
  /* GstFooSink -> foosink<N> */
559
  type_name = g_quark_to_string (q);
560 561
  if (strncmp (type_name, "Gst", 3) == 0)
    type_name += 3;
562 563
  name = g_strdup_printf ("%s%d", type_name, count);
  l = strlen (name);
564
  for (i = 0; i < l; i++)
565
    name[i] = g_ascii_tolower (name[i]);
566

567 568 569
  GST_OBJECT_LOCK (object);
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;
570

571 572 573 574
  g_free (object->name);
  object->name = name;

  GST_OBJECT_UNLOCK (object);
575

576 577 578 579
  return TRUE;

had_parent:
  {
580
    g_free (name);
581 582 583 584
    GST_WARNING ("parented objects can't be renamed");
    GST_OBJECT_UNLOCK (object);
    return FALSE;
  }
585 586
}

587 588
/**
 * gst_object_set_name:
589
 * @object: a #GstObject
590
 * @name:   new name of object
591
 *
592
 * Sets the name of @object, or gives @object a guaranteed unique
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
593
 * name (if @name is NULL).
594 595 596
 * This function makes a copy of the provided name, so the caller
 * retains ownership of the name it sent.
 *
597 598 599
 * Returns: TRUE if the name could be set. Since Objects that have
 * a parent cannot be renamed, this function returns FALSE in those
 * cases.
600
 *
601
 * MT safe.  This function grabs and releases @object's LOCK.
602
 */
603
gboolean
604
gst_object_set_name (GstObject * object, const gchar * name)
605
{
606
  gboolean result;
607

608 609
  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);

610
  GST_OBJECT_LOCK (object);
611

612 613 614 615 616 617
  /* parented objects cannot be renamed */
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;

  if (name != NULL) {
    g_free (object->name);
618
    object->name = g_strdup (name);
619
    GST_OBJECT_UNLOCK (object);
620 621
    result = TRUE;
  } else {
622
    GST_OBJECT_UNLOCK (object);
623
    result = gst_object_set_name_default (object);
624
  }
625 626 627 628
  /* FIXME-0.11: this misses a g_object_notify (object, "name"); unless called
   * from gst_object_set_property.
   * Ideally remove such custom setters (or make it static).
   */
629 630 631 632 633
  return result;

  /* error */
had_parent:
  {
Stefan Kost's avatar
Stefan Kost committed
634
    GST_WARNING ("parented objects can't be renamed");
635
    GST_OBJECT_UNLOCK (object);
636 637
    return FALSE;
  }
638 639 640 641
}

/**
 * gst_object_get_name:
642
 * @object: a #GstObject
643
 *
644
 * Returns a copy of the name of @object.
645 646 647
 * Caller should g_free() the return value after usage.
 * For a nameless object, this returns NULL, which you can safely g_free()
 * as well.
648
 *
649 650 651
 * Free-function: g_free
 *
 * Returns: (transfer full): the name of @object. g_free() after usage.
652
 *
653
 * MT safe. This function grabs and releases @object's LOCK.
654
 */
655
gchar *
656
gst_object_get_name (GstObject * object)
657
{
658 659
  gchar *result = NULL;

660 661
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

662
  GST_OBJECT_LOCK (object);
663
  result = g_strdup (object->name);
664
  GST_OBJECT_UNLOCK (object);
665 666 667 668

  return result;
}

Erik Walthinsen's avatar
Erik Walthinsen committed
669 670
/**
 * gst_object_set_parent:
671
 * @object: a #GstObject
Erik Walthinsen's avatar
Erik Walthinsen committed
672 673
 * @parent: new parent of object
 *
674
 * Sets the parent of @object to @parent. The object's reference count will
Wim Taymans's avatar
Wim Taymans committed
675
 * be incremented, and any floating reference will be removed (see gst_object_ref_sink()).
676
 *
677 678
 * Returns: TRUE if @parent could be set or FALSE when @object
 * already had a parent or @object and @parent are the same.
679
 *
680
 * MT safe. Grabs and releases @object's LOCK.
Erik Walthinsen's avatar
Erik Walthinsen committed
681
 */
682
gboolean
683
gst_object_set_parent (GstObject * object, GstObject * parent)
684
{
685 686 687
  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
  g_return_val_if_fail (GST_IS_OBJECT (parent), FALSE);
  g_return_val_if_fail (object != parent, FALSE);
688

689 690
  GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object,
      "set parent (ref and sink)");
691

692
  GST_OBJECT_LOCK (object);
693 694 695
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;

Erik Walthinsen's avatar
Erik Walthinsen committed
696
  object->parent = parent;
697
  gst_object_ref_sink (object);
698
  GST_OBJECT_UNLOCK (object);
Erik Walthinsen's avatar
Erik Walthinsen committed
699

700 701 702 703
  /* FIXME, this does not work, the deep notify takes the lock from the parent
   * object and deadlocks when the parent holds its lock when calling this
   * function (like _element_add_pad()) */
  /* g_object_notify_by_pspec ((GObject *)object, properties[PROP_PARENT]); */
704

705 706
  return TRUE;

707
  /* ERROR handling */
708 709
had_parent:
  {
710 711
    GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object,
        "set parent failed, object already had a parent");
712
    GST_OBJECT_UNLOCK (object);
713 714
    return FALSE;
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
715 716 717 718
}

/**
 * gst_object_get_parent:
719
 * @object: a #GstObject
Erik Walthinsen's avatar
Erik Walthinsen committed
720
 *
721 722
 * Returns the parent of @object. This function increases the refcount
 * of the parent object so you should gst_object_unref() it after usage.
Erik Walthinsen's avatar
Erik Walthinsen committed
723
 *
724 725
 * Returns: (transfer full): parent of @object, this can be NULL if @object
 *   has no parent. unref after usage.
726
 *
727
 * MT safe. Grabs and releases @object's LOCK.
Erik Walthinsen's avatar
Erik Walthinsen committed
728
 */
729 730
GstObject *
gst_object_get_parent (GstObject * object)
731
{
732 733
  GstObject *result = NULL;

734
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
Erik Walthinsen's avatar
Erik Walthinsen committed
735

736
  GST_OBJECT_LOCK (object);
737 738 739
  result = object->parent;
  if (G_LIKELY (result))
    gst_object_ref (result);
740
  GST_OBJECT_UNLOCK (object);
741 742

  return result;
Erik Walthinsen's avatar
Erik Walthinsen committed
743 744 745 746
}

/**
 * gst_object_unparent:
747
 * @object: a #GstObject to unparent
Erik Walthinsen's avatar
Erik Walthinsen committed
748
 *
749
 * Clear the parent of @object, removing the associated reference.
750
 * This function decreases the refcount of @object.
751
 *
752
 * MT safe. Grabs and releases @object's lock.
Erik Walthinsen's avatar
Erik Walthinsen committed
753
 */
754
void
755
gst_object_unparent (GstObject * object)
756
{
757 758
  GstObject *parent;

759
  g_return_if_fail (GST_IS_OBJECT (object));
Erik Walthinsen's avatar
Erik Walthinsen committed
760

761
  GST_OBJECT_LOCK (object);
762
  parent = object->parent;
763

764
  if (G_LIKELY (parent != NULL)) {
765
    GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
766
    object->parent = NULL;
767
    GST_OBJECT_UNLOCK (object);
768

769
    /* g_object_notify_by_pspec ((GObject *)object, properties[PROP_PARENT]); */
770 771 772

    gst_object_unref (object);
  } else {
773
    GST_OBJECT_UNLOCK (object);
774
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
775 776
}

777 778
/**
 * gst_object_has_ancestor:
779 780
 * @object: a #GstObject to check
 * @ancestor: a #GstObject to check as ancestor
781 782
 *
 * Check if @object has an ancestor @ancestor somewhere up in
783
 * the hierarchy. One can e.g. check if a #GstElement is inside a #GstPipeline.
784 785 786
 *
 * Returns: TRUE if @ancestor is an ancestor of @object.
 *
787
 * MT safe. Grabs and releases @object's locks.
788 789 790 791
 */
gboolean
gst_object_has_ancestor (GstObject * object, GstObject * ancestor)
{
792
  GstObject *parent, *tmp;
793

794
  if (!ancestor || !object)
795 796
    return FALSE;

797 798 799 800 801 802
  parent = gst_object_ref (object);
  do {
    if (parent == ancestor) {
      gst_object_unref (parent);
      return TRUE;
    }
803

804
    tmp = gst_object_get_parent (parent);
805
    gst_object_unref (parent);
806 807
    parent = tmp;
  } while (parent);
808

809
  return FALSE;
810 811
}