<commit_before>/* GStreamer
 *
 * Copyright (C) <2005> <NAME> <ensonic at users dot sf dot net>
 * Copyright (C) 2007 <NAME> <<EMAIL>>
 *
 * gstcontroller.c: dynamic parameter control subsystem
 *
 * 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:gstcontroller
 * @short_description: dynamic parameter control subsystem
 *
 * The controller subsystem offers a lightweight way to adjust gobject
 * properties over stream-time. It works by using time-stamped value pairs that
 * are queued for element-properties. At run-time the elements continously pull
 * values changes for the current stream-time.
 *
 * What needs to be changed in a #GstElement?
 * Very little - it is just two steps to make a plugin controllable!
 * <orderedlist>
 *   <listitem><para>
 *     mark gobject-properties paramspecs that make sense to be controlled,
 *     by GST_PARAM_CONTROLLABLE.
 *   </para></listitem>
 *   <listitem><para>
 *     when processing data (get, chain, loop function) at the beginning call
 *     gst_object_sync_values(element,timestamp).
 *     This will made the controller to update all gobject properties that are under
 *     control with the current values based on timestamp.
 *   </para></listitem>
 * </orderedlist>
 *
 * What needs to be done in applications?
 * Again its not a lot to change.
 * <orderedlist>
 *   <listitem><para>
 *     first put some properties under control, by calling
 *     controller = g_object_control_properties(object, "prop1", "prop2",...);
 *   </para></listitem>
 *   <listitem><para>
 *     Get a #GstControlSource for the property and set it up.
 *     csource = gst_interpolation_control_source_new ();
 *     gst_interpolation_control_source_set_interpolation_mode(csource, mode);
 *     gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
 *     gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
 *   </para></listitem>
 *   <listitem><para>
 *     Set the #GstControlSource in the controller.
 *     gst_controller_set_control_source (controller, "prop1", csource);
 *   </para></listitem>
 *   <listitem><para>
 *     start your pipeline
 *   </para></listitem>
 * </orderedlist>
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "gstcontroller.h"
#include "gstcontrollerprivate.h"
#include "gstcontrolsource.h"
#include "gstinterpolationcontrolsource.h"

#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);

static GObjectClass *parent_class = NULL;
GQuark priv_gst_controller_key;

/* property ids */
enum
{
  PROP_CONTROL_RATE = 1
};

struct _GstControllerPrivate
{
  GstClockTime control_rate;
  GstClockTime last_sync;
};

/* helper */

static void
gst_controlled_property_add_interpolation_control_source (GstControlledProperty
    * self)
{
  GstControlSource *csource =
      GST_CONTROL_SOURCE (gst_interpolation_control_source_new ());

  GST_INFO
      ("Adding a GstInterpolationControlSource because of backward compatibility");
  g_return_if_fail (!self->csource);
  gst_control_source_bind (GST_CONTROL_SOURCE (csource), self->pspec);
  self->csource = csource;
}

/*
 * gst_controlled_property_new:
 * @object: for which object the controlled property should be set up
 * @name: the name of the property to be controlled
 *
 * Private method which initializes the fields of a new controlled property
 * structure.
 *
 * Returns: a freshly allocated structure or %NULL
 */
static GstControlledProperty *
gst_controlled_property_new (GObject * object, const gchar * name)
{
  GstControlledProperty *prop = NULL;
  GParamSpec *pspec;

  GST_INFO ("trying to put property '%s' under control", name);

  /* check if the object has a property of that name */
  if ((pspec =
          g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
    GST_DEBUG ("  psec->flags : 0x%08x", pspec->flags);

    /* check if this param is witable */
    g_return_val_if_fail ((pspec->flags & G_PARAM_WRITABLE), NULL);
    /* check if property is controlable */
    g_return_val_if_fail ((pspec->flags & GST_PARAM_CONTROLLABLE), NULL);
    /* check if this param is not construct-only */
    g_return_val_if_fail (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY), NULL);

    if ((prop = g_new0 (GstControlledProperty, 1))) {
      prop->pspec = pspec;
      prop->name = pspec->name;
      prop->disabled = FALSE;
      memset (&prop->last_value, 0, sizeof (GValue));
      g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
    }
  } else {
    GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
        name);
  }
  return prop;
}

/*
 * gst_controlled_property_free:
 * @prop: the object to free
 *
 * Private method which frees all data allocated by a #GstControlledProperty
 * instance.
 */
static void
gst_controlled_property_free (GstControlledProperty * prop)
{
  if (prop->csource)
    g_object_unref (prop->csource);
  g_value_unset (&prop->last_value);
  g_free (prop);
}

/*
 * gst_controller_find_controlled_property:
 * @self: the controller object to search for a property in
 * @name: the gobject property name to look for
 *
 * Searches the list of properties under control.
 *
 * Returns: a #GstControlledProperty object of %NULL if the property is not
 * being controlled.
 */
static GstControlledProperty *
gst_controller_find_controlled_property (GstController * self,
    const gchar * name)
{
  GstControlledProperty *prop;
  GList *node;

  for (node = self->properties; node; node = g_list_next (node)) {
    prop = node->data;
    /* FIXME: eventually use GQuark to speed it up */
    if (!strcmp (prop->name, name)) {
      return prop;
    }
  }
  GST_DEBUG ("controller does not (yet) manage property '%s'", name);

  return NULL;
}

/* methods */

/**
 * gst_controller_new_valist:
 * @object: the object of which some properties should be controlled
 * @var_args: %NULL terminated list of property names that should be controlled
 *
 * Creates a new GstController for the given object's properties
 *
 * Returns: the new controller.
 */
GstController *
gst_controller_new_valist (GObject * object, va_list var_args)
{
  GstController *self;
  GstControlledProperty *prop;
  gboolean ref_existing = TRUE;
  gchar *name;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);

  GST_INFO ("setting up a new controller");

  self = g_object_get_qdata (object, priv_gst_controller_key);
  /* create GstControlledProperty for each property */
  while ((name = va_arg (var_args, gchar *))) {
    /* test if this property isn't yet controlled */
    if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
      /* create GstControlledProperty and add to self->propeties List */
      if ((prop = gst_controlled_property_new (object, name))) {
        /* if we don't have a controller object yet, now is the time to create one */
        if (!self) {
          self = g_object_new (GST_TYPE_CONTROLLER, NULL);
          self->object = g_object_ref (object);
          /* store the controller */
          g_object_set_qdata (object, priv_gst_controller_key, self);
          ref_existing = FALSE;
        } else {
          /* only want one single _ref(), even for multiple properties */
          if (ref_existing) {
            g_object_ref (self);
            ref_existing = FALSE;
            GST_INFO ("returning existing controller");
          }
        }
        self->properties = g_list_prepend (self->properties, prop);
      }
    } else {
      GST_WARNING ("trying to control property again");
      if (ref_existing) {
        g_object_ref (self);
        ref_existing = FALSE;
      }
    }
  }
  va_end (var_args);

  if (self)
    GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
  return self;
}

/**
 * gst_controller_new_list:
 * @object: the object of which some properties should be controlled
 * @list: list of property names that should be controlled
 *
 * Creates a new GstController for the given object's properties
 *
 * Returns: the new controller.
 */
GstController *
gst_controller_new_list (GObject * object, GList * list)
{
  GstController *self;
  GstControlledProperty *prop;
  gboolean ref_existing = TRUE;
  gchar *name;
  GList *node;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);

  GST_INFO ("setting up a new controller");

  self = g_object_get_qdata (object, priv_gst_controller_key);
  /* create GstControlledProperty for each property */
  for (node = list; node; node = g_list_next (node)) {
    name = (gchar *) node->data;
    /* test if this property isn't yet controlled */
    if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
      /* create GstControlledProperty and add to self->propeties List */
      if ((prop = gst_controlled_property_new (object, name))) {
        /* if we don't have a controller object yet, now is the time to create one */
        if (!self) {
          self = g_object_new (GST_TYPE_CONTROLLER, NULL);
          self->object = g_object_ref (object);
          /* store the controller */
          g_object_set_qdata (object, priv_gst_controller_key, self);
          ref_existing = FALSE;
        } else {
          /* only want one single _ref(), even for multiple properties */
          if (ref_existing) {
            g_object_ref (self);
            ref_existing = FALSE;
            GST_INFO ("returning existing controller");
          }
        }
        self->properties = g_list_prepend (self->properties, prop);
      }
    } else {
      GST_WARNING ("trying to control property again");
      if (ref_existing) {
        g_object_ref (self);
        ref_existing = FALSE;
      }<commit_msg>controller: remove dead assignment.<commit_after>/* GStreamer
 *
 * Copyright (C) <2005> <NAME> <ensonic at users dot sf dot net>
 * Copyright (C) 2007 <NAME> <<EMAIL>>
 *
 * gstcontroller.c: dynamic parameter control subsystem
 *
 * 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:gstcontroller
 * @short_description: dynamic parameter control subsystem
 *
 * The controller subsystem offers a lightweight way to adjust gobject
 * properties over stream-time. It works by using time-stamped value pairs that
 * are queued for element-properties. At run-time the elements continously pull
 * values changes for the current stream-time.
 *
 * What needs to be changed in a #GstElement?
 * Very little - it is just two steps to make a plugin controllable!
 * <orderedlist>
 *   <listitem><para>
 *     mark gobject-properties paramspecs that make sense to be controlled,
 *     by GST_PARAM_CONTROLLABLE.
 *   </para></listitem>
 *   <listitem><para>
 *     when processing data (get, chain, loop function) at the beginning call
 *     gst_object_sync_values(element,timestamp).
 *     This will made the controller to update all gobject properties that are under
 *     control with the current values based on timestamp.
 *   </para></listitem>
 * </orderedlist>
 *
 * What needs to be done in applications?
 * Again its not a lot to change.
 * <orderedlist>
 *   <listitem><para>
 *     first put some properties under control, by calling
 *     controller = g_object_control_properties(object, "prop1", "prop2",...);
 *   </para></listitem>
 *   <listitem><para>
 *     Get a #GstControlSource for the property and set it up.
 *     csource = gst_interpolation_control_source_new ();
 *     gst_interpolation_control_source_set_interpolation_mode(csource, mode);
 *     gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
 *     gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
 *   </para></listitem>
 *   <listitem><para>
 *     Set the #GstControlSource in the controller.
 *     gst_controller_set_control_source (controller, "prop1", csource);
 *   </para></listitem>
 *   <listitem><para>
 *     start your pipeline
 *   </para></listitem>
 * </orderedlist>
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "gstcontroller.h"
#include "gstcontrollerprivate.h"
#include "gstcontrolsource.h"
#include "gstinterpolationcontrolsource.h"

#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);

static GObjectClass *parent_class = NULL;
GQuark priv_gst_controller_key;

/* property ids */
enum
{
  PROP_CONTROL_RATE = 1
};

struct _GstControllerPrivate
{
  GstClockTime control_rate;
  GstClockTime last_sync;
};

/* helper */

static void
gst_controlled_property_add_interpolation_control_source (GstControlledProperty
    * self)
{
  GstControlSource *csource =
      GST_CONTROL_SOURCE (gst_interpolation_control_source_new ());

  GST_INFO
      ("Adding a GstInterpolationControlSource because of backward compatibility");
  g_return_if_fail (!self->csource);
  gst_control_source_bind (GST_CONTROL_SOURCE (csource), self->pspec);
  self->csource = csource;
}

/*
 * gst_controlled_property_new:
 * @object: for which object the controlled property should be set up
 * @name: the name of the property to be controlled
 *
 * Private method which initializes the fields of a new controlled property
 * structure.
 *
 * Returns: a freshly allocated structure or %NULL
 */
static GstControlledProperty *
gst_controlled_property_new (GObject * object, const gchar * name)
{
  GstControlledProperty *prop = NULL;
  GParamSpec *pspec;

  GST_INFO ("trying to put property '%s' under control", name);

  /* check if the object has a property of that name */
  if ((pspec =
          g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
    GST_DEBUG ("  psec->flags : 0x%08x", pspec->flags);

    /* check if this param is witable */
    g_return_val_if_fail ((pspec->flags & G_PARAM_WRITABLE), NULL);
    /* check if property is controlable */
    g_return_val_if_fail ((pspec->flags & GST_PARAM_CONTROLLABLE), NULL);
    /* check if this param is not construct-only */
    g_return_val_if_fail (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY), NULL);

    if ((prop = g_new0 (GstControlledProperty, 1))) {
      prop->pspec = pspec;
      prop->name = pspec->name;
      prop->disabled = FALSE;
      memset (&prop->last_value, 0, sizeof (GValue));
      g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
    }
  } else {
    GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
        name);
  }
  return prop;
}

/*
 * gst_controlled_property_free:
 * @prop: the object to free
 *
 * Private method which frees all data allocated by a #GstControlledProperty
 * instance.
 */
static void
gst_controlled_property_free (GstControlledProperty * prop)
{
  if (prop->csource)
    g_object_unref (prop->csource);
  g_value_unset (&prop->last_value);
  g_free (prop);
}

/*
 * gst_controller_find_controlled_property:
 * @self: the controller object to search for a property in
 * @name: the gobject property name to look for
 *
 * Searches the list of properties under control.
 *
 * Returns: a #GstControlledProperty object of %NULL if the property is not
 * being controlled.
 */
static GstControlledProperty *
gst_controller_find_controlled_property (GstController * self,
    const gchar * name)
{
  GstControlledProperty *prop;
  GList *node;

  for (node = self->properties; node; node = g_list_next (node)) {
    prop = node->data;
    /* FIXME: eventually use GQuark to speed it up */
    if (!strcmp (prop->name, name)) {
      return prop;
    }
  }
  GST_DEBUG ("controller does not (yet) manage property '%s'", name);

  return NULL;
}

/* methods */

/**
 * gst_controller_new_valist:
 * @object: the object of which some properties should be controlled
 * @var_args: %NULL terminated list of property names that should be controlled
 *
 * Creates a new GstController for the given object's properties
 *
 * Returns: the new controller.
 */
GstController *
gst_controller_new_valist (GObject * object, va_list var_args)
{
  GstController *self;
  GstControlledProperty *prop;
  gboolean ref_existing = TRUE;
  gchar *name;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);

  GST_INFO ("setting up a new controller");

  self = g_object_get_qdata (object, priv_gst_controller_key);
  /* create GstControlledProperty for each property */
  while ((name = va_arg (var_args, gchar *))) {
    /* test if this property isn't yet controlled */
    if (!self || !gst_controller_find_controlled_property (self, name)) {
      /* create GstControlledProperty and add to self->propeties List */
      if ((prop = gst_controlled_property_new (object, name))) {
        /* if we don't have a controller object yet, now is the time to create one */
        if (!self) {
          self = g_object_new (GST_TYPE_CONTROLLER, NULL);
          self->object = g_object_ref (object);
          /* store the controller */
          g_object_set_qdata (object, priv_gst_controller_key, self);
          ref_existing = FALSE;
        } else {
          /* only want one single _ref(), even for multiple properties */
          if (ref_existing) {
            g_object_ref (self);
            ref_existing = FALSE;
            GST_INFO ("returning existing controller");
          }
        }
        self->properties = g_list_prepend (self->properties, prop);
      }
    } else {
      GST_WARNING ("trying to control property again");
      if (ref_existing) {
        g_object_ref (self);
        ref_existing = FALSE;
      }
    }
  }
  va_end (var_args);

  if (self)
    GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
  return self;
}

/**
 * gst_controller_new_list:
 * @object: the object of which some properties should be controlled
 * @list: list of property names that should be controlled
 *
 * Creates a new GstController for the given object's properties
 *
 * Returns: the new controller.
 */
GstController *
gst_controller_new_list (GObject * object, GList * list)
{
  GstController *self;
  GstControlledProperty *prop;
  gboolean ref_existing = TRUE;
  gchar *name;
  GList *node;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);

  GST_INFO ("setting up a new controller");

  self = g_object_get_qdata (object, priv_gst_controller_key);
  /* create GstControlledProperty for each property */
  for (node = list; node; node = g_list_next (node)) {
    name = (gchar *) node->data;
    /* test if this property isn't yet controlled */
    if (!self || !gst_controller_find_controlled_property (self, name)) {
      /* create GstControlledProperty and add to self->propeties List */
      if ((prop = gst_controlled_property_new (object, name))) {
        /* if we don't have a controller object yet, now is the time to create one */
        if (!self) {
          self = g_object_new (GST_TYPE_CONTROLLER, NULL);
          self->object = g_object_ref (object);
          /* store the controller */
          g_object_set_qdata (object, priv_gst_controller_key, self);
          ref_existing = FALSE;
        } else {
          /* only want one single _ref(), even for multiple properties */
          if (ref_existing) {
            g_object_ref (self);
            ref_existing = FALSE;
            GST_INFO ("returning existing controller");
          }
        }
        self->properties = g_list_prepend (self->properties, prop);
      }
    } else {
      GST_WARNING ("trying to control property again");
      if (ref_existing) {
        g_object_ref (self);
        ref_existing = FALSE;
      }
{'fraction_non_alphanumeric': 0.09873929361947839, 'fraction_numerical': 0.003560773746511404, 'mean_word_length': 3.4742734122712595, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5813162', 'n_tokens_mistral': 6403, 'n_tokens_neox': 6287, 'n_words': 1997}