Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / videofilters / gstzebrastripe.c
1 /* GStreamer
2  * Copyright (C) 2011 David Schleef <ds@entropywave.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19 /**
20  * SECTION:element-gstzebrastripe
21  *
22  * The zebrastripe element marks areas of images in a video stream
23  * that are brighter than a threshold with a diagonal zebra stripe
24  * pattern.  Typically, this is used to aid in adjusting the exposure
25  * setting on the camera.  Setting the threshold to 95 or 100 will
26  * show areas that are completely overexposed and clipping.  A
27  * threshold setting of 70 is often used to properly adjust skin
28  * tones.
29  *
30  * <refsect2>
31  * <title>Example launch line</title>
32  * |[
33  * gst-launch -v videotestsrc ! zebrastripe ! xvimagesink
34  * ]|
35  * Marks overexposed areas of the video with zebra stripes.
36  *
37  * The threshold property is expressed as percentage of full scale,
38  * whereas common usage expresses thresholds in terms of IRE.  The
39  * property setting can be calculated from IRE by using the formula
40  * percent = (IRE * 1.075) - 7.5.  Note that 100 IRE corresponds to
41  * 100 %, and 70 IRE corresponds to 68 %.
42  * </refsect2>
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <gst/gst.h>
50 #include <gst/base/gstbasetransform.h>
51 #include <gst/video/video.h>
52 #include <math.h>
53 #include "gstzebrastripe.h"
54
55 GST_DEBUG_CATEGORY_STATIC (gst_zebra_stripe_debug_category);
56 #define GST_CAT_DEFAULT gst_zebra_stripe_debug_category
57
58 /* prototypes */
59
60
61 static void gst_zebra_stripe_set_property (GObject * object,
62     guint property_id, const GValue * value, GParamSpec * pspec);
63 static void gst_zebra_stripe_get_property (GObject * object,
64     guint property_id, GValue * value, GParamSpec * pspec);
65 static void gst_zebra_stripe_finalize (GObject * object);
66
67 static gboolean gst_zebra_stripe_start (GstBaseTransform * trans);
68 static gboolean gst_zebra_stripe_stop (GstBaseTransform * trans);
69
70 static GstFlowReturn
71 gst_zebra_stripe_prefilter (GstVideoFilter2 * videofilter2, GstBuffer * buf);
72
73 static GstVideoFilter2Functions gst_zebra_stripe_filter_functions[];
74
75 enum
76 {
77   PROP_0,
78   PROP_THRESHOLD
79 };
80
81 #define DEFAULT_THRESHOLD 90
82
83 /* class initialization */
84
85 #define DEBUG_INIT(bla) \
86   GST_DEBUG_CATEGORY_INIT (gst_zebra_stripe_debug_category, "zebrastripe", 0, \
87       "debug category for zebrastripe element");
88
89 GST_BOILERPLATE_FULL (GstZebraStripe, gst_zebra_stripe, GstVideoFilter2,
90     GST_TYPE_VIDEO_FILTER2, DEBUG_INIT);
91
92 static void
93 gst_zebra_stripe_base_init (gpointer g_class)
94 {
95   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
96
97   gst_element_class_set_details_simple (element_class, "Zebra stripe overlay",
98       "Filter/Analysis",
99       "Overlays zebra striping on overexposed areas of video",
100       "David Schleef <ds@entropywave.com>");
101 }
102
103 static void
104 gst_zebra_stripe_class_init (GstZebraStripeClass * klass)
105 {
106   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
107   GstVideoFilter2Class *video_filter2_class = GST_VIDEO_FILTER2_CLASS (klass);
108   GstBaseTransformClass *base_transform_class =
109       GST_BASE_TRANSFORM_CLASS (klass);
110
111   gobject_class->set_property = gst_zebra_stripe_set_property;
112   gobject_class->get_property = gst_zebra_stripe_get_property;
113   gobject_class->finalize = gst_zebra_stripe_finalize;
114   base_transform_class->start = GST_DEBUG_FUNCPTR (gst_zebra_stripe_start);
115   base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_zebra_stripe_stop);
116
117   video_filter2_class->prefilter =
118       GST_DEBUG_FUNCPTR (gst_zebra_stripe_prefilter);
119
120   g_object_class_install_property (gobject_class, PROP_THRESHOLD,
121       g_param_spec_int ("threshold", "Threshold",
122           "Threshold above which the video is striped", 0, 100,
123           DEFAULT_THRESHOLD,
124           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
125
126   gst_video_filter2_class_add_functions (video_filter2_class,
127       gst_zebra_stripe_filter_functions);
128 }
129
130 static void
131 gst_zebra_stripe_init (GstZebraStripe * zebrastripe,
132     GstZebraStripeClass * zebrastripe_class)
133 {
134
135 }
136
137 void
138 gst_zebra_stripe_set_property (GObject * object, guint property_id,
139     const GValue * value, GParamSpec * pspec)
140 {
141   GstZebraStripe *zebrastripe;
142
143   g_return_if_fail (GST_IS_ZEBRA_STRIPE (object));
144   zebrastripe = GST_ZEBRA_STRIPE (object);
145
146   switch (property_id) {
147     case PROP_THRESHOLD:
148       zebrastripe->threshold = g_value_get_int (value);
149       zebrastripe->y_threshold =
150           16 + floor (0.5 + 2.19 * zebrastripe->threshold);
151       break;
152     default:
153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154       break;
155   }
156 }
157
158 void
159 gst_zebra_stripe_get_property (GObject * object, guint property_id,
160     GValue * value, GParamSpec * pspec)
161 {
162   GstZebraStripe *zebrastripe;
163
164   g_return_if_fail (GST_IS_ZEBRA_STRIPE (object));
165   zebrastripe = GST_ZEBRA_STRIPE (object);
166
167   switch (property_id) {
168     case PROP_THRESHOLD:
169       g_value_set_int (value, zebrastripe->threshold);
170       break;
171     default:
172       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
173       break;
174   }
175 }
176
177 void
178 gst_zebra_stripe_finalize (GObject * object)
179 {
180   g_return_if_fail (GST_IS_ZEBRA_STRIPE (object));
181
182   /* clean up object here */
183
184   G_OBJECT_CLASS (parent_class)->finalize (object);
185 }
186
187
188 static gboolean
189 gst_zebra_stripe_start (GstBaseTransform * trans)
190 {
191
192   return TRUE;
193 }
194
195 static gboolean
196 gst_zebra_stripe_stop (GstBaseTransform * trans)
197 {
198
199   return TRUE;
200 }
201
202 static GstFlowReturn
203 gst_zebra_stripe_prefilter (GstVideoFilter2 * videofilter2, GstBuffer * buf)
204 {
205   GstZebraStripe *zebrastripe = GST_ZEBRA_STRIPE (videofilter2);
206
207   zebrastripe->t++;
208
209   return GST_FLOW_OK;
210 }
211
212 static GstFlowReturn
213 gst_zebra_stripe_filter_ip_planarY (GstVideoFilter2 * videofilter2,
214     GstBuffer * buf, int start, int end)
215 {
216   GstZebraStripe *zebrastripe = GST_ZEBRA_STRIPE (videofilter2);
217   int width = GST_VIDEO_FILTER2_WIDTH (zebrastripe);
218   int i, j;
219   int threshold = zebrastripe->y_threshold;
220   int t = zebrastripe->t;
221   guint8 *ydata;
222   int ystride;
223
224   ydata = GST_BUFFER_DATA (buf);
225   ystride =
226       gst_video_format_get_row_stride (GST_VIDEO_FILTER2_FORMAT (videofilter2),
227       0, width);
228
229   for (j = start; j < end; j++) {
230     guint8 *data = ydata + ystride * j;
231     for (i = 0; i < width; i++) {
232       if (data[i] >= threshold) {
233         if ((i + j + t) & 0x4)
234           data[i] = 16;
235       }
236     }
237   }
238   return GST_FLOW_OK;
239 }
240
241 static GstFlowReturn
242 gst_zebra_stripe_filter_ip_YxYy (GstVideoFilter2 * videofilter2,
243     GstBuffer * buf, int start, int end)
244 {
245   GstZebraStripe *zebrastripe = GST_ZEBRA_STRIPE (videofilter2);
246   GstVideoFormat format = GST_VIDEO_FILTER2_FORMAT (zebrastripe);
247   int width = GST_VIDEO_FILTER2_WIDTH (zebrastripe);
248   int i, j;
249   int threshold = zebrastripe->y_threshold;
250   int t = zebrastripe->t;
251   guint8 *ydata;
252   int ystride;
253
254   ydata = GST_BUFFER_DATA (buf);
255   ystride = gst_video_format_get_row_stride (format, 0, width);
256
257   if (format == GST_VIDEO_FORMAT_UYVY) {
258     ydata++;
259   }
260
261   for (j = start; j < end; j++) {
262     guint8 *data = ydata + ystride * j;
263     for (i = 0; i < width; i++) {
264       if (data[2 * i] >= threshold) {
265         if ((i + j + t) & 0x4)
266           data[2 * i] = 16;
267       }
268     }
269   }
270   return GST_FLOW_OK;
271 }
272
273 static GstFlowReturn
274 gst_zebra_stripe_filter_ip_AYUV (GstVideoFilter2 * videofilter2,
275     GstBuffer * buf, int start, int end)
276 {
277   GstZebraStripe *zebrastripe = GST_ZEBRA_STRIPE (videofilter2);
278   int width = GST_VIDEO_FILTER2_WIDTH (zebrastripe);
279   int i, j;
280   int threshold = zebrastripe->y_threshold;
281   int t = zebrastripe->t;
282   guint8 *ydata;
283   int ystride;
284
285   ydata = GST_BUFFER_DATA (buf);
286   ystride =
287       gst_video_format_get_row_stride (GST_VIDEO_FILTER2_FORMAT (videofilter2),
288       0, width);
289
290   ydata++;
291   for (j = start; j < end; j++) {
292     guint8 *data = ydata + ystride * j;
293     for (i = 0; i < width; i++) {
294       if (data[4 * i] >= threshold) {
295         if ((i + j + t) & 0x4)
296           data[4 * i] = 16;
297       }
298     }
299   }
300
301   return GST_FLOW_OK;
302 }
303
304 static GstVideoFilter2Functions gst_zebra_stripe_filter_functions[] = {
305   {GST_VIDEO_FORMAT_I420, NULL, gst_zebra_stripe_filter_ip_planarY},
306   {GST_VIDEO_FORMAT_YV12, NULL, gst_zebra_stripe_filter_ip_planarY},
307   {GST_VIDEO_FORMAT_Y41B, NULL, gst_zebra_stripe_filter_ip_planarY},
308   {GST_VIDEO_FORMAT_Y42B, NULL, gst_zebra_stripe_filter_ip_planarY},
309   {GST_VIDEO_FORMAT_NV12, NULL, gst_zebra_stripe_filter_ip_planarY},
310   {GST_VIDEO_FORMAT_NV21, NULL, gst_zebra_stripe_filter_ip_planarY},
311   {GST_VIDEO_FORMAT_YUV9, NULL, gst_zebra_stripe_filter_ip_planarY},
312   {GST_VIDEO_FORMAT_YVU9, NULL, gst_zebra_stripe_filter_ip_planarY},
313   {GST_VIDEO_FORMAT_Y444, NULL, gst_zebra_stripe_filter_ip_planarY},
314   {GST_VIDEO_FORMAT_UYVY, NULL, gst_zebra_stripe_filter_ip_YxYy},
315   {GST_VIDEO_FORMAT_YUY2, NULL, gst_zebra_stripe_filter_ip_YxYy},
316   {GST_VIDEO_FORMAT_YVYU, NULL, gst_zebra_stripe_filter_ip_YxYy},
317   {GST_VIDEO_FORMAT_AYUV, NULL, gst_zebra_stripe_filter_ip_AYUV},
318   {GST_VIDEO_FORMAT_UNKNOWN}
319 };