Merging gst-plugins-bad
[platform/upstream/gstreamer.git] / gst / geometrictransform / gstmirror.c
1 /*
2  * GStreamer
3  * Copyright (C) 2010 Filippo Argiolas <filippo.argiolas@gmail.com>
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  * SECTION:element-mirror
46  * @title: mirror
47  * @see_also: geometrictransform
48  *
49  * Mirror is a geometric transform element. It splits the image into two halves
50  * and reflects one over each other.
51  *
52  * ## Example launch line
53  * |[
54  * gst-launch-1.0 -v videotestsrc ! mirror ! videoconvert ! autovideosink
55  * ]|
56  *
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #  include <config.h>
61 #endif
62
63 #include <gst/gst.h>
64 #include <math.h>
65
66 #include "gstmirror.h"
67
68 GST_DEBUG_CATEGORY_STATIC (gst_mirror_debug);
69 #define GST_CAT_DEFAULT gst_mirror_debug
70
71 enum
72 {
73   PROP_0,
74   PROP_MODE
75 };
76
77 #define DEFAULT_PROP_MODE GST_MIRROR_MODE_LEFT
78
79 #define gst_mirror_parent_class parent_class
80 G_DEFINE_TYPE (GstMirror, gst_mirror, GST_TYPE_GEOMETRIC_TRANSFORM);
81 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (mirror, "mirror", GST_RANK_NONE,
82     GST_TYPE_MIRROR, GST_DEBUG_CATEGORY_INIT (gst_mirror_debug, "mirror", 0,
83         "mirror"));
84
85 #define GST_TYPE_MIRROR_MODE (gst_mirror_mode_get_type())
86 static GType
87 gst_mirror_mode_get_type (void)
88 {
89   static GType mode_type = 0;
90
91   static const GEnumValue modes[] = {
92     {GST_MIRROR_MODE_LEFT, "Split horizontally and reflect left into right",
93         "left"},
94     {GST_MIRROR_MODE_RIGHT, "Split horizontally and reflect right into left",
95         "right"},
96     {GST_MIRROR_MODE_TOP, "Split vertically and reflect top into bottom",
97         "top"},
98     {GST_MIRROR_MODE_BOTTOM, "Split vertically and reflect bottom into top",
99         "bottom"},
100     {0, NULL, NULL},
101   };
102
103   if (!mode_type) {
104     mode_type = g_enum_register_static ("GstMirrorMode", modes);
105   }
106   return mode_type;
107 }
108
109
110 static void
111 gst_mirror_set_property (GObject * object, guint prop_id,
112     const GValue * value, GParamSpec * pspec)
113 {
114   GstMirror *filter = GST_MIRROR_CAST (object);
115
116   switch (prop_id) {
117     case PROP_MODE:
118     {
119       gint mode;
120
121       GST_OBJECT_LOCK (filter);
122       mode = g_value_get_enum (value);
123
124       if (mode != filter->mode) {
125         GstGeometricTransform *gt;
126
127         gt = GST_GEOMETRIC_TRANSFORM_CAST (object);
128         filter->mode = mode;
129         gst_geometric_transform_set_need_remap (gt);
130       }
131
132       GST_OBJECT_UNLOCK (filter);
133       break;
134     }
135     default:
136       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137       break;
138   }
139 }
140
141 static void
142 gst_mirror_get_property (GObject * object, guint prop_id,
143     GValue * value, GParamSpec * pspec)
144 {
145   GstMirror *filter = GST_MIRROR_CAST (object);
146
147   switch (prop_id) {
148     case PROP_MODE:
149       g_value_set_enum (value, filter->mode);
150       break;
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153       break;
154   }
155 }
156
157 static gboolean
158 mirror_map (GstGeometricTransform * gt, gint x, gint y, gdouble * in_x,
159     gdouble * in_y)
160 {
161   GstMirror *mirror = GST_MIRROR_CAST (gt);
162
163   gdouble hw = gt->width / 2.0 - 1.0;
164   gdouble hh = gt->height / 2.0 - 1.0;
165
166   switch (mirror->mode) {
167     case GST_MIRROR_MODE_LEFT:
168       if (x > hw)
169         *in_x = gt->width - 1.0 - x;
170       else
171         *in_x = x;
172       *in_y = y;
173       break;
174     case GST_MIRROR_MODE_RIGHT:
175       if (x > hw)
176         *in_x = x;
177       else
178         *in_x = gt->width - 1.0 - x;
179       *in_y = y;
180       break;
181     case GST_MIRROR_MODE_TOP:
182       if (y > hh)
183         *in_y = gt->height - 1.0 - y;
184       else
185         *in_y = y;
186       *in_x = x;
187       break;
188     case GST_MIRROR_MODE_BOTTOM:
189       if (y > hh)
190         *in_y = y;
191       else
192         *in_y = gt->height - 1.0 - y;
193       *in_x = x;
194       break;
195     default:
196       g_assert_not_reached ();
197   }
198
199   GST_DEBUG_OBJECT (mirror, "Inversely mapped %d %d into %lf %lf",
200       x, y, *in_x, *in_y);
201
202   return TRUE;
203 }
204
205 static void
206 gst_mirror_class_init (GstMirrorClass * klass)
207 {
208   GObjectClass *gobject_class;
209   GstElementClass *gstelement_class;
210   GstGeometricTransformClass *gstgt_class;
211
212   gobject_class = (GObjectClass *) klass;
213   gstelement_class = (GstElementClass *) klass;
214   gstgt_class = (GstGeometricTransformClass *) klass;
215
216   gst_element_class_set_static_metadata (gstelement_class,
217       "mirror",
218       "Transform/Effect/Video",
219       "Split the image into two halves and reflect one over each other",
220       "Filippo Argiolas <filippo.argiolas@gmail.com>");
221
222   gobject_class->set_property = gst_mirror_set_property;
223   gobject_class->get_property = gst_mirror_get_property;
224
225   g_object_class_install_property (gobject_class, PROP_MODE,
226       g_param_spec_enum ("mode", "Mirror Mode",
227           "How to split the video frame and which side reflect",
228           GST_TYPE_MIRROR_MODE, DEFAULT_PROP_MODE,
229           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
230
231   gstgt_class->map_func = mirror_map;
232
233   gst_type_mark_as_plugin_api (GST_TYPE_MIRROR_MODE, 0);
234 }
235
236 static void
237 gst_mirror_init (GstMirror * filter)
238 {
239   GstGeometricTransform *gt = GST_GEOMETRIC_TRANSFORM (filter);
240
241   filter->mode = DEFAULT_PROP_MODE;
242   gt->off_edge_pixels = GST_GT_OFF_EDGES_PIXELS_CLAMP;
243 }