gst: Add some more gobject-introspection annotations
[platform/upstream/gstreamer.git] / gst / gstminiobject.c
1 /* GStreamer
2  * Copyright (C) 2005 David Schleef <ds@schleef.org>
3  *
4  * gstminiobject.h: Header for GstMiniObject
5  *
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.
10  *
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.
15  *
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.
20  */
21 /**
22  * SECTION:gstminiobject
23  * @short_description: Lightweight base class for the GStreamer object hierarchy
24  *
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.
29  *
30  * Last reviewed on 2005-11-23 (0.9.5)
31  */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "gst/gst_private.h"
37 #include "gst/gstminiobject.h"
38 #include "gst/gstinfo.h"
39 #include <gobject/gvaluecollector.h>
40
41 #ifndef GST_DISABLE_TRACE
42 #include "gsttrace.h"
43 static GstAllocTrace *_gst_mini_object_trace;
44 #endif
45
46 #define GST_MINI_OBJECT_GET_CLASS_UNCHECKED(obj) \
47     ((GstMiniObjectClass *) (((GTypeInstance*)(obj))->g_class))
48
49 #if 0
50 static void gst_mini_object_base_init (gpointer g_class);
51 static void gst_mini_object_base_finalize (gpointer g_class);
52 #endif
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);
55
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,
59     GValue * dest_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);
65
66 static GstMiniObject *gst_mini_object_copy_default (const GstMiniObject * obj);
67 static void gst_mini_object_finalize (GstMiniObject * obj);
68
69 GType
70 gst_mini_object_get_type (void)
71 {
72   static volatile GType _gst_mini_object_type = 0;
73
74   if (g_once_init_enter (&_gst_mini_object_type)) {
75     GType _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,
81       (char *) "p",
82       gst_value_mini_object_collect,
83       (char *) "p",
84       gst_value_mini_object_lcopy
85     };
86     static const GTypeInfo mini_object_info = {
87       sizeof (GstMiniObjectClass),
88 #if 0
89       gst_mini_object_base_init,
90       gst_mini_object_base_finalize,
91 #else
92       NULL, NULL,
93 #endif
94       gst_mini_object_class_init,
95       NULL,
96       NULL,
97       sizeof (GstMiniObject),
98       0,
99       (GInstanceInitFunc) gst_mini_object_init,
100       &value_table
101     };
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)
105     };
106
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);
110
111 #ifndef GST_DISABLE_TRACE
112     _gst_mini_object_trace = gst_alloc_trace_register (g_type_name (_type));
113 #endif
114     g_once_init_leave (&_gst_mini_object_type, _type);
115   }
116
117   return _gst_mini_object_type;
118 }
119
120 #if 0
121 static void
122 gst_mini_object_base_init (gpointer g_class)
123 {
124   /* do nothing */
125 }
126
127 static void
128 gst_mini_object_base_finalize (gpointer g_class)
129 {
130   /* do nothing */
131 }
132 #endif
133
134 static void
135 gst_mini_object_class_init (gpointer g_class, gpointer class_data)
136 {
137   GstMiniObjectClass *mo_class = GST_MINI_OBJECT_CLASS (g_class);
138
139   mo_class->copy = gst_mini_object_copy_default;
140   mo_class->finalize = gst_mini_object_finalize;
141 }
142
143 static void
144 gst_mini_object_init (GTypeInstance * instance, gpointer klass)
145 {
146   GstMiniObject *mini_object = GST_MINI_OBJECT_CAST (instance);
147
148   mini_object->refcount = 1;
149 }
150
151 static GstMiniObject *
152 gst_mini_object_copy_default (const GstMiniObject * obj)
153 {
154   g_warning ("GstMiniObject classes must implement GstMiniObject::copy");
155   return NULL;
156 }
157
158 static void
159 gst_mini_object_finalize (GstMiniObject * obj)
160 {
161   /* do nothing */
162
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:
165    * gstbuffer
166    * gstevent
167    * gstmessage
168    * gstquery
169    */
170 }
171
172 /**
173  * gst_mini_object_new:
174  * @type: the #GType of the mini-object to create
175  *
176  * Creates a new mini-object of the desired type.
177  *
178  * MT safe
179  *
180  * Returns: (transfer full): the new mini-object.
181  */
182 GstMiniObject *
183 gst_mini_object_new (GType type)
184 {
185   GstMiniObject *mini_object;
186
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);
190
191 #ifndef GST_DISABLE_TRACE
192   gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
193 #endif
194
195   return mini_object;
196 }
197
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.
201  *
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
205  *    object.
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!
210  */
211
212 /**
213  * gst_mini_object_copy:
214  * @mini_object: the mini-object to copy
215  *
216  * Creates a copy of the mini-object.
217  *
218  * MT safe
219  *
220  * Returns: (transfer full): the new mini-object.
221  */
222 GstMiniObject *
223 gst_mini_object_copy (const GstMiniObject * mini_object)
224 {
225   GstMiniObjectClass *mo_class;
226
227   g_return_val_if_fail (mini_object != NULL, NULL);
228
229   mo_class = GST_MINI_OBJECT_GET_CLASS (mini_object);
230
231   return mo_class->copy (mini_object);
232 }
233
234 /**
235  * gst_mini_object_is_writable:
236  * @mini_object: the mini-object to check
237  *
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.
242  *
243  * MT safe
244  *
245  * Returns: TRUE if the object is writable.
246  */
247 gboolean
248 gst_mini_object_is_writable (const GstMiniObject * mini_object)
249 {
250   g_return_val_if_fail (mini_object != NULL, FALSE);
251
252   return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1) &&
253       ((mini_object->flags & GST_MINI_OBJECT_FLAG_READONLY) == 0);
254 }
255
256 /**
257  * gst_mini_object_make_writable:
258  * @mini_object: (transfer full): the mini-object to make writable
259  *
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.
263  *
264  * MT safe
265  *
266  * Returns: (transfer full): a mini-object (possibly the same pointer) that
267  *     is writable.
268  */
269 GstMiniObject *
270 gst_mini_object_make_writable (GstMiniObject * mini_object)
271 {
272   GstMiniObject *ret;
273
274   g_return_val_if_fail (mini_object != NULL, NULL);
275
276   if (gst_mini_object_is_writable (mini_object)) {
277     ret = mini_object;
278   } else {
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);
283   }
284
285   return ret;
286 }
287
288 /**
289  * gst_mini_object_ref:
290  * @mini_object: the mini-object
291  *
292  * Increase the reference count of the mini-object.
293  *
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
299  * is a #GstBuffer.
300  *
301  * Returns: (transfer full): the mini-object.
302  */
303 GstMiniObject *
304 gst_mini_object_ref (GstMiniObject * mini_object)
305 {
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
309    * the object
310    g_return_val_if_fail (mini_object->refcount > 0, NULL);
311    */
312   g_return_val_if_fail (GST_IS_MINI_OBJECT (mini_object), NULL);
313
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);
317
318   g_atomic_int_inc (&mini_object->refcount);
319
320   return mini_object;
321 }
322
323 static void
324 gst_mini_object_free (GstMiniObject * mini_object)
325 {
326   GstMiniObjectClass *mo_class;
327
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);
334
335   g_atomic_int_inc (&mini_object->refcount);
336
337   mo_class = GST_MINI_OBJECT_GET_CLASS_UNCHECKED (mini_object);
338   mo_class->finalize (mini_object);
339
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);
345 #endif
346     g_type_free_instance ((GTypeInstance *) mini_object);
347   }
348 }
349
350 /**
351  * gst_mini_object_unref:
352  * @mini_object: the mini-object
353  *
354  * Decreases the reference count of the mini-object, possibly freeing
355  * the mini-object.
356  */
357 void
358 gst_mini_object_unref (GstMiniObject * mini_object)
359 {
360   g_return_if_fail (GST_IS_MINI_OBJECT (mini_object));
361   g_return_if_fail (mini_object->refcount > 0);
362
363   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
364       mini_object,
365       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
366       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
367
368   if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
369     gst_mini_object_free (mini_object);
370   }
371 }
372
373 /**
374  * gst_mini_object_replace:
375  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
376  *     be replaced
377  * @newdata: pointer to new mini-object
378  *
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.
382  */
383 void
384 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
385 {
386   GstMiniObject *olddata_val;
387
388   g_return_if_fail (olddata != NULL);
389
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);
393
394   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
395
396   if (olddata_val == newdata)
397     return;
398
399   if (newdata)
400     gst_mini_object_ref (newdata);
401
402   while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
403           olddata_val, newdata)) {
404     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
405   }
406
407   if (olddata_val)
408     gst_mini_object_unref (olddata_val);
409 }
410
411 static void
412 gst_value_mini_object_init (GValue * value)
413 {
414   value->data[0].v_pointer = NULL;
415 }
416
417 static void
418 gst_value_mini_object_free (GValue * value)
419 {
420   if (value->data[0].v_pointer) {
421     gst_mini_object_unref (GST_MINI_OBJECT_CAST (value->data[0].v_pointer));
422   }
423 }
424
425 static void
426 gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value)
427 {
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].
431             v_pointer));
432   } else {
433     dest_value->data[0].v_pointer = NULL;
434   }
435 }
436
437 static gpointer
438 gst_value_mini_object_peek_pointer (const GValue * value)
439 {
440   return value->data[0].v_pointer;
441 }
442
443 static gchar *
444 gst_value_mini_object_collect (GValue * value, guint n_collect_values,
445     GTypeCValue * collect_values, guint collect_flags)
446 {
447   if (collect_values[0].v_pointer) {
448     value->data[0].v_pointer =
449         gst_mini_object_ref (collect_values[0].v_pointer);
450   } else {
451     value->data[0].v_pointer = NULL;
452   }
453
454   return NULL;
455 }
456
457 static gchar *
458 gst_value_mini_object_lcopy (const GValue * value, guint n_collect_values,
459     GTypeCValue * collect_values, guint collect_flags)
460 {
461   gpointer *mini_object_p = collect_values[0].v_pointer;
462
463   if (!mini_object_p) {
464     return g_strdup_printf ("value location for '%s' passed as NULL",
465         G_VALUE_TYPE_NAME (value));
466   }
467
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;
472   else
473     *mini_object_p = gst_mini_object_ref (value->data[0].v_pointer);
474
475   return NULL;
476 }
477
478 /**
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
482  *
483  * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
484  * @mini_object.
485  * The caller retains ownership of the reference.
486  */
487 void
488 gst_value_set_mini_object (GValue * value, GstMiniObject * mini_object)
489 {
490   gpointer *pointer_p;
491
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));
494
495   pointer_p = &value->data[0].v_pointer;
496   gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
497 }
498
499 /**
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
503  *
504  * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
505  * @mini_object.
506  * Takes over the ownership of the caller's reference to @mini_object;
507  * the caller doesn't have to unref it any more.
508  */
509 void
510 gst_value_take_mini_object (GValue * value, GstMiniObject * mini_object)
511 {
512   gpointer *pointer_p;
513
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));
516
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 */
521   if (mini_object)
522     gst_mini_object_unref (mini_object);
523 }
524
525 /**
526  * gst_value_get_mini_object:
527  * @value:   a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
528  *
529  * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue.
530  * Does not increase the refcount of the returned object.
531  *
532  * Returns: (transfer none): mini object contents of @value
533  */
534 GstMiniObject *
535 gst_value_get_mini_object (const GValue * value)
536 {
537   g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
538
539   return value->data[0].v_pointer;
540 }
541
542 /**
543  * gst_value_dup_mini_object:
544  * @value:   a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
545  *
546  * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue,
547  * increasing its reference count.
548  *
549  * Returns: (transfer full): mini object contents of @value
550  *
551  * Since: 0.10.20
552  */
553 GstMiniObject *
554 gst_value_dup_mini_object (const GValue * value)
555 {
556   g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
557
558   return gst_mini_object_ref (value->data[0].v_pointer);
559 }
560
561
562 /* param spec */
563
564 static void
565 param_mini_object_init (GParamSpec * pspec)
566 {
567   /* GParamSpecMiniObject *ospec = G_PARAM_SPEC_MINI_OBJECT (pspec); */
568 }
569
570 static void
571 param_mini_object_set_default (GParamSpec * pspec, GValue * value)
572 {
573   value->data[0].v_pointer = NULL;
574 }
575
576 static gboolean
577 param_mini_object_validate (GParamSpec * pspec, GValue * value)
578 {
579   GstMiniObject *mini_object = value->data[0].v_pointer;
580   gboolean changed = FALSE;
581
582   if (mini_object
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;
587     changed = TRUE;
588   }
589
590   return changed;
591 }
592
593 static gint
594 param_mini_object_values_cmp (GParamSpec * pspec,
595     const GValue * value1, const GValue * value2)
596 {
597   guint8 *p1 = value1->data[0].v_pointer;
598   guint8 *p2 = value2->data[0].v_pointer;
599
600   /* not much to compare here, try to at least provide stable lesser/greater result */
601
602   return p1 < p2 ? -1 : p1 > p2;
603 }
604
605 GType
606 gst_param_spec_mini_object_get_type (void)
607 {
608   static GType type;
609
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 */
616       NULL,                     /* finalize */
617       param_mini_object_set_default,    /* value_set_default */
618       param_mini_object_validate,       /* value_validate */
619       param_mini_object_values_cmp,     /* values_cmp */
620     };
621     /* FIXME 0.11: Should really be GstParamSpecMiniObject */
622     type = g_param_type_register_static ("GParamSpecMiniObject", &pspec_info);
623   }
624
625   return type;
626 }
627
628 /**
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
635  *
636  * Creates a new #GParamSpec instance that hold #GstMiniObject references.
637  *
638  * Returns: (transfer full): a newly allocated #GParamSpec instance
639  */
640 GParamSpec *
641 gst_param_spec_mini_object (const char *name, const char *nick,
642     const char *blurb, GType object_type, GParamFlags flags)
643 {
644   GstParamSpecMiniObject *ospec;
645
646   g_return_val_if_fail (g_type_is_a (object_type, GST_TYPE_MINI_OBJECT), NULL);
647
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;
651
652   return G_PARAM_SPEC (ospec);
653 }