• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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