1 /*
2 # (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
3 # (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
4 # (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as published by
8 # the Free Software Foundation; either version 2.1 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
19 */
20
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include "libv4lprocessing.h"
27 #include "libv4lprocessing-priv.h"
28 #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
29
30 #define CLIP256(color) (((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color)))
31 #define CLIP(color, min, max) (((color) > (max)) ? (max) : (((color) < (min)) ? (min) : (color)))
32
whitebalance_active(struct v4lprocessing_data * data)33 static int whitebalance_active(struct v4lprocessing_data *data)
34 {
35 int wb;
36
37 wb = v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
38 if (!wb) {
39 /* Reset cached color averages */
40 data->green_avg = 0;
41 }
42
43 return wb;
44 }
45
whitebalance_calculate_lookup_tables_generic(struct v4lprocessing_data * data,int green_avg,int comp1_avg,int comp2_avg)46 static int whitebalance_calculate_lookup_tables_generic(
47 struct v4lprocessing_data *data, int green_avg, int comp1_avg, int comp2_avg)
48 {
49 int i, avg_avg;
50 const int threshold = 64;
51 const int max_step = 128;
52
53 /* Clip averages (restricts maximum white balance correction) */
54 green_avg = CLIP(green_avg, 512, 3072);
55 comp1_avg = CLIP(comp1_avg, 512, 3072);
56 comp2_avg = CLIP(comp2_avg, 512, 3072);
57
58 /* First frame ? */
59 if (data->green_avg == 0) {
60 data->green_avg = green_avg;
61 data->comp1_avg = comp1_avg;
62 data->comp2_avg = comp2_avg;
63 } else {
64 /* Slowly adjust the averages used for the correction, so that
65 we do not get a sudden change in colors */
66 int throttling = 0;
67
68 if (abs(data->green_avg - green_avg) > max_step) {
69 if (data->green_avg < green_avg)
70 data->green_avg += max_step;
71 else
72 data->green_avg -= max_step;
73 throttling = 1;
74 } else
75 data->green_avg = green_avg;
76
77 if (abs(data->comp1_avg - comp1_avg) > max_step) {
78 if (data->comp1_avg < comp1_avg)
79 data->comp1_avg += max_step;
80 else
81 data->comp1_avg -= max_step;
82 throttling = 1;
83 } else
84 data->comp1_avg = comp1_avg;
85
86 if (abs(data->comp2_avg - comp2_avg) > max_step) {
87 if (data->comp2_avg < comp2_avg)
88 data->comp2_avg += max_step;
89 else
90 data->comp2_avg -= max_step;
91 throttling = 1;
92 } else
93 data->comp2_avg = comp2_avg;
94
95 /*
96 * If we are still converging to a stable update situation,
97 * re-calc the lookup tables next frame, but only if no
98 * other processing plugin has already asked for a shorter
99 * update cycle, as asking for an update each frame while
100 * some other pluging is trying to adjust hw settings is bad.
101 */
102 if (throttling && data->lookup_table_update_counter == 0)
103 data->lookup_table_update_counter =
104 V4L2PROCESSING_UPDATE_RATE;
105 }
106
107 if (abs(data->green_avg - data->comp1_avg) < threshold &&
108 abs(data->green_avg - data->comp2_avg) < threshold &&
109 abs(data->comp1_avg - data->comp2_avg) < threshold)
110 return 0;
111
112 avg_avg = (data->green_avg + data->comp1_avg + data->comp2_avg) / 3;
113
114 for (i = 0; i < 256; i++) {
115 data->comp1[i] = CLIP256(data->comp1[i] * avg_avg / data->comp1_avg);
116 data->green[i] = CLIP256(data->green[i] * avg_avg / data->green_avg);
117 data->comp2[i] = CLIP256(data->comp2[i] * avg_avg / data->comp2_avg);
118 }
119
120 return 1;
121 }
122
whitebalance_calculate_lookup_tables_bayer(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt,int starts_with_green)123 static int whitebalance_calculate_lookup_tables_bayer(
124 struct v4lprocessing_data *data, unsigned char *buf,
125 const struct v4l2_format *fmt, int starts_with_green)
126 {
127 int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0;
128 int green_avg, comp1_avg, comp2_avg;
129
130 for (y = 0; y < fmt->fmt.pix.height; y += 2) {
131 for (x = 0; x < fmt->fmt.pix.width; x += 2) {
132 a1 += *buf++;
133 a2 += *buf++;
134 }
135 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
136 for (x = 0; x < fmt->fmt.pix.width; x += 2) {
137 b1 += *buf++;
138 b2 += *buf++;
139 }
140 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
141 }
142
143 if (starts_with_green) {
144 green_avg = a1 / 2 + b2 / 2;
145 comp1_avg = a2;
146 comp2_avg = b1;
147 } else {
148 green_avg = a2 / 2 + b1 / 2;
149 comp1_avg = a1;
150 comp2_avg = b2;
151 }
152
153 /* Norm avg to ~ 0 - 4095 */
154 green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
155 comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
156 comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
157
158 return whitebalance_calculate_lookup_tables_generic(data, green_avg,
159 comp1_avg, comp2_avg);
160 }
161
whitebalance_calculate_lookup_tables_rgb(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt)162 static int whitebalance_calculate_lookup_tables_rgb(
163 struct v4lprocessing_data *data, unsigned char *buf,
164 const struct v4l2_format *fmt)
165 {
166 int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0;
167
168 for (y = 0; y < fmt->fmt.pix.height; y++) {
169 for (x = 0; x < fmt->fmt.pix.width; x++) {
170 comp1_avg += *buf++;
171 green_avg += *buf++;
172 comp2_avg += *buf++;
173 }
174 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3;
175 }
176
177 /* Norm avg to ~ 0 - 4095 */
178 green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
179 comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
180 comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
181
182 return whitebalance_calculate_lookup_tables_generic(data, green_avg,
183 comp1_avg, comp2_avg);
184 }
185
186
whitebalance_calculate_lookup_tables(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt)187 static int whitebalance_calculate_lookup_tables(
188 struct v4lprocessing_data *data,
189 unsigned char *buf, const struct v4l2_format *fmt)
190 {
191 switch (fmt->fmt.pix.pixelformat) {
192 case V4L2_PIX_FMT_SGBRG8:
193 case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
194 return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1);
195
196 case V4L2_PIX_FMT_SBGGR8:
197 case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
198 return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0);
199
200 case V4L2_PIX_FMT_RGB24:
201 case V4L2_PIX_FMT_BGR24:
202 return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt);
203 }
204
205 return 0; /* Should never happen */
206 }
207
208 struct v4lprocessing_filter whitebalance_filter = {
209 whitebalance_active, whitebalance_calculate_lookup_tables
210 };
211