gstobject.c 31.7 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 23
 *
 * 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.
 */

24 25
#include "gst_private.h"

26
#include "gstobject.h"
27
#include "gstmarshal.h"
28
#include "gstinfo.h"
29
#include "gstatomic_impl.h"
30

31 32 33
#ifndef GST_DISABLE_TRACE
#include "gsttrace.h"
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#define DEBUG_REFCOUNT
#define REFCOUNT_HACK

/* Refcount hack: since glib is not threadsafe, the glib refcounter can be
 * screwed up and the object can be freed unexpectedly. We use an evil hack
 * to work around this problem. We set the glib refcount to a high value so
 * that glib will never unref the object under realistic circumstances. Then
 * we use our own atomic refcounting to do proper MT safe refcounting.
 *
 * A proper fix is of course to make the glib refcounting threadsafe which is
 * planned.
 */
#ifdef REFCOUNT_HACK
#define PATCH_REFCOUNT(obj)    ((GObject*)(obj))->ref_count = 100000;
#define PATCH_REFCOUNT1(obj)    ((GObject*)(obj))->ref_count = 1;
#else
#define PATCH_REFCOUNT(obj)
#define PATCH_REFCOUNT1(obj)
#endif

Erik Walthinsen's avatar
Erik Walthinsen committed
55
/* Object signals and args */
56 57
enum
{
Erik Walthinsen's avatar
Erik Walthinsen committed
58
  PARENT_SET,
59
  PARENT_UNSET,
60
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
61
  OBJECT_SAVED,
62
#endif
Wim Taymans's avatar
Wim Taymans committed
63
  DEEP_NOTIFY,
Erik Walthinsen's avatar
Erik Walthinsen committed
64 65 66
  LAST_SIGNAL
};

67 68
enum
{
Erik Walthinsen's avatar
Erik Walthinsen committed
69
  ARG_0,
70
  ARG_NAME
71
      /* FILL ME */
Erik Walthinsen's avatar
Erik Walthinsen committed
72 73
};

74 75
enum
{
76 77 78 79
  SO_OBJECT_LOADED,
  SO_LAST_SIGNAL
};

80
GType _gst_object_type = 0;
81
static GHashTable *object_name_counts = NULL;
82

83
G_LOCK_DEFINE_STATIC (object_name_mutex);
84

85 86 87
typedef struct _GstSignalObject GstSignalObject;
typedef struct _GstSignalObjectClass GstSignalObjectClass;

88 89 90
static GType gst_signal_object_get_type (void);
static void gst_signal_object_class_init (GstSignalObjectClass * klass);
static void gst_signal_object_init (GstSignalObject * object);
91

Wim Taymans's avatar
Wim Taymans committed
92
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
93
static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
Wim Taymans's avatar
Wim Taymans committed
94
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
95

96
static void gst_object_class_init (GstObjectClass * klass);
97
static void gst_object_init (GTypeInstance * instance, gpointer g_class);
98

99
#ifndef GST_DISABLE_TRACE
100 101
static GObject *gst_object_constructor (GType type,
    guint n_construct_properties, GObjectConstructParam * construct_params);
102
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
103

104 105 106 107 108 109
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);
static void gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs);
Wim Taymans's avatar
Wim Taymans committed
110

111 112
static void gst_object_dispose (GObject * object);
static void gst_object_finalize (GObject * object);
113

114
static gboolean gst_object_set_name_default (GstObject * object,
115 116
    const gchar * type_name);

117
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
118 119
static void gst_object_real_restore_thyself (GstObject * object,
    xmlNodePtr self);
120 121
#endif

122
static GObjectClass *parent_class = NULL;
Erik Walthinsen's avatar
Erik Walthinsen committed
123 124
static guint gst_object_signals[LAST_SIGNAL] = { 0 };

125
GType
126 127
gst_object_get_type (void)
{
128
  if (!_gst_object_type) {
129 130 131 132 133 134 135 136
    static const GTypeInfo object_info = {
      sizeof (GstObjectClass),
      NULL,
      NULL,
      (GClassInitFunc) gst_object_class_init,
      NULL,
      NULL,
      sizeof (GstObject),
137
      0,
138
      gst_object_init,
139
      NULL
Erik Walthinsen's avatar
Erik Walthinsen committed
140
    };
141

142
    _gst_object_type =
143 144
        g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info,
        G_TYPE_FLAG_ABSTRACT);
Erik Walthinsen's avatar
Erik Walthinsen committed
145
  }
146
  return _gst_object_type;
Erik Walthinsen's avatar
Erik Walthinsen committed
147 148
}

149
static void
150
gst_object_class_init (GstObjectClass * klass)
151
{
152
  GObjectClass *gobject_class;
Erik Walthinsen's avatar
Erik Walthinsen committed
153

154
  gobject_class = (GObjectClass *) klass;
Erik Walthinsen's avatar
Erik Walthinsen committed
155

156
  parent_class = g_type_class_ref (G_TYPE_OBJECT);
Erik Walthinsen's avatar
Erik Walthinsen committed
157

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
158 159
  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_object_set_property);
  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_object_get_property);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160

Wim Taymans's avatar
Wim Taymans committed
161
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NAME,
162
      g_param_spec_string ("name", "Name", "The name of the object",
163
          NULL, G_PARAM_READWRITE));
Wim Taymans's avatar
Wim Taymans committed
164

Erik Walthinsen's avatar
Erik Walthinsen committed
165
  gst_object_signals[PARENT_SET] =
166 167 168
      g_signal_new ("parent-set", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
      G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
      g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
169
  gst_object_signals[PARENT_UNSET] =
170 171 172
      g_signal_new ("parent-unset", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, parent_unset), NULL,
      NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
173
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
174
  /* FIXME This should be the GType of xmlNodePtr instead of G_TYPE_POINTER */
175
  gst_object_signals[OBJECT_SAVED] =
176 177 178 179
      g_signal_new ("object-saved", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL,
      NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);

180
  klass->restore_thyself = gst_object_real_restore_thyself;
181
#endif
Wim Taymans's avatar
Wim Taymans committed
182
  gst_object_signals[DEEP_NOTIFY] =
183 184 185 186 187
      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,
      NULL, gst_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE, 2, G_TYPE_OBJECT,
      G_TYPE_PARAM);
188 189

  klass->path_string_separator = "/";
190
  klass->lock = g_mutex_new ();
191 192

  klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
Wim Taymans's avatar
Wim Taymans committed
193

194
  /* see the comments at gst_object_dispatch_properties_changed */
Wim Taymans's avatar
Wim Taymans committed
195
  gobject_class->dispatch_properties_changed
196
      = GST_DEBUG_FUNCPTR (gst_object_dispatch_properties_changed);
197

198
  gobject_class->dispose = gst_object_dispose;
199
  gobject_class->finalize = gst_object_finalize;
200 201 202
#ifndef GST_DISABLE_TRACE
  gobject_class->constructor = gst_object_constructor;
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
203 204
}

205
static void
206
gst_object_init (GTypeInstance * instance, gpointer g_class)
207
{
208 209
  GstObject *object = GST_OBJECT (instance);

210
  object->lock = g_mutex_new ();
Erik Walthinsen's avatar
Erik Walthinsen committed
211
  object->parent = NULL;
Wim Taymans's avatar
Wim Taymans committed
212
  object->name = NULL;
213 214
  gst_atomic_int_init (&(object)->refcount, 1);
  PATCH_REFCOUNT (object);
215
  gst_object_set_name_default (object, G_OBJECT_CLASS_NAME (g_class));
216 217

  object->flags = 0;
218
  GST_FLAG_SET (object, GST_OBJECT_FLOATING);
Erik Walthinsen's avatar
Erik Walthinsen committed
219 220
}

221 222
#ifndef GST_DISABLE_TRACE
static GObject *
223 224
gst_object_constructor (GType type, guint n_construct_properties,
    GObjectConstructParam * construct_params)
225 226 227
{
  const gchar *name;
  GstAllocTrace *trace;
228 229 230
  GObject *obj =
      G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties,
      construct_params);
231 232 233 234 235 236 237 238

  name = g_type_name (type);

  trace = gst_alloc_trace_get (name);
  if (!trace) {
    trace = gst_alloc_trace_register (name);
  }
  gst_alloc_trace_new (trace, obj);
239

240 241 242
  return obj;
}
#endif
243 244 245 246
/**
 * gst_object_ref:
 * @object: GstObject to reference
 *
247 248 249 250 251 252 253
 * Increments the refence count on the object. This function
 * does not take the lock on the object because it relies on
 * 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
254 255
 *
 * Returns: A pointer to the object
256
 */
257 258
GstObject *
gst_object_ref (GstObject * object)
259 260 261
{
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

262 263 264 265 266 267
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
      GST_OBJECT_REFCOUNT_VALUE (object),
      GST_OBJECT_REFCOUNT_VALUE (object) + 1);
#else
268
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
269 270 271 272 273 274 275 276 277 278 279
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1);
#endif
#endif

#ifdef REFCOUNT_HACK
  gst_atomic_int_inc (&object->refcount);
  PATCH_REFCOUNT (object);
#else
  /* FIXME, not MT safe because glib is not MT safe */
  g_object_ref (object);
#endif
280 281 282 283 284 285 286 287 288

  return object;
}

/**
 * gst_object_unref:
 * @object: GstObject to unreference
 *
 * Decrements the refence count on the object.  If reference count hits
289 290 291 292 293 294 295 296 297 298 299
 * zero, destroy the object. This function does not take the lock
 * on the object as it relies on atomic refcounting.
 *
 * The unref method should never be called with the LOCK held since
 * this might deadlock the dispose function.
 * 
 * Returns: NULL, so that constructs like
 *
 *   object = gst_object_unref (object);
 *
 *  automatically clear the input object pointer.
300
 */
301
GstObject *
302
gst_object_unref (GstObject * object)
303
{
304 305 306 307 308 309 310
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

#ifdef REFCOUNT_HACK
  g_return_val_if_fail (GST_OBJECT_REFCOUNT_VALUE (object) > 0, NULL);
#else
  g_return_val_if_fail (((GObject *) object)->ref_count > 0, NULL);
#endif
311

312 313
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
314
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
315 316 317 318 319 320 321
      GST_OBJECT_REFCOUNT_VALUE (object),
      GST_OBJECT_REFCOUNT_VALUE (object) - 1);
#else
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1);
#endif
#endif
322

323 324 325 326 327 328 329 330 331 332 333 334 335
#ifdef REFCOUNT_HACK
  if (G_UNLIKELY (gst_atomic_int_dec_and_test (&object->refcount))) {
    PATCH_REFCOUNT1 (object);
    g_object_unref (object);
  } else {
    PATCH_REFCOUNT (object);
  }
#else
  /* FIXME, not MT safe because glib is not MT safe */
  g_object_unref (object);
#endif

  return NULL;
336 337 338 339 340 341 342 343
}

/**
 * gst_object_sink:
 * @object: GstObject to sink
 *
 * Removes floating reference on an object.  Any newly created object has
 * a refcount of 1 and is FLOATING.  This function should be used when
344
 * creating a new object to symbolically 'take ownership' of the object.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
345
 * Use #gst_object_set_parent to have this done for you.
346
 *
347
 * MT safe. This function grabs and releases the object lock.
348 349
 */
void
350
gst_object_sink (GstObject * object)
351 352 353
{
  g_return_if_fail (GST_IS_OBJECT (object));

354
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");
Wim Taymans's avatar
Wim Taymans committed
355

356 357 358 359
  GST_LOCK (object);
  if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
    GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
    GST_UNLOCK (object);
360
    gst_object_unref (object);
361 362
  } else {
    GST_UNLOCK (object);
363 364 365
  }
}

366
/**
367
 * gst_object_replace:
368 369 370 371
 * @oldobj: pointer to place of old GstObject
 * @newobj: new GstObject
 *
 * Unrefs the object pointer to by oldobj, refs the newobj and
372 373 374 375
 * puts the newobj in *oldobj. Be carefull when calling this
 * function, it does not take any locks. You might want to lock
 * the object owning the oldobj pointer before calling this
 * function.
376 377 378
 *
 * Make sure not to LOCK the oldobj because it might be unreffed
 * which could cause a deadlock when it is disposed.
379 380
 */
void
381
gst_object_replace (GstObject ** oldobj, GstObject * newobj)
382
{
383 384 385
  g_return_if_fail (oldobj != NULL);
  g_return_if_fail (*oldobj == NULL || GST_IS_OBJECT (*oldobj));
  g_return_if_fail (newobj == NULL || GST_IS_OBJECT (newobj));
386

387 388 389 390 391 392 393 394
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
  GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s (%d) with %s (%d)",
      *oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
      *oldobj ? GST_OBJECT_REFCOUNT_VALUE (*oldobj) : 0,
      newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
      newobj ? GST_OBJECT_REFCOUNT_VALUE (newobj) : 0);
#else
395
  GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s (%d) with %s (%d)",
396
      *oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
397 398 399
      *oldobj ? G_OBJECT (*oldobj)->ref_count : 0,
      newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
      newobj ? G_OBJECT (newobj)->ref_count : 0);
400 401
#endif
#endif
Wim Taymans's avatar
Wim Taymans committed
402

403
  if (G_LIKELY (*oldobj != newobj)) {
404 405 406 407
    if (newobj)
      gst_object_ref (newobj);
    if (*oldobj)
      gst_object_unref (*oldobj);
408 409 410 411 412

    *oldobj = newobj;
  }
}

413 414
/* dispose is called when the object has to release all links
 * to other objects */
415
static void
416
gst_object_dispose (GObject * object)
417
{
418
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
419

420 421
  GST_LOCK (object);
  GST_FLAG_SET (GST_OBJECT (object), GST_OBJECT_DESTROYED);
422
  GST_OBJECT_PARENT (object) = NULL;
423 424 425 426
  GST_UNLOCK (object);

  /* need to patch refcount so it is finalized */
  PATCH_REFCOUNT1 (object)
427

428
      parent_class->dispose (object);
429 430
}

431
/* finalize is called when the object has to free its resources */
432
static void
433
gst_object_finalize (GObject * object)
434
{
435
  GstObject *gstobject = GST_OBJECT (object);
436

437
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "finalize");
438

439 440
  g_signal_handlers_destroy (object);

441
  g_free (gstobject->name);
442
  g_mutex_free (gstobject->lock);
443

444 445 446 447
#ifndef GST_DISABLE_TRACE
  {
    const gchar *name;
    GstAllocTrace *trace;
448

449 450 451 452 453 454 455
    name = g_type_name (G_OBJECT_TYPE (object));
    trace = gst_alloc_trace_get (name);
    g_assert (trace);
    gst_alloc_trace_free (trace, object);
  }
#endif

456
  parent_class->finalize (object);
457 458
}

459 460 461
/* Changing a GObject property of a GstObject will result in "deep_notify"
 * 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
462
 * top-level bin to catch property-change notifications for all contained
463 464 465 466 467 468 469
 * elements. 
 *
 * This function is not MT safe in glib so we need to lock it with a 
 * classwide mutex.
 *
 * MT safe.
 */
Wim Taymans's avatar
Wim Taymans committed
470
static void
471 472
gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs)
Wim Taymans's avatar
Wim Taymans committed
473
{
474
  GstObject *gst_object, *parent, *old_parent;
Wim Taymans's avatar
Wim Taymans committed
475
  guint i;
476 477 478 479 480 481 482
  gchar *name, *debug_name;
  GstObjectClass *klass;

  /* we fail when this is not a GstObject */
  g_return_if_fail (GST_IS_OBJECT (object));

  klass = GST_OBJECT_GET_CLASS (object);
Wim Taymans's avatar
Wim Taymans committed
483

484
  GST_CLASS_LOCK (klass);
Wim Taymans's avatar
Wim Taymans committed
485
  /* do the standard dispatching */
486
  PATCH_REFCOUNT (object);
487 488
  G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
      pspecs);
489 490 491 492 493
  PATCH_REFCOUNT (object);

  gst_object = GST_OBJECT_CAST (object);
  name = gst_object_get_name (gst_object);
  debug_name = GST_STR_NULL (name);
Wim Taymans's avatar
Wim Taymans committed
494 495

  /* now let the parent dispatch those, too */
496 497 498 499
  parent = gst_object_get_parent (gst_object);
  while (parent) {
    /* for debugging ... */
    gchar *parent_name = gst_object_get_name (parent);
500 501

#ifndef GST_DISABLE_GST_DEBUG
502
    gchar *debug_parent_name = GST_STR_NULL (parent_name);
503
#endif
504

Wim Taymans's avatar
Wim Taymans committed
505 506
    /* need own category? */
    for (i = 0; i < n_pspecs; i++) {
507 508 509 510 511 512 513 514
      GST_CAT_LOG (GST_CAT_EVENT, "deep notification from %s to %s (%s)",
          debug_name, debug_parent_name, pspecs[i]->name);

      /* not MT safe because of glib, fixed by taking class lock higher up */
      PATCH_REFCOUNT (parent);
      PATCH_REFCOUNT (object);
      g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
          g_quark_from_string (pspecs[i]->name), GST_OBJECT_CAST (object),
515
          pspecs[i]);
516 517
      PATCH_REFCOUNT (parent);
      PATCH_REFCOUNT (object);
Wim Taymans's avatar
Wim Taymans committed
518
    }
519
    g_free (parent_name);
Wim Taymans's avatar
Wim Taymans committed
520

521 522 523
    old_parent = parent;
    parent = gst_object_get_parent (old_parent);
    gst_object_unref (old_parent);
Wim Taymans's avatar
Wim Taymans committed
524
  }
525 526
  g_free (name);
  GST_CLASS_UNLOCK (klass);
Wim Taymans's avatar
Wim Taymans committed
527 528 529 530 531 532 533
}

/** 
 * 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.
Wim Taymans's avatar
Wim Taymans committed
534 535
 * @excluded_props: a set of user-specified properties to exclude or
 *  NULL to show all changes.
Wim Taymans's avatar
Wim Taymans committed
536
 *
537 538 539
 * A default deep_notify signal callback for an element. The user data 
 * 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
540
 * using g_print.
541
 *
542 543
 * MT safe. This function grabs and releases the object's LOCK or getting the
 *          path string of the object.
Wim Taymans's avatar
Wim Taymans committed
544 545
 */
void
546 547
gst_object_default_deep_notify (GObject * object, GstObject * orig,
    GParamSpec * pspec, gchar ** excluded_props)
Wim Taymans's avatar
Wim Taymans committed
548
{
549
  GValue value = { 0, };        /* the important thing is that value.type = 0 */
550
  gchar *str = NULL;
551
  gchar *name = NULL;
Wim Taymans's avatar
Wim Taymans committed
552 553 554 555 556

  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)
557
        return;
Wim Taymans's avatar
Wim Taymans committed
558 559 560 561 562 563 564
      excluded_props++;
    }
    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
    g_object_get_property (G_OBJECT (orig), pspec->name, &value);

    if (G_IS_PARAM_SPEC_ENUM (pspec)) {
      GEnumValue *enum_value;
565 566

      enum_value =
567 568
          g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (pspec->value_type)),
          g_value_get_enum (&value));
Wim Taymans's avatar
Wim Taymans committed
569 570

      str = g_strdup_printf ("%s (%d)", enum_value->value_nick,
571
          enum_value->value);
572
    } else {
Wim Taymans's avatar
Wim Taymans committed
573 574
      str = g_strdup_value_contents (&value);
    }
575 576 577
    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
578 579 580
    g_free (str);
    g_value_unset (&value);
  } else {
581
    name = gst_object_get_path_string (orig);
582
    g_warning ("Parameter %s not readable in %s.", pspec->name, name);
583
    g_free (name);
Wim Taymans's avatar
Wim Taymans committed
584 585 586
  }
}

587
static gboolean
588
gst_object_set_name_default (GstObject * object, const gchar * type_name)
589 590
{
  gint count;
591
  gchar *name, *tmp;
592
  gboolean result;
593

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
594 595
  /* to ensure guaranteed uniqueness across threads, only one thread
   * may ever assign a name */
596 597
  G_LOCK (object_name_mutex);

598 599
  if (!object_name_counts) {
    object_name_counts = g_hash_table_new_full (g_str_hash, g_str_equal,
600
        g_free, NULL);
601
  }
602 603

  count = GPOINTER_TO_INT (g_hash_table_lookup (object_name_counts, type_name));
604 605 606
  g_hash_table_insert (object_name_counts, g_strdup (type_name),
      GINT_TO_POINTER (count + 1));

607 608
  G_UNLOCK (object_name_mutex);

609 610 611 612 613 614
  /* GstFooSink -> foosinkN */
  if (strncmp (type_name, "Gst", 3) == 0)
    type_name += 3;
  tmp = g_strdup_printf ("%s%d", type_name, count);
  name = g_ascii_strdown (tmp, strlen (tmp));
  g_free (tmp);
615

616
  result = gst_object_set_name (object, name);
617
  g_free (name);
618 619

  return result;
620 621
}

622 623
/**
 * gst_object_set_name:
624 625
 * @object: a #GstObject to set the name of
 * @name:   new name of object
626
 *
627
 * Sets the name of the object, or gives the object a guaranteed unique
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
628
 * name (if @name is NULL).
629 630 631 632 633 634 635
 * This function makes a copy of the provided name, so the caller
 * retains ownership of the name it sent.
 *
 * Returns: TRUE if the name could be set. Objects that have
 * a parent cannot be renamed.
 *
 * MT safe.  This function grabs and releases the object's LOCK.
636
 */
637
gboolean
638
gst_object_set_name (GstObject * object, const gchar * name)
639
{
640
  gboolean result;
641

642 643 644
  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);

  GST_LOCK (object);
645

646 647 648 649 650 651
  /* parented objects cannot be renamed */
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;

  if (name != NULL) {
    g_free (object->name);
652
    object->name = g_strdup (name);
653 654 655 656 657 658 659 660 661 662 663 664 665 666
    GST_UNLOCK (object);
    result = TRUE;
  } else {
    GST_UNLOCK (object);
    result = gst_object_set_name_default (object, G_OBJECT_TYPE_NAME (object));
  }
  return result;

  /* error */
had_parent:
  {
    GST_UNLOCK (object);
    return FALSE;
  }
667 668 669 670
}

/**
 * gst_object_get_name:
671 672 673 674 675 676
 * @object: a #GstObject to get the name of
 *
 * Returns a copy of the name of the object.
 * Caller should g_free() the return value after usage.
 * For a nameless object, this returns NULL, which you can safely g_free()
 * as well.
677
 *
678
 * Returns: the name of the object. g_free() after usage.
679
 *
680
 * MT safe. This function grabs and releases the object's LOCK.
681
 */
682
gchar *
683
gst_object_get_name (GstObject * object)
684
{
685 686
  gchar *result = NULL;

687 688
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
  GST_LOCK (object);
  result = g_strdup (object->name);
  GST_UNLOCK (object);

  return result;
}

/**
 * gst_object_set_name_prefix:
 * @object:      a #GstObject to set the name prefix of
 * @name_prefix: new name prefix of object
 *
 * Sets the name prefix of the object.
 * This function makes a copy of the provided name prefix, so the caller
 * retains ownership of the name prefix it sent.
 *
 * MT safe.  This function grabs and releases the object's LOCK.
 */
void
gst_object_set_name_prefix (GstObject * object, const gchar * name_prefix)
{
  g_return_if_fail (GST_IS_OBJECT (object));

  GST_LOCK (object);
  g_free (object->name_prefix);
  object->name_prefix = g_strdup (name_prefix); /* NULL gives NULL */
  GST_UNLOCK (object);
}

/**
 * gst_object_get_name_prefix:
 * @object: a #GstObject to get the name prefix of
 *
 * Returns a copy of the name prefix of the object.
 * Caller should g_free() the return value after usage.
 * For a prefixless object, this returns NULL, which you can safely g_free()
 * as well.
 *
 * Returns: the name prefix of the object. g_free() after usage.
 *
729
 * MT safe. This function grabs and releases the object's LOCK.
730 731 732 733 734 735 736 737 738 739 740 741 742
 */
gchar *
gst_object_get_name_prefix (GstObject * object)
{
  gchar *result = NULL;

  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

  GST_LOCK (object);
  result = g_strdup (object->name_prefix);
  GST_UNLOCK (object);

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

/**
 * gst_object_set_parent:
 * @object: GstObject to set parent of
 * @parent: new parent of object
 *
750 751 752 753
 * Sets the parent of @object. The object's reference count will be incremented,
 * and any floating reference will be removed (see gst_object_sink()).
 *
 * Causes the parent-set signal to be emitted.
754 755 756 757 758
 *
 * Returns: TRUE if the parent could be set or FALSE when the object
 * already had a parent, the object and parent are the same or wrong
 * parameters were provided.
 *
759
 * MT safe. Grabs and releases the object's LOCK.
Erik Walthinsen's avatar
Erik Walthinsen committed
760
 */
761
gboolean
762
gst_object_set_parent (GstObject * object, GstObject * parent)
763
{
764 765 766
  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);
767

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
768
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
769 770 771 772 773 774 775 776

  GST_LOCK (object);
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;

  /* sink object, we don't call our own function because we don't
   * need to release/acquire the lock needlessly or touch the refcount
   * in the floating case. */
Erik Walthinsen's avatar
Erik Walthinsen committed
777
  object->parent = parent;
778 779 780 781 782 783 784
  if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
    GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
    GST_UNLOCK (object);
  } else {
    GST_UNLOCK (object);
    gst_object_ref (object);
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
785

786
  g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
787

788 789
  return TRUE;

790
  /* ERROR handling */
791 792 793 794 795
had_parent:
  {
    GST_UNLOCK (object);
    return FALSE;
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
796 797 798 799 800 801
}

/**
 * gst_object_get_parent:
 * @object: GstObject to get parent of
 *
802 803
 * 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
804
 *
805 806 807
 * Returns: parent of the object, this can be NULL if the object has no
 *   parent. unref after usage.
 *
808
 * MT safe. Grabs and releases the object's LOCK.
Erik Walthinsen's avatar
Erik Walthinsen committed
809
 */
810 811
GstObject *
gst_object_get_parent (GstObject * object)
812
{
813 814
  GstObject *result = NULL;

815
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
Erik Walthinsen's avatar
Erik Walthinsen committed
816

817 818 819 820 821 822 823
  GST_LOCK (object);
  result = object->parent;
  if (G_LIKELY (result))
    gst_object_ref (result);
  GST_UNLOCK (object);

  return result;
Erik Walthinsen's avatar
Erik Walthinsen committed
824 825 826 827 828 829
}

/**
 * gst_object_unparent:
 * @object: GstObject to unparent
 *
830
 * Clear the parent of @object, removing the associated reference.
831 832 833
 * This function decreases the refcount of the object so the object
 * might not point to valid memory anymore after calling this function.
 *
834
 * MT safe. Grabs and releases the object's lock.
Erik Walthinsen's avatar
Erik Walthinsen committed
835
 */
836
void
837
gst_object_unparent (GstObject * object)
838
{
839 840
  GstObject *parent;

841
  g_return_if_fail (GST_IS_OBJECT (object));
Erik Walthinsen's avatar
Erik Walthinsen committed
842

843 844
  GST_LOCK (object);
  parent = object->parent;
845

846 847 848 849
  if (G_LIKELY (parent != NULL)) {
    GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
    object->parent = NULL;
    GST_UNLOCK (object);
850

851 852 853 854 855 856 857
    g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
        parent);

    gst_object_unref (object);
  } else {
    GST_UNLOCK (object);
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
858 859
}

860
/**
861 862 863
 * gst_object_check_uniqueness:
 * @list: a list of #GstObject to check through
 * @name: the name to search for
864
 *
865 866 867 868 869
 * Checks to see if there is any object named @name in @list. This function
 * does not do any locking of any kind. You might want to protect the
 * provided list with the lock of the owner of the list. This function
 * will lock each GstObject in the list to compare the name, so be
 * carefull when passing a list with a locked object.
870
 *
871
 * Returns: TRUE if the name does not appear in the list, FALSE if it does.
872
 *
873
 * MT safe. Grabs and releases the LOCK of each object in the list.
874
 */
875
gboolean
876
gst_object_check_uniqueness (GList * list, const gchar * name)
877
{
878 879
  gboolean result = TRUE;

880
  g_return_val_if_fail (name != NULL, FALSE);
Erik Walthinsen's avatar
Erik Walthinsen committed
881

882 883 884
  for (; list; list = g_list_next (list)) {
    GstObject *child;
    gboolean eq;
885

886
    child = GST_OBJECT (list->data);
887

888 889 890
    GST_LOCK (child);
    eq = strcmp (GST_OBJECT_NAME (child), name) == 0;
    GST_UNLOCK (child);
891

892 893 894 895 896 897
    if (G_UNLIKELY (eq)) {
      result = FALSE;
      break;
    }
  }
  return result;
Erik Walthinsen's avatar
Erik Walthinsen committed
898
}
899

Erik Walthinsen's avatar
Erik Walthinsen committed
900

901
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
Wim Taymans's avatar
Wim Taymans committed
902 903 904 905 906 907 908 909 910
/**
 * gst_object_save_thyself:
 * @object: GstObject to save
 * @parent: The parent XML node to save the object into
 *
 * Saves the given object into the parent XML node.
 *
 * Returns: the new xmlNodePtr with the saved object
 */
911
xmlNodePtr
Thomas Vander Stichele's avatar