/* GStreamer * Copyright (C) 2001 Steve Baker * * gstdparam_smooth.c: Realtime smoothed dynamic parameter * * 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. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "dparam_smooth.h" #include "dparammanager.h" GST_DEBUG_CATEGORY_EXTERN (_gst_control_debug); static void gst_dpsmooth_class_init (GstDParamSmoothClass * klass); static void gst_dpsmooth_init (GstDParamSmooth * dparam); static void gst_dpsmooth_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_dpsmooth_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_dpsmooth_do_update_float (GstDParam * dparam, gint64 timestamp, GValue * value, GstDParamUpdateInfo update_info); static void gst_dpsmooth_value_changed_float (GstDParam * dparam); static void gst_dpsmooth_do_update_double (GstDParam * dparam, gint64 timestamp, GValue * value, GstDParamUpdateInfo update_info); static void gst_dpsmooth_value_changed_double (GstDParam * dparam); enum { ARG_0, ARG_UPDATE_PERIOD, ARG_SLOPE_TIME, ARG_SLOPE_DELTA_FLOAT, ARG_SLOPE_DELTA_DOUBLE, ARG_SLOPE_DELTA_INT, ARG_SLOPE_DELTA_INT64, }; GType gst_dpsmooth_get_type (void) { static GType dpsmooth_type = 0; if (!dpsmooth_type) { static const GTypeInfo dpsmooth_info = { sizeof (GstDParamSmoothClass), NULL, NULL, (GClassInitFunc) gst_dpsmooth_class_init, NULL, NULL, sizeof (GstDParamSmooth), 0, (GInstanceInitFunc) gst_dpsmooth_init, }; dpsmooth_type = g_type_register_static (GST_TYPE_DPARAM, "GstDParamSmooth", &dpsmooth_info, 0); } return dpsmooth_type; } static void gst_dpsmooth_class_init (GstDParamSmoothClass * klass) { GObjectClass *gobject_class; GstDParamSmoothClass *dpsmooth_class; GstObjectClass *gstobject_class; gobject_class = (GObjectClass *) klass; dpsmooth_class = (GstDParamSmoothClass *) klass; gstobject_class = (GstObjectClass *) klass; gobject_class->get_property = gst_dpsmooth_get_property; gobject_class->set_property = gst_dpsmooth_set_property; g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_PERIOD, g_param_spec_int64 ("update_period", "Update Period (nanoseconds)", "Number of nanoseconds between updates", 0LL, G_MAXINT64, 2000000LL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLOPE_TIME, g_param_spec_int64 ("slope_time", "Slope Time (nanoseconds)", "The time period to define slope_delta by", 0LL, G_MAXINT64, 10000000LL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLOPE_DELTA_FLOAT, g_param_spec_float ("slope_delta_float", "Slope Delta float", "The amount a float value can change for a given slope_time", 0.0F, G_MAXFLOAT, 0.2F, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLOPE_DELTA_DOUBLE, g_param_spec_double ("slope_delta_double", "Slope Delta double", "The amount a double value can change for a given slope_time", 0.0, G_MAXDOUBLE, 0.2, G_PARAM_READWRITE)); /*gstobject_class->save_thyself = gst_dparam_save_thyself; */ } static void gst_dpsmooth_init (GstDParamSmooth * dpsmooth) { g_return_if_fail (dpsmooth != NULL); } /** * gst_dpsmooth_new: * @type: the type that this dparam will store * * Returns: a new instance of GstDParam */ GstDParam * gst_dpsmooth_new (GType type) { GstDParam *dparam; GstDParamSmooth *dpsmooth; dpsmooth = g_object_new (gst_dpsmooth_get_type (), NULL); dparam = GST_DPARAM (dpsmooth); GST_DPARAM_TYPE (dparam) = type; switch (type) { case G_TYPE_FLOAT:{ dparam->do_update_func = gst_dpsmooth_do_update_float; g_signal_connect (G_OBJECT (dpsmooth), "value_changed", G_CALLBACK (gst_dpsmooth_value_changed_float), NULL); break; } case G_TYPE_DOUBLE:{ dparam->do_update_func = gst_dpsmooth_do_update_double; g_signal_connect (G_OBJECT (dpsmooth), "value_changed", G_CALLBACK (gst_dpsmooth_value_changed_double), NULL); break; } default: /* we don't support this type here */ dparam->do_update_func = gst_dparam_do_update_default; break; } return dparam; } static void gst_dpsmooth_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstDParam *dparam; GstDParamSmooth *dpsmooth; g_return_if_fail (GST_IS_DPSMOOTH (object)); dpsmooth = GST_DPSMOOTH (object); dparam = GST_DPARAM (object); GST_DPARAM_LOCK (dparam); switch (prop_id) { case ARG_UPDATE_PERIOD: dpsmooth->update_period = g_value_get_int64 (value); GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE; break; case ARG_SLOPE_TIME: dpsmooth->slope_time = g_value_get_int64 (value); GST_DEBUG ("dpsmooth->slope_time:%" G_GINT64_FORMAT, dpsmooth->slope_time); GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE; break; case ARG_SLOPE_DELTA_FLOAT: dpsmooth->slope_delta_float = g_value_get_float (value); GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE; break; case ARG_SLOPE_DELTA_DOUBLE: dpsmooth->slope_delta_double = g_value_get_double (value); GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE; break; default: break; } GST_DPARAM_UNLOCK (dparam); } static void gst_dpsmooth_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDParam *dparam; GstDParamSmooth *dpsmooth; g_return_if_fail (GST_IS_DPSMOOTH (object)); dpsmooth = GST_DPSMOOTH (object); dparam = GST_DPARAM (object); switch (prop_id) { case ARG_UPDATE_PERIOD: g_value_set_int64 (value, dpsmooth->update_period); break; case ARG_SLOPE_TIME: g_value_set_int64 (value, dpsmooth->slope_time); break; case ARG_SLOPE_DELTA_FLOAT: g_value_set_float (value, dpsmooth->slope_delta_float); break; case ARG_SLOPE_DELTA_DOUBLE: g_value_set_double (value, dpsmooth->slope_delta_double); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_dpsmooth_value_changed_float (GstDParam * dparam) { GstDParamSmooth *dpsmooth; gfloat time_ratio; g_return_if_fail (GST_IS_DPSMOOTH (dparam)); dpsmooth = GST_DPSMOOTH (dparam); if (GST_DPARAM_IS_LOG (dparam)) { dparam->value_float = log (dparam->value_float); } dpsmooth->start_float = dpsmooth->current_float; dpsmooth->diff_float = dparam->value_float - dpsmooth->start_float; time_ratio = ABS (dpsmooth->diff_float) / dpsmooth->slope_delta_float; dpsmooth->duration_interp = (gint64) (time_ratio * (gfloat) dpsmooth->slope_time); dpsmooth->need_interp_times = TRUE; GST_DEBUG ("%f to %f ratio:%f duration:%" G_GINT64_FORMAT "\n", dpsmooth->start_float, dparam->value_float, time_ratio, dpsmooth->duration_interp); } static void gst_dpsmooth_do_update_float (GstDParam * dparam, gint64 timestamp, GValue * value, GstDParamUpdateInfo update_info) { gfloat time_ratio; GstDParamSmooth *dpsmooth = GST_DPSMOOTH (dparam); GST_DPARAM_LOCK (dparam); if (dpsmooth->need_interp_times) { dpsmooth->start_interp = timestamp; dpsmooth->end_interp = timestamp + dpsmooth->duration_interp; dpsmooth->need_interp_times = FALSE; } if ((update_info == GST_DPARAM_UPDATE_FIRST) || (timestamp >= dpsmooth->end_interp)) { if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_float (value, exp (dparam->value_float)); } else { g_value_set_float (value, dparam->value_float); } dpsmooth->current_float = dparam->value_float; GST_DEBUG ("interp finished at %" G_GINT64_FORMAT, timestamp); GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_READY_FOR_UPDATE (dparam) = FALSE; GST_DPARAM_UNLOCK (dparam); return; } if (timestamp <= dpsmooth->start_interp) { if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_float (value, exp (dpsmooth->start_float)); } else { g_value_set_float (value, dpsmooth->start_float); } GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->start_interp + dpsmooth->update_period; GST_DEBUG ("interp started at %" G_GINT64_FORMAT, timestamp); GST_DPARAM_UNLOCK (dparam); return; } time_ratio = (gfloat) (timestamp - dpsmooth->start_interp) / (gfloat) dpsmooth->duration_interp; GST_DEBUG ("start:%" G_GINT64_FORMAT " current:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT " ratio%f", dpsmooth->start_interp, timestamp, dpsmooth->end_interp, time_ratio); GST_DEBUG ("pre start:%f current:%f target:%f", dpsmooth->start_float, dpsmooth->current_float, dparam->value_float); dpsmooth->current_float = dpsmooth->start_float + (dpsmooth->diff_float * time_ratio); GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp + dpsmooth->update_period; if (GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) > dpsmooth->end_interp) { GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->end_interp; } GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_float (value, exp (dpsmooth->current_float)); } else { g_value_set_float (value, dpsmooth->current_float); } GST_DEBUG ("post start:%f current:%f target:%f", dpsmooth->start_float, dpsmooth->current_float, dparam->value_float); GST_DPARAM_UNLOCK (dparam); } static void gst_dpsmooth_value_changed_double (GstDParam * dparam) { GstDParamSmooth *dpsmooth; gdouble time_ratio; g_return_if_fail (GST_IS_DPSMOOTH (dparam)); dpsmooth = GST_DPSMOOTH (dparam); if (GST_DPARAM_IS_LOG (dparam)) { dparam->value_double = log (dparam->value_double); } dpsmooth->start_double = dpsmooth->current_double; dpsmooth->diff_double = dparam->value_double - dpsmooth->start_double; time_ratio = ABS (dpsmooth->diff_double) / dpsmooth->slope_delta_double; dpsmooth->duration_interp = (gint64) (time_ratio * (gdouble) dpsmooth->slope_time); dpsmooth->need_interp_times = TRUE; GST_DEBUG ("%f to %f ratio:%f duration:%" G_GINT64_FORMAT "\n", dpsmooth->start_double, dparam->value_double, time_ratio, dpsmooth->duration_interp); } static void gst_dpsmooth_do_update_double (GstDParam * dparam, gint64 timestamp, GValue * value, GstDParamUpdateInfo update_info) { gdouble time_ratio; GstDParamSmooth *dpsmooth = GST_DPSMOOTH (dparam); GST_DPARAM_LOCK (dparam); if (dpsmooth->need_interp_times) { dpsmooth->start_interp = timestamp; dpsmooth->end_interp = timestamp + dpsmooth->duration_interp; dpsmooth->need_interp_times = FALSE; } if ((update_info == GST_DPARAM_UPDATE_FIRST) || (timestamp >= dpsmooth->end_interp)) { if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_double (value, exp (dparam->value_double)); } else { g_value_set_double (value, dparam->value_double); } dpsmooth->current_double = dparam->value_double; GST_DEBUG ("interp finished at %" G_GINT64_FORMAT, timestamp); GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_READY_FOR_UPDATE (dparam) = FALSE; GST_DPARAM_UNLOCK (dparam); return; } if (timestamp <= dpsmooth->start_interp) { if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_double (value, exp (dpsmooth->start_double)); } else { g_value_set_double (value, dpsmooth->start_double); } GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->start_interp + dpsmooth->update_period; GST_DEBUG ("interp started at %" G_GINT64_FORMAT, timestamp); GST_DPARAM_UNLOCK (dparam); return; } time_ratio = (gdouble) (timestamp - dpsmooth->start_interp) / (gdouble) dpsmooth->duration_interp; GST_DEBUG ("start:%" G_GINT64_FORMAT " current:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT " ratio%f", dpsmooth->start_interp, timestamp, dpsmooth->end_interp, time_ratio); GST_DEBUG ("pre start:%f current:%f target:%f", dpsmooth->start_double, dpsmooth->current_double, dparam->value_double); dpsmooth->current_double = dpsmooth->start_double + (dpsmooth->diff_double * time_ratio); GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp + dpsmooth->update_period; if (GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) > dpsmooth->end_interp) { GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->end_interp; } GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp; if (GST_DPARAM_IS_LOG (dparam)) { g_value_set_double (value, exp (dpsmooth->current_double)); } else { g_value_set_double (value, dpsmooth->current_double); } GST_DEBUG ("post start:%f current:%f target:%f", dpsmooth->start_double, dpsmooth->current_double, dparam->value_double); GST_DPARAM_UNLOCK (dparam); }