gstreamer_core/libs/gst/controller/gstcontroller.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
    79 #include "gstinterpolationcontrolsource.h"
    79 #include "gstinterpolationcontrolsource.h"
    80 
    80 
    81 #ifdef __SYMBIAN32__
    81 #ifdef __SYMBIAN32__
    82 #include <glib_global.h>
    82 #include <glib_global.h>
    83 #include <gobject_global.h>
    83 #include <gobject_global.h>
       
    84 
    84 #endif
    85 #endif
    85 #define GST_CAT_DEFAULT controller_debug
    86 #define GST_CAT_DEFAULT controller_debug
    86 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
    87 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
    87 
    88 
    88 static GObjectClass *parent_class = NULL;
    89 static GObjectClass *parent_class = NULL;
   148 
   149 
   149     if ((prop = g_new0 (GstControlledProperty, 1))) {
   150     if ((prop = g_new0 (GstControlledProperty, 1))) {
   150       prop->pspec = pspec;
   151       prop->pspec = pspec;
   151       prop->name = pspec->name;
   152       prop->name = pspec->name;
   152       prop->disabled = FALSE;
   153       prop->disabled = FALSE;
   153       memset (&prop->last_value, 0, sizeof (GValue));
       
   154       g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
       
   155     }
   154     }
   156   } else {
   155   } else {
   157     GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
   156     GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
   158         name);
   157         name);
   159   }
   158   }
   170 static void
   169 static void
   171 gst_controlled_property_free (GstControlledProperty * prop)
   170 gst_controlled_property_free (GstControlledProperty * prop)
   172 {
   171 {
   173   if (prop->csource)
   172   if (prop->csource)
   174     g_object_unref (prop->csource);
   173     g_object_unref (prop->csource);
   175   g_value_unset (&prop->last_value);
       
   176   g_free (prop);
   174   g_free (prop);
   177 }
   175 }
   178 
   176 
   179 /*
   177 /*
   180  * gst_controller_find_controlled_property:
   178  * gst_controller_find_controlled_property:
   203   GST_DEBUG ("controller does not (yet) manage property '%s'", name);
   201   GST_DEBUG ("controller does not (yet) manage property '%s'", name);
   204 
   202 
   205   return NULL;
   203   return NULL;
   206 }
   204 }
   207 
   205 
   208 /*
       
   209  * gst_controller_add_property:
       
   210  * @self: the controller object or %NULL if none yet exists
       
   211  * @object: object to bind the property
       
   212  * @name: name of projecty in @object
       
   213  * @ref_existing: pointer to flag that tracks if we need to ref an existng
       
   214  *   controller still
       
   215  *
       
   216  * Creates a new #GstControlledProperty if there is none for property @name yet.
       
   217  * In case this is the first controlled propery, it creates the controller as
       
   218  * well.
       
   219  *
       
   220  * Returns: a newly created controller object or reffed existing one with the
       
   221  * given property bound.
       
   222  */
       
   223 static GstController *
       
   224 gst_controller_add_property (GstController * self, GObject * object,
       
   225     gchar * name, gboolean * ref_existing)
       
   226 {
       
   227   /* test if this property isn't yet controlled */
       
   228   if (!self || !gst_controller_find_controlled_property (self, name)) {
       
   229     GstControlledProperty *prop;
       
   230 
       
   231     /* create GstControlledProperty and add to self->propeties List */
       
   232     if ((prop = gst_controlled_property_new (object, name))) {
       
   233       /* if we don't have a controller object yet, now is the time to create one */
       
   234       if (!self) {
       
   235         self = g_object_new (GST_TYPE_CONTROLLER, NULL);
       
   236         self->object = g_object_ref (object);
       
   237         /* store the controller */
       
   238         g_object_set_qdata (object, priv_gst_controller_key, self);
       
   239         *ref_existing = FALSE;
       
   240       } else {
       
   241         /* only want one single _ref(), even for multiple properties */
       
   242         if (*ref_existing) {
       
   243           g_object_ref (self);
       
   244           *ref_existing = FALSE;
       
   245           GST_INFO ("returning existing controller");
       
   246         }
       
   247       }
       
   248       self->properties = g_list_prepend (self->properties, prop);
       
   249     }
       
   250   } else {
       
   251     GST_WARNING ("trying to control property again");
       
   252     if (*ref_existing) {
       
   253       g_object_ref (self);
       
   254       *ref_existing = FALSE;
       
   255     }
       
   256   }
       
   257   return self;
       
   258 }
       
   259 
       
   260 /* methods */
   206 /* methods */
   261 
   207 
   262 /**
   208 /**
   263  * gst_controller_new_valist:
   209  * gst_controller_new_valist:
   264  * @object: the object of which some properties should be controlled
   210  * @object: the object of which some properties should be controlled
   274 
   220 
   275 GstController *
   221 GstController *
   276 gst_controller_new_valist (GObject * object, va_list var_args)
   222 gst_controller_new_valist (GObject * object, va_list var_args)
   277 {
   223 {
   278   GstController *self;
   224   GstController *self;
       
   225   GstControlledProperty *prop;
   279   gboolean ref_existing = TRUE;
   226   gboolean ref_existing = TRUE;
   280   gchar *name;
   227   gchar *name;
   281 
   228 
   282   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
   229   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
   283 
   230 
   284   GST_INFO ("setting up a new controller");
   231   GST_INFO ("setting up a new controller");
   285 
   232 
   286   self = g_object_get_qdata (object, priv_gst_controller_key);
   233   self = g_object_get_qdata (object, priv_gst_controller_key);
   287   /* create GstControlledProperty for each property */
   234   /* create GstControlledProperty for each property */
   288   while ((name = va_arg (var_args, gchar *))) {
   235   while ((name = va_arg (var_args, gchar *))) {
   289     self = gst_controller_add_property (self, object, name, &ref_existing);
   236     /* test if this property isn't yet controlled */
       
   237     if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
       
   238       /* create GstControlledProperty and add to self->propeties List */
       
   239       if ((prop = gst_controlled_property_new (object, name))) {
       
   240         /* if we don't have a controller object yet, now is the time to create one */
       
   241         if (!self) {
       
   242           self = g_object_new (GST_TYPE_CONTROLLER, NULL);
       
   243           self->object = g_object_ref (object);
       
   244           /* store the controller */
       
   245           g_object_set_qdata (object, priv_gst_controller_key, self);
       
   246           ref_existing = FALSE;
       
   247         } else {
       
   248           /* only want one single _ref(), even for multiple properties */
       
   249           if (ref_existing) {
       
   250             g_object_ref (self);
       
   251             ref_existing = FALSE;
       
   252             GST_INFO ("returning existing controller");
       
   253           }
       
   254         }
       
   255         self->properties = g_list_prepend (self->properties, prop);
       
   256       }
       
   257     } else {
       
   258       GST_WARNING ("trying to control property again");
       
   259       if (ref_existing) {
       
   260         g_object_ref (self);
       
   261         ref_existing = FALSE;
       
   262       }
       
   263     }
   290   }
   264   }
   291   va_end (var_args);
   265   va_end (var_args);
   292 
   266 
   293   if (self)
   267   if (self)
   294     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
   268     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
   310 
   284 
   311 GstController *
   285 GstController *
   312 gst_controller_new_list (GObject * object, GList * list)
   286 gst_controller_new_list (GObject * object, GList * list)
   313 {
   287 {
   314   GstController *self;
   288   GstController *self;
       
   289   GstControlledProperty *prop;
   315   gboolean ref_existing = TRUE;
   290   gboolean ref_existing = TRUE;
   316   gchar *name;
   291   gchar *name;
   317   GList *node;
   292   GList *node;
   318 
   293 
   319   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
   294   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
   322 
   297 
   323   self = g_object_get_qdata (object, priv_gst_controller_key);
   298   self = g_object_get_qdata (object, priv_gst_controller_key);
   324   /* create GstControlledProperty for each property */
   299   /* create GstControlledProperty for each property */
   325   for (node = list; node; node = g_list_next (node)) {
   300   for (node = list; node; node = g_list_next (node)) {
   326     name = (gchar *) node->data;
   301     name = (gchar *) node->data;
   327     self = gst_controller_add_property (self, object, name, &ref_existing);
   302     /* test if this property isn't yet controlled */
       
   303     if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
       
   304       /* create GstControlledProperty and add to self->propeties List */
       
   305       if ((prop = gst_controlled_property_new (object, name))) {
       
   306         /* if we don't have a controller object yet, now is the time to create one */
       
   307         if (!self) {
       
   308           self = g_object_new (GST_TYPE_CONTROLLER, NULL);
       
   309           self->object = g_object_ref (object);
       
   310           /* store the controller */
       
   311           g_object_set_qdata (object, priv_gst_controller_key, self);
       
   312           ref_existing = FALSE;
       
   313         } else {
       
   314           /* only want one single _ref(), even for multiple properties */
       
   315           if (ref_existing) {
       
   316             g_object_ref (self);
       
   317             ref_existing = FALSE;
       
   318             GST_INFO ("returning existing controller");
       
   319           }
       
   320         }
       
   321         self->properties = g_list_prepend (self->properties, prop);
       
   322       }
       
   323     } else {
       
   324       GST_WARNING ("trying to control property again");
       
   325       if (ref_existing) {
       
   326         g_object_ref (self);
       
   327         ref_existing = FALSE;
       
   328       }
       
   329     }
   328   }
   330   }
   329 
   331 
   330   if (self)
   332   if (self)
   331     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
   333     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
   332   return self;
   334   return self;
   600 gst_controller_get_control_source (GstController * self, gchar * property_name)
   602 gst_controller_get_control_source (GstController * self, gchar * property_name)
   601 {
   603 {
   602   GstControlledProperty *prop;
   604   GstControlledProperty *prop;
   603   GstControlSource *ret = NULL;
   605   GstControlSource *ret = NULL;
   604 
   606 
   605   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
       
   606   g_return_val_if_fail (property_name, NULL);
       
   607 
       
   608   g_mutex_lock (self->lock);
   607   g_mutex_lock (self->lock);
   609   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
   608   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
   610     ret = prop->csource;
   609     ret = prop->csource;
   611   }
   610   }
   612   g_mutex_unlock (self->lock);
   611   g_mutex_unlock (self->lock);
   624  * @timestamp: the time the control-change should be read from
   623  * @timestamp: the time the control-change should be read from
   625  *
   624  *
   626  * Gets the value for the given controller-handled property at the requested
   625  * Gets the value for the given controller-handled property at the requested
   627  * time.
   626  * time.
   628  *
   627  *
   629  * Returns: the GValue of the property at the given time, or %NULL if the
   628  * Returns: the GValue of the property at the given time, or %NULL if the property isn't handled by the controller
   630  * property isn't handled by the controller
       
   631  */
   629  */
   632 #ifdef __SYMBIAN32__
   630 #ifdef __SYMBIAN32__
   633 EXPORT_C
   631 EXPORT_C
   634 #endif
   632 #endif
   635 
   633 
   692       GST_CLOCK_TIME_NONE);
   690       GST_CLOCK_TIME_NONE);
   693 
   691 
   694   g_mutex_lock (self->lock);
   692   g_mutex_lock (self->lock);
   695 
   693 
   696   /* TODO: Implement more logic, depending on interpolation mode
   694   /* TODO: Implement more logic, depending on interpolation mode
   697    * and control points
   695    * and control points */
   698    * FIXME: we need playback direction
       
   699    */
       
   700   ret = self->priv->last_sync + self->priv->control_rate;
   696   ret = self->priv->last_sync + self->priv->control_rate;
   701 
   697 
   702   g_mutex_unlock (self->lock);
   698   g_mutex_unlock (self->lock);
   703 
   699 
   704   return ret;
   700   return ret;
   710  * @timestamp: the time that should be processed
   706  * @timestamp: the time that should be processed
   711  *
   707  *
   712  * Sets the properties of the element, according to the controller that (maybe)
   708  * Sets the properties of the element, according to the controller that (maybe)
   713  * handles them and for the given timestamp.
   709  * handles them and for the given timestamp.
   714  *
   710  *
   715  * If this function fails, it is most likely the application developers fault.
       
   716  * Most probably the control sources are not setup correctly.
       
   717  *
       
   718  * Returns: %TRUE if the controller values could be applied to the object
   711  * Returns: %TRUE if the controller values could be applied to the object
   719  * properties, %FALSE otherwise
   712  * properties, %FALSE otherwise
   720  */
   713  */
   721 #ifdef __SYMBIAN32__
   714 #ifdef __SYMBIAN32__
   722 EXPORT_C
   715 EXPORT_C
   725 gboolean
   718 gboolean
   726 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
   719 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
   727 {
   720 {
   728   GstControlledProperty *prop;
   721   GstControlledProperty *prop;
   729   GList *node;
   722   GList *node;
   730   gboolean ret = TRUE, val_ret;
   723   gboolean ret = FALSE;
   731   GValue value = { 0, };
       
   732 
   724 
   733   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
   725   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
   734   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
   726   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
   735 
   727 
   736   GST_LOG ("sync_values");
   728   GST_LOG ("sync_values");
   737 
   729 
   738   g_mutex_lock (self->lock);
   730   g_mutex_lock (self->lock);
   739   g_object_freeze_notify (self->object);
       
   740   /* go over the controlled properties of the controller */
   731   /* go over the controlled properties of the controller */
   741   for (node = self->properties; node; node = g_list_next (node)) {
   732   for (node = self->properties; node; node = g_list_next (node)) {
       
   733     GValue value = { 0, };
   742     prop = node->data;
   734     prop = node->data;
       
   735 
       
   736     GST_DEBUG ("  property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
       
   737         timestamp);
   743 
   738 
   744     if (!prop->csource || prop->disabled)
   739     if (!prop->csource || prop->disabled)
   745       continue;
   740       continue;
   746 
   741 
   747     GST_LOG ("property '%s' at ts=%" G_GUINT64_FORMAT, prop->name, timestamp);
       
   748 
       
   749     /* we can make this faster
       
   750      * http://bugzilla.gnome.org/show_bug.cgi?id=536939
       
   751      */
       
   752     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
   742     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
   753     val_ret = gst_control_source_get_value (prop->csource, timestamp, &value);
   743     ret = gst_control_source_get_value (prop->csource, timestamp, &value);
   754     if (G_LIKELY (val_ret)) {
   744     if (ret) {
   755       /* always set the value for first time, but then only if it changed
   745       g_object_set_property (self->object, prop->name, &value);
   756        * this should limit g_object_notify invocations.
   746       g_value_unset (&value);
   757        * FIXME: can we detect negative playback rates?
       
   758        */
       
   759       if ((timestamp < self->priv->last_sync) ||
       
   760           gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
       
   761         g_object_set_property (self->object, prop->name, &value);
       
   762         g_value_copy (&value, &prop->last_value);
       
   763       }
       
   764     } else {
       
   765       GST_DEBUG ("no control value for param %s", prop->name);
       
   766     }
   747     }
   767     g_value_unset (&value);
       
   768     ret &= val_ret;
       
   769   }
   748   }
   770   self->priv->last_sync = timestamp;
   749   self->priv->last_sync = timestamp;
   771   g_object_thaw_notify (self->object);
       
   772 
   750 
   773   g_mutex_unlock (self->lock);
   751   g_mutex_unlock (self->lock);
   774 
   752 
   775   return ret;
   753   return ret;
   776 }
   754 }
  1002   /* register properties */
   980   /* register properties */
  1003   g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
   981   g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
  1004       g_param_spec_uint64 ("control-rate",
   982       g_param_spec_uint64 ("control-rate",
  1005           "control rate",
   983           "control rate",
  1006           "Controlled properties will be updated at least every control-rate nanoseconds",
   984           "Controlled properties will be updated at least every control-rate nanoseconds",
  1007           1, G_MAXUINT, 100 * GST_MSECOND,
   985           1, G_MAXUINT, 100 * GST_MSECOND, G_PARAM_READWRITE));
  1008           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
  1009 
   986 
  1010   /* register signals */
   987   /* register signals */
  1011   /* set defaults for overridable methods */
   988   /* set defaults for overridable methods */
  1012 }
   989 }
  1013 #ifdef __SYMBIAN32__
   990 #ifdef __SYMBIAN32__
  1016 
   993 
  1017 
   994 
  1018 GType
   995 GType
  1019 gst_controller_get_type (void)
   996 gst_controller_get_type (void)
  1020 {
   997 {
  1021   static volatile gsize type = 0;
   998   static GType type = 0;
  1022 
   999 
  1023   if (g_once_init_enter (&type)) {
  1000   if (type == 0) {
  1024     GType _type;
       
  1025     static const GTypeInfo info = {
  1001     static const GTypeInfo info = {
  1026       sizeof (GstControllerClass),
  1002       sizeof (GstControllerClass),
  1027       NULL,                     /* base_init */
  1003       NULL,                     /* base_init */
  1028       NULL,                     /* base_finalize */
  1004       NULL,                     /* base_finalize */
  1029       (GClassInitFunc) _gst_controller_class_init,      /* class_init */
  1005       (GClassInitFunc) _gst_controller_class_init,      /* class_init */
  1032       sizeof (GstController),
  1008       sizeof (GstController),
  1033       0,                        /* n_preallocs */
  1009       0,                        /* n_preallocs */
  1034       (GInstanceInitFunc) _gst_controller_init, /* instance_init */
  1010       (GInstanceInitFunc) _gst_controller_init, /* instance_init */
  1035       NULL                      /* value_table */
  1011       NULL                      /* value_table */
  1036     };
  1012     };
  1037     _type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
  1013     type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
  1038     g_once_init_leave (&type, _type);
       
  1039   }
  1014   }
  1040   return type;
  1015   return type;
  1041 }
  1016 }
  1042 
  1017 
  1043 /* FIXME: backward compatibility functions */
  1018 /* FIXME: backward compatibility functions */