1 /*
2  * colorspace conversion functions
3  *    -- yuv to rgb colorspace conversions
4  *
5  * (c) 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 <sys/time.h>
17 #include <sys/types.h>
18 
19 #include "grab-ng.h"
20 
21 /* ------------------------------------------------------------------- */
22 
23 #define CLIP         320
24 
25 #if 0
26 # define RED_NULL    137
27 # define BLUE_NULL   156
28 # define LUN_MUL     360
29 # define RED_MUL     512
30 # define BLUE_MUL    512
31 #else
32 # define RED_NULL    128
33 # define BLUE_NULL   128
34 # define LUN_MUL     256
35 # define RED_MUL     512
36 # define BLUE_MUL    512
37 #endif
38 
39 #define GREEN1_MUL  (-RED_MUL/2)
40 #define GREEN2_MUL  (-BLUE_MUL/6)
41 #define RED_ADD     (-RED_NULL  * RED_MUL)
42 #define BLUE_ADD    (-BLUE_NULL * BLUE_MUL)
43 #define GREEN1_ADD  (-RED_ADD/2)
44 #define GREEN2_ADD  (-BLUE_ADD/6)
45 
46 /* lookup tables */
47 static unsigned int  ng_yuv_gray[256];
48 static unsigned int  ng_yuv_red[256];
49 static unsigned int  ng_yuv_blue[256];
50 static unsigned int  ng_yuv_g1[256];
51 static unsigned int  ng_yuv_g2[256];
52 static unsigned int  ng_clip[256 + 2 * CLIP];
53 
54 #define GRAY(val)		ng_yuv_gray[val]
55 #define RED(gray,red)		ng_clip[ CLIP + gray + ng_yuv_red[red] ]
56 #define GREEN(gray,red,blue)	ng_clip[ CLIP + gray + ng_yuv_g1[red] +	\
57 						       ng_yuv_g2[blue] ]
58 #define BLUE(gray,blue)		ng_clip[ CLIP + gray + ng_yuv_blue[blue] ]
59 
60 /* ------------------------------------------------------------------- */
61 /* packed pixel yuv to gray / rgb                                      */
62 
63 static void
yuv422_to_gray(unsigned char * restrict dest,unsigned char * restrict s,int p)64 yuv422_to_gray(unsigned char* restrict dest, unsigned char* restrict s,
65 	       int p)
66 {
67     unsigned char* restrict d = dest;
68 
69     while (p) {
70 	d[0] = GRAY(s[0]);
71 	p--;
72 	d++;
73 	s+=2;
74     }
75 }
76 
77 static void
yuv422_to_rgb24(unsigned char * restrict dest,unsigned char * restrict s,int p)78 yuv422_to_rgb24(unsigned char* restrict dest, unsigned char* restrict s,
79 		int p)
80 {
81     unsigned char* restrict d = dest;
82     int gray;
83 
84     while (p) {
85 	gray = GRAY(s[0]);
86 	d[0] = RED(gray,s[3]);
87 	d[1] = GREEN(gray,s[3],s[1]);
88 	d[2] = BLUE(gray,s[1]);
89 	gray = GRAY(s[2]);
90 	d[3] = RED(gray,s[3]);
91 	d[4] = GREEN(gray,s[3],s[1]);
92 	d[5] = BLUE(gray,s[1]);
93 	d += 6;
94 	s += 4;
95 	p -= 2;
96     }
97 }
98 
99 void
ng_yuv422_to_lut2(unsigned char * restrict dest,unsigned char * restrict s,int p)100 ng_yuv422_to_lut2(unsigned char* restrict dest, unsigned char* restrict s,
101 		  int p)
102 {
103     unsigned short* restrict d = (unsigned short*)dest;
104     int gray;
105 
106     while (p) {
107 	gray   = GRAY(s[0]);
108 	*(d++) =
109 	    ng_lut_red[RED(gray,s[3])] |
110 	    ng_lut_green[GREEN(gray,s[3],s[1])] |
111 	    ng_lut_blue[BLUE(gray,s[1])];
112 	gray   = GRAY(s[2]);
113 	*(d++) =
114 	    ng_lut_red[RED(gray,s[3])] |
115 	    ng_lut_green[GREEN(gray,s[3],s[1])] |
116 	    ng_lut_blue[BLUE(gray,s[1])];
117 	s += 4;
118 	p -= 2;
119     }
120 }
121 
122 void
ng_yuv422_to_lut4(unsigned char * restrict dest,unsigned char * restrict s,int p)123 ng_yuv422_to_lut4(unsigned char* restrict dest, unsigned char* restrict s,
124 		  int p)
125 {
126     unsigned int* restrict d = (unsigned int*)dest;
127     int gray;
128 
129     while (p) {
130 	gray   = GRAY(s[0]);
131 	*(d++) =
132 	    ng_lut_red[RED(gray,s[3])] |
133 	    ng_lut_green[GREEN(gray,s[3],s[1])] |
134 	    ng_lut_blue[BLUE(gray,s[1])];
135 	gray   = GRAY(s[2]);
136 	*(d++) =
137 	    ng_lut_red[RED(gray,s[3])] |
138 	    ng_lut_green[GREEN(gray,s[3],s[1])] |
139 	    ng_lut_blue[BLUE(gray,s[1])];
140 	s += 4;
141 	p -= 2;
142     }
143 }
144 
145 /* ------------------------------------------------------------------- */
146 /* planar yuv to gray / rgb                                            */
147 
148 static void
yuv42xp_to_gray(void * h,struct ng_video_buf * out,struct ng_video_buf * in)149 yuv42xp_to_gray(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
150 {
151     unsigned char* restrict y;
152     unsigned char* restrict d;
153     unsigned char* dp;
154     unsigned int i,j;
155 
156     dp = out->data;
157     y  = in->data;
158 
159     for (i = 0; i < in->fmt.height; i++) {
160 	d = dp;
161 	for (j = 0; j < in->fmt.width; j++) {
162 	    *d = GRAY(*y);
163 	    d++,y++;
164 	}
165 	dp += out->fmt.bytesperline;
166     }
167 }
168 
169 static void
yuv420p_to_rgb24(void * h,struct ng_video_buf * out,struct ng_video_buf * in)170 yuv420p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
171 {
172     unsigned char *restrict y, *restrict u, *restrict v, *restrict d;
173     unsigned char *us,*vs;
174     unsigned char *dp;
175     unsigned int i,j;
176     int gray;
177 
178     dp = out->data;
179     y  = in->data;
180     u  = y + in->fmt.width * in->fmt.height;
181     v  = u + in->fmt.width * in->fmt.height / 4;
182 
183     for (i = 0; i < in->fmt.height; i++) {
184 	d = dp;
185 	us = u; vs = v;
186 	for (j = 0; j < in->fmt.width; j+= 2) {
187 	    gray   = GRAY(*y);
188 	    *(d++) = RED(gray,*v);
189 	    *(d++) = GREEN(gray,*v,*u);
190 	    *(d++) = BLUE(gray,*u);
191 	    y++;
192 	    gray   = GRAY(*y);
193 	    *(d++) = RED(gray,*v);
194 	    *(d++) = GREEN(gray,*v,*u);
195 	    *(d++) = BLUE(gray,*u);
196 	    y++; u++; v++;
197 	}
198 	if (0 == (i % 2)) {
199 	    u = us; v = vs;
200 	}
201 	dp += out->fmt.bytesperline;
202     }
203 }
204 
205 static void
yuv422p_to_rgb24(void * h,struct ng_video_buf * out,struct ng_video_buf * in)206 yuv422p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
207 {
208     unsigned char *restrict y, *restrict u, *restrict v, *restrict d;
209     unsigned char *dp;
210     unsigned int i,j;
211     int gray;
212 
213     dp = out->data;
214     y  = in->data;
215     u  = y + in->fmt.width * in->fmt.height;
216     v  = u + in->fmt.width * in->fmt.height / 2;
217 
218     for (i = 0; i < in->fmt.height; i++) {
219 	d = dp;
220 	for (j = 0; j < in->fmt.width; j+= 2) {
221 	    gray   = GRAY(*y);
222 	    *(d++) = RED(gray,*v);
223 	    *(d++) = GREEN(gray,*v,*u);
224 	    *(d++) = BLUE(gray,*u);
225 	    y++;
226 	    gray   = GRAY(*y);
227 	    *(d++) = RED(gray,*v);
228 	    *(d++) = GREEN(gray,*v,*u);
229 	    *(d++) = BLUE(gray,*u);
230 	    y++; u++; v++;
231 	}
232 	dp += out->fmt.bytesperline;
233     }
234 }
235 
236 void
ng_yuv420p_to_lut2(void * h,struct ng_video_buf * out,struct ng_video_buf * in)237 ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
238 {
239     unsigned char *restrict y, *restrict u, *restrict v;
240     unsigned char *us,*vs;
241     unsigned char *dp;
242     unsigned short *restrict d;
243     unsigned int i,j;
244     int gray;
245 
246     dp = out->data;
247     y  = in->data;
248     u  = y + in->fmt.width * in->fmt.height;
249     v  = u + in->fmt.width * in->fmt.height / 4;
250 
251     for (i = 0; i < in->fmt.height; i++) {
252 	d = (unsigned short*) dp;
253 	us = u; vs = v;
254 	for (j = 0; j < in->fmt.width; j+= 2) {
255 	    gray   = GRAY(*y);
256 	    *(d++) =
257 		ng_lut_red[RED(gray,*v)] |
258 		ng_lut_green[GREEN(gray,*v,*u)] |
259 		ng_lut_blue[BLUE(gray,*u)];
260 	    y++;
261 	    gray   = GRAY(*y);
262 	    *(d++) =
263 		ng_lut_red[RED(gray,*v)] |
264 		ng_lut_green[GREEN(gray,*v,*u)] |
265 		ng_lut_blue[BLUE(gray,*u)];
266 	    y++; u++; v++;
267 	}
268 	if (0 == (i % 2)) {
269 	    u = us; v = vs;
270 	}
271 	dp += out->fmt.bytesperline;
272     }
273 }
274 
275 void
ng_yuv422p_to_lut2(void * h,struct ng_video_buf * out,struct ng_video_buf * in)276 ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
277 {
278     unsigned char *restrict y, *restrict u, *restrict v;
279     unsigned char *dp;
280     unsigned short *restrict d;
281     unsigned int i,j;
282     int gray;
283 
284     dp = out->data;
285     y  = in->data;
286     u  = y + in->fmt.width * in->fmt.height;
287     v  = u + in->fmt.width * in->fmt.height / 2;
288 
289     for (i = 0; i < in->fmt.height; i++) {
290 	d = (unsigned short*) dp;
291 	for (j = 0; j < in->fmt.width; j+= 2) {
292 	    gray   = GRAY(*y);
293 	    *(d++) =
294 		ng_lut_red[RED(gray,*v)] |
295 		ng_lut_green[GREEN(gray,*v,*u)] |
296 		ng_lut_blue[BLUE(gray,*u)];
297 	    y++;
298 	    gray   = GRAY(*y);
299 	    *(d++) =
300 		ng_lut_red[RED(gray,*v)] |
301 		ng_lut_green[GREEN(gray,*v,*u)] |
302 		ng_lut_blue[BLUE(gray,*u)];
303 	    y++; u++; v++;
304 	}
305 	dp += out->fmt.bytesperline;
306     }
307 }
308 
309 void
ng_yuv420p_to_lut4(void * h,struct ng_video_buf * out,struct ng_video_buf * in)310 ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
311 {
312     unsigned char *restrict y, *restrict u, *restrict v;
313     unsigned char *us,*vs;
314     unsigned char *dp;
315     unsigned int  *restrict d;
316     unsigned int i,j;
317     int gray;
318 
319     dp = out->data;
320     y  = in->data;
321     u  = y + in->fmt.width * in->fmt.height;
322     v  = u + in->fmt.width * in->fmt.height / 4;
323 
324     for (i = 0; i < in->fmt.height; i++) {
325 	d = (unsigned int*) dp;
326 	us = u; vs = v;
327 	for (j = 0; j < in->fmt.width; j+= 2) {
328 	    gray   = GRAY(*y);
329 	    *(d++) =
330 		ng_lut_red[RED(gray,*v)] |
331 		ng_lut_green[GREEN(gray,*v,*u)] |
332 		ng_lut_blue[BLUE(gray,*u)];
333 	    y++;
334 	    gray   = GRAY(*y);
335 	    *(d++) =
336 		ng_lut_red[RED(gray,*v)] |
337 		ng_lut_green[GREEN(gray,*v,*u)] |
338 		ng_lut_blue[BLUE(gray,*u)];
339 	    y++; u++; v++;
340 	}
341 	if (0 == (i % 2)) {
342 	    u = us; v = vs;
343 	}
344 	dp += out->fmt.bytesperline;
345     }
346 }
347 
348 void
ng_yuv422p_to_lut4(void * h,struct ng_video_buf * out,struct ng_video_buf * in)349 ng_yuv422p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in)
350 {
351     unsigned char *restrict y, *restrict u, *restrict v;
352     unsigned char *dp;
353     unsigned int  *restrict d;
354     unsigned int i,j;
355     int gray;
356 
357     dp = out->data;
358     y  = in->data;
359     u  = y + in->fmt.width * in->fmt.height;
360     v  = u + in->fmt.width * in->fmt.height / 2;
361 
362     for (i = 0; i < in->fmt.height; i++) {
363 	d = (unsigned int*) dp;
364 	for (j = 0; j < in->fmt.width; j+= 2) {
365 	    gray   = GRAY(*y);
366 	    *(d++) =
367 		ng_lut_red[RED(gray,*v)] |
368 		ng_lut_green[GREEN(gray,*v,*u)] |
369 		ng_lut_blue[BLUE(gray,*u)];
370 	    y++;
371 	    gray   = GRAY(*y);
372 	    *(d++) =
373 		ng_lut_red[RED(gray,*v)] |
374 		ng_lut_green[GREEN(gray,*v,*u)] |
375 		ng_lut_blue[BLUE(gray,*u)];
376 	    y++; u++; v++;
377 	}
378 	dp += out->fmt.bytesperline;
379     }
380 }
381 
382 /* ------------------------------------------------------------------- */
383 
384 static struct ng_video_conv conv_list[] = {
385     {
386 	NG_GENERIC_PACKED,
387 	.fmtid_in =	VIDEO_YUYV,
388 	.fmtid_out =	VIDEO_RGB24,
389 	.priv =		yuv422_to_rgb24,
390     },{
391 	NG_GENERIC_PACKED,
392 	.fmtid_in =	VIDEO_YUYV,
393 	.fmtid_out =	VIDEO_GRAY,
394 	.priv =		yuv422_to_gray,
395     },{
396 	.init =		ng_conv_nop_init,
397 	.fini =		ng_conv_nop_fini,
398 	.frame =	yuv422p_to_rgb24,
399 	.fmtid_in =	VIDEO_YUV422P,
400 	.fmtid_out =	VIDEO_RGB24,
401     },{
402 	.init =		ng_conv_nop_init,
403 	.fini =		ng_conv_nop_fini,
404 	.frame =	yuv420p_to_rgb24,
405 	.fmtid_in =	VIDEO_YUV420P,
406 	.fmtid_out =	VIDEO_RGB24,
407     },{
408 	.init =		ng_conv_nop_init,
409 	.fini =		ng_conv_nop_fini,
410 	.frame =	yuv42xp_to_gray,
411 	.fmtid_in =	VIDEO_YUV422P,
412 	.fmtid_out =	VIDEO_GRAY,
413     },{
414 	.init =		ng_conv_nop_init,
415 	.fini =		ng_conv_nop_fini,
416 	.frame =	yuv42xp_to_gray,
417 	.fmtid_in =	VIDEO_YUV420P,
418 	.fmtid_out =	VIDEO_GRAY,
419     }
420 };
421 static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv);
422 
423 /* ------------------------------------------------------------------- */
424 
ng_color_yuv2rgb_init(void)425 void ng_color_yuv2rgb_init(void)
426 {
427     int i;
428 
429     /* init Lookup tables */
430     for (i = 0; i < 256; i++) {
431 	ng_yuv_gray[i] = i * LUN_MUL >> 8;
432 	ng_yuv_red[i]  = (RED_ADD    + i * RED_MUL)    >> 8;
433 	ng_yuv_blue[i] = (BLUE_ADD   + i * BLUE_MUL)   >> 8;
434 	ng_yuv_g1[i]   = (GREEN1_ADD + i * GREEN1_MUL) >> 8;
435 	ng_yuv_g2[i]   = (GREEN2_ADD + i * GREEN2_MUL) >> 8;
436     }
437     for (i = 0; i < CLIP; i++)
438 	ng_clip[i] = 0;
439     for (; i < CLIP + 256; i++)
440 	ng_clip[i] = i - CLIP;
441     for (; i < 2 * CLIP + 256; i++)
442 	ng_clip[i] = 255;
443 
444     /* register stuff */
445     ng_conv_register(NG_PLUGIN_MAGIC,"built-in",conv_list,nconv);
446 }
447