1 /*
2 * GStreamer
3 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Alternatively, the contents of this file may be used under the
24 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
25 * which case the following provisions apply instead of the ones
26 * mentioned above:
27 *
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Library General Public
30 * License as published by the Free Software Foundation; either
31 * version 2 of the License, or (at your option) any later version.
32 *
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Library General Public License for more details.
37 *
38 * You should have received a copy of the GNU Library General Public
39 * License along with this library; if not, write to the
40 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
41 * Boston, MA 02110-1301, USA.
42 */
43
44 /*
45 * Thanks to Jerry Huxtable <http://www.jhlabs.com> work on its java
46 * image editor and filters. The algorithms here were extracted from
47 * his code.
48 */
49
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54
55 #include <gst/gst.h>
56 #include <math.h>
57
58 #include "gstcirclegeometrictransform.h"
59
60 GST_DEBUG_CATEGORY_STATIC (gst_circle_geometric_transform_debug);
61 #define GST_CAT_DEFAULT gst_circle_geometric_transform_debug
62
63 GstGeometricTransformClass *parent_class;
64
65 enum
66 {
67 PROP_0,
68 PROP_X_CENTER,
69 PROP_Y_CENTER,
70 PROP_RADIUS
71 };
72
73 #define DEFAULT_X_CENTER 0.5
74 #define DEFAULT_Y_CENTER 0.5
75 #define DEFAULT_RADIUS 0.35
76
77 static void
gst_circle_geometric_transform_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)78 gst_circle_geometric_transform_set_property (GObject * object, guint prop_id,
79 const GValue * value, GParamSpec * pspec)
80 {
81 GstCircleGeometricTransform *cgt;
82 GstGeometricTransform *gt;
83 gdouble v;
84
85 gt = GST_GEOMETRIC_TRANSFORM_CAST (object);
86 cgt = GST_CIRCLE_GEOMETRIC_TRANSFORM_CAST (object);
87
88 GST_OBJECT_LOCK (cgt);
89 switch (prop_id) {
90 case PROP_X_CENTER:
91 v = g_value_get_double (value);
92 if (v != cgt->x_center) {
93 cgt->x_center = v;
94 gst_geometric_transform_set_need_remap (gt);
95 }
96 break;
97 case PROP_Y_CENTER:
98 v = g_value_get_double (value);
99 if (v != cgt->y_center) {
100 cgt->y_center = v;
101 gst_geometric_transform_set_need_remap (gt);
102 }
103 break;
104 case PROP_RADIUS:
105 v = g_value_get_double (value);
106 if (v != cgt->radius) {
107 cgt->radius = v;
108 gst_geometric_transform_set_need_remap (gt);
109 }
110 break;
111 default:
112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113 break;
114 }
115 GST_OBJECT_UNLOCK (cgt);
116 }
117
118 static void
gst_circle_geometric_transform_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)119 gst_circle_geometric_transform_get_property (GObject * object, guint prop_id,
120 GValue * value, GParamSpec * pspec)
121 {
122 GstCircleGeometricTransform *cgt;
123
124 cgt = GST_CIRCLE_GEOMETRIC_TRANSFORM_CAST (object);
125
126 switch (prop_id) {
127 case PROP_X_CENTER:
128 g_value_set_double (value, cgt->x_center);
129 break;
130 case PROP_Y_CENTER:
131 g_value_set_double (value, cgt->y_center);
132 break;
133 case PROP_RADIUS:
134 g_value_set_double (value, cgt->radius);
135 break;
136 default:
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138 break;
139 }
140 }
141
142 /* GObject vmethod implementations */
143
144 static gboolean
circle_geometric_transform_precalc(GstGeometricTransform * gt)145 circle_geometric_transform_precalc (GstGeometricTransform * gt)
146 {
147 GstCircleGeometricTransform *cgt = GST_CIRCLE_GEOMETRIC_TRANSFORM_CAST (gt);
148
149 cgt->precalc_x_center = cgt->x_center * gt->width;
150 cgt->precalc_y_center = cgt->y_center * gt->height;
151 cgt->precalc_radius =
152 cgt->radius * 0.5 * sqrt (gt->width * gt->width +
153 gt->height * gt->height);
154 cgt->precalc_radius2 = cgt->precalc_radius * cgt->precalc_radius;
155
156 return TRUE;
157 }
158
159 static void
gst_circle_geometric_transform_class_init(GstCircleGeometricTransformClass * klass)160 gst_circle_geometric_transform_class_init (GstCircleGeometricTransformClass *
161 klass)
162 {
163 GObjectClass *gobject_class;
164 GstGeometricTransformClass *gstgt_class;
165
166 gobject_class = (GObjectClass *) klass;
167 gstgt_class = (GstGeometricTransformClass *) klass;
168
169 parent_class = g_type_class_peek_parent (klass);
170
171 gobject_class->set_property = gst_circle_geometric_transform_set_property;
172 gobject_class->get_property = gst_circle_geometric_transform_get_property;
173
174 /* FIXME I don't like the idea of x-center and y-center being in % and
175 * radius and intensity in absolute values, I think no one likes it, but
176 * I can't see a way to have nice default values without % */
177 g_object_class_install_property (gobject_class, PROP_X_CENTER,
178 g_param_spec_double ("x-center", "x center",
179 "X axis center of the circle_geometric_transform effect",
180 0.0, 1.0, DEFAULT_X_CENTER,
181 GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182 g_object_class_install_property (gobject_class, PROP_Y_CENTER,
183 g_param_spec_double ("y-center", "y center",
184 "Y axis center of the circle_geometric_transform effect",
185 0.0, 1.0, DEFAULT_Y_CENTER,
186 GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 g_object_class_install_property (gobject_class, PROP_RADIUS,
188 g_param_spec_double ("radius", "radius",
189 "radius of the circle_geometric_transform effect", 0.0, 1.0,
190 DEFAULT_RADIUS,
191 GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192
193 gstgt_class->prepare_func = circle_geometric_transform_precalc;
194
195 gst_type_mark_as_plugin_api (GST_TYPE_CIRCLE_GEOMETRIC_TRANSFORM, 0);
196 }
197
198 static void
gst_circle_geometric_transform_init(GstCircleGeometricTransform * filter,GstCircleGeometricTransformClass * gclass)199 gst_circle_geometric_transform_init (GstCircleGeometricTransform * filter,
200 GstCircleGeometricTransformClass * gclass)
201 {
202 filter->x_center = DEFAULT_X_CENTER;
203 filter->y_center = DEFAULT_Y_CENTER;
204 filter->radius = DEFAULT_RADIUS;
205 }
206
207 GType
gst_circle_geometric_transform_get_type(void)208 gst_circle_geometric_transform_get_type (void)
209 {
210 static GType circle_geometric_transform_type = 0;
211
212 if (!circle_geometric_transform_type) {
213 static const GTypeInfo circle_geometric_transform_info = {
214 sizeof (GstCircleGeometricTransformClass),
215 NULL,
216 NULL,
217 (GClassInitFunc) gst_circle_geometric_transform_class_init,
218 NULL,
219 NULL,
220 sizeof (GstCircleGeometricTransform),
221 0,
222 (GInstanceInitFunc) gst_circle_geometric_transform_init,
223 };
224
225 circle_geometric_transform_type =
226 g_type_register_static (GST_TYPE_GEOMETRIC_TRANSFORM,
227 "GstCircleGeometricTransform", &circle_geometric_transform_info,
228 G_TYPE_FLAG_ABSTRACT);
229
230 GST_DEBUG_CATEGORY_INIT (gst_circle_geometric_transform_debug,
231 "circlegeometrictransform", 0,
232 "Base class for geometric transform elements that operate "
233 "on a circular area");
234 }
235 return circle_geometric_transform_type;
236 }
237