gstobject.c 31.6 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 500 501
  parent = gst_object_get_parent (gst_object);
  while (parent) {
    /* for debugging ... */
    gchar *parent_name = gst_object_get_name (parent);
    gchar *debug_parent_name = GST_STR_NULL (parent_name);

Wim Taymans's avatar
Wim Taymans committed
502 503
    /* need own category? */
    for (i = 0; i < n_pspecs; i++) {
504 505 506 507 508 509 510 511
      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),
512
          pspecs[i]);
513 514
      PATCH_REFCOUNT (parent);
      PATCH_REFCOUNT (object);
Wim Taymans's avatar
Wim Taymans committed
515
    }
516
    g_free (parent_name);
Wim Taymans's avatar
Wim Taymans committed
517

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

/** 
 * 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
531 532
 * @excluded_props: a set of user-specified properties to exclude or
 *  NULL to show all changes.
Wim Taymans's avatar
Wim Taymans committed
533
 *
534 535 536
 * 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
537
 * using g_print.
538
 *
539 540
 * 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
541 542
 */
void
543 544
gst_object_default_deep_notify (GObject * object, GstObject * orig,
    GParamSpec * pspec, gchar ** excluded_props)
Wim Taymans's avatar
Wim Taymans committed
545
{
546
  GValue value = { 0, };        /* the important thing is that value.type = 0 */
547
  gchar *str = NULL;
548
  gchar *name = NULL;
Wim Taymans's avatar
Wim Taymans committed
549 550 551 552 553

  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)
554
        return;
Wim Taymans's avatar
Wim Taymans committed
555 556 557 558 559 560 561
      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;
562 563

      enum_value =
564 565
          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
566 567

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

584
static gboolean
585
gst_object_set_name_default (GstObject * object, const gchar * type_name)
586 587
{
  gint count;
588
  gchar *name, *tmp;
589
  gboolean result;
590

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

595 596
  if (!object_name_counts) {
    object_name_counts = g_hash_table_new_full (g_str_hash, g_str_equal,
597
        g_free, NULL);
598
  }
599 600

  count = GPOINTER_TO_INT (g_hash_table_lookup (object_name_counts, type_name));
601 602 603
  g_hash_table_insert (object_name_counts, g_strdup (type_name),
      GINT_TO_POINTER (count + 1));

604 605
  G_UNLOCK (object_name_mutex);

606 607 608 609 610 611
  /* 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);
612

613
  result = gst_object_set_name (object, name);
614
  g_free (name);
615 616

  return result;
617 618
}

619 620
/**
 * gst_object_set_name:
621 622
 * @object: a #GstObject to set the name of
 * @name:   new name of object
623
 *
624
 * Sets the name of the object, or gives the object a guaranteed unique
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
625
 * name (if @name is NULL).
626 627 628 629 630 631 632
 * 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.
633
 */
634
gboolean
635
gst_object_set_name (GstObject * object, const gchar * name)
636
{
637
  gboolean result;
638

639 640 641
  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);

  GST_LOCK (object);
642

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

  if (name != NULL) {
    g_free (object->name);
649
    object->name = g_strdup (name);
650 651 652 653 654 655 656 657 658 659 660 661 662 663
    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;
  }
664 665 666 667
}

/**
 * gst_object_get_name:
668 669 670 671 672 673
 * @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.
674
 *
675
 * Returns: the name of the object. g_free() after usage.
676
 *
677
 * MT safe. This function grabs and releases the object's LOCK.
678
 */
679
gchar *
680
gst_object_get_name (GstObject * object)
681
{
682 683
  gchar *result = NULL;

684 685
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);

686 687 688 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
  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.
 *
726
 * MT safe. This function grabs and releases the object's LOCK.
727 728 729 730 731 732 733 734 735 736 737 738 739
 */
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
740 741 742 743 744 745 746
}

/**
 * gst_object_set_parent:
 * @object: GstObject to set parent of
 * @parent: new parent of object
 *
747 748 749 750
 * 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.
751 752 753 754 755
 *
 * 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.
 *
756
 * MT safe. Grabs and releases the object's LOCK.
Erik Walthinsen's avatar
Erik Walthinsen committed
757
 */
758
gboolean
759
gst_object_set_parent (GstObject * object, GstObject * parent)
760
{
761 762 763
  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);
764

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

  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
774
  object->parent = parent;
775 776 777 778 779 780 781
  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
782

783
  g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
784

785 786
  return TRUE;

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

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

812
  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
Erik Walthinsen's avatar
Erik Walthinsen committed
813

814 815 816 817 818 819 820
  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
821 822 823 824 825 826
}

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

838
  g_return_if_fail (GST_IS_OBJECT (object));
Erik Walthinsen's avatar
Erik Walthinsen committed
839

840 841
  GST_LOCK (object);
  parent = object->parent;
842

843 844 845 846
  if (G_LIKELY (parent != NULL)) {
    GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
    object->parent = NULL;
    GST_UNLOCK (object);
847

848 849 850 851 852 853 854
    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
855 856
}

857
/**
858 859 860
 * gst_object_check_uniqueness:
 * @list: a list of #GstObject to check through
 * @name: the name to search for
861
 *
862 863 864 865 866
 * 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.
867
 *
868
 * Returns: TRUE if the name does not appear in the list, FALSE if it does.
869
 *
870
 * MT safe. Grabs and releases the LOCK of each object in the list.
871
 */
872
gboolean
873
gst_object_check_uniqueness (GList * list, const gchar * name)
874
{
875 876
  gboolean result = TRUE;

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

879 880 881
  for (; list; list = g_list_next (list)) {
    GstObject *child;
    gboolean eq;
882

883
    child = GST_OBJECT (list->data);
884

885 886 887
    GST_LOCK (child);
    eq = strcmp (GST_OBJECT_NAME (child), name) == 0;
    GST_UNLOCK (child);
888

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

Erik Walthinsen's avatar
Erik Walthinsen committed
897

898
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
Wim Taymans's avatar
Wim Taymans committed
899 900 901 902 903 904 905 906 907
/**
 * 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
 */
908
xmlNodePtr
909
gst_object_save_thyself (GstObject * object, xmlNodePtr parent)
910 911 912 913 914 915
{
  GstObjectClass *oclass;

  g_return_val_if_fail (GST_IS_OBJECT (object), parent);
  g_return_val_if_fail (parent != NULL, parent);

Wim Taymans's avatar
Wim Taymans committed
916 917
  oclass = GST_OBJECT_GET_CLASS (object);