1 /* GStreamer
2 * Copyright (C) 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
3 *
4 * gstdparam_smooth.c: Realtime smoothed dynamic parameter
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <math.h>
27 #include <string.h>
28 #include <gst/gstinfo.h>
30 #include "dparam_smooth.h"
31 #include "dparammanager.h"
33 GST_DEBUG_CATEGORY_EXTERN (_gst_control_debug);
35 static void gst_dpsmooth_class_init (GstDParamSmoothClass * klass);
36 static void gst_dpsmooth_init (GstDParamSmooth * dparam);
37 static void gst_dpsmooth_set_property (GObject * object, guint prop_id,
38 const GValue * value, GParamSpec * pspec);
39 static void gst_dpsmooth_get_property (GObject * object, guint prop_id,
40 GValue * value, GParamSpec * pspec);
41 static void gst_dpsmooth_do_update_float (GstDParam * dparam, gint64 timestamp,
42 GValue * value, GstDParamUpdateInfo update_info);
43 static void gst_dpsmooth_value_changed_float (GstDParam * dparam);
44 static void gst_dpsmooth_do_update_double (GstDParam * dparam, gint64 timestamp,
45 GValue * value, GstDParamUpdateInfo update_info);
46 static void gst_dpsmooth_value_changed_double (GstDParam * dparam);
48 enum
49 {
50 ARG_0,
51 ARG_UPDATE_PERIOD,
52 ARG_SLOPE_TIME,
53 ARG_SLOPE_DELTA_FLOAT,
54 ARG_SLOPE_DELTA_DOUBLE,
55 ARG_SLOPE_DELTA_INT,
56 ARG_SLOPE_DELTA_INT64,
57 };
59 GType
60 gst_dpsmooth_get_type (void)
61 {
62 static GType dpsmooth_type = 0;
64 if (!dpsmooth_type) {
65 static const GTypeInfo dpsmooth_info = {
66 sizeof (GstDParamSmoothClass),
67 NULL,
68 NULL,
69 (GClassInitFunc) gst_dpsmooth_class_init,
70 NULL,
71 NULL,
72 sizeof (GstDParamSmooth),
73 0,
74 (GInstanceInitFunc) gst_dpsmooth_init,
75 };
77 dpsmooth_type =
78 g_type_register_static (GST_TYPE_DPARAM, "GstDParamSmooth",
79 &dpsmooth_info, 0);
80 }
81 return dpsmooth_type;
82 }
84 static void
85 gst_dpsmooth_class_init (GstDParamSmoothClass * klass)
86 {
87 GObjectClass *gobject_class;
88 GstDParamSmoothClass *dpsmooth_class;
89 GstObjectClass *gstobject_class;
91 gobject_class = (GObjectClass *) klass;
92 dpsmooth_class = (GstDParamSmoothClass *) klass;
93 gstobject_class = (GstObjectClass *) klass;
95 gobject_class->get_property = gst_dpsmooth_get_property;
96 gobject_class->set_property = gst_dpsmooth_set_property;
98 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_PERIOD,
99 g_param_spec_int64 ("update_period",
100 "Update Period (nanoseconds)",
101 "Number of nanoseconds between updates",
102 0LL, G_MAXINT64, 2000000LL, G_PARAM_READWRITE));
104 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLOPE_TIME,
105 g_param_spec_int64 ("slope_time",
106 "Slope Time (nanoseconds)",
107 "The time period to define slope_delta by",
108 0LL, G_MAXINT64, 10000000LL, G_PARAM_READWRITE));
110 g_object_class_install_property (G_OBJECT_CLASS (klass),
111 ARG_SLOPE_DELTA_FLOAT,
112 g_param_spec_float ("slope_delta_float", "Slope Delta float",
113 "The amount a float value can change for a given slope_time",
114 0.0F, G_MAXFLOAT, 0.2F, G_PARAM_READWRITE));
116 g_object_class_install_property (G_OBJECT_CLASS (klass),
117 ARG_SLOPE_DELTA_DOUBLE,
118 g_param_spec_double ("slope_delta_double", "Slope Delta double",
119 "The amount a double value can change for a given slope_time",
120 0.0, G_MAXDOUBLE, 0.2, G_PARAM_READWRITE));
122 /*gstobject_class->save_thyself = gst_dparam_save_thyself; */
124 }
126 static void
127 gst_dpsmooth_init (GstDParamSmooth * dpsmooth)
128 {
129 g_return_if_fail (dpsmooth != NULL);
130 }
132 /**
133 * gst_dpsmooth_new:
134 * @type: the type that this dparam will store
135 *
136 * Returns: a new instance of GstDParam
137 */
138 GstDParam *
139 gst_dpsmooth_new (GType type)
140 {
141 GstDParam *dparam;
142 GstDParamSmooth *dpsmooth;
144 dpsmooth = g_object_new (gst_dpsmooth_get_type (), NULL);
145 dparam = GST_DPARAM (dpsmooth);
147 GST_DPARAM_TYPE (dparam) = type;
149 switch (type) {
150 case G_TYPE_FLOAT:{
151 dparam->do_update_func = gst_dpsmooth_do_update_float;
152 g_signal_connect (G_OBJECT (dpsmooth), "value_changed",
153 G_CALLBACK (gst_dpsmooth_value_changed_float), NULL);
154 break;
155 }
156 case G_TYPE_DOUBLE:{
157 dparam->do_update_func = gst_dpsmooth_do_update_double;
158 g_signal_connect (G_OBJECT (dpsmooth), "value_changed",
159 G_CALLBACK (gst_dpsmooth_value_changed_double), NULL);
160 break;
161 }
162 default:
163 /* we don't support this type here */
164 dparam->do_update_func = gst_dparam_do_update_default;
165 break;
166 }
167 return dparam;
168 }
170 static void
171 gst_dpsmooth_set_property (GObject * object, guint prop_id,
172 const GValue * value, GParamSpec * pspec)
173 {
174 GstDParam *dparam;
175 GstDParamSmooth *dpsmooth;
177 g_return_if_fail (GST_IS_DPSMOOTH (object));
179 dpsmooth = GST_DPSMOOTH (object);
180 dparam = GST_DPARAM (object);
182 GST_DPARAM_LOCK (dparam);
184 switch (prop_id) {
185 case ARG_UPDATE_PERIOD:
186 dpsmooth->update_period = g_value_get_int64 (value);
187 GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE;
188 break;
190 case ARG_SLOPE_TIME:
191 dpsmooth->slope_time = g_value_get_int64 (value);
192 GST_DEBUG ("dpsmooth->slope_time:%"
193 G_GINT64_FORMAT, dpsmooth->slope_time);
194 GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE;
195 break;
197 case ARG_SLOPE_DELTA_FLOAT:
198 dpsmooth->slope_delta_float = g_value_get_float (value);
199 GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE;
200 break;
202 case ARG_SLOPE_DELTA_DOUBLE:
203 dpsmooth->slope_delta_double = g_value_get_double (value);
204 GST_DPARAM_READY_FOR_UPDATE (dparam) = TRUE;
205 break;
207 default:
208 break;
209 }
210 GST_DPARAM_UNLOCK (dparam);
211 }
213 static void
214 gst_dpsmooth_get_property (GObject * object, guint prop_id, GValue * value,
215 GParamSpec * pspec)
216 {
217 GstDParam *dparam;
218 GstDParamSmooth *dpsmooth;
220 g_return_if_fail (GST_IS_DPSMOOTH (object));
222 dpsmooth = GST_DPSMOOTH (object);
223 dparam = GST_DPARAM (object);
225 switch (prop_id) {
226 case ARG_UPDATE_PERIOD:
227 g_value_set_int64 (value, dpsmooth->update_period);
228 break;
229 case ARG_SLOPE_TIME:
230 g_value_set_int64 (value, dpsmooth->slope_time);
231 break;
232 case ARG_SLOPE_DELTA_FLOAT:
233 g_value_set_float (value, dpsmooth->slope_delta_float);
234 break;
235 case ARG_SLOPE_DELTA_DOUBLE:
236 g_value_set_double (value, dpsmooth->slope_delta_double);
237 break;
238 default:
239 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240 break;
241 }
242 }
244 static void
245 gst_dpsmooth_value_changed_float (GstDParam * dparam)
246 {
247 GstDParamSmooth *dpsmooth;
248 gfloat time_ratio;
250 g_return_if_fail (GST_IS_DPSMOOTH (dparam));
251 dpsmooth = GST_DPSMOOTH (dparam);
253 if (GST_DPARAM_IS_LOG (dparam)) {
254 dparam->value_float = log (dparam->value_float);
255 }
256 dpsmooth->start_float = dpsmooth->current_float;
257 dpsmooth->diff_float = dparam->value_float - dpsmooth->start_float;
259 time_ratio = ABS (dpsmooth->diff_float) / dpsmooth->slope_delta_float;
260 dpsmooth->duration_interp =
261 (gint64) (time_ratio * (gfloat) dpsmooth->slope_time);
263 dpsmooth->need_interp_times = TRUE;
265 GST_DEBUG ("%f to %f ratio:%f duration:%"
266 G_GINT64_FORMAT "\n",
267 dpsmooth->start_float, dparam->value_float, time_ratio,
268 dpsmooth->duration_interp);
269 }
271 static void
272 gst_dpsmooth_do_update_float (GstDParam * dparam, gint64 timestamp,
273 GValue * value, GstDParamUpdateInfo update_info)
274 {
275 gfloat time_ratio;
276 GstDParamSmooth *dpsmooth = GST_DPSMOOTH (dparam);
278 GST_DPARAM_LOCK (dparam);
280 if (dpsmooth->need_interp_times) {
281 dpsmooth->start_interp = timestamp;
282 dpsmooth->end_interp = timestamp + dpsmooth->duration_interp;
283 dpsmooth->need_interp_times = FALSE;
284 }
286 if ((update_info == GST_DPARAM_UPDATE_FIRST)
287 || (timestamp >= dpsmooth->end_interp)) {
288 if (GST_DPARAM_IS_LOG (dparam)) {
289 g_value_set_float (value, exp (dparam->value_float));
290 } else {
291 g_value_set_float (value, dparam->value_float);
292 }
293 dpsmooth->current_float = dparam->value_float;
295 GST_DEBUG ("interp finished at %" G_GINT64_FORMAT, timestamp);
297 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
298 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp;
300 GST_DPARAM_READY_FOR_UPDATE (dparam) = FALSE;
301 GST_DPARAM_UNLOCK (dparam);
302 return;
303 }
305 if (timestamp <= dpsmooth->start_interp) {
306 if (GST_DPARAM_IS_LOG (dparam)) {
307 g_value_set_float (value, exp (dpsmooth->start_float));
308 } else {
309 g_value_set_float (value, dpsmooth->start_float);
310 }
311 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
312 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) =
313 dpsmooth->start_interp + dpsmooth->update_period;
315 GST_DEBUG ("interp started at %" G_GINT64_FORMAT, timestamp);
317 GST_DPARAM_UNLOCK (dparam);
318 return;
320 }
322 time_ratio =
323 (gfloat) (timestamp -
324 dpsmooth->start_interp) / (gfloat) dpsmooth->duration_interp;
326 GST_DEBUG ("start:%" G_GINT64_FORMAT " current:%" G_GINT64_FORMAT " end:%"
327 G_GINT64_FORMAT " ratio%f", dpsmooth->start_interp, timestamp,
328 dpsmooth->end_interp, time_ratio);
329 GST_DEBUG ("pre start:%f current:%f target:%f", dpsmooth->start_float,
330 dpsmooth->current_float, dparam->value_float);
332 dpsmooth->current_float =
333 dpsmooth->start_float + (dpsmooth->diff_float * time_ratio);
335 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) =
336 timestamp + dpsmooth->update_period;
337 if (GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) > dpsmooth->end_interp) {
338 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->end_interp;
339 }
341 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
343 if (GST_DPARAM_IS_LOG (dparam)) {
344 g_value_set_float (value, exp (dpsmooth->current_float));
345 } else {
346 g_value_set_float (value, dpsmooth->current_float);
347 }
349 GST_DEBUG ("post start:%f current:%f target:%f", dpsmooth->start_float,
350 dpsmooth->current_float, dparam->value_float);
352 GST_DPARAM_UNLOCK (dparam);
353 }
355 static void
356 gst_dpsmooth_value_changed_double (GstDParam * dparam)
357 {
358 GstDParamSmooth *dpsmooth;
359 gdouble time_ratio;
361 g_return_if_fail (GST_IS_DPSMOOTH (dparam));
362 dpsmooth = GST_DPSMOOTH (dparam);
364 if (GST_DPARAM_IS_LOG (dparam)) {
365 dparam->value_double = log (dparam->value_double);
366 }
367 dpsmooth->start_double = dpsmooth->current_double;
368 dpsmooth->diff_double = dparam->value_double - dpsmooth->start_double;
370 time_ratio = ABS (dpsmooth->diff_double) / dpsmooth->slope_delta_double;
371 dpsmooth->duration_interp =
372 (gint64) (time_ratio * (gdouble) dpsmooth->slope_time);
374 dpsmooth->need_interp_times = TRUE;
376 GST_DEBUG ("%f to %f ratio:%f duration:%"
377 G_GINT64_FORMAT "\n",
378 dpsmooth->start_double, dparam->value_double, time_ratio,
379 dpsmooth->duration_interp);
380 }
382 static void
383 gst_dpsmooth_do_update_double (GstDParam * dparam, gint64 timestamp,
384 GValue * value, GstDParamUpdateInfo update_info)
385 {
386 gdouble time_ratio;
387 GstDParamSmooth *dpsmooth = GST_DPSMOOTH (dparam);
389 GST_DPARAM_LOCK (dparam);
391 if (dpsmooth->need_interp_times) {
392 dpsmooth->start_interp = timestamp;
393 dpsmooth->end_interp = timestamp + dpsmooth->duration_interp;
394 dpsmooth->need_interp_times = FALSE;
395 }
397 if ((update_info == GST_DPARAM_UPDATE_FIRST)
398 || (timestamp >= dpsmooth->end_interp)) {
399 if (GST_DPARAM_IS_LOG (dparam)) {
400 g_value_set_double (value, exp (dparam->value_double));
401 } else {
402 g_value_set_double (value, dparam->value_double);
403 }
404 dpsmooth->current_double = dparam->value_double;
406 GST_DEBUG ("interp finished at %" G_GINT64_FORMAT, timestamp);
408 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
409 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = timestamp;
411 GST_DPARAM_READY_FOR_UPDATE (dparam) = FALSE;
412 GST_DPARAM_UNLOCK (dparam);
413 return;
414 }
416 if (timestamp <= dpsmooth->start_interp) {
417 if (GST_DPARAM_IS_LOG (dparam)) {
418 g_value_set_double (value, exp (dpsmooth->start_double));
419 } else {
420 g_value_set_double (value, dpsmooth->start_double);
421 }
422 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
423 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) =
424 dpsmooth->start_interp + dpsmooth->update_period;
426 GST_DEBUG ("interp started at %" G_GINT64_FORMAT, timestamp);
428 GST_DPARAM_UNLOCK (dparam);
429 return;
431 }
433 time_ratio =
434 (gdouble) (timestamp -
435 dpsmooth->start_interp) / (gdouble) dpsmooth->duration_interp;
437 GST_DEBUG ("start:%" G_GINT64_FORMAT " current:%" G_GINT64_FORMAT " end:%"
438 G_GINT64_FORMAT " ratio%f", dpsmooth->start_interp, timestamp,
439 dpsmooth->end_interp, time_ratio);
440 GST_DEBUG ("pre start:%f current:%f target:%f", dpsmooth->start_double,
441 dpsmooth->current_double, dparam->value_double);
443 dpsmooth->current_double =
444 dpsmooth->start_double + (dpsmooth->diff_double * time_ratio);
446 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) =
447 timestamp + dpsmooth->update_period;
448 if (GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) > dpsmooth->end_interp) {
449 GST_DPARAM_NEXT_UPDATE_TIMESTAMP (dparam) = dpsmooth->end_interp;
450 }
452 GST_DPARAM_LAST_UPDATE_TIMESTAMP (dparam) = timestamp;
454 if (GST_DPARAM_IS_LOG (dparam)) {
455 g_value_set_double (value, exp (dpsmooth->current_double));
456 } else {
457 g_value_set_double (value, dpsmooth->current_double);
458 }
460 GST_DEBUG ("post start:%f current:%f target:%f", dpsmooth->start_double,
461 dpsmooth->current_double, dparam->value_double);
463 GST_DPARAM_UNLOCK (dparam);
464 }