gst/gstpoll.c: Fix compilation of GstPoll with mingw32. Fixes bug #526236.
[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 DEBUG_REFCOUNT
47
48 #if 0
49 static void gst_mini_object_base_init (gpointer g_class);
50 static void gst_mini_object_base_finalize (gpointer g_class);
51 #endif
52 static void gst_mini_object_class_init (gpointer g_class, gpointer class_data);
53 static void gst_mini_object_init (GTypeInstance * instance, gpointer klass);
54
55 static void gst_value_mini_object_init (GValue * value);
56 static void gst_value_mini_object_free (GValue * value);
57 static void gst_value_mini_object_copy (const GValue * src_value,
58     GValue * dest_value);
59 static gpointer gst_value_mini_object_peek_pointer (const GValue * value);
60 static gchar *gst_value_mini_object_collect (GValue * value,
61     guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
62 static gchar *gst_value_mini_object_lcopy (const GValue * value,
63     guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
64
65 static GstMiniObject *gst_mini_object_copy_default (const GstMiniObject * obj);
66 static void gst_mini_object_finalize (GstMiniObject * obj);
67
68 GType
69 gst_mini_object_get_type (void)
70 {
71   static GType _gst_mini_object_type = 0;
72
73   if (G_UNLIKELY (_gst_mini_object_type == 0)) {
74     GTypeValueTable value_table = {
75       gst_value_mini_object_init,
76       gst_value_mini_object_free,
77       gst_value_mini_object_copy,
78       gst_value_mini_object_peek_pointer,
79       "p",
80       gst_value_mini_object_collect,
81       "p",
82       gst_value_mini_object_lcopy
83     };
84     GTypeInfo mini_object_info = {
85       sizeof (GstMiniObjectClass),
86 #if 0
87       gst_mini_object_base_init,
88       gst_mini_object_base_finalize,
89 #else
90       NULL, NULL,
91 #endif
92       gst_mini_object_class_init,
93       NULL,
94       NULL,
95       sizeof (GstMiniObject),
96       0,
97       (GInstanceInitFunc) gst_mini_object_init,
98       NULL
99     };
100     static const GTypeFundamentalInfo mini_object_fundamental_info = {
101       (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
102           G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
103     };
104
105     mini_object_info.value_table = &value_table;
106
107     _gst_mini_object_type = g_type_fundamental_next ();
108     g_type_register_fundamental (_gst_mini_object_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 =
113         gst_alloc_trace_register (g_type_name (_gst_mini_object_type));
114 #endif
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
164 /**
165  * gst_mini_object_new:
166  * @type: the #GType of the mini-object to create
167  *
168  * Creates a new mini-object of the desired type.
169  *
170  * MT safe
171  *
172  * Returns: the new mini-object.
173  */
174 GstMiniObject *
175 gst_mini_object_new (GType type)
176 {
177   GstMiniObject *mini_object;
178
179   /* we don't support dynamic types because they really aren't useful,
180    * and could cause refcount problems */
181   mini_object = (GstMiniObject *) g_type_create_instance (type);
182
183 #ifndef GST_DISABLE_TRACE
184   gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
185 #endif
186
187   return mini_object;
188 }
189
190 /* FIXME 0.11: Current way of doing the copy makes it impossible
191  * to currectly chain to the parent classes and do a copy in a
192  * subclass without knowing all internals of the parent classes.
193  *
194  * For 0.11 we should do something like the following:
195  *  - The GstMiniObjectClass::copy() implementation of GstMiniObject
196  *    should call g_type_create_instance() with the type of the source
197  *    object.
198  *  - All GstMiniObjectClass::copy() implementations should as first
199  *    thing chain up to the parent class and then do whatever they need
200  *    to do to copy their type specific data. Note that this way the
201  *    instance_init() functions are called!
202  */
203
204 /**
205  * gst_mini_object_copy:
206  * @mini_object: the mini-object to copy
207  *
208  * Creates a copy of the mini-object.
209  *
210  * MT safe
211  *
212  * Returns: the new mini-object.
213  */
214 GstMiniObject *
215 gst_mini_object_copy (const GstMiniObject * mini_object)
216 {
217   GstMiniObjectClass *mo_class;
218
219   g_return_val_if_fail (mini_object != NULL, NULL);
220
221   mo_class = GST_MINI_OBJECT_GET_CLASS (mini_object);
222
223   return mo_class->copy (mini_object);
224 }
225
226 /**
227  * gst_mini_object_is_writable:
228  * @mini_object: the mini-object to check
229  *
230  * Checks if a mini-object is writable.  A mini-object is writable
231  * if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY
232  * flag is not set.  Modification of a mini-object should only be
233  * done after verifying that it is writable.
234  *
235  * MT safe
236  *
237  * Returns: TRUE if the object is writable.
238  */
239 gboolean
240 gst_mini_object_is_writable (const GstMiniObject * mini_object)
241 {
242   g_return_val_if_fail (mini_object != NULL, FALSE);
243
244   return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1) &&
245       ((mini_object->flags & GST_MINI_OBJECT_FLAG_READONLY) == 0);
246 }
247
248 /**
249  * gst_mini_object_make_writable:
250  * @mini_object: the mini-object to make writable
251  *
252  * Checks if a mini-object is writable.  If not, a writable copy is made and
253  * returned.  This gives away the reference to the original mini object,
254  * and returns a reference to the new object.
255  *
256  * MT safe
257  *
258  * Returns: a mini-object (possibly the same pointer) that is writable.
259  */
260 GstMiniObject *
261 gst_mini_object_make_writable (GstMiniObject * mini_object)
262 {
263   GstMiniObject *ret;
264
265   g_return_val_if_fail (mini_object != NULL, NULL);
266
267   if (gst_mini_object_is_writable (mini_object)) {
268     ret = (GstMiniObject *) mini_object;
269   } else {
270     ret = gst_mini_object_copy (mini_object);
271     gst_mini_object_unref ((GstMiniObject *) mini_object);
272   }
273
274   return ret;
275 }
276
277 /**
278  * gst_mini_object_ref:
279  * @mini_object: the mini-object
280  *
281  * Increase the reference count of the mini-object.
282  *
283  * Note that the refcount affects the writeability
284  * of @mini-object, see gst_mini_object_is_writable(). It is 
285  * important to note that keeping additional references to
286  * GstMiniObject instances can potentially increase the number
287  * of memcpy operations in a pipeline, especially if the miniobject
288  * is a #GstBuffer.
289  *
290  * Returns: the mini-object.
291  */
292 GstMiniObject *
293 gst_mini_object_ref (GstMiniObject * mini_object)
294 {
295   g_return_val_if_fail (mini_object != NULL, NULL);
296   /* we cannot assert that the refcount > 0 since a bufferalloc
297    * function might resurrect an object
298    g_return_val_if_fail (mini_object->refcount > 0, NULL);
299    */
300 #ifdef DEBUG_REFCOUNT
301   g_return_val_if_fail (GST_IS_MINI_OBJECT (mini_object), NULL);
302
303   GST_CAT_LOG (GST_CAT_REFCOUNTING, "%p ref %d->%d",
304       mini_object,
305       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
306       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
307 #endif
308
309   g_atomic_int_inc (&mini_object->refcount);
310
311   return mini_object;
312 }
313
314 static void
315 gst_mini_object_free (GstMiniObject * mini_object)
316 {
317   GstMiniObjectClass *mo_class;
318
319   mo_class = GST_MINI_OBJECT_GET_CLASS (mini_object);
320   mo_class->finalize (mini_object);
321
322   /* if the refcount is still 0 we can really free the
323    * object, else the finalize method recycled the object */
324   if (g_atomic_int_get (&mini_object->refcount) == 0) {
325 #ifndef GST_DISABLE_TRACE
326     gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
327 #endif
328     g_type_free_instance ((GTypeInstance *) mini_object);
329   }
330 }
331
332 /**
333  * gst_mini_object_unref:
334  * @mini_object: the mini-object
335  *
336  * Decreases the reference count of the mini-object, possibly freeing
337  * the mini-object.
338  */
339 void
340 gst_mini_object_unref (GstMiniObject * mini_object)
341 {
342   g_return_if_fail (mini_object != NULL);
343   g_return_if_fail (mini_object->refcount > 0);
344
345 #ifdef DEBUG_REFCOUNT
346   g_return_if_fail (GST_IS_MINI_OBJECT (mini_object));
347
348   GST_CAT_LOG (GST_CAT_REFCOUNTING, "%p unref %d->%d",
349       mini_object,
350       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
351       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
352 #endif
353
354   if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
355     gst_mini_object_free (mini_object);
356   }
357 }
358
359 /**
360  * gst_mini_object_replace:
361  * @olddata: pointer to a pointer to a mini-object to be replaced
362  * @newdata: pointer to new mini-object
363  *
364  * Modifies a pointer to point to a new mini-object.  The modification
365  * is done atomically, and the reference counts are updated correctly.
366  * Either @newdata and the value pointed to by @olddata may be NULL.
367  */
368 void
369 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
370 {
371   GstMiniObject *olddata_val;
372
373   g_return_if_fail (olddata != NULL);
374
375 #ifdef DEBUG_REFCOUNT
376   GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
377       *olddata, *olddata ? (*olddata)->refcount : 0,
378       newdata, newdata ? newdata->refcount : 0);
379 #endif
380
381   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
382
383   if (olddata_val == newdata)
384     return;
385
386   if (newdata)
387     gst_mini_object_ref (newdata);
388
389   while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
390           olddata_val, newdata)) {
391     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
392   }
393
394   if (olddata_val)
395     gst_mini_object_unref (olddata_val);
396 }
397
398 static void
399 gst_value_mini_object_init (GValue * value)
400 {
401   value->data[0].v_pointer = NULL;
402 }
403
404 static void
405 gst_value_mini_object_free (GValue * value)
406 {
407   if (value->data[0].v_pointer) {
408     gst_mini_object_unref (GST_MINI_OBJECT_CAST (value->data[0].v_pointer));
409   }
410 }
411
412 static void
413 gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value)
414 {
415   if (src_value->data[0].v_pointer) {
416     dest_value->data[0].v_pointer =
417         gst_mini_object_ref (GST_MINI_OBJECT_CAST (src_value->data[0].
418             v_pointer));
419   } else {
420     dest_value->data[0].v_pointer = NULL;
421   }
422 }
423
424 static gpointer
425 gst_value_mini_object_peek_pointer (const GValue * value)
426 {
427   return value->data[0].v_pointer;
428 }
429
430 static gchar *
431 gst_value_mini_object_collect (GValue * value, guint n_collect_values,
432     GTypeCValue * collect_values, guint collect_flags)
433 {
434   gst_value_set_mini_object (value, collect_values[0].v_pointer);
435
436   return NULL;
437 }
438
439 static gchar *
440 gst_value_mini_object_lcopy (const GValue * value, guint n_collect_values,
441     GTypeCValue * collect_values, guint collect_flags)
442 {
443   gpointer *mini_object_p = collect_values[0].v_pointer;
444
445   if (!mini_object_p) {
446     return g_strdup_printf ("value location for '%s' passed as NULL",
447         G_VALUE_TYPE_NAME (value));
448   }
449
450   if (!value->data[0].v_pointer)
451     *mini_object_p = NULL;
452   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
453     *mini_object_p = value->data[0].v_pointer;
454   else
455     *mini_object_p = gst_mini_object_ref (value->data[0].v_pointer);
456
457   return NULL;
458 }
459
460 /**
461  * gst_value_set_mini_object:
462  * @value:       a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
463  * @mini_object: mini object value to set
464  *
465  * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
466  * @mini_object.
467  * The caller retains ownership of the reference.
468  */
469 void
470 gst_value_set_mini_object (GValue * value, GstMiniObject * mini_object)
471 {
472   gpointer *pointer_p;
473
474   g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
475   g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
476
477   pointer_p = &value->data[0].v_pointer;
478   gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
479 }
480
481 /**
482  * gst_value_take_mini_object:
483  * @value:       a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
484  * @mini_object: mini object value to take
485  *
486  * Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
487  * @mini_object.
488  * Takes over the ownership of the caller's reference to @mini_object;
489  * the caller doesn't have to unref it any more.
490  */
491 void
492 gst_value_take_mini_object (GValue * value, GstMiniObject * mini_object)
493 {
494   gpointer *pointer_p;
495
496   g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
497   g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
498
499   pointer_p = &value->data[0].v_pointer;
500   /* takes additional refcount */
501   gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
502   /* remove additional refcount */
503   if (mini_object)
504     gst_mini_object_unref (mini_object);
505 }
506
507 /**
508  * gst_value_get_mini_object:
509  * @value:   a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
510  *
511  * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue.
512  * Does not increase the refcount of the returned object.
513  *
514  * Returns: mini object contents of @value
515  */
516 GstMiniObject *
517 gst_value_get_mini_object (const GValue * value)
518 {
519   g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
520
521   return value->data[0].v_pointer;
522 }
523
524 /**
525  * gst_value_dup_mini_object:
526  * @value:   a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
527  *
528  * Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue,
529  * increasing its reference count.
530  *
531  * Returns: mini object contents of @value
532  *
533  * Since: 0.10.19
534  */
535 GstMiniObject *
536 gst_value_dup_mini_object (const GValue * value)
537 {
538   g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
539
540   return gst_mini_object_ref (value->data[0].v_pointer);
541 }
542
543
544 /* param spec */
545
546 static void
547 param_mini_object_init (GParamSpec * pspec)
548 {
549   /* GParamSpecMiniObject *ospec = G_PARAM_SPEC_MINI_OBJECT (pspec); */
550 }
551
552 static void
553 param_mini_object_set_default (GParamSpec * pspec, GValue * value)
554 {
555   value->data[0].v_pointer = NULL;
556 }
557
558 static gboolean
559 param_mini_object_validate (GParamSpec * pspec, GValue * value)
560 {
561   GstParamSpecMiniObject *ospec = GST_PARAM_SPEC_MINI_OBJECT (pspec);
562   GstMiniObject *mini_object = value->data[0].v_pointer;
563   gboolean changed = FALSE;
564
565   if (mini_object
566       && !g_value_type_compatible (G_OBJECT_TYPE (mini_object),
567           G_PARAM_SPEC_VALUE_TYPE (ospec))) {
568     gst_mini_object_unref (mini_object);
569     value->data[0].v_pointer = NULL;
570     changed = TRUE;
571   }
572
573   return changed;
574 }
575
576 static gint
577 param_mini_object_values_cmp (GParamSpec * pspec,
578     const GValue * value1, const GValue * value2)
579 {
580   guint8 *p1 = value1->data[0].v_pointer;
581   guint8 *p2 = value2->data[0].v_pointer;
582
583   /* not much to compare here, try to at least provide stable lesser/greater result */
584
585   return p1 < p2 ? -1 : p1 > p2;
586 }
587
588 GType
589 gst_param_spec_mini_object_get_type (void)
590 {
591   static GType type;
592
593   if (G_UNLIKELY (type) == 0) {
594     static const GParamSpecTypeInfo pspec_info = {
595       sizeof (GstParamSpecMiniObject),  /* instance_size */
596       16,                       /* n_preallocs */
597       param_mini_object_init,   /* instance_init */
598       G_TYPE_OBJECT,            /* value_type */
599       NULL,                     /* finalize */
600       param_mini_object_set_default,    /* value_set_default */
601       param_mini_object_validate,       /* value_validate */
602       param_mini_object_values_cmp,     /* values_cmp */
603     };
604     /* FIXME 0.11: Should really be GstParamSpecMiniObject */
605     type = g_param_type_register_static ("GParamSpecMiniObject", &pspec_info);
606   }
607
608   return type;
609 }
610
611 /**
612  * gst_param_spec_mini_object:
613  * @name: the canonical name of the property
614  * @nick: the nickname of the property
615  * @blurb: a short description of the property
616  * @object_type: the #GstMiniObjectType for the property
617  * @flags: a combination of #GParamFlags
618  *
619  * Creates a new #GParamSpec instance that hold #GstMiniObject references.
620  *
621  * Returns: a newly allocated #GParamSpec instance
622  */
623 GParamSpec *
624 gst_param_spec_mini_object (const char *name, const char *nick,
625     const char *blurb, GType object_type, GParamFlags flags)
626 {
627   GstParamSpecMiniObject *ospec;
628
629   g_return_val_if_fail (g_type_is_a (object_type, GST_TYPE_MINI_OBJECT), NULL);
630
631   ospec = g_param_spec_internal (GST_TYPE_PARAM_MINI_OBJECT,
632       name, nick, blurb, flags);
633   G_PARAM_SPEC (ospec)->value_type = object_type;
634
635   return G_PARAM_SPEC (ospec);
636 }