mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-29 15:22:17 +00:00
cf671d7b0a
API: gst_mini_object_weak_ref() API: gst_mini_object_weak_unref() Add weak referencing functionality to GstMiniObject, which allows to get notifications when an mini object is destroyed but doesn't increase the real refcount. This is mostly useful for bindings. Fixes bug #609473.
798 lines
23 KiB
C
798 lines
23 KiB
C
/* GStreamer
|
|
* Copyright (C) 2005 David Schleef <ds@schleef.org>
|
|
*
|
|
* gstminiobject.h: Header for GstMiniObject
|
|
*
|
|
* 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.
|
|
*/
|
|
/**
|
|
* SECTION:gstminiobject
|
|
* @short_description: Lightweight base class for the GStreamer object hierarchy
|
|
*
|
|
* #GstMiniObject is a baseclass like #GObject, but has been stripped down of
|
|
* features to be fast and small.
|
|
* It offers sub-classing and ref-counting in the same way as #GObject does.
|
|
* It has no properties and no signal-support though.
|
|
*
|
|
* Last reviewed on 2005-11-23 (0.9.5)
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gst/gst_private.h"
|
|
#include "gst/gstminiobject.h"
|
|
#include "gst/gstinfo.h"
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
#ifndef GST_DISABLE_TRACE
|
|
#include "gsttrace.h"
|
|
static GstAllocTrace *_gst_mini_object_trace;
|
|
#endif
|
|
|
|
#define GST_MINI_OBJECT_GET_CLASS_UNCHECKED(obj) \
|
|
((GstMiniObjectClass *) (((GTypeInstance*)(obj))->g_class))
|
|
|
|
/* Structure used for storing weak references */
|
|
typedef struct
|
|
{
|
|
GstMiniObject *object;
|
|
guint n_weak_refs;
|
|
struct
|
|
{
|
|
GstMiniObjectWeakNotify notify;
|
|
gpointer data;
|
|
} weak_refs[1]; /* flexible array */
|
|
} WeakRefStack;
|
|
|
|
/* Structure for storing a mini object's private data */
|
|
struct _GstMiniObjectPrivateData
|
|
{
|
|
WeakRefStack *wstack;
|
|
};
|
|
|
|
#if 0
|
|
static void gst_mini_object_base_init (gpointer g_class);
|
|
static void gst_mini_object_base_finalize (gpointer g_class);
|
|
#endif
|
|
static void gst_mini_object_class_init (gpointer g_class, gpointer class_data);
|
|
static void gst_mini_object_init (GTypeInstance * instance, gpointer klass);
|
|
|
|
static void gst_value_mini_object_init (GValue * value);
|
|
static void gst_value_mini_object_free (GValue * value);
|
|
static void weak_refs_notify (WeakRefStack * data);
|
|
static void gst_value_mini_object_copy (const GValue * src_value,
|
|
GValue * dest_value);
|
|
static gpointer gst_value_mini_object_peek_pointer (const GValue * value);
|
|
static gchar *gst_value_mini_object_collect (GValue * value,
|
|
guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
|
|
static gchar *gst_value_mini_object_lcopy (const GValue * value,
|
|
guint n_collect_values, GTypeCValue * collect_values, guint collect_flags);
|
|
|
|
static GstMiniObject *gst_mini_object_copy_default (const GstMiniObject * obj);
|
|
static void gst_mini_object_finalize (GstMiniObject * obj);
|
|
|
|
/* Mutex used for weak referencing */
|
|
G_LOCK_DEFINE_STATIC (weak_refs_mutex);
|
|
|
|
GType
|
|
gst_mini_object_get_type (void)
|
|
{
|
|
static volatile GType _gst_mini_object_type = 0;
|
|
|
|
if (g_once_init_enter (&_gst_mini_object_type)) {
|
|
GType _type;
|
|
static const GTypeValueTable value_table = {
|
|
gst_value_mini_object_init,
|
|
gst_value_mini_object_free,
|
|
gst_value_mini_object_copy,
|
|
gst_value_mini_object_peek_pointer,
|
|
(char *) "p",
|
|
gst_value_mini_object_collect,
|
|
(char *) "p",
|
|
gst_value_mini_object_lcopy
|
|
};
|
|
static const GTypeInfo mini_object_info = {
|
|
sizeof (GstMiniObjectClass),
|
|
#if 0
|
|
gst_mini_object_base_init,
|
|
gst_mini_object_base_finalize,
|
|
#else
|
|
NULL, NULL,
|
|
#endif
|
|
gst_mini_object_class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstMiniObject),
|
|
0,
|
|
(GInstanceInitFunc) gst_mini_object_init,
|
|
&value_table
|
|
};
|
|
static const GTypeFundamentalInfo mini_object_fundamental_info = {
|
|
(G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
|
|
G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
|
|
};
|
|
|
|
_type = g_type_fundamental_next ();
|
|
g_type_register_fundamental (_type, "GstMiniObject",
|
|
&mini_object_info, &mini_object_fundamental_info, G_TYPE_FLAG_ABSTRACT);
|
|
|
|
#ifndef GST_DISABLE_TRACE
|
|
_gst_mini_object_trace = gst_alloc_trace_register (g_type_name (_type));
|
|
#endif
|
|
g_once_init_leave (&_gst_mini_object_type, _type);
|
|
}
|
|
|
|
return _gst_mini_object_type;
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
gst_mini_object_base_init (gpointer g_class)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
|
|
static void
|
|
gst_mini_object_base_finalize (gpointer g_class)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
gst_mini_object_class_init (gpointer g_class, gpointer class_data)
|
|
{
|
|
GstMiniObjectClass *mo_class = GST_MINI_OBJECT_CLASS (g_class);
|
|
|
|
mo_class->copy = gst_mini_object_copy_default;
|
|
mo_class->finalize = gst_mini_object_finalize;
|
|
|
|
/* Set the instance data type */
|
|
g_type_class_add_private (g_class, sizeof (GstMiniObjectPrivateData));
|
|
}
|
|
|
|
static void
|
|
gst_mini_object_init (GTypeInstance * instance, gpointer klass)
|
|
{
|
|
GstMiniObject *mini_object = GST_MINI_OBJECT_CAST (instance);
|
|
|
|
mini_object->refcount = 1;
|
|
|
|
/* Initialize the mini object's private data */
|
|
|
|
mini_object->priv = (GstMiniObjectPrivateData *)
|
|
G_TYPE_INSTANCE_GET_PRIVATE (instance, GST_TYPE_MINI_OBJECT,
|
|
GstMiniObjectPrivateData);
|
|
|
|
mini_object->priv->wstack = NULL;
|
|
}
|
|
|
|
static GstMiniObject *
|
|
gst_mini_object_copy_default (const GstMiniObject * obj)
|
|
{
|
|
g_warning ("GstMiniObject classes must implement GstMiniObject::copy");
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gst_mini_object_finalize (GstMiniObject * obj)
|
|
{
|
|
/* do nothing */
|
|
|
|
/* WARNING: if anything is ever put in this method, make sure that the
|
|
* following sub-classes' finalize method chains up to this one:
|
|
* gstbuffer
|
|
* gstevent
|
|
* gstmessage
|
|
* gstquery
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_new:
|
|
* @type: the #GType of the mini-object to create
|
|
*
|
|
* Creates a new mini-object of the desired type.
|
|
*
|
|
* MT safe
|
|
*
|
|
* Returns: (transfer full): the new mini-object.
|
|
*/
|
|
GstMiniObject *
|
|
gst_mini_object_new (GType type)
|
|
{
|
|
GstMiniObject *mini_object;
|
|
|
|
/* we don't support dynamic types because they really aren't useful,
|
|
* and could cause refcount problems */
|
|
mini_object = (GstMiniObject *) g_type_create_instance (type);
|
|
|
|
#ifndef GST_DISABLE_TRACE
|
|
gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
|
|
#endif
|
|
|
|
return mini_object;
|
|
}
|
|
|
|
/* FIXME 0.11: Current way of doing the copy makes it impossible
|
|
* to currectly chain to the parent classes and do a copy in a
|
|
* subclass without knowing all internals of the parent classes.
|
|
*
|
|
* For 0.11 we should do something like the following:
|
|
* - The GstMiniObjectClass::copy() implementation of GstMiniObject
|
|
* should call g_type_create_instance() with the type of the source
|
|
* object.
|
|
* - All GstMiniObjectClass::copy() implementations should as first
|
|
* thing chain up to the parent class and then do whatever they need
|
|
* to do to copy their type specific data. Note that this way the
|
|
* instance_init() functions are called!
|
|
*/
|
|
|
|
/**
|
|
* gst_mini_object_copy:
|
|
* @mini_object: the mini-object to copy
|
|
*
|
|
* Creates a copy of the mini-object.
|
|
*
|
|
* MT safe
|
|
*
|
|
* Returns: (transfer full): the new mini-object.
|
|
*/
|
|
GstMiniObject *
|
|
gst_mini_object_copy (const GstMiniObject * mini_object)
|
|
{
|
|
GstMiniObjectClass *mo_class;
|
|
|
|
g_return_val_if_fail (mini_object != NULL, NULL);
|
|
|
|
mo_class = GST_MINI_OBJECT_GET_CLASS (mini_object);
|
|
|
|
return mo_class->copy (mini_object);
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_is_writable:
|
|
* @mini_object: the mini-object to check
|
|
*
|
|
* Checks if a mini-object is writable. A mini-object is writable
|
|
* if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY
|
|
* flag is not set. Modification of a mini-object should only be
|
|
* done after verifying that it is writable.
|
|
*
|
|
* MT safe
|
|
*
|
|
* Returns: TRUE if the object is writable.
|
|
*/
|
|
gboolean
|
|
gst_mini_object_is_writable (const GstMiniObject * mini_object)
|
|
{
|
|
g_return_val_if_fail (mini_object != NULL, FALSE);
|
|
|
|
return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1) &&
|
|
((mini_object->flags & GST_MINI_OBJECT_FLAG_READONLY) == 0);
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_make_writable:
|
|
* @mini_object: (transfer full): the mini-object to make writable
|
|
*
|
|
* Checks if a mini-object is writable. If not, a writable copy is made and
|
|
* returned. This gives away the reference to the original mini object,
|
|
* and returns a reference to the new object.
|
|
*
|
|
* MT safe
|
|
*
|
|
* Returns: (transfer full): a mini-object (possibly the same pointer) that
|
|
* is writable.
|
|
*/
|
|
GstMiniObject *
|
|
gst_mini_object_make_writable (GstMiniObject * mini_object)
|
|
{
|
|
GstMiniObject *ret;
|
|
|
|
g_return_val_if_fail (mini_object != NULL, NULL);
|
|
|
|
if (gst_mini_object_is_writable (mini_object)) {
|
|
ret = mini_object;
|
|
} else {
|
|
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (mini_object)));
|
|
ret = gst_mini_object_copy (mini_object);
|
|
gst_mini_object_unref (mini_object);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_ref:
|
|
* @mini_object: the mini-object
|
|
*
|
|
* Increase the reference count of the mini-object.
|
|
*
|
|
* Note that the refcount affects the writeability
|
|
* of @mini-object, see gst_mini_object_is_writable(). It is
|
|
* important to note that keeping additional references to
|
|
* GstMiniObject instances can potentially increase the number
|
|
* of memcpy operations in a pipeline, especially if the miniobject
|
|
* is a #GstBuffer.
|
|
*
|
|
* Returns: (transfer full): the mini-object.
|
|
*/
|
|
GstMiniObject *
|
|
gst_mini_object_ref (GstMiniObject * mini_object)
|
|
{
|
|
g_return_val_if_fail (mini_object != NULL, NULL);
|
|
/* we can't assert that the refcount > 0 since the _free functions
|
|
* increments the refcount from 0 to 1 again to allow resurecting
|
|
* the object
|
|
g_return_val_if_fail (mini_object->refcount > 0, NULL);
|
|
*/
|
|
g_return_val_if_fail (GST_IS_MINI_OBJECT (mini_object), NULL);
|
|
|
|
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
|
|
|
|
g_atomic_int_inc (&mini_object->refcount);
|
|
|
|
return mini_object;
|
|
}
|
|
|
|
static void
|
|
weak_refs_notify (WeakRefStack * wstack)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < wstack->n_weak_refs; i++)
|
|
wstack->weak_refs[i].notify (wstack->weak_refs[i].data, wstack->object);
|
|
g_free (wstack);
|
|
}
|
|
|
|
static void
|
|
gst_mini_object_free (GstMiniObject * mini_object)
|
|
{
|
|
GstMiniObjectClass *mo_class;
|
|
|
|
/* At this point, the refcount of the object is 0. We increase the refcount
|
|
* here because if a subclass recycles the object and gives out a new
|
|
* reference we don't want to free the instance anymore. */
|
|
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
|
|
|
|
g_atomic_int_inc (&mini_object->refcount);
|
|
|
|
mo_class = GST_MINI_OBJECT_GET_CLASS_UNCHECKED (mini_object);
|
|
mo_class->finalize (mini_object);
|
|
|
|
/* decrement the refcount again, if the subclass recycled the object we don't
|
|
* want to free the instance anymore */
|
|
if (G_LIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
|
|
/* The weak reference stack is freed in the notification function */
|
|
if (mini_object->priv->wstack)
|
|
weak_refs_notify (mini_object->priv->wstack);
|
|
|
|
#ifndef GST_DISABLE_TRACE
|
|
gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
|
|
#endif
|
|
g_type_free_instance ((GTypeInstance *) mini_object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_unref:
|
|
* @mini_object: the mini-object
|
|
*
|
|
* Decreases the reference count of the mini-object, possibly freeing
|
|
* the mini-object.
|
|
*/
|
|
void
|
|
gst_mini_object_unref (GstMiniObject * mini_object)
|
|
{
|
|
g_return_if_fail (GST_IS_MINI_OBJECT (mini_object));
|
|
g_return_if_fail (mini_object->refcount > 0);
|
|
|
|
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
|
|
mini_object,
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
|
|
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
|
|
|
|
if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
|
|
gst_mini_object_free (mini_object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_weak_ref: (skip)
|
|
* @mini_object: #GstMiniObject to reference weakly
|
|
* @notify: callback to invoke before the mini object is freed
|
|
* @data: extra data to pass to notify
|
|
*
|
|
* Adds a weak reference callback to a mini object. Weak references are
|
|
* used for notification when a mini object is finalized. They are called
|
|
* "weak references" because they allow you to safely hold a pointer
|
|
* to the mini object without calling gst_mini_object_ref()
|
|
* (gst_mini_object_ref() adds a strong reference, that is, forces the object
|
|
* to stay alive).
|
|
*
|
|
* Since: 0.10.34
|
|
*/
|
|
void
|
|
gst_mini_object_weak_ref (GstMiniObject * object,
|
|
GstMiniObjectWeakNotify notify, gpointer data)
|
|
{
|
|
guint i;
|
|
|
|
g_return_if_fail (GST_IS_MINI_OBJECT (object));
|
|
g_return_if_fail (notify != NULL);
|
|
g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
|
|
|
|
G_LOCK (weak_refs_mutex);
|
|
|
|
if (object->priv->wstack) {
|
|
/* Don't add the weak reference if it already exists. */
|
|
for (i = 0; i < object->priv->wstack->n_weak_refs; i++) {
|
|
if (object->priv->wstack->weak_refs[i].notify == notify &&
|
|
object->priv->wstack->weak_refs[i].data == data) {
|
|
g_warning ("%s: Attempt to re-add existing weak ref %p(%p) failed.",
|
|
G_STRFUNC, notify, data);
|
|
goto found;
|
|
}
|
|
}
|
|
|
|
i = object->priv->wstack->n_weak_refs++;
|
|
object->priv->wstack =
|
|
g_realloc (object->priv->wstack, sizeof (*(object->priv->wstack)) +
|
|
sizeof (object->priv->wstack->weak_refs[0]) * i);
|
|
} else {
|
|
object->priv->wstack = g_renew (WeakRefStack, NULL, 1);
|
|
object->priv->wstack->object = object;
|
|
object->priv->wstack->n_weak_refs = 1;
|
|
i = 0;
|
|
}
|
|
object->priv->wstack->weak_refs[i].notify = notify;
|
|
object->priv->wstack->weak_refs[i].data = data;
|
|
found:
|
|
G_UNLOCK (weak_refs_mutex);
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_weak_unref: (skip)
|
|
* @mini_object: #GstMiniObject to remove a weak reference from
|
|
* @notify: callback to search for
|
|
* @data: data to search for
|
|
*
|
|
* Removes a weak reference callback to a mini object.
|
|
*
|
|
* Since: 0.10.34
|
|
*/
|
|
void
|
|
gst_mini_object_weak_unref (GstMiniObject * object,
|
|
GstMiniObjectWeakNotify notify, gpointer data)
|
|
{
|
|
gboolean found_one = FALSE;
|
|
|
|
g_return_if_fail (GST_IS_MINI_OBJECT (object));
|
|
g_return_if_fail (notify != NULL);
|
|
|
|
G_LOCK (weak_refs_mutex);
|
|
|
|
if (object->priv->wstack) {
|
|
guint i;
|
|
|
|
for (i = 0; i < object->priv->wstack->n_weak_refs; i++)
|
|
if (object->priv->wstack->weak_refs[i].notify == notify &&
|
|
object->priv->wstack->weak_refs[i].data == data) {
|
|
found_one = TRUE;
|
|
object->priv->wstack->n_weak_refs -= 1;
|
|
if (i != object->priv->wstack->n_weak_refs)
|
|
object->priv->wstack->weak_refs[i] =
|
|
object->priv->wstack->weak_refs[object->priv->wstack->
|
|
n_weak_refs];
|
|
|
|
break;
|
|
}
|
|
}
|
|
G_UNLOCK (weak_refs_mutex);
|
|
if (!found_one)
|
|
g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data);
|
|
}
|
|
|
|
/**
|
|
* gst_mini_object_replace:
|
|
* @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
|
|
* be replaced
|
|
* @newdata: pointer to new mini-object
|
|
*
|
|
* Modifies a pointer to point to a new mini-object. The modification
|
|
* is done atomically, and the reference counts are updated correctly.
|
|
* Either @newdata and the value pointed to by @olddata may be NULL.
|
|
*/
|
|
void
|
|
gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
|
|
{
|
|
GstMiniObject *olddata_val;
|
|
|
|
g_return_if_fail (olddata != NULL);
|
|
|
|
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
|
|
*olddata, *olddata ? (*olddata)->refcount : 0,
|
|
newdata, newdata ? newdata->refcount : 0);
|
|
|
|
olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
|
|
|
|
if (olddata_val == newdata)
|
|
return;
|
|
|
|
if (newdata)
|
|
gst_mini_object_ref (newdata);
|
|
|
|
while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
|
|
olddata_val, newdata)) {
|
|
olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
|
|
}
|
|
|
|
if (olddata_val)
|
|
gst_mini_object_unref (olddata_val);
|
|
}
|
|
|
|
static void
|
|
gst_value_mini_object_init (GValue * value)
|
|
{
|
|
value->data[0].v_pointer = NULL;
|
|
}
|
|
|
|
static void
|
|
gst_value_mini_object_free (GValue * value)
|
|
{
|
|
if (value->data[0].v_pointer) {
|
|
gst_mini_object_unref (GST_MINI_OBJECT_CAST (value->data[0].v_pointer));
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value)
|
|
{
|
|
if (src_value->data[0].v_pointer) {
|
|
dest_value->data[0].v_pointer =
|
|
gst_mini_object_ref (GST_MINI_OBJECT_CAST (src_value->data[0].
|
|
v_pointer));
|
|
} else {
|
|
dest_value->data[0].v_pointer = NULL;
|
|
}
|
|
}
|
|
|
|
static gpointer
|
|
gst_value_mini_object_peek_pointer (const GValue * value)
|
|
{
|
|
return value->data[0].v_pointer;
|
|
}
|
|
|
|
static gchar *
|
|
gst_value_mini_object_collect (GValue * value, guint n_collect_values,
|
|
GTypeCValue * collect_values, guint collect_flags)
|
|
{
|
|
if (collect_values[0].v_pointer) {
|
|
value->data[0].v_pointer =
|
|
gst_mini_object_ref (collect_values[0].v_pointer);
|
|
} else {
|
|
value->data[0].v_pointer = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gchar *
|
|
gst_value_mini_object_lcopy (const GValue * value, guint n_collect_values,
|
|
GTypeCValue * collect_values, guint collect_flags)
|
|
{
|
|
gpointer *mini_object_p = collect_values[0].v_pointer;
|
|
|
|
if (!mini_object_p) {
|
|
return g_strdup_printf ("value location for '%s' passed as NULL",
|
|
G_VALUE_TYPE_NAME (value));
|
|
}
|
|
|
|
if (!value->data[0].v_pointer)
|
|
*mini_object_p = NULL;
|
|
else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
|
|
*mini_object_p = value->data[0].v_pointer;
|
|
else
|
|
*mini_object_p = gst_mini_object_ref (value->data[0].v_pointer);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gst_value_set_mini_object:
|
|
* @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
|
|
* @mini_object: (transfer none): mini object value to set
|
|
*
|
|
* Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
|
|
* @mini_object.
|
|
* The caller retains ownership of the reference.
|
|
*/
|
|
void
|
|
gst_value_set_mini_object (GValue * value, GstMiniObject * mini_object)
|
|
{
|
|
gpointer *pointer_p;
|
|
|
|
g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
|
|
g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
|
|
|
|
pointer_p = &value->data[0].v_pointer;
|
|
gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
|
|
}
|
|
|
|
/**
|
|
* gst_value_take_mini_object:
|
|
* @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
|
|
* @mini_object: (transfer full): mini object value to take
|
|
*
|
|
* Set the contents of a %GST_TYPE_MINI_OBJECT derived #GValue to
|
|
* @mini_object.
|
|
* Takes over the ownership of the caller's reference to @mini_object;
|
|
* the caller doesn't have to unref it any more.
|
|
*/
|
|
void
|
|
gst_value_take_mini_object (GValue * value, GstMiniObject * mini_object)
|
|
{
|
|
gpointer *pointer_p;
|
|
|
|
g_return_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value));
|
|
g_return_if_fail (mini_object == NULL || GST_IS_MINI_OBJECT (mini_object));
|
|
|
|
pointer_p = &value->data[0].v_pointer;
|
|
/* takes additional refcount */
|
|
gst_mini_object_replace ((GstMiniObject **) pointer_p, mini_object);
|
|
/* remove additional refcount */
|
|
if (mini_object)
|
|
gst_mini_object_unref (mini_object);
|
|
}
|
|
|
|
/**
|
|
* gst_value_get_mini_object:
|
|
* @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
|
|
*
|
|
* Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue.
|
|
* Does not increase the refcount of the returned object.
|
|
*
|
|
* Returns: (transfer none): mini object contents of @value
|
|
*/
|
|
GstMiniObject *
|
|
gst_value_get_mini_object (const GValue * value)
|
|
{
|
|
g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
|
|
|
|
return value->data[0].v_pointer;
|
|
}
|
|
|
|
/**
|
|
* gst_value_dup_mini_object:
|
|
* @value: a valid #GValue of %GST_TYPE_MINI_OBJECT derived type
|
|
*
|
|
* Get the contents of a %GST_TYPE_MINI_OBJECT derived #GValue,
|
|
* increasing its reference count. If the contents of the #GValue
|
|
* are %NULL, %NULL will be returned.
|
|
*
|
|
* Returns: (transfer full): mini object contents of @value
|
|
*
|
|
* Since: 0.10.20
|
|
*/
|
|
GstMiniObject *
|
|
gst_value_dup_mini_object (const GValue * value)
|
|
{
|
|
g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL);
|
|
|
|
return value->data[0].v_pointer ? gst_mini_object_ref (value->
|
|
data[0].v_pointer) : NULL;
|
|
}
|
|
|
|
|
|
/* param spec */
|
|
|
|
static void
|
|
param_mini_object_init (GParamSpec * pspec)
|
|
{
|
|
/* GParamSpecMiniObject *ospec = G_PARAM_SPEC_MINI_OBJECT (pspec); */
|
|
}
|
|
|
|
static void
|
|
param_mini_object_set_default (GParamSpec * pspec, GValue * value)
|
|
{
|
|
value->data[0].v_pointer = NULL;
|
|
}
|
|
|
|
static gboolean
|
|
param_mini_object_validate (GParamSpec * pspec, GValue * value)
|
|
{
|
|
GstMiniObject *mini_object = value->data[0].v_pointer;
|
|
gboolean changed = FALSE;
|
|
|
|
if (mini_object
|
|
&& !g_value_type_compatible (G_OBJECT_TYPE (mini_object),
|
|
pspec->value_type)) {
|
|
gst_mini_object_unref (mini_object);
|
|
value->data[0].v_pointer = NULL;
|
|
changed = TRUE;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
static gint
|
|
param_mini_object_values_cmp (GParamSpec * pspec,
|
|
const GValue * value1, const GValue * value2)
|
|
{
|
|
guint8 *p1 = value1->data[0].v_pointer;
|
|
guint8 *p2 = value2->data[0].v_pointer;
|
|
|
|
/* not much to compare here, try to at least provide stable lesser/greater result */
|
|
|
|
return p1 < p2 ? -1 : p1 > p2;
|
|
}
|
|
|
|
GType
|
|
gst_param_spec_mini_object_get_type (void)
|
|
{
|
|
static GType type;
|
|
|
|
if (G_UNLIKELY (type) == 0) {
|
|
static const GParamSpecTypeInfo pspec_info = {
|
|
sizeof (GstParamSpecMiniObject), /* instance_size */
|
|
16, /* n_preallocs */
|
|
param_mini_object_init, /* instance_init */
|
|
G_TYPE_OBJECT, /* value_type */
|
|
NULL, /* finalize */
|
|
param_mini_object_set_default, /* value_set_default */
|
|
param_mini_object_validate, /* value_validate */
|
|
param_mini_object_values_cmp, /* values_cmp */
|
|
};
|
|
/* FIXME 0.11: Should really be GstParamSpecMiniObject */
|
|
type = g_param_type_register_static ("GParamSpecMiniObject", &pspec_info);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
/**
|
|
* gst_param_spec_mini_object:
|
|
* @name: the canonical name of the property
|
|
* @nick: the nickname of the property
|
|
* @blurb: a short description of the property
|
|
* @object_type: the #GstMiniObject #GType for the property
|
|
* @flags: a combination of #GParamFlags
|
|
*
|
|
* Creates a new #GParamSpec instance that hold #GstMiniObject references.
|
|
*
|
|
* Returns: (transfer full): a newly allocated #GParamSpec instance
|
|
*/
|
|
GParamSpec *
|
|
gst_param_spec_mini_object (const char *name, const char *nick,
|
|
const char *blurb, GType object_type, GParamFlags flags)
|
|
{
|
|
GstParamSpecMiniObject *ospec;
|
|
|
|
g_return_val_if_fail (g_type_is_a (object_type, GST_TYPE_MINI_OBJECT), NULL);
|
|
|
|
ospec = g_param_spec_internal (GST_TYPE_PARAM_MINI_OBJECT,
|
|
name, nick, blurb, flags);
|
|
G_PARAM_SPEC (ospec)->value_type = object_type;
|
|
|
|
return G_PARAM_SPEC (ospec);
|
|
}
|