1 /*
2  * colorspace conversion functions
3  *    -- translate RGB using lookup tables
4  *
5  *  (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
6  *
7  */
8 
9 #define NG_PRIVATE
10 #include "config.h"
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <pthread.h>
16 #include <inttypes.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 
20 #include "grab-ng.h"
21 #include "byteswap.h"
22 
23 unsigned long   ng_lut_red[256];
24 unsigned long   ng_lut_green[256];
25 unsigned long   ng_lut_blue[256];
26 
27 /* ------------------------------------------------------------------- */
28 
29 void
ng_rgb24_to_lut2(unsigned char * restrict dest,unsigned char * restrict src,int p)30 ng_rgb24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
31 		 int p)
32 {
33     uint16_t* restrict d = (uint16_t*)dest;
34 
35     while (p-- > 0) {
36 	*(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] |
37 	    ng_lut_blue[src[2]];
38 	src += 3;
39     }
40 }
41 
42 static void
bgr24_to_lut2(unsigned char * restrict dest,unsigned char * restrict src,int p)43 bgr24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
44 	      int p)
45 {
46     uint16_t* restrict d = (uint16_t*)dest;
47 
48     while (p-- > 0) {
49 	*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
50 	    ng_lut_blue[src[0]];
51 	src += 3;
52     }
53 }
54 
55 static void
rgb32_to_lut2(unsigned char * restrict dest,unsigned char * restrict src,int p)56 rgb32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
57 	      int p)
58 {
59     uint16_t* restrict d = (uint16_t*)dest;
60 
61     while (p-- > 0) {
62 	*(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] |
63 	    ng_lut_blue[src[3]];
64 	src += 4;
65     }
66 }
67 
68 static void
bgr32_to_lut2(unsigned char * restrict dest,unsigned char * restrict src,int p)69 bgr32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
70 	      int p)
71 {
72     uint16_t* restrict d = (uint16_t*)dest;
73 
74     while (p-- > 0) {
75        *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
76 	   ng_lut_blue[src[0]];
77 	src += 4;
78     }
79 }
80 
81 static void
gray_to_lut2(unsigned char * restrict dest,unsigned char * restrict src,int p)82 gray_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
83 	     int p)
84 {
85     uint16_t* restrict d = (uint16_t*)dest;
86 
87     while (p-- > 0) {
88 	*(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src];
89 	src++;
90     }
91 }
92 
93 /* ------------------------------------------------------------------- */
94 
95 void
ng_rgb24_to_lut4(unsigned char * restrict dest,unsigned char * restrict src,int p)96 ng_rgb24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
97 		 int p)
98 {
99     unsigned int* restrict d = (unsigned int*)dest;
100 
101     while (p-- > 0) {
102 	*(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] |
103 	    ng_lut_blue[src[2]];
104 	src += 3;
105     }
106 }
107 
108 static void
bgr24_to_lut4(unsigned char * restrict dest,unsigned char * restrict src,int p)109 bgr24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
110 	      int p)
111 {
112     unsigned int* restrict d = (unsigned int*)dest;
113 
114     while (p-- > 0) {
115 	*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
116 	    ng_lut_blue[src[0]];
117 	src += 3;
118     }
119 }
120 
121 static void
rgb32_to_lut4(unsigned char * restrict dest,unsigned char * restrict src,int p)122 rgb32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
123 	      int p)
124 {
125     unsigned int* restrict d = (unsigned int*)dest;
126 
127     while (p-- > 0) {
128 	*(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] |
129 	    ng_lut_blue[src[3]];
130 	src += 4;
131     }
132 }
133 
134 static void
bgr32_to_lut4(unsigned char * restrict dest,unsigned char * restrict src,int p)135 bgr32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
136 	      int p)
137 {
138     unsigned int* restrict d = (unsigned int*)dest;
139 
140     while (p-- > 0) {
141        *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
142 	   ng_lut_blue[src[0]];
143 	src += 4;
144     }
145 }
146 
147 static void
gray_to_lut4(unsigned char * restrict dest,unsigned char * restrict src,int p)148 gray_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
149 	     int p)
150 {
151     unsigned int* restrict d = (unsigned int*)dest;
152 
153     while (p-- > 0) {
154 	*(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src];
155 	src++;
156     }
157 }
158 
159 /* ------------------------------------------------------------------- */
160 
161 static struct ng_video_conv lut2_list[] = {
162     {
163 	NG_GENERIC_PACKED,
164 	.fmtid_in =	VIDEO_RGB24,
165 	.priv =		ng_rgb24_to_lut2,
166     }, {
167 	NG_GENERIC_PACKED,
168 	.fmtid_in =	VIDEO_BGR24,
169 	.priv =		bgr24_to_lut2,
170     }, {
171 	NG_GENERIC_PACKED,
172 	.fmtid_in =	VIDEO_RGB32,
173 	.priv =		rgb32_to_lut2,
174     }, {
175 	NG_GENERIC_PACKED,
176 	.fmtid_in =	VIDEO_BGR32,
177 	.priv =		bgr32_to_lut2,
178     }, {
179 	NG_GENERIC_PACKED,
180 	.fmtid_in =	VIDEO_GRAY,
181 	.priv =		gray_to_lut2,
182     }, {
183 	NG_GENERIC_PACKED,
184 	.fmtid_in =	VIDEO_YUYV,
185 	.priv =		ng_yuv422_to_lut2,
186     },{
187 	.init =		ng_conv_nop_init,
188 	.fini =		ng_conv_nop_fini,
189 	.frame =	ng_yuv422p_to_lut2,
190 	.fmtid_in =	VIDEO_YUV422P,
191     },{
192 	.init =		ng_conv_nop_init,
193 	.fini =		ng_conv_nop_fini,
194 	.frame =	ng_yuv420p_to_lut2,
195 	.fmtid_in =	VIDEO_YUV420P,
196     }
197 };
198 
199 static struct ng_video_conv lut4_list[] = {
200     {
201 	NG_GENERIC_PACKED,
202 	.fmtid_in =	VIDEO_RGB24,
203 	.priv =		ng_rgb24_to_lut4,
204     }, {
205 	NG_GENERIC_PACKED,
206 	.fmtid_in =	VIDEO_BGR24,
207 	.priv =		bgr24_to_lut4,
208     }, {
209 	NG_GENERIC_PACKED,
210 	.fmtid_in =	VIDEO_RGB32,
211 	.priv =		rgb32_to_lut4,
212     }, {
213 	NG_GENERIC_PACKED,
214 	.fmtid_in =	VIDEO_BGR32,
215 	.priv =		bgr32_to_lut4,
216     }, {
217 	NG_GENERIC_PACKED,
218 	.fmtid_in =	VIDEO_GRAY,
219 	.priv =		gray_to_lut4,
220     }, {
221 	NG_GENERIC_PACKED,
222 	.fmtid_in =	VIDEO_YUYV,
223 	.priv =		ng_yuv422_to_lut4,
224     },{
225 	.init =		ng_conv_nop_init,
226 	.fini =		ng_conv_nop_fini,
227 	.frame =	ng_yuv422p_to_lut4,
228 	.fmtid_in =	VIDEO_YUV422P,
229     },{
230 	.init =		ng_conv_nop_init,
231 	.fini =		ng_conv_nop_fini,
232 	.frame =	ng_yuv420p_to_lut4,
233 	.fmtid_in =	VIDEO_YUV420P,
234     }
235 };
236 
237 static const unsigned int nconv2 = sizeof(lut2_list)/sizeof(lut2_list[0]);
238 static const unsigned int nconv4 = sizeof(lut4_list)/sizeof(lut4_list[0]);
239 
240 void
ng_lut_init(unsigned long red_mask,unsigned long green_mask,unsigned long blue_mask,unsigned int fmtid,int swap)241 ng_lut_init(unsigned long red_mask, unsigned long green_mask,
242 	    unsigned long blue_mask, unsigned int fmtid, int swap)
243 {
244     static int      once=0;
245     int             rgb_red_bits = 0;
246     int             rgb_red_shift = 0;
247     int             rgb_green_bits = 0;
248     int             rgb_green_shift = 0;
249     int             rgb_blue_bits = 0;
250     int             rgb_blue_shift = 0;
251     unsigned int    i;
252     unsigned int    mask;
253 
254     if (once++) {
255 	fprintf(stderr,"panic: ng_lut_init called twice\n");
256 	exit(1);
257     }
258 
259     for (i = 0; i < 32; i++) {
260 	mask = (1 << i);
261 	if (red_mask & mask)
262 	    rgb_red_bits++;
263 	else if (!rgb_red_bits)
264 	    rgb_red_shift++;
265 	if (green_mask & mask)
266 	    rgb_green_bits++;
267 	else if (!rgb_green_bits)
268 	    rgb_green_shift++;
269 	if (blue_mask & mask)
270 	    rgb_blue_bits++;
271 	else if (!rgb_blue_bits)
272 	    rgb_blue_shift++;
273     }
274 #if 0
275     printf("color: bits shift\n");
276     printf("red  : %04i %05i\n", rgb_red_bits, rgb_red_shift);
277     printf("green: %04i %05i\n", rgb_green_bits, rgb_green_shift);
278     printf("blue : %04i %05i\n", rgb_blue_bits, rgb_blue_shift);
279 #endif
280 
281     if (rgb_red_bits > 8)
282 	for (i = 0; i < 256; i++)
283 	    ng_lut_red[i] = (i << (rgb_red_bits + rgb_red_shift - 8));
284     else
285 	for (i = 0; i < 256; i++)
286 	    ng_lut_red[i] = (i >> (8 - rgb_red_bits)) << rgb_red_shift;
287 
288     if (rgb_green_bits > 8)
289 	for (i = 0; i < 256; i++)
290 	    ng_lut_green[i] = (i << (rgb_green_bits + rgb_green_shift - 8));
291     else
292 	for (i = 0; i < 256; i++)
293 	    ng_lut_green[i] = (i >> (8 - rgb_green_bits)) << rgb_green_shift;
294 
295     if (rgb_blue_bits > 8)
296 	for (i = 0; i < 256; i++)
297 	    ng_lut_blue[i] = (i << (rgb_blue_bits + rgb_blue_shift - 8));
298     else
299 	for (i = 0; i < 256; i++)
300 	    ng_lut_blue[i] = (i >> (8 - rgb_blue_bits)) << rgb_blue_shift;
301 
302     switch (ng_vfmt_to_depth[fmtid]) {
303     case 16:
304 	if (swap) {
305 	    for (i = 0; i < 256; i++) {
306 		ng_lut_red[i] = SWAP2(ng_lut_red[i]);
307 		ng_lut_green[i] = SWAP2(ng_lut_green[i]);
308 		ng_lut_blue[i] = SWAP2(ng_lut_blue[i]);
309 	    }
310 	}
311 	for (i = 0; i < nconv2; i++)
312 	    lut2_list[i].fmtid_out = fmtid;
313 	ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut2_list,nconv2);
314 	break;
315     case 32:
316 	if (swap) {
317 	    for (i = 0; i < 256; i++) {
318 		ng_lut_red[i] = SWAP4(ng_lut_red[i]);
319 		ng_lut_green[i] = SWAP4(ng_lut_green[i]);
320 		ng_lut_blue[i] = SWAP4(ng_lut_blue[i]);
321 	    }
322 	}
323 	for (i = 0; i < nconv4; i++)
324 	    lut4_list[i].fmtid_out = fmtid;
325 	ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut4_list,nconv4);
326 	break;
327     }
328 }
329