2 * Copyright (C) 2005 David Schleef <ds@schleef.org>
4 * gstminiobject.h: Header for GstMiniObject
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 * SECTION:gstminiobject
23 * @short_description: Lightweight base class for the GStreamer object hierarchy
25 * #GstMiniObject is a baseclass like #GObject, but has been stripped down of
26 * features to be fast and small.
27 * It offers sub-classing and ref-counting in the same way as #GObject does.
28 * It has no properties and no signal-support though.
30 * Last reviewed on 2005-11-23 (0.9.5)
36 #include "gst/gst_private.h"
37 #include "gst/gstminiobject.h"
38 #include "gst/gstinfo.h"
39 #include <gobject/gvaluecollector.h>
41 #ifndef GST_DISABLE_TRACE
43 static GstAllocTrace *_gst_mini_object_trace;
46 #define GST_MINI_OBJECT_GET_CLASS_UNCHECKED(obj) \
47 ((GstMiniObjectClass *) (((GTypeInstance*)(obj))->g_class))
50 static void gst_mini_object_base_init (gpointer g_class);
51 static void gst_mini_object_base_finalize (gpointer g_class);
53 static void gst_mini_object_class_init (gpointer g_class, gpointer class_data);
54 static void gst_mini_object_init (GTypeInstance * instance, gpointer klass);
56 static void gst_value_mini_object_init (GValue * value);
57 static void gst_value_mini_object_free (GValue * value);
58 static void gst_value_mini_object_copy (const GValue * src_value,
60 static gpointer gst_value_mini_object_peek_pointer (const GValue * value);
61 static gchar *gst_value_mini_object_collect (GValue * value,
62 guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
63 static gchar *gst_value_mini_object_lcopy (const GValue * value,
64 guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
66 static GstMiniObject *gst_mini_object_copy_default (const GstMiniObject * obj);
67 static void gst_mini_object_finalize (GstMiniObject * obj);
70 gst_mini_object_get_type (void)
72 static volatile GType _gst_mini_object_type = 0;
74 if (g_once_init_enter (&_gst_mini_object_type)) {
76 static const GTypeValueTable value_table = {
77 gst_value_mini_object_init,
78 gst_value_mini_object_free,
79 gst_value_mini_object_copy,
80 gst_value_mini_object_peek_pointer,
82 gst_value_mini_object_collect,
84 gst_value_mini_object_lcopy
86 static const GTypeInfo mini_object_info = {
87 sizeof (GstMiniObjectClass),
89 gst_mini_object_base_init,
90 gst_mini_object_base_finalize,
94 gst_mini_object_class_init,
97 sizeof (GstMiniObject),
99 (GInstanceInitFunc) gst_mini_object_init,
102 static const GTypeFundamentalInfo mini_object_fundamental_info = {
103 (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
104 G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
107 _type = g_type_fundamental_next ();
108 g_type_register_fundamental (_type, "GstMiniObject",
109 &mini_object_info, &mini_object_fundamental_info, G_TYPE_FLAG_ABSTRACT);
111 #ifndef GST_DISABLE_TRACE
112 _gst_mini_object_trace = gst_alloc_trace_register (g_type_name (_type));
114 g_once_init_leave (&_gst_mini_object_type, _type);
117 return _gst_mini_object_type;
122 gst_mini_object_base_init (gpointer g_class)
128 gst_mini_object_base_finalize (gpointer g_class)
135 gst_mini_object_class_init (gpointer g_class, gpointer class_data)
137 GstMiniObjectClass *mo_class = GST_MINI_OBJECT_CLASS (g_class);
139 mo_class->copy = gst_mini_object_copy_default;
140 mo_class->finalize = gst_mini_object_finalize;
144 gst_mini_object_init (GTypeInstance * instance, gpointer klass)
146 GstMiniObject *mini_object = GST_MINI_OBJECT_CAST (instance);
148 mini_object->refcount = 1;
151 static GstMiniObject *
152 gst_mini_object_copy_default (const GstMiniObject * obj)
154 g_warning ("GstMiniObject classes must implement GstMiniObject::copy");
159 gst_mini_object_finalize (GstMiniObject * obj)
163 /* WARNING: if anything is ever put in this method, make sure that the
164 * following sub-classes' finalize method chains up to this one:
173 * gst_mini_object_new:
174 * @type: the #GType of the mini-object to create
176 * Creates a new mini-object of the desired type.
180 * Returns: (transfer full): the new mini-object.
183 gst_mini_object_new (GType type)
185 GstMiniObject *mini_object;
187 /* we don't support dynamic types because they really aren't useful,
188 * and could cause refcount problems */
189 mini_object = (GstMiniObject *) g_type_create_instance (type);
191 #ifndef GST_DISABLE_TRACE
192 gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
198 /* FIXME 0.11: Current way of doing the copy makes it impossible
199 * to currectly chain to the parent classes and do a copy in a
200 * subclass without knowing all internals of the parent classes.
202 * For 0.11 we should do something like the following:
203 * - The GstMiniObjectClass::copy() implementation of GstMiniObject
204 * should call g_type_create_instance() with the type of the source
206 * - All GstMiniObjectClass::copy() implementations should as first
207 * thing chain up to the parent class and then do whatever they need
208 * to do to copy their type specific data. Note that this way the
209 * instance_init() functions are called!
213 * gst_mini_object_copy:
214 * @mini_object: the mini-object to copy
216 * Creates a copy of the mini-object.
220 * Returns: (transfer full): the new mini-object.
223 gst_mini_object_copy (const GstMiniObject * mini_object)
225 GstMiniObjectClass *mo_class;
227 g_return_val_if_fail (mini_object != NULL, NULL);
229 mo_class = GST_MINI_OBJECT_GET_CLASS (mini_object);
231 return mo_class->copy (mini_object);
235 * gst_mini_object_is_writable:
236 * @mini_object: the mini-object to check
238 * Checks if a mini-object is writable. A mini-object is writable
239 * if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY
240 * flag is not set. Modification of a mini-object should only be
241 * done after verifying that it is writable.
245 * Returns: TRUE if the object is writable.
248 gst_mini_object_is_writable (const GstMiniObject * mini_object)
250 g_return_val_if_fail (mini_object != NULL, FALSE);
252 return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1) &&
253 ((mini_object->flags & GST_MINI_OBJECT_FLAG_READONLY) == 0);
257 * gst_mini_object_make_writable:
258 * @mini_object: (transfer full): the mini-object to make writable
260 * Checks if a mini-object is writable. If not, a writable copy is made and
261 * returned. This gives away the reference to the original mini object,
262 * and returns a reference to the new object.
266 * Returns: (transfer full): a mini-object (possibly the same pointer) that
270 gst_mini_object_make_writable (GstMiniObject * mini_object)
274 g_return_val_if_fail (mini_object != NULL, NULL);
276 if (gst_mini_object_is_writable (mini_object)) {
279 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject",
280 g_type_name (G_TYPE_FROM_INSTANCE (mini_object)));
281 ret = gst_mini_object_copy (mini_object);
282 gst_mini_object_unref (mini_object);
289 * gst_mini_object_ref:
290 * @mini_object: the mini-object
292 * Increase the reference count of the mini-object.
294 * Note that the refcount affects the writeability
295 * of @mini-object, see gst_mini_object_is_writable(). It is
296 * important to note that keeping additional references to
297 * GstMiniObject instances can potentially increase the number
298 * of memcpy operations in a pipeline, especially if the miniobject
301 * Returns: the mini-object.
304 gst_mini_object_ref (GstMiniObject * mini_object)
306 g_return_val_if_fail (mini_object != NULL, NULL);
307 /* we can't assert that the refcount > 0 since the _free functions
308 * increments the refcount from 0 to 1 again to allow resurecting
310 g_return_val_if_fail (mini_object->refcount > 0, NULL);
312 g_return_val_if_fail (GST_IS_MINI_OBJECT (mini_object), NULL);
314 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
315 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
316 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
318 g_atomic_int_inc (&mini_object->refcount);
324 gst_mini_object_free (GstMiniObject * mini_object)
326 GstMiniObjectClass *mo_class;
328 /* At this point, the refcount of the object is 0. We increase the refcount
329 * here because if a subclass recycles the object and gives out a new
330 * reference we don't want to free the instance anymore. */
331 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
332 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
333 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
335 g_atomic_int_inc (&mini_object->refcount);
337 mo_class = GST_MINI_OBJECT_GET_CLASS_UNCHECKED (mini_object);
338 mo_class->finalize (mini_object);
340 /* decrement the refcount again, if the subclass recycled the object we don't
341 * want to free the instance anymore */
342 if (G_LIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
343 #ifndef GST_DISABLE_TRACE
344 gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
346 g_type_free_instance ((GTypeInstance *) mini_object);
351 * gst_mini_object_unref:
352 * @mini_object: the mini-object
354 * Decreases the reference count of the mini-object, possibly freeing
358 gst_mini_object_unref (GstMiniObject * mini_object)
360 g_return_if_fail (GST_IS_MINI_OBJECT (mini_object));
361 g_return_if_fail (mini_object->refcount > 0);
363 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
365 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
366 GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
368 if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
369 gst_mini_object_free (mini_object);
374 * gst_mini_object_replace:
375 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
377 * @newdata: pointer to new mini-object
379 * Modifies a pointer to point to a new mini-object. The modification
380 * is done atomically, and the reference counts are updated correctly.
381 * Either @newdata and the value pointed to by @olddata may be NULL.
384 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
386 GstMiniObject *olddata_val;
388 g_return_if_fail (olddata != NULL);
390 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
391 *olddata, *olddata ? (*olddata)->refcount : 0,
392 newdata, newdata ? newdata->refcount : 0);
394 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
396 if (olddata_val == newdata)
400 gst_mini_object_ref (newdata);
402 while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
403 olddata_val, newdata)) {
404 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
408 gst_mini_object_unref (olddata_val);
412 gst_value_mini_object_init (GValue * value)
414 value->data[0].v_pointer = NULL;
418 gst_value_mini_object_free (GValue * value)
420 if (value->data[0].v_pointer) {
421 gst_mini_object_unref (GST_MINI_OBJECT_CAST (value->data[0].v_pointer));
426 gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value)
428 if (src_value->data[0].v_pointer) {
429 dest_value->data[0].v_pointer =
430 gst_mini_object_ref (GST_MINI_OBJECT_CAST (src_value->data[0].
433 dest_value->data[0].v_pointer = NULL;
438 gst_value_mini_object_peek_pointer (const GValue * value)
440 return value->data[0].v_pointer;
444 gst_value_mini_object_collect (GValue * value, guint n_collect_values,
445 GTypeCValue * collect_values, guint collect_flags)
447 if (collect_values[0].v_pointer) {
448 value->data[0].v_pointer =
449 gst_mini_object_ref (collect_values[0].v_pointer);
451 value->data[0].v_pointer = NULL;
458 gst_value_mini_object_lcopy (const GValue * value, guint n_collect_values,
459 GTypeCValue * collect_values, guint collect_flags)
461 gpointer *mini_object_p = collect_values[0].v_pointer;
463 if (!mini_object_p) {
464 return g_strdup_printf ("value location for '%s' passed as NULL",
465 G_VALUE_TYPE_NAME (value));
468 if (!value->data[0].v_pointer)
469 *mini_object_p = NULL;
470 else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
471 *mini_object_p = value->data[0].v_pointer;
473 *mini_object_p = gst_mini_object_ref (value->data[0].v_pointer);
479 * gst_value_set_mini_object:
480 * @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
481 * @mini_object: (transfer none): mini object value to set
483 * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
485 * The caller retains ownership of the reference.
488 gst_value_set_mini_object (GValue * value, GstMiniObject * mini_object)
492 g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
493 g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
495 pointer_p = &value->data[0].v_pointer;
496 gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
500 * gst_value_take_mini_object:
501 * @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
502 * @mini_object: (transfer full): mini object value to take
504 * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
506 * Takes over the ownership of the caller's reference to @mini_object;
507 * the caller doesn't have to unref it any more.
510 gst_value_take_mini_object (GValue * value, GstMiniObject * mini_object)
514 g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
515 g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
517 pointer_p = &value->data[0].v_pointer;
518 /* takes additional refcount */
519 gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
520 /* remove additional refcount */
522 gst_mini_object_unref (mini_object);
526 * gst_value_get_mini_object:
527 * @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
529 * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue.
530 * Does not increase the refcount of the returned object.
532 * Returns: (transfer none): mini object contents of @value
535 gst_value_get_mini_object (const GValue * value)
537 g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
539 return value->data[0].v_pointer;
543 * gst_value_dup_mini_object:
544 * @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
546 * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue,
547 * increasing its reference count.
549 * Returns: (transfer full): mini object contents of @value
554 gst_value_dup_mini_object (const GValue * value)
556 g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
558 return gst_mini_object_ref (value->data[0].v_pointer);
565 param_mini_object_init (GParamSpec * pspec)
567 /* GParamSpecMiniObject *ospec = G_PARAM_SPEC_MINI_OBJECT (pspec); */
571 param_mini_object_set_default (GParamSpec * pspec, GValue * value)
573 value->data[0].v_pointer = NULL;
577 param_mini_object_validate (GParamSpec * pspec, GValue * value)
579 GstMiniObject *mini_object = value->data[0].v_pointer;
580 gboolean changed = FALSE;
583 && !g_value_type_compatible (G_OBJECT_TYPE (mini_object),
584 pspec->value_type)) {
585 gst_mini_object_unref (mini_object);
586 value->data[0].v_pointer = NULL;
594 param_mini_object_values_cmp (GParamSpec * pspec,
595 const GValue * value1, const GValue * value2)
597 guint8 *p1 = value1->data[0].v_pointer;
598 guint8 *p2 = value2->data[0].v_pointer;
600 /* not much to compare here, try to at least provide stable lesser/greater result */
602 return p1 < p2 ? -1 : p1 > p2;
606 gst_param_spec_mini_object_get_type (void)
610 if (G_UNLIKELY (type) == 0) {
611 static const GParamSpecTypeInfo pspec_info = {
612 sizeof (GstParamSpecMiniObject), /* instance_size */
613 16, /* n_preallocs */
614 param_mini_object_init, /* instance_init */
615 G_TYPE_OBJECT, /* value_type */
617 param_mini_object_set_default, /* value_set_default */
618 param_mini_object_validate, /* value_validate */
619 param_mini_object_values_cmp, /* values_cmp */
621 /* FIXME 0.11: Should really be GstParamSpecMiniObject */
622 type = g_param_type_register_static ("GParamSpecMiniObject", &pspec_info);
629 * gst_param_spec_mini_object:
630 * @name: the canonical name of the property
631 * @nick: the nickname of the property
632 * @blurb: a short description of the property
633 * @object_type: the #GstMiniObject #GType for the property
634 * @flags: a combination of #GParamFlags
636 * Creates a new #GParamSpec instance that hold #GstMiniObject references.
638 * Returns: (transfer full): a newly allocated #GParamSpec instance
641 gst_param_spec_mini_object (const char *name, const char *nick,
642 const char *blurb, GType object_type, GParamFlags flags)
644 GstParamSpecMiniObject *ospec;
646 g_return_val_if_fail (g_type_is_a (object_type, GST_TYPE_MINI_OBJECT), NULL);
648 ospec = g_param_spec_internal (GST_TYPE_PARAM_MINI_OBJECT,
649 name, nick, blurb, flags);
650 G_PARAM_SPEC (ospec)->value_type = object_type;
652 return G_PARAM_SPEC (ospec);