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 static const struct v4lprocessing_filter *filters[] = {
31 &whitebalance_filter,
32 &autogain_filter,
33 &gamma_filter,
34 };
35
v4lprocessing_create(int fd,struct v4lcontrol_data * control)36 struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *control)
37 {
38 struct v4lprocessing_data *data =
39 calloc(1, sizeof(struct v4lprocessing_data));
40
41 if (!data) {
42 fprintf(stderr, "libv4lprocessing: error: out of memory!\n");
43 return NULL;
44 }
45
46 data->fd = fd;
47 data->control = control;
48
49 return data;
50 }
51
v4lprocessing_destroy(struct v4lprocessing_data * data)52 void v4lprocessing_destroy(struct v4lprocessing_data *data)
53 {
54 free(data);
55 }
56
v4lprocessing_pre_processing(struct v4lprocessing_data * data)57 int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
58 {
59 int i;
60
61 data->do_process = 0;
62 for (i = 0; i < ARRAY_SIZE(filters); i++) {
63 if (filters[i]->active(data))
64 data->do_process = 1;
65 }
66
67 data->controls_changed |= v4lcontrol_controls_changed(data->control);
68
69 return data->do_process;
70 }
71
v4lprocessing_update_lookup_tables(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt)72 static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
73 unsigned char *buf, const struct v4l2_format *fmt)
74 {
75 int i;
76
77 for (i = 0; i < 256; i++) {
78 data->comp1[i] = i;
79 data->green[i] = i;
80 data->comp2[i] = i;
81 }
82
83 data->lookup_table_active = 0;
84 for (i = 0; i < ARRAY_SIZE(filters); i++) {
85 if (filters[i]->active(data)) {
86 if (filters[i]->calculate_lookup_tables(data, buf, fmt))
87 data->lookup_table_active = 1;
88 }
89 }
90 }
91
v4lprocessing_do_processing(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt)92 static void v4lprocessing_do_processing(struct v4lprocessing_data *data,
93 unsigned char *buf, const struct v4l2_format *fmt)
94 {
95 int x, y;
96
97 switch (fmt->fmt.pix.pixelformat) {
98 case V4L2_PIX_FMT_SGBRG8:
99 case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
100 for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
101 for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
102 *buf = data->green[*buf];
103 buf++;
104 *buf = data->comp1[*buf];
105 buf++;
106 }
107 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
108 for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
109 *buf = data->comp2[*buf];
110 buf++;
111 *buf = data->green[*buf];
112 buf++;
113 }
114 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
115 }
116 break;
117
118 case V4L2_PIX_FMT_SBGGR8:
119 case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
120 for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
121 for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
122 *buf = data->comp1[*buf];
123 buf++;
124 *buf = data->green[*buf];
125 buf++;
126 }
127 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
128 for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
129 *buf = data->green[*buf];
130 buf++;
131 *buf = data->comp2[*buf];
132 buf++;
133 }
134 buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
135 }
136 break;
137
138 case V4L2_PIX_FMT_RGB24:
139 case V4L2_PIX_FMT_BGR24:
140 for (y = 0; y < fmt->fmt.pix.height; y++) {
141 for (x = 0; x < fmt->fmt.pix.width; x++) {
142 *buf = data->comp1[*buf];
143 buf++;
144 *buf = data->green[*buf];
145 buf++;
146 *buf = data->comp2[*buf];
147 buf++;
148 }
149 buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width;
150 }
151 break;
152 }
153 }
154
v4lprocessing_processing(struct v4lprocessing_data * data,unsigned char * buf,const struct v4l2_format * fmt)155 void v4lprocessing_processing(struct v4lprocessing_data *data,
156 unsigned char *buf, const struct v4l2_format *fmt)
157 {
158 if (!data->do_process)
159 return;
160
161 /* Do we support the current pixformat? */
162 switch (fmt->fmt.pix.pixelformat) {
163 case V4L2_PIX_FMT_SGBRG8:
164 case V4L2_PIX_FMT_SGRBG8:
165 case V4L2_PIX_FMT_SBGGR8:
166 case V4L2_PIX_FMT_SRGGB8:
167 case V4L2_PIX_FMT_RGB24:
168 case V4L2_PIX_FMT_BGR24:
169 break;
170 default:
171 return; /* Non supported pix format */
172 }
173
174 if (data->controls_changed ||
175 data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) {
176 data->controls_changed = 0;
177 data->lookup_table_update_counter = 0;
178 /* Do this after resetting lookup_table_update_counter so that filters can
179 force the next update to be sooner when they changed camera settings */
180 v4lprocessing_update_lookup_tables(data, buf, fmt);
181 } else
182 data->lookup_table_update_counter++;
183
184 if (data->lookup_table_active)
185 v4lprocessing_do_processing(data, buf, fmt);
186
187 data->do_process = 0;
188 }
189