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 } |
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); |
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); |
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 */ |