Branch data Line data Source code
1 : : /* GStreamer
2 : : *
3 : : * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 : : *
5 : : * gstinterpolationcontrolsource.c: Control source that provides several
6 : : * interpolation methods
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Library General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Library General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Library General Public
19 : : * License along with this library; if not, write to the
20 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 : : * Boston, MA 02111-1307, USA.
22 : : */
23 : :
24 : : /**
25 : : * SECTION:gstinterpolationcontrolsource
26 : : * @short_description: interpolation control source
27 : : *
28 : : * #GstInterpolationControlSource is a #GstControlSource, that interpolates values between user-given
29 : : * control points. It supports several interpolation modes and property types.
30 : : *
31 : : * To use #GstInterpolationControlSource get a new instance by calling
32 : : * gst_interpolation_control_source_new(), bind it to a #GParamSpec, select a interpolation mode with
33 : : * gst_interpolation_control_source_set_interpolation_mode() and set some control points by calling
34 : : * gst_interpolation_control_source_set().
35 : : *
36 : : * All functions are MT-safe.
37 : : *
38 : : */
39 : :
40 : : #include <glib-object.h>
41 : : #include <gst/gst.h>
42 : :
43 : : #include "gstcontrolsource.h"
44 : : #include "gstinterpolationcontrolsource.h"
45 : : #include "gstinterpolationcontrolsourceprivate.h"
46 : :
47 : : #define GST_CAT_DEFAULT controller_debug
48 : : GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
49 : :
50 [ + + ]: 130 : G_DEFINE_TYPE (GstInterpolationControlSource, gst_interpolation_control_source,
51 : 130 : GST_TYPE_CONTROL_SOURCE);
52 : :
53 : : static GObjectClass *parent_class = NULL;
54 : :
55 : : /*
56 : : * gst_control_point_free:
57 : : * @prop: the object to free
58 : : *
59 : : * Private method which frees all data allocated by a #GstControlPoint
60 : : * instance.
61 : : */
62 : : static void
63 : 35 : gst_control_point_free (GstControlPoint * cp)
64 : : {
65 [ - + ]: 70 : g_return_if_fail (cp);
66 : :
67 : 35 : g_value_unset (&cp->value);
68 : 35 : g_slice_free (GstControlPoint, cp);
69 : : }
70 : :
71 : : static void
72 : 19 : gst_interpolation_control_source_reset (GstInterpolationControlSource * self)
73 : : {
74 : 19 : GstControlSource *csource = (GstControlSource *) self;
75 : :
76 : 19 : csource->get_value = NULL;
77 : 19 : csource->get_value_array = NULL;
78 : :
79 : 19 : self->priv->type = self->priv->base = G_TYPE_INVALID;
80 : :
81 [ + - ]: 19 : if (G_IS_VALUE (&self->priv->default_value))
82 : 19 : g_value_unset (&self->priv->default_value);
83 [ + - ]: 19 : if (G_IS_VALUE (&self->priv->minimum_value))
84 : 19 : g_value_unset (&self->priv->minimum_value);
85 [ + - ]: 19 : if (G_IS_VALUE (&self->priv->maximum_value))
86 : 19 : g_value_unset (&self->priv->maximum_value);
87 : :
88 [ + + ]: 19 : if (self->priv->values) {
89 : 14 : g_sequence_free (self->priv->values);
90 : 14 : self->priv->values = NULL;
91 : : }
92 : :
93 : 19 : self->priv->nvalues = 0;
94 : 19 : self->priv->valid_cache = FALSE;
95 : 19 : }
96 : :
97 : : /**
98 : : * gst_interpolation_control_source_new:
99 : : *
100 : : * This returns a new, unbound #GstInterpolationControlSource.
101 : : *
102 : : * Returns: a new, unbound #GstInterpolationControlSource.
103 : : */
104 : : GstInterpolationControlSource *
105 : 19 : gst_interpolation_control_source_new (void)
106 : : {
107 : 19 : return g_object_newv (GST_TYPE_INTERPOLATION_CONTROL_SOURCE, 0, NULL);
108 : : }
109 : :
110 : : /**
111 : : * gst_interpolation_control_source_set_interpolation_mode:
112 : : * @self: the #GstInterpolationControlSource object
113 : : * @mode: interpolation mode
114 : : *
115 : : * Sets the given interpolation mode.
116 : : *
117 : : * <note><para>User interpolation is not yet available and quadratic interpolation
118 : : * is deprecated and maps to cubic interpolation.</para></note>
119 : : *
120 : : * Returns: %TRUE if the interpolation mode could be set, %FALSE otherwise
121 : : */
122 : : /* *INDENT-OFF* */
123 : : gboolean
124 : 35 : gst_interpolation_control_source_set_interpolation_mode (
125 : : GstInterpolationControlSource * self, GstInterpolateMode mode)
126 : : /* *INDENT-ON* */
127 : : {
128 : 35 : gboolean ret = TRUE;
129 : 35 : GstControlSource *csource = GST_CONTROL_SOURCE (self);
130 : :
131 [ + + ]: 35 : if (mode >= priv_gst_num_interpolation_methods
132 [ - + ]: 34 : || priv_gst_interpolation_methods[mode] == NULL) {
133 [ - + ]: 1 : GST_WARNING ("interpolation mode %d invalid or not implemented yet", mode);
134 : 1 : return FALSE;
135 : : }
136 : :
137 [ - + ]: 34 : if (mode == GST_INTERPOLATE_QUADRATIC) {
138 [ # # ]: 0 : GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
139 : : "interpolation mode");
140 : : }
141 : :
142 [ - + ]: 34 : if (mode == GST_INTERPOLATE_USER) {
143 [ # # ]: 0 : GST_WARNING ("User interpolation mode is not implemented yet");
144 : 0 : return FALSE;
145 : : }
146 : :
147 : 34 : g_mutex_lock (self->lock);
148 [ - - - + : 34 : switch (self->priv->base) {
- - + + -
- - - ]
149 : : case G_TYPE_INT:
150 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_int;
151 : 0 : csource->get_value_array =
152 : 0 : priv_gst_interpolation_methods[mode]->get_int_value_array;
153 : 0 : break;
154 : : case G_TYPE_UINT:{
155 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_uint;
156 : 0 : csource->get_value_array =
157 : 0 : priv_gst_interpolation_methods[mode]->get_uint_value_array;
158 : 0 : break;
159 : : }
160 : : case G_TYPE_LONG:{
161 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_long;
162 : 0 : csource->get_value_array =
163 : 0 : priv_gst_interpolation_methods[mode]->get_long_value_array;
164 : 0 : break;
165 : : }
166 : : case G_TYPE_ULONG:{
167 : 26 : csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong;
168 : 26 : csource->get_value_array =
169 : 26 : priv_gst_interpolation_methods[mode]->get_ulong_value_array;
170 : 26 : break;
171 : : }
172 : : case G_TYPE_INT64:{
173 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_int64;
174 : 0 : csource->get_value_array =
175 : 0 : priv_gst_interpolation_methods[mode]->get_int64_value_array;
176 : 0 : break;
177 : : }
178 : : case G_TYPE_UINT64:{
179 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64;
180 : 0 : csource->get_value_array =
181 : 0 : priv_gst_interpolation_methods[mode]->get_uint64_value_array;
182 : 0 : break;
183 : : }
184 : : case G_TYPE_FLOAT:{
185 : 2 : csource->get_value = priv_gst_interpolation_methods[mode]->get_float;
186 : 2 : csource->get_value_array =
187 : 2 : priv_gst_interpolation_methods[mode]->get_float_value_array;
188 : 2 : break;
189 : : }
190 : : case G_TYPE_DOUBLE:{
191 : 6 : csource->get_value = priv_gst_interpolation_methods[mode]->get_double;
192 : 6 : csource->get_value_array =
193 : 6 : priv_gst_interpolation_methods[mode]->get_double_value_array;
194 : 6 : break;
195 : : }
196 : : case G_TYPE_BOOLEAN:{
197 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean;
198 : 0 : csource->get_value_array =
199 : 0 : priv_gst_interpolation_methods[mode]->get_boolean_value_array;
200 : 0 : break;
201 : : }
202 : : case G_TYPE_ENUM:{
203 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_enum;
204 : 0 : csource->get_value_array =
205 : 0 : priv_gst_interpolation_methods[mode]->get_enum_value_array;
206 : 0 : break;
207 : : }
208 : : case G_TYPE_STRING:{
209 : 0 : csource->get_value = priv_gst_interpolation_methods[mode]->get_string;
210 : 0 : csource->get_value_array =
211 : 0 : priv_gst_interpolation_methods[mode]->get_string_value_array;
212 : 0 : break;
213 : : }
214 : : default:
215 : 0 : ret = FALSE;
216 : 0 : break;
217 : : }
218 : :
219 : : /* Incomplete implementation */
220 [ + - ][ + - ]: 34 : if (!ret || !csource->get_value || !csource->get_value_array) {
[ - + ]
221 : 0 : gst_interpolation_control_source_reset (self);
222 : 0 : ret = FALSE;
223 : : }
224 : :
225 : 34 : self->priv->valid_cache = FALSE;
226 : 34 : self->priv->interpolation_mode = mode;
227 : :
228 : 34 : g_mutex_unlock (self->lock);
229 : :
230 : 35 : return ret;
231 : : }
232 : :
233 : : static gboolean
234 : 19 : gst_interpolation_control_source_bind (GstControlSource * source,
235 : : GParamSpec * pspec)
236 : : {
237 : : GType type, base;
238 : 19 : GstInterpolationControlSource *self =
239 : : (GstInterpolationControlSource *) source;
240 : 19 : gboolean ret = TRUE;
241 : :
242 : : /* get the fundamental base type */
243 : 19 : self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
244 [ - + ]: 19 : while ((type = g_type_parent (type)))
245 : 0 : base = type;
246 : :
247 : 19 : self->priv->base = base;
248 : : /* restore type */
249 : 19 : type = self->priv->type;
250 : :
251 [ - + ]: 19 : if (!gst_interpolation_control_source_set_interpolation_mode (self,
252 : 19 : self->priv->interpolation_mode))
253 : 0 : return FALSE;
254 : :
255 [ - - - + : 19 : switch (base) {
- - + + -
- - - ]
256 : : case G_TYPE_INT:{
257 : 0 : GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
258 : :
259 : 0 : g_value_init (&self->priv->default_value, type);
260 : 0 : g_value_set_int (&self->priv->default_value, tpspec->default_value);
261 : 0 : g_value_init (&self->priv->minimum_value, type);
262 : 0 : g_value_set_int (&self->priv->minimum_value, tpspec->minimum);
263 : 0 : g_value_init (&self->priv->maximum_value, type);
264 : 0 : g_value_set_int (&self->priv->maximum_value, tpspec->maximum);
265 : 0 : break;
266 : : }
267 : : case G_TYPE_UINT:{
268 : 0 : GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
269 : :
270 : 0 : g_value_init (&self->priv->default_value, type);
271 : 0 : g_value_set_uint (&self->priv->default_value, tpspec->default_value);
272 : 0 : g_value_init (&self->priv->minimum_value, type);
273 : 0 : g_value_set_uint (&self->priv->minimum_value, tpspec->minimum);
274 : 0 : g_value_init (&self->priv->maximum_value, type);
275 : 0 : g_value_set_uint (&self->priv->maximum_value, tpspec->maximum);
276 : 0 : break;
277 : : }
278 : : case G_TYPE_LONG:{
279 : 0 : GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
280 : :
281 : 0 : g_value_init (&self->priv->default_value, type);
282 : 0 : g_value_set_long (&self->priv->default_value, tpspec->default_value);
283 : 0 : g_value_init (&self->priv->minimum_value, type);
284 : 0 : g_value_set_long (&self->priv->minimum_value, tpspec->minimum);
285 : 0 : g_value_init (&self->priv->maximum_value, type);
286 : 0 : g_value_set_long (&self->priv->maximum_value, tpspec->maximum);
287 : 0 : break;
288 : : }
289 : : case G_TYPE_ULONG:{
290 : 15 : GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
291 : :
292 : 15 : g_value_init (&self->priv->default_value, type);
293 : 15 : g_value_set_ulong (&self->priv->default_value, tpspec->default_value);
294 : 15 : g_value_init (&self->priv->minimum_value, type);
295 : 15 : g_value_set_ulong (&self->priv->minimum_value, tpspec->minimum);
296 : 15 : g_value_init (&self->priv->maximum_value, type);
297 : 15 : g_value_set_ulong (&self->priv->maximum_value, tpspec->maximum);
298 : 15 : break;
299 : : }
300 : : case G_TYPE_INT64:{
301 : 0 : GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
302 : :
303 : 0 : g_value_init (&self->priv->default_value, type);
304 : 0 : g_value_set_int64 (&self->priv->default_value, tpspec->default_value);
305 : 0 : g_value_init (&self->priv->minimum_value, type);
306 : 0 : g_value_set_int64 (&self->priv->minimum_value, tpspec->minimum);
307 : 0 : g_value_init (&self->priv->maximum_value, type);
308 : 0 : g_value_set_int64 (&self->priv->maximum_value, tpspec->maximum);
309 : 0 : break;
310 : : }
311 : : case G_TYPE_UINT64:{
312 : 0 : GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
313 : :
314 : 0 : g_value_init (&self->priv->default_value, type);
315 : 0 : g_value_set_uint64 (&self->priv->default_value, tpspec->default_value);
316 : 0 : g_value_init (&self->priv->minimum_value, type);
317 : 0 : g_value_set_uint64 (&self->priv->minimum_value, tpspec->minimum);
318 : 0 : g_value_init (&self->priv->maximum_value, type);
319 : 0 : g_value_set_uint64 (&self->priv->maximum_value, tpspec->maximum);
320 : 0 : break;
321 : : }
322 : : case G_TYPE_FLOAT:{
323 : 1 : GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
324 : :
325 : 1 : g_value_init (&self->priv->default_value, type);
326 : 1 : g_value_set_float (&self->priv->default_value, tpspec->default_value);
327 : 1 : g_value_init (&self->priv->minimum_value, type);
328 : 1 : g_value_set_float (&self->priv->minimum_value, tpspec->minimum);
329 : 1 : g_value_init (&self->priv->maximum_value, type);
330 : 1 : g_value_set_float (&self->priv->maximum_value, tpspec->maximum);
331 : 1 : break;
332 : : }
333 : : case G_TYPE_DOUBLE:{
334 : 3 : GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
335 : :
336 : 3 : g_value_init (&self->priv->default_value, type);
337 : 3 : g_value_set_double (&self->priv->default_value, tpspec->default_value);
338 : 3 : g_value_init (&self->priv->minimum_value, type);
339 : 3 : g_value_set_double (&self->priv->minimum_value, tpspec->minimum);
340 : 3 : g_value_init (&self->priv->maximum_value, type);
341 : 3 : g_value_set_double (&self->priv->maximum_value, tpspec->maximum);
342 : 3 : break;
343 : : }
344 : : case G_TYPE_BOOLEAN:{
345 : 0 : GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
346 : :
347 : 0 : g_value_init (&self->priv->default_value, type);
348 : 0 : g_value_set_boolean (&self->priv->default_value, tpspec->default_value);
349 : 0 : break;
350 : : }
351 : : case G_TYPE_ENUM:{
352 : 0 : GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
353 : :
354 : 0 : g_value_init (&self->priv->default_value, type);
355 : 0 : g_value_set_enum (&self->priv->default_value, tpspec->default_value);
356 : 0 : break;
357 : : }
358 : : case G_TYPE_STRING:{
359 : 0 : GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
360 : :
361 : 0 : g_value_init (&self->priv->default_value, type);
362 : 0 : g_value_set_string (&self->priv->default_value, tpspec->default_value);
363 : 0 : break;
364 : : }
365 : : default:
366 [ # # ]: 0 : GST_WARNING ("incomplete implementation for paramspec type '%s'",
367 : : G_PARAM_SPEC_TYPE_NAME (pspec));
368 : 0 : ret = FALSE;
369 : 0 : break;
370 : : }
371 : :
372 [ + - ]: 19 : if (ret) {
373 : 19 : self->priv->valid_cache = FALSE;
374 : 19 : self->priv->nvalues = 0;
375 : : } else {
376 : 0 : gst_interpolation_control_source_reset (self);
377 : : }
378 : :
379 : 19 : return ret;
380 : : }
381 : :
382 : : /*
383 : : * gst_control_point_compare:
384 : : * @p1: a pointer to a #GstControlPoint
385 : : * @p2: a pointer to a #GstControlPoint
386 : : *
387 : : * Compare function for g_list operations that operates on two #GstControlPoint
388 : : * parameters.
389 : : */
390 : : static gint
391 : 22 : gst_control_point_compare (gconstpointer p1, gconstpointer p2)
392 : : {
393 : 22 : GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
394 : 22 : GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
395 : :
396 [ + + ]: 22 : return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
397 : : }
398 : :
399 : : /*
400 : : * gst_control_point_find:
401 : : * @p1: a pointer to a #GstControlPoint
402 : : * @p2: a pointer to a #GstClockTime
403 : : *
404 : : * Compare function for g_list operations that operates on a #GstControlPoint and
405 : : * a #GstClockTime.
406 : : */
407 : : static gint
408 : 36 : gst_control_point_find (gconstpointer p1, gconstpointer p2)
409 : : {
410 : 36 : GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
411 : 36 : GstClockTime ct2 = *(GstClockTime *) p2;
412 : :
413 [ + + ]: 36 : return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
414 : : }
415 : :
416 : : static GstControlPoint *
417 : 35 : _make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp,
418 : : const GValue * value)
419 : : {
420 : : GstControlPoint *cp;
421 : :
422 : : /* create a new GstControlPoint */
423 : 35 : cp = g_slice_new0 (GstControlPoint);
424 : 35 : cp->timestamp = timestamp;
425 : 35 : g_value_init (&cp->value, self->priv->type);
426 : 35 : g_value_copy (value, &cp->value);
427 : :
428 : 35 : return cp;
429 : : }
430 : :
431 : : static void
432 : 35 : gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
433 : : self, GstClockTime timestamp, const GValue * value)
434 : : {
435 : : GSequenceIter *iter;
436 : :
437 : : /* check if a control point for the timestamp already exists */
438 : :
439 : : /* iter contains the iter right *after* timestamp */
440 [ + + ]: 35 : if (G_LIKELY (self->priv->values)) {
441 : 19 : iter =
442 : 19 : g_sequence_search (self->priv->values, ×tamp,
443 : : (GCompareDataFunc) gst_control_point_find, NULL);
444 [ + - ]: 19 : if (iter) {
445 : 19 : GSequenceIter *prev = g_sequence_iter_prev (iter);
446 : 19 : GstControlPoint *cp = g_sequence_get (prev);
447 : :
448 : : /* If the timestamp is the same just update the control point value */
449 [ - + ]: 19 : if (cp->timestamp == timestamp) {
450 : : /* update control point */
451 : 0 : g_value_reset (&cp->value);
452 : 0 : g_value_copy (value, &cp->value);
453 : 0 : goto done;
454 : : }
455 : : }
456 : : } else {
457 : 16 : self->priv->values =
458 : 16 : g_sequence_new ((GDestroyNotify) gst_control_point_free);
459 : : }
460 : :
461 : : /* sort new cp into the prop->values list */
462 : 35 : g_sequence_insert_sorted (self->priv->values, _make_new_cp (self, timestamp,
463 : : value), (GCompareDataFunc) gst_control_point_compare, NULL);
464 : 35 : self->priv->nvalues++;
465 : :
466 : : done:
467 : 35 : self->priv->valid_cache = FALSE;
468 : 35 : }
469 : :
470 : :
471 : : /**
472 : : * gst_interpolation_control_source_set:
473 : : * @self: the #GstInterpolationControlSource object
474 : : * @timestamp: the time the control-change is scheduled for
475 : : * @value: the control-value
476 : : *
477 : : * Set the value of given controller-handled property at a certain time.
478 : : *
479 : : * Returns: FALSE if the values couldn't be set, TRUE otherwise.
480 : : */
481 : : gboolean
482 : 34 : gst_interpolation_control_source_set (GstInterpolationControlSource * self,
483 : : GstClockTime timestamp, const GValue * value)
484 : : {
485 [ - + ][ + - ]: 34 : g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
[ + - ][ - + ]
486 [ - + ]: 34 : g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
487 [ - + ]: 34 : g_return_val_if_fail (G_IS_VALUE (value), FALSE);
488 [ - + ]: 34 : g_return_val_if_fail (G_VALUE_TYPE (value) == self->priv->type, FALSE);
489 : :
490 : 34 : g_mutex_lock (self->lock);
491 : 34 : gst_interpolation_control_source_set_internal (self, timestamp, value);
492 : 34 : g_mutex_unlock (self->lock);
493 : :
494 : 34 : return TRUE;
495 : : }
496 : :
497 : : /**
498 : : * gst_interpolation_control_source_set_from_list:
499 : : * @self: the #GstInterpolationControlSource object
500 : : * @timedvalues: a list with #GstTimedValue items
501 : : *
502 : : * Sets multiple timed values at once.
503 : : *
504 : : * Returns: FALSE if the values couldn't be set, TRUE otherwise.
505 : : */
506 : : gboolean
507 : 2 : gst_interpolation_control_source_set_from_list (GstInterpolationControlSource *
508 : : self, const GSList * timedvalues)
509 : : {
510 : : const GSList *node;
511 : : GstTimedValue *tv;
512 : 2 : gboolean res = FALSE;
513 : :
514 [ - + ][ + - ]: 2 : g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
[ + - ][ - + ]
515 : :
516 [ + - ][ + + ]: 4 : for (node = timedvalues; node; node = g_slist_next (node)) {
517 : 2 : tv = node->data;
518 [ + + ]: 2 : if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
519 [ - + ]: 1 : GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
520 : : GST_FUNCTION);
521 [ - + ]: 1 : } else if (!G_IS_VALUE (&tv->value)) {
522 [ # # ]: 0 : GST_WARNING ("GstTimedValued with invalid value passed to %s",
523 : : GST_FUNCTION);
524 [ - + ]: 1 : } else if (G_VALUE_TYPE (&tv->value) != self->priv->type) {
525 [ # # ]: 0 : GST_WARNING ("incompatible value type for property");
526 : : } else {
527 : 1 : g_mutex_lock (self->lock);
528 : 1 : gst_interpolation_control_source_set_internal (self, tv->timestamp,
529 : 1 : &tv->value);
530 : 1 : g_mutex_unlock (self->lock);
531 : 1 : res = TRUE;
532 : : }
533 : : }
534 : 2 : return res;
535 : : }
536 : :
537 : : /**
538 : : * gst_interpolation_control_source_unset:
539 : : * @self: the #GstInterpolationControlSource object
540 : : * @timestamp: the time the control-change should be removed from
541 : : *
542 : : * Used to remove the value of given controller-handled property at a certain
543 : : * time.
544 : : *
545 : : * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
546 : : */
547 : : gboolean
548 : 9 : gst_interpolation_control_source_unset (GstInterpolationControlSource * self,
549 : : GstClockTime timestamp)
550 : : {
551 : : GSequenceIter *iter;
552 : 9 : gboolean res = FALSE;
553 : :
554 [ - + ][ + - ]: 9 : g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
[ + - ][ - + ]
555 [ - + ]: 9 : g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
556 : :
557 : 9 : g_mutex_lock (self->lock);
558 : : /* check if a control point for the timestamp exists */
559 [ + + ][ + - ]: 9 : if (G_LIKELY (self->priv->values) && (iter =
560 : 8 : g_sequence_search (self->priv->values, ×tamp,
561 : : (GCompareDataFunc) gst_control_point_find, NULL))) {
562 : : GstControlPoint *cp;
563 : :
564 : : /* Iter contains the iter right after timestamp, i.e.
565 : : * we need to get the previous one and check the timestamp
566 : : */
567 : 8 : iter = g_sequence_iter_prev (iter);
568 : 8 : cp = g_sequence_get (iter);
569 [ + - ]: 8 : if (cp->timestamp == timestamp) {
570 : 8 : g_sequence_remove (iter);
571 : 8 : self->priv->nvalues--;
572 : 8 : self->priv->valid_cache = FALSE;
573 : 8 : res = TRUE;
574 : : }
575 : : }
576 : 9 : g_mutex_unlock (self->lock);
577 : :
578 : 9 : return res;
579 : : }
580 : :
581 : : /**
582 : : * gst_interpolation_control_source_unset_all:
583 : : * @self: the #GstInterpolationControlSource object
584 : : *
585 : : * Used to remove all time-stamped values of given controller-handled property
586 : : *
587 : : */
588 : : void
589 : 2 : gst_interpolation_control_source_unset_all (GstInterpolationControlSource *
590 : : self)
591 : : {
592 [ - + ][ + - ]: 4 : g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self));
[ + - ][ - + ]
593 : :
594 : 2 : g_mutex_lock (self->lock);
595 : : /* free GstControlPoint structures */
596 [ + - ]: 2 : if (self->priv->values) {
597 : 2 : g_sequence_free (self->priv->values);
598 : 2 : self->priv->values = NULL;
599 : : }
600 : 2 : self->priv->nvalues = 0;
601 : 2 : self->priv->valid_cache = FALSE;
602 : :
603 : 2 : g_mutex_unlock (self->lock);
604 : : }
605 : :
606 : : static void
607 : 0 : _append_control_point (GstControlPoint * cp, GList ** l)
608 : : {
609 : 0 : *l = g_list_prepend (*l, cp);
610 : 0 : }
611 : :
612 : : /**
613 : : * gst_interpolation_control_source_get_all:
614 : : * @self: the #GstInterpolationControlSource to get the list from
615 : : *
616 : : * Returns a read-only copy of the list of #GstTimedValue for the given property.
617 : : * Free the list after done with it.
618 : : *
619 : : * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
620 : : */
621 : : GList *
622 : 0 : gst_interpolation_control_source_get_all (GstInterpolationControlSource * self)
623 : : {
624 : 0 : GList *res = NULL;
625 : :
626 [ # # ][ # # ]: 0 : g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL);
[ # # ][ # # ]
627 : :
628 : 0 : g_mutex_lock (self->lock);
629 [ # # ]: 0 : if (G_LIKELY (self->priv->values))
630 : 0 : g_sequence_foreach (self->priv->values, (GFunc) _append_control_point,
631 : : &res);
632 : 0 : g_mutex_unlock (self->lock);
633 : :
634 : 0 : return g_list_reverse (res);
635 : : }
636 : :
637 : : /**
638 : : * gst_interpolation_control_source_get_count:
639 : : * @self: the #GstInterpolationControlSource to get the number of values from
640 : : *
641 : : * Returns the number of control points that are set.
642 : : *
643 : : * Returns: the number of control points that are set.
644 : : *
645 : : */
646 : : gint
647 : 8 : gst_interpolation_control_source_get_count (GstInterpolationControlSource *
648 : : self)
649 : : {
650 [ - + ][ + - ]: 8 : g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0);
[ + - ][ - + ]
651 : 8 : return self->priv->nvalues;
652 : : }
653 : :
654 : :
655 : : static void
656 : 19 : gst_interpolation_control_source_init (GstInterpolationControlSource * self)
657 : : {
658 : 19 : self->lock = g_mutex_new ();
659 : 19 : self->priv =
660 : 19 : G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE,
661 : : GstInterpolationControlSourcePrivate);
662 : 19 : self->priv->interpolation_mode = GST_INTERPOLATE_NONE;
663 : 19 : }
664 : :
665 : : static void
666 : 19 : gst_interpolation_control_source_finalize (GObject * obj)
667 : : {
668 : 19 : GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj);
669 : :
670 : 19 : g_mutex_lock (self->lock);
671 : 19 : gst_interpolation_control_source_reset (self);
672 : 19 : g_mutex_unlock (self->lock);
673 : 19 : g_mutex_free (self->lock);
674 : 19 : G_OBJECT_CLASS (parent_class)->finalize (obj);
675 : 19 : }
676 : :
677 : : static void
678 : 19 : gst_interpolation_control_source_dispose (GObject * obj)
679 : : {
680 : 19 : G_OBJECT_CLASS (parent_class)->dispose (obj);
681 : 19 : }
682 : :
683 : : static void
684 : 18 : gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
685 : : * klass)
686 : : {
687 : 18 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
688 : 18 : GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
689 : :
690 : 18 : parent_class = g_type_class_peek_parent (klass);
691 : 18 : g_type_class_add_private (klass,
692 : : sizeof (GstInterpolationControlSourcePrivate));
693 : :
694 : 18 : gobject_class->finalize = gst_interpolation_control_source_finalize;
695 : 18 : gobject_class->dispose = gst_interpolation_control_source_dispose;
696 : 18 : csource_class->bind = gst_interpolation_control_source_bind;
697 : 18 : }
|