3 * Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
5 * gstcontrolbindingargb.c: Attachment for multiple control sources to gargb
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.
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.
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.
24 * SECTION:gstcontrolbindingargb
25 * @short_description: attachment for control source sources to argb properties
27 * A value mapping object that attaches multiple control sources to a guint
28 * gobject properties representing a color.
31 #include <glib-object.h>
34 #include "gstcontrolbindingargb.h"
38 #define GST_CAT_DEFAULT control_binding_debug
39 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
41 static void gst_control_binding_argb_dispose (GObject * object);
42 static void gst_control_binding_argb_finalize (GObject * object);
44 static gboolean gst_control_binding_argb_sync_values (GstControlBinding * _self,
45 GstObject * object, GstClockTime timestamp, GstClockTime last_sync);
46 static GValue *gst_control_binding_argb_get_value (GstControlBinding * _self,
47 GstClockTime timestamp);
48 static gboolean gst_control_binding_argb_get_value_array (GstControlBinding *
49 _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
53 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbindingargb", 0, \
54 "dynamic parameter control source attachment");
56 G_DEFINE_TYPE_WITH_CODE (GstControlBindingARGB, gst_control_binding_argb,
57 GST_TYPE_CONTROL_BINDING, _do_init);
60 gst_control_binding_argb_class_init (GstControlBindingARGBClass * klass)
62 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
63 GstControlBindingClass *control_binding_class =
64 GST_CONTROL_BINDING_CLASS (klass);
66 gobject_class->dispose = gst_control_binding_argb_dispose;
67 gobject_class->finalize = gst_control_binding_argb_finalize;
69 control_binding_class->sync_values = gst_control_binding_argb_sync_values;
70 control_binding_class->get_value = gst_control_binding_argb_get_value;
71 control_binding_class->get_value_array =
72 gst_control_binding_argb_get_value_array;
76 gst_control_binding_argb_init (GstControlBindingARGB * self)
81 gst_control_binding_argb_dispose (GObject * object)
83 GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (object);
86 gst_object_replace ((GstObject **) & self->cs_a, NULL);
88 gst_object_replace ((GstObject **) & self->cs_r, NULL);
90 gst_object_replace ((GstObject **) & self->cs_g, NULL);
92 gst_object_replace ((GstObject **) & self->cs_b, NULL);
96 gst_control_binding_argb_finalize (GObject * object)
98 GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (object);
100 g_value_unset (&self->cur_value);
104 gst_control_binding_argb_sync_values (GstControlBinding * _self,
105 GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
107 GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self);
108 gdouble src_val_a = 1.0, src_val_r = 0.0, src_val_g = 0.0, src_val_b = 0.0;
111 g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), FALSE);
113 GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT,
114 _self->name, GST_TIME_ARGS (timestamp));
117 ret &= gst_control_source_get_value (self->cs_a, timestamp, &src_val_a);
119 ret &= gst_control_source_get_value (self->cs_r, timestamp, &src_val_r);
121 ret &= gst_control_source_get_value (self->cs_g, timestamp, &src_val_g);
123 ret &= gst_control_source_get_value (self->cs_b, timestamp, &src_val_b);
124 if (G_LIKELY (ret)) {
125 guint src_val = (((guint) (CLAMP (src_val_a, 0.0, 1.0) * 255)) << 24) |
126 (((guint) (CLAMP (src_val_r, 0.0, 1.0) * 255)) << 16) |
127 (((guint) (CLAMP (src_val_g, 0.0, 1.0) * 255)) << 8) |
128 ((guint) (CLAMP (src_val_b, 0.0, 1.0) * 255));
129 GST_LOG_OBJECT (object, " new value 0x%08x", src_val);
130 /* always set the value for first time, but then only if it changed
131 * this should limit g_object_notify invocations.
132 * FIXME: can we detect negative playback rates?
134 if ((timestamp < last_sync) || (src_val != self->last_value)) {
135 GValue *dst_val = &self->cur_value;
137 g_value_set_uint (dst_val, src_val);
138 /* we can make this faster
139 * http://bugzilla.gnome.org/show_bug.cgi?id=536939
141 g_object_set_property ((GObject *) object, _self->name, dst_val);
142 self->last_value = src_val;
145 GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name);
151 gst_control_binding_argb_get_value (GstControlBinding * _self,
152 GstClockTime timestamp)
154 GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self);
155 GValue *dst_val = NULL;
156 gdouble src_val_a = 1.0, src_val_r = 0.0, src_val_g = 0.0, src_val_b = 0.0;
159 g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), NULL);
160 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
162 /* get current value via control source */
164 ret &= gst_control_source_get_value (self->cs_a, timestamp, &src_val_a);
166 ret &= gst_control_source_get_value (self->cs_r, timestamp, &src_val_r);
168 ret &= gst_control_source_get_value (self->cs_g, timestamp, &src_val_g);
170 ret &= gst_control_source_get_value (self->cs_b, timestamp, &src_val_b);
171 if (G_LIKELY (ret)) {
172 guint src_val = (((guint) (CLAMP (src_val_a, 0.0, 1.0) * 255)) << 24) |
173 (((guint) (CLAMP (src_val_r, 0.0, 1.0) * 255)) << 16) |
174 (((guint) (CLAMP (src_val_g, 0.0, 1.0) * 255)) << 8) |
175 ((guint) (CLAMP (src_val_b, 0.0, 1.0) * 255));
176 dst_val = g_new0 (GValue, 1);
177 g_value_init (dst_val, G_TYPE_UINT);
178 g_value_set_uint (dst_val, src_val);
180 GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT,
181 _self->name, GST_TIME_ARGS (timestamp));
188 gst_control_binding_argb_get_value_array (GstControlBinding * _self,
189 GstClockTime timestamp, GstClockTime interval, guint n_values,
192 GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self);
194 gdouble *src_val_a = NULL, *src_val_r = NULL, *src_val_g = NULL, *src_val_b =
199 g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), FALSE);
200 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
201 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
202 g_return_val_if_fail (values, FALSE);
205 src_val_a = g_new0 (gdouble, n_values);
206 ret &= gst_control_source_get_value_array (self->cs_a, timestamp,
207 interval, n_values, src_val_a);
210 src_val_r = g_new0 (gdouble, n_values);
211 ret &= gst_control_source_get_value_array (self->cs_r, timestamp,
212 interval, n_values, src_val_r);
215 src_val_g = g_new0 (gdouble, n_values);
216 ret &= gst_control_source_get_value_array (self->cs_g, timestamp,
217 interval, n_values, src_val_g);
220 src_val_b = g_new0 (gdouble, n_values);
221 ret &= gst_control_source_get_value_array (self->cs_b, timestamp,
222 interval, n_values, src_val_b);
224 if (G_LIKELY (ret)) {
225 for (i = 0; i < n_values; i++) {
226 gdouble a = 1.0, r = 0.0, g = 0.0, b = 0.0;
227 if (src_val_a && !isnan (src_val_a[i]))
229 if (src_val_r && !isnan (src_val_r[i]))
231 if (src_val_g && !isnan (src_val_g[i]))
233 if (src_val_b && !isnan (src_val_b[i]))
235 src_val = (((guint) (CLAMP (a, 0.0, 1.0) * 255)) << 24) |
236 (((guint) (CLAMP (r, 0.0, 1.0) * 255)) << 16) |
237 (((guint) (CLAMP (g, 0.0, 1.0) * 255)) << 8) |
238 ((guint) (CLAMP (b, 0.0, 1.0) * 255));
239 g_value_init (&values[i], G_TYPE_UINT);
240 g_value_set_uint (&values[i], src_val);
243 GST_LOG ("failed to get control value for property %s at ts %"
244 GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
253 /* mapping function */
256 * gst_control_binding_argb_new:
257 * @object: the object of the property
258 * @property_name: the property-name to attach the control source
259 * @cs_a: the control source for the alpha channel
260 * @cs_r: the control source for the red channel
261 * @cs_g: the control source for the green channel
262 * @cs_b: the control source for the blue channel
264 * Create a new control-binding that attaches the given #GstControlSource to the
267 * Returns: the new #GstControlBindingARGB
270 gst_control_binding_argb_new (GstObject * object, const gchar * property_name,
271 GstControlSource * cs_a, GstControlSource * cs_r, GstControlSource * cs_g,
272 GstControlSource * cs_b)
274 GstControlBindingARGB *self = NULL;
277 GST_INFO_OBJECT (object, "trying to put property '%s' under control",
280 /* check if the object has a property of that name */
281 if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
283 GST_DEBUG_OBJECT (object, " psec->flags : 0x%08x", pspec->flags);
285 /* check if this param is witable && controlable && !construct-only */
286 g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE |
287 GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) ==
288 (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL);
290 g_return_val_if_fail (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_UINT, NULL);
292 if ((self = (GstControlBindingARGB *)
293 g_object_newv (GST_TYPE_CONTROL_BINDING_ARGB, 0, NULL))) {
294 // move below to construct()
295 ((GstControlBinding *) self)->pspec = pspec;
296 ((GstControlBinding *) self)->name = pspec->name;
298 self->cs_a = gst_object_ref (cs_a);
300 self->cs_r = gst_object_ref (cs_r);
302 self->cs_g = gst_object_ref (cs_g);
304 self->cs_b = gst_object_ref (cs_b);
306 g_value_init (&self->cur_value, G_TYPE_UINT);
309 GST_WARNING_OBJECT (object, "class '%s' has no property '%s'",
310 G_OBJECT_TYPE_NAME (object), property_name);
312 return (GstControlBinding *) self;