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