1 /*
2 * libng filter -- Smooth the image to reduce snow at bad TV receiption
3 *
4 *
5 * Filter options
6 * --------------
7 *
8 * There are 2 options available that can be turned on and off separately.
9 *
10 * Smooth over time: Calculate average of previous and current frame.
11 * Longer filter lengths could improve static
12 * images but would be unusable for movies and
13 * require high CPU power. I found averaging of
14 * 2 frames the most useful filter.
15 *
16 * Smooth horizontally: For every pixel, the average of the actual colour
17 * and the colour of the pixel to the left is displayed.
18 *
19 *
20 * (c) 2002 Klaus Peichl <pei@freenet.de> (smoothing filter),
21 * Gerd Knorr <kraxel@bytesex.org> (framework)
22 *
23 */
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <pthread.h>
30
31 #include "grab-ng.h"
32
33 /* ------------------------------------------------------------------- */
34
35 typedef struct {
36 struct ng_video_buf * pLastFrame;
37 }
38 SMOOTH_BUFFER;
39
40
41 static int smoothTime = 1;
42 static int smoothHorizontal = 1;
43
44
45 static void inline
46 invert_bytes(unsigned char *dst, unsigned char *src, int bytes)
47 {
48 while (bytes--)
49 *(dst++) = 0xff - *(src++);
50 }
51
52
53 #if 1
54
55 /*
56 Fast 32-bit smoothing
57 */
58 static void inline
59 smooth_native_32bit(unsigned int *last,
60 unsigned int *dst,
61 unsigned int *src,
62 int pixels)
63 {
64 unsigned int old,new, old2,new2;
65
66 if (smoothTime && smoothHorizontal) {
67
68 /* Smoothing in time and horizontally */
69
70 old2 = *last;
71 new2 = *src;
72
73 while (pixels--) {
74
75 old = *last;
76 new = *src++;
77 *last++ = new;
78
79 /*
80 Fast averaging:
81 All 4 bytes (of which only 3 are used) can be averaged in one 32bit-word.
82 The lowest 2 bits of every colour are thrown away to avoid influences
83 between the colours.
84 */
85
86 *dst++ =
87 ((new >> 2) & 0x3F3F3F3F) +
88 ((new2 >> 2) & 0x3F3F3F3F) +
89 ((old >> 2) & 0x3F3F3F3F) +
90 ((old2 >> 2) & 0x3F3F3F3F);
91
92 old2 = old;
93 new2 = new;
94 }
95 }
96 else if (smoothTime) {
97
98 /* Smoothing in time only */
99
100 while (pixels--) {
101
102 old = *last;
103 new = *src++;
104 *last++ = new;
105
106 /*
107 Fast averaging:
108 All 4 bytes (of which only 3 are used) can be averaged in one 32bit-word.
109 The lowest bit of every colour is thrown away to avoid influences
110 between the colours.
111 */
112
113 *dst++ =
114 ((new >> 1) & 0x7F7F7F7F) +
115 ((old >> 1) & 0x7F7F7F7F);
116 }
117 }
118 else if (smoothHorizontal) {
119
120 /* Smooth horizontally only */
121
122 new2 = *src;
123
124 while (pixels--) {
125
126 new = *src++;
127 *last++ = new;
128
129 /*
130 Fast averaging:
131 All 4 bytes (of which only 3 are used) can be averaged in one 32bit-word.
132 The lowest bit of every colour is thrown away to avoid influences
133 between the colours.
134 */
135
136 *dst++ =
137 ((new >> 1) & 0x7F7F7F7F) +
138 ((new2 >> 1) & 0x7F7F7F7F);
139
140 new2 = new;
141 }
142 }
143 else {
144
145 /* No smoothing at all */
146
147 while (pixels--) {
148 new = *src++;
149 *last++ = new;
150 *dst++ = new;
151 }
152 }
153 }
154
155 #else
156
157 /*
158 This is an alternative implementation of the above function
159 which does not throw away the lowest bits before addition.
160 It is derived from the byte-based 24-bit-function below but
161 processes 4 bytes for every pixel instead of 3.
162 */
163
164 static void inline
165 smooth_native_32bit(unsigned char *last,
166 unsigned char *dst,
167 unsigned char *src,
168 int pixels)
169 {
170 unsigned char oldR,newR, oldR2,newR2;
171 unsigned char oldG,newG, oldG2,newG2;
172 unsigned char oldB,newB, oldB2,newB2;
173 unsigned char oldP,newP, oldP2,newP2;
174
175 if (smoothTime && smoothHorizontal) {
176
177 /* Smoothing in time and horizontally */
178
179 oldR2 = last[0];
180 oldG2 = last[1];
181 oldB2 = last[2];
182 oldP2 = last[3];
183 newR2 = src[0];
184 newG2 = src[1];
185 newB2 = src[2];
186 newP2 = src[3];
187
188 while (pixels--) {
189
190 oldR = *last; newR = *src++; *last++ = newR;
191 oldG = *last; newG = *src++; *last++ = newG;
192 oldB = *last; newB = *src++; *last++ = newB;
193 oldP = *last; newP = *src++; *last++ = newP;
194
195 *dst++ = (newR + oldR + newR2 + oldR2) / 4;
196 *dst++ = (newG + oldG + newG2 + oldG2) / 4;
197 *dst++ = (newB + oldB + newB2 + oldB2) / 4;
198 *dst++ = (newP + oldP + newP2 + oldP2) / 4;
199
200 oldR2 = oldR;
201 oldG2 = oldG;
202 oldB2 = oldB;
203 oldP2 = oldP;
204
205 newR2 = newR;
206 newG2 = newG;
207 newB2 = newB;
208 newP2 = newP;
209 }
210 }
211 else if (smoothTime) {
212
213 /* Smoothing in time only */
214
215 while (pixels--) {
216
217 oldR = *last; newR = *src++; *last++ = newR;
218 oldG = *last; newG = *src++; *last++ = newG;
219 oldB = *last; newB = *src++; *last++ = newB;
220 oldP = *last; newP = *src++; *last++ = newP;
221
222 *dst++ = (newR + oldR) / 2;
223 *dst++ = (newG + oldG) / 2;
224 *dst++ = (newB + oldB) / 2;
225 *dst++ = (newP + oldP) / 2;
226 }
227 }
228 else if (smoothHorizontal) {
229
230 /* Smooth horizontally only */
231
232 newR2 = src[0];
233 newG2 = src[1];
234 newB2 = src[2];
235 newP2 = src[3];
236
237 while (pixels--) {
238
239 newR = *src++; *last++ = newR;
240 newG = *src++; *last++ = newG;
241 newB = *src++; *last++ = newB;
242 newP = *src++; *last++ = newP;
243
244 *dst++ = (newR + newR2) / 2;
245 *dst++ = (newG + newG2) / 2;
246 *dst++ = (newB + newB2) / 2;
247 *dst++ = (newP + newP2) / 2;
248
249 newR2 = newR;
250 newG2 = newG;
251 newB2 = newB;
252 newP2 = newP;
253 }
254 }
255 else {
256
257 /* No smoothing at all */
258
259 while (pixels--) {
260 newR = *src++; *last++ = newR; *dst++ = newR;
261 newG = *src++; *last++ = newG; *dst++ = newG;
262 newB = *src++; *last++ = newB; *dst++ = newB;
263 newP = *src++; *last++ = newP; *dst++ = newP;
264
265 }
266 }
267 }
268 #endif
269
270
271 static void inline
272 smooth_native_24bit(unsigned char *last,
273 unsigned char *dst,
274 unsigned char *src,
275 int pixels)
276 {
277 unsigned char oldR,newR, oldR2,newR2;
278 unsigned char oldG,newG, oldG2,newG2;
279 unsigned char oldB,newB, oldB2,newB2;
280
281 if (smoothTime && smoothHorizontal) {
282
283 /* Smoothing in time and horizontally */
284
285 oldR2 = last[0];
286 oldG2 = last[1];
287 oldB2 = last[2];
288 newR2 = src[0];
289 newG2 = src[1];
290 newB2 = src[2];
291
292 while (pixels--) {
293
294 oldR = *last; newR = *src++; *last++ = newR;
295 oldG = *last; newG = *src++; *last++ = newG;
296 oldB = *last; newB = *src++; *last++ = newB;
297
298 *dst++ = (newR + oldR + newR2 + oldR2) / 4;
299 *dst++ = (newG + oldG + newG2 + oldG2) / 4;
300 *dst++ = (newB + oldB + newB2 + oldB2) / 4;
301
302 oldR2 = oldR;
303 oldG2 = oldG;
304 oldB2 = oldB;
305
306 newR2 = newR;
307 newG2 = newG;
308 newB2 = newB;
309 }
310 }
311 else if (smoothTime) {
312
313 /* Smoothing in time only */
314
315 while (pixels--) {
316
317 oldR = *last; newR = *src++; *last++ = newR;
318 oldG = *last; newG = *src++; *last++ = newG;
319 oldB = *last; newB = *src++; *last++ = newB;
320
321 *dst++ = (newR + oldR) / 2;
322 *dst++ = (newG + oldG) / 2;
323 *dst++ = (newB + oldB) / 2;
324 }
325 }
326 else if (smoothHorizontal) {
327
328 /* Smooth horizontally only */
329
330 newR2 = src[0];
331 newG2 = src[1];
332 newB2 = src[2];
333
334 while (pixels--) {
335
336 newR = *src++; *last++ = newR;
337 newG = *src++; *last++ = newG;
338 newB = *src++; *last++ = newB;
339
340 *dst++ = (newR + newR2) / 2;
341 *dst++ = (newG + newG2) / 2;
342 *dst++ = (newB + newB2) / 2;
343
344 newR2 = newR;
345 newG2 = newG;
346 newB2 = newB;
347 }
348 }
349 else {
350
351 /* No smoothing at all */
352
353 while (pixels--) {
354 newR = *src++; *last++ = newR; *dst++ = newR;
355 newG = *src++; *last++ = newG; *dst++ = newG;
356 newB = *src++; *last++ = newB; *dst++ = newB;
357
358 }
359 }
360 }
361
362
363 static void inline
364 smooth_native_16bit(unsigned short *last,
365 unsigned short *dst,
366 unsigned short *src,
367 unsigned short maskR,
368 unsigned short maskG,
369 unsigned short maskB,
370 int pixels)
371 {
372 unsigned short old,new, old2,new2;
373 unsigned short red,green,blue;
374
375 if (smoothTime && smoothHorizontal) {
376
377 /* Smoothing in time and horizontally */
378
379 old2 = *last;
380 new2 = *src;
381
382 while (pixels--) {
383
384 old = *last;
385 new = *src++;
386 *last++ = new;
387
388 red = ( ((new & maskR) + (old & maskR) + (new2 & maskR) + (old2 & maskR))/4 ) & maskR;
389 green = ( ((new & maskG) + (old & maskG) + (new2 & maskG) + (old2 & maskG))/4 ) & maskG;
390 blue = ( ((new & maskB) + (old & maskB) + (new2 & maskB) + (old2 & maskB))/4 ) & maskB;
391 *dst++ = red | green | blue;
392
393 old2 = old;
394 new2 = new;
395 }
396 }
397 else if (smoothTime) {
398
399 /* Smoothing in time only */
400
401 while (pixels--) {
402
403 old = *last;
404 new = *src++;
405 *last++ = new;
406
407 red = ( ((new & maskR) + (old & maskR))/2 ) & maskR;
408 green = ( ((new & maskG) + (old & maskG))/2 ) & maskG;
409 blue = ( ((new & maskB) + (old & maskB))/2 ) & maskB;
410 *dst++ = red | green | blue;
411 }
412 }
413 else if (smoothHorizontal) {
414
415 /* Smooth horizontally only */
416
417 new2 = *src;
418
419 while (pixels--) {
420
421 new = *src++;
422 *last++ = new;
423
424 red = ( ((new & maskR) + (new2 & maskR))/2 ) & maskR;
425 green = ( ((new & maskG) + (new2 & maskG))/2 ) & maskG;
426 blue = ( ((new & maskB) + (new2 & maskB))/2 ) & maskB;
427 *dst++ = red | green | blue;
428
429 new2 = new;
430 }
431 }
432 else {
433
434 /* No smoothing at all */
435
436 while (pixels--) {
437 new = *src++;
438 *last++ = new;
439 *dst++ = new;
440 }
441 }
442 }
443
444
445 /* ------------------------------------------------------------------- */
446
447 static void *init(struct ng_video_fmt *out)
448 {
449 /* don't have to carry around status info */
450 static SMOOTH_BUFFER smooth_buffer;
451
452 smooth_buffer.pLastFrame = ng_malloc_video_buf(out, out->height * out->bytesperline);
453
454 return &smooth_buffer;
455 }
456
457 static struct ng_video_buf*
458 frame(void *h, struct ng_video_buf *in)
459 {
460 SMOOTH_BUFFER *handle = h;
461 struct ng_video_buf *out;
462 unsigned char *dst;
463 unsigned char *src;
464 unsigned char *last;
465 unsigned int y,cnt;
466
467 out = ng_malloc_video_buf(&in->fmt, in->fmt.height * in->fmt.bytesperline);
468 out->info = in->info;
469
470 dst = out->data;
471 src = in->data;
472 last = handle->pLastFrame->data;
473 cnt = in->fmt.width * ng_vfmt_to_depth[in->fmt.fmtid] / 8;
474
475 for (y = 0; y < in->fmt.height; y++) {
476 switch (in->fmt.fmtid) {
477 case VIDEO_GRAY:
478 case VIDEO_BGR24:
479 case VIDEO_RGB24:
480 smooth_native_24bit((unsigned char*)last,
481 (unsigned char*)dst,
482 (unsigned char*)src,
483 in->fmt.width);
484 break;
485 case VIDEO_BGR32:
486 case VIDEO_RGB32:
487 case VIDEO_YUYV:
488 case VIDEO_UYVY:
489 smooth_native_32bit((unsigned int*)last,
490 (unsigned int*)dst,
491 (unsigned int*)src,
492 in->fmt.width);
493 break;
494 case VIDEO_RGB15_NATIVE:
495 smooth_native_16bit((unsigned short*)last,
496 (unsigned short*)dst,
497 (unsigned short*)src,
498 0x7C00, /* mask for red */
499 0x03E0, /* mask for green */
500 0x001F, /* mask for blue */
501 in->fmt.width);
502 break;
503 case VIDEO_RGB16_NATIVE:
504 smooth_native_16bit((unsigned short*)last,
505 (unsigned short*)dst,
506 (unsigned short*)src,
507 0xF800, /* mask for red */
508 0x07E0, /* mask for green */
509 0x001F, /* mask for blue */
510 in->fmt.width);
511 break;
512 }
513 dst += out->fmt.bytesperline;
514 src += in->fmt.bytesperline;
515 last += in->fmt.bytesperline;
516 }
517
518 ng_release_video_buf(in);
519 return out;
520 }
521
522 static void fini(void *handle)
523 {
524 ng_release_video_buf(handle);
525 }
526
527
528 static int read_attr(struct ng_attribute *attr)
529 {
530 int value;
531
532 switch (attr->id) {
533 case 0:
534 value = smoothTime;
535 break;
536 case 1:
537 value = smoothHorizontal;
538 break;
539 default:
540 value = 0;
541 }
542
543 return value;
544 }
545
546 static void write_attr(struct ng_attribute *attr, int value)
547 {
548 switch (attr->id) {
549 case 0:
550 smoothTime = value;
551 break;
552 case 1:
553 smoothHorizontal = value;
554 break;
555 }
556 }
557
558
559 /* ------------------------------------------------------------------- */
560
561 static struct ng_attribute attrs[] = {
562 {
563 id: 0,
564 name: "smooth over time",
565 type: ATTR_TYPE_BOOL,
566 defval: 1,
567 read: read_attr,
568 write: write_attr,
569 },{
570 id: 1,
571 name: "smooth horizontally",
572 type: ATTR_TYPE_BOOL,
573 defval: 1,
574 read: read_attr,
575 write: write_attr,
576 },{
577 /* end of list */
578 }
579 };
580
581
582 static struct ng_filter filter = {
583 name: "smooth",
584 attrs: attrs,
585 fmts:
586 (1 << VIDEO_GRAY) |
587 (1 << VIDEO_RGB15_NATIVE) |
588 (1 << VIDEO_RGB16_NATIVE) |
589 (1 << VIDEO_BGR24) |
590 (1 << VIDEO_RGB24) |
591 (1 << VIDEO_BGR32) |
592 (1 << VIDEO_RGB32) |
593 (1 << VIDEO_YUYV) |
594 (1 << VIDEO_UYVY),
595 init: init,
596 frame: frame,
597 fini: fini,
598 };
599
600 extern void ng_plugin_init(void);
601 void ng_plugin_init(void)
602 {
603 ng_filter_register(NG_PLUGIN_MAGIC,__FILE__,&filter);
604 }
605
|
This page was automatically generated by the
LXR engine.
|