Port gtk-doc comments to their equivalent markdown syntax
[platform/upstream/gstreamer.git] / libs / gst / controller / gsttriggercontrolsource.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *               2011 Stefan Sauer <ensonic@users.sf.net>
5  *
6  * gsttriggercontrolsource.c: Control source that provides some values at time-
7  *                            stamps
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25  /**
26  * SECTION:gsttriggercontrolsource
27  * @title: GstTriggerControlSource
28  * @short_description: trigger control source
29  *
30  * #GstTriggerControlSource is a #GstControlSource, that returns values from user-given
31  * control points. It allows for a tolerance on the time-stamps.
32  *
33  * To use #GstTriggerControlSource get a new instance by calling
34  * gst_trigger_control_source_new(), bind it to a #GParamSpec and set some
35  * control points by calling gst_timed_value_control_source_set().
36  *
37  * All functions are MT-safe.
38  */
39
40 #include <glib-object.h>
41 #include <gst/gst.h>
42
43 #include "gsttriggercontrolsource.h"
44 #include "gst/glib-compat-private.h"
45 #include "gst/math-compat.h"
46
47 #define GST_CAT_DEFAULT controller_debug
48 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
49
50 struct _GstTriggerControlSourcePrivate
51 {
52   gint64 tolerance;
53 };
54
55 /* control point accessors */
56
57 /*  returns the default value of the property, except for times with specific values */
58 /*  needed for one-shot events, such as notes and triggers */
59
60 static inline gdouble
61 _interpolate_trigger (GstTimedValueControlSource * self, GSequenceIter * iter,
62     GstClockTime timestamp)
63 {
64   GstControlPoint *cp;
65   gint64 tolerance = ((GstTriggerControlSource *) self)->priv->tolerance;
66   gboolean found = FALSE;
67
68   cp = g_sequence_get (iter);
69   if (GST_CLOCK_DIFF (cp->timestamp, timestamp) <= tolerance) {
70     found = TRUE;
71   } else {
72     if ((iter = g_sequence_iter_next (iter)) && !g_sequence_iter_is_end (iter)) {
73       cp = g_sequence_get (iter);
74       if (GST_CLOCK_DIFF (timestamp, cp->timestamp) <= tolerance) {
75         found = TRUE;
76       }
77     }
78   }
79   if (found) {
80     return cp->value;
81   }
82   return NAN;
83 }
84
85 static gboolean
86 interpolate_trigger_get (GstTimedValueControlSource * self,
87     GstClockTime timestamp, gdouble * value)
88 {
89   gboolean ret = FALSE;
90   GSequenceIter *iter;
91
92   g_mutex_lock (&self->lock);
93
94   iter =
95       gst_timed_value_control_source_find_control_point_iter (self, timestamp);
96   if (iter) {
97     *value = _interpolate_trigger (self, iter, timestamp);
98     if (!isnan (*value))
99       ret = TRUE;
100   }
101   g_mutex_unlock (&self->lock);
102   return ret;
103 }
104
105 static gboolean
106 interpolate_trigger_get_value_array (GstTimedValueControlSource * self,
107     GstClockTime timestamp, GstClockTime interval, guint n_values,
108     gdouble * values)
109 {
110   gboolean ret = FALSE;
111   guint i;
112   GstClockTime ts = timestamp;
113   GstClockTime next_ts = 0;
114   gdouble val;
115   GSequenceIter *iter1 = NULL, *iter2 = NULL;
116   gboolean triggered = FALSE;
117
118   g_mutex_lock (&self->lock);
119   for (i = 0; i < n_values; i++) {
120     val = NAN;
121     if (ts >= next_ts) {
122       iter1 = gst_timed_value_control_source_find_control_point_iter (self, ts);
123       if (!iter1) {
124         if (G_LIKELY (self->values))
125           iter2 = g_sequence_get_begin_iter (self->values);
126         else
127           iter2 = NULL;
128       } else {
129         iter2 = g_sequence_iter_next (iter1);
130       }
131
132       if (iter2 && !g_sequence_iter_is_end (iter2)) {
133         GstControlPoint *cp;
134
135         cp = g_sequence_get (iter2);
136         next_ts = cp->timestamp;
137       } else {
138         next_ts = GST_CLOCK_TIME_NONE;
139       }
140
141       if (iter1) {
142         val = _interpolate_trigger (self, iter1, ts);
143         if (!isnan (val))
144           ret = TRUE;
145       } else {
146         g_mutex_unlock (&self->lock);
147         return FALSE;
148       }
149       triggered = TRUE;
150     } else if (triggered) {
151       if (iter1) {
152         val = _interpolate_trigger (self, iter1, ts);
153         if (!isnan (val))
154           ret = TRUE;
155       } else {
156         g_mutex_unlock (&self->lock);
157         return FALSE;
158       }
159       triggered = FALSE;
160     }
161     *values = val;
162     ts += interval;
163     values++;
164   }
165   g_mutex_unlock (&self->lock);
166   return ret;
167 }
168
169 enum
170 {
171   PROP_TOLERANCE = 1,
172 };
173
174 #define _do_init \
175   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "trigger control source", 0, \
176     "timeline value trigger control source")
177
178 G_DEFINE_TYPE_WITH_CODE (GstTriggerControlSource, gst_trigger_control_source,
179     GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, _do_init);
180
181 /**
182  * gst_trigger_control_source_new:
183  *
184  * This returns a new, unbound #GstTriggerControlSource.
185  *
186  * Returns: (transfer full): a new, unbound #GstTriggerControlSource.
187  */
188 GstControlSource *
189 gst_trigger_control_source_new (void)
190 {
191   return g_object_newv (GST_TYPE_TRIGGER_CONTROL_SOURCE, 0, NULL);
192 }
193
194 static void
195 gst_trigger_control_source_init (GstTriggerControlSource * self)
196 {
197   GstControlSource *csource = (GstControlSource *) self;
198
199   self->priv =
200       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_TRIGGER_CONTROL_SOURCE,
201       GstTriggerControlSourcePrivate);
202
203   csource->get_value = (GstControlSourceGetValue) interpolate_trigger_get;
204   csource->get_value_array = (GstControlSourceGetValueArray)
205       interpolate_trigger_get_value_array;
206 }
207
208 static void
209 gst_trigger_control_source_set_property (GObject * object, guint prop_id,
210     const GValue * value, GParamSpec * pspec)
211 {
212   GstTriggerControlSource *self = GST_TRIGGER_CONTROL_SOURCE (object);
213
214   switch (prop_id) {
215     case PROP_TOLERANCE:
216       GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (self);
217       self->priv->tolerance = g_value_get_int64 (value);
218       GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (self);
219       break;
220     default:
221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222       break;
223   }
224 }
225
226 static void
227 gst_trigger_control_source_get_property (GObject * object, guint prop_id,
228     GValue * value, GParamSpec * pspec)
229 {
230   GstTriggerControlSource *self = GST_TRIGGER_CONTROL_SOURCE (object);
231
232   switch (prop_id) {
233     case PROP_TOLERANCE:
234       g_value_set_int64 (value, self->priv->tolerance);
235       break;
236     default:
237       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
238       break;
239   }
240 }
241
242 static void
243 gst_trigger_control_source_class_init (GstTriggerControlSourceClass * klass)
244 {
245   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
246
247   g_type_class_add_private (klass, sizeof (GstTriggerControlSourcePrivate));
248
249   gobject_class->set_property = gst_trigger_control_source_set_property;
250   gobject_class->get_property = gst_trigger_control_source_get_property;
251
252   g_object_class_install_property (gobject_class, PROP_TOLERANCE,
253       g_param_spec_int64 ("tolerance", "Tolerance",
254           "Amount of ns a control time can be off to still trigger",
255           0, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256
257 }