00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdio.h>
00014
00015 #ifdef HAVE_STDINT_H
00016 #include <stdint.h>
00017 #endif
00018
00019 #include <stdlib.h>
00020 #include <string.h>
00021
00022 #include "config.h"
00023 #include "filter.h"
00024 #include "frame.h"
00025 #include "dsputil.h"
00026
00027 #ifdef MMX
00028 #include "i386/mmx.h"
00029 #endif
00030
00031
00032 #define LUMA_THRESHOLD_DEFAULT 15
00033 #define CHROMA_THRESHOLD_DEFAULT 25
00034
00035
00036 #define LUMA_THRESHOLD1_DEFAULT 10
00037 #define LUMA_THRESHOLD2_DEFAULT 1
00038 #define CHROMA_THRESHOLD1_DEFAULT 20
00039 #define CHROMA_THRESHOLD2_DEFAULT 2
00040
00041
00042
00043
00044
00045 typedef struct ThisFilter
00046 {
00047 VideoFilter vf;
00048
00049 uint64_t Luma_threshold_mask1;
00050 uint64_t Luma_threshold_mask2;
00051 uint64_t Chroma_threshold_mask1;
00052 uint64_t Chroma_threshold_mask2;
00053 uint8_t Luma_threshold1;
00054 uint8_t Luma_threshold2;
00055 uint8_t Chroma_threshold1;
00056 uint8_t Chroma_threshold2;
00057 uint8_t *average;
00058 int average_size;
00059 int offsets[3];
00060 int pitches[3];
00061
00062 TF_STRUCT;
00063
00064 } ThisFilter;
00065
00066 static int alloc_avg(ThisFilter *filter, int size)
00067 {
00068 if (filter->average_size >= size)
00069 return 1;
00070
00071 uint8_t *tmp = realloc(filter->average, size);
00072 if (!tmp)
00073 {
00074 fprintf(stderr, "Couldn't allocate memory for DNR buffer\n");
00075 return 0;
00076 }
00077
00078 filter->average = tmp;
00079 filter->average_size = size;
00080
00081 return 1;
00082 }
00083
00084 static int init_avg(ThisFilter *filter, VideoFrame *frame)
00085 {
00086 if (!alloc_avg(filter, frame->size))
00087 return 0;
00088
00089 if ((filter->offsets[0] != frame->offsets[0]) ||
00090 (filter->offsets[1] != frame->offsets[1]) ||
00091 (filter->offsets[2] != frame->offsets[2]) ||
00092 (filter->pitches[0] != frame->pitches[0]) ||
00093 (filter->pitches[1] != frame->pitches[1]) ||
00094 (filter->pitches[2] != frame->pitches[2]))
00095 {
00096 memcpy(filter->average, frame->buf, frame->size);
00097 memcpy(filter->offsets, frame->offsets, sizeof(int) * 3);
00098 memcpy(filter->pitches, frame->pitches, sizeof(int) * 3);
00099 }
00100
00101 return 1;
00102 }
00103
00104 static void init_vars(ThisFilter *tf, VideoFrame *frame,
00105 int *thr1, int *thr2, int *height,
00106 uint8_t **avg, uint8_t **buf)
00107 {
00108 thr1[0] = tf->Luma_threshold1;
00109 thr1[1] = tf->Chroma_threshold1;
00110 thr1[2] = tf->Chroma_threshold1;
00111
00112 thr2[0] = tf->Luma_threshold2;
00113 thr2[1] = tf->Chroma_threshold2;
00114 thr2[2] = tf->Chroma_threshold2;
00115
00116 height[0] = frame->height;
00117 height[1] = frame->height >> 1;
00118 height[2] = frame->height >> 1;
00119
00120 avg[0] = tf->average + frame->offsets[0];
00121 avg[1] = tf->average + frame->offsets[1];
00122 avg[2] = tf->average + frame->offsets[2];
00123
00124 buf[0] = frame->buf + frame->offsets[0];
00125 buf[1] = frame->buf + frame->offsets[1];
00126 buf[2] = frame->buf + frame->offsets[2];
00127 }
00128
00129 int quickdnr(VideoFilter *f, VideoFrame *frame)
00130 {
00131 ThisFilter *tf = (ThisFilter *)f;
00132 int thr1[3], thr2[3], height[3];
00133 uint8_t *avg[3], *buf[3];
00134 int i, y;
00135
00136 TF_VARS;
00137
00138 TF_START;
00139
00140 if (!init_avg(tf, frame))
00141 return 0;
00142
00143 init_vars(tf, frame, thr1, thr2, height, avg, buf);
00144
00145 for (i = 0; i < 3; i++)
00146 {
00147 int sz = height[i] * frame->pitches[i];
00148 for (y = 0; y < sz; y++)
00149 {
00150 if (abs(avg[i][y] - buf[i][y]) < thr1[i])
00151 buf[i][y] = avg[i][y] = (avg[i][y] + buf[i][y]) >> 1;
00152 else
00153 avg[i][y] = buf[i][y];
00154 }
00155 }
00156
00157 TF_END(tf, "QuickDNR: ");
00158
00159 return 0;
00160 }
00161
00162 int quickdnr2(VideoFilter *f, VideoFrame *frame)
00163 {
00164 ThisFilter *tf = (ThisFilter *)f;
00165 int thr1[3], thr2[3], height[3];
00166 uint8_t *avg[3], *buf[3];
00167 int i, y;
00168
00169 TF_VARS;
00170
00171 TF_START;
00172
00173 if (!init_avg(tf, frame))
00174 return 0;
00175
00176 init_vars(tf, frame, thr1, thr2, height, avg, buf);
00177
00178 for (i = 0; i < 3; i++)
00179 {
00180 int sz = height[i] * frame->pitches[i];
00181 for (y = 0; y < sz; y++)
00182 {
00183 int t = abs(avg[i][y] - buf[i][y]);
00184 if (t < thr1[i])
00185 {
00186 if (t > thr2[i])
00187 avg[i][y] = (avg[i][y] + buf[i][y]) >> 1;
00188 buf[i][y] = avg[i][y];
00189 }
00190 else
00191 {
00192 avg[i][y] = buf[i][y];
00193 }
00194 }
00195 }
00196
00197 TF_END(tf, "QuickDNR2: ");
00198
00199 return 0;
00200 }
00201
00202 #ifdef MMX
00203
00204 int quickdnrMMX(VideoFilter *f, VideoFrame *frame)
00205 {
00206 ThisFilter *tf = (ThisFilter *)f;
00207 const uint64_t sign_convert = 0x8080808080808080LL;
00208 int thr1[3], thr2[3], height[3];
00209 uint64_t *avg[3], *buf[3];
00210 int i, y;
00211
00212 TF_VARS;
00213
00214 TF_START;
00215
00216 if (!init_avg(tf, frame))
00217 return 0;
00218
00219 init_vars(tf, frame, thr1, thr2, height, (uint8_t**) avg, (uint8_t**) buf);
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 asm volatile("emms\n\t");
00234
00235 asm volatile("movq (%0), %%mm4" : : "r" (&sign_convert));
00236
00237 for (i = 0; i < 3; i++)
00238 {
00239 int sz = (height[i] * frame->pitches[i]) >> 3;
00240
00241 if (0 == i)
00242 asm volatile("movq (%0), %%mm5" : : "r" (&tf->Luma_threshold_mask1));
00243 else
00244 asm volatile("movq (%0), %%mm5" : : "r" (&tf->Chroma_threshold_mask1));
00245
00246 for (y = 0; y < sz; y++)
00247 {
00248 asm volatile(
00249 "movq (%0), %%mm0 \n\t"
00250 "movq (%1), %%mm1 \n\t"
00251 "movq %%mm0, %%mm2 \n\t"
00252 "movq %%mm1, %%mm3 \n\t"
00253 "movq %%mm1, %%mm7 \n\t"
00254
00255 "pcmpgtb %%mm0, %%mm1 \n\t"
00256 "psubb %%mm0, %%mm3 \n\t"
00257 "psubb %%mm7, %%mm0 \n\t"
00258 "pand %%mm1, %%mm3 \n\t"
00259 "pandn %%mm0,%%mm1 \n\t"
00260 "por %%mm1, %%mm3 \n\t"
00261
00262 "paddb %%mm4, %%mm3 \n\t"
00263 "pcmpgtb %%mm5, %%mm3 \n\t"
00264
00265 "pavgb %%mm7, %%mm2 \n\t"
00266 "pand %%mm3, %%mm7 \n\t"
00267 "pandn %%mm2,%%mm3 \n\t"
00268 "por %%mm7, %%mm3 \n\t"
00269 "movq %%mm3, (%0) \n\t"
00270 "movq %%mm3, (%1) \n\t"
00271 : : "r" (avg[i]), "r" (buf[i])
00272 );
00273 buf[i]++;
00274 avg[i]++;
00275 }
00276 }
00277
00278 asm volatile("emms\n\t");
00279
00280
00281 for (i = 0; i < 3; i++)
00282 {
00283 int thr1[3], thr2[3], height[3];
00284 uint8_t *avg8[3], *buf8[3];
00285 int end, beg;
00286
00287 init_vars(tf, frame, thr1, thr2, height, avg8, buf8);
00288
00289 end = height[i] * frame->pitches[i];
00290 beg = end & ~0x7;
00291
00292 if (beg == end)
00293 continue;
00294
00295 for (y = beg; y < end; y++)
00296 {
00297 if (abs(avg8[i][y] - buf8[i][y]) < thr1[i])
00298 buf8[i][y] = avg8[i][y] = (avg8[i][y] + buf8[i][y]) >> 1;
00299 else
00300 avg8[i][y] = buf8[i][y];
00301 }
00302 }
00303
00304 TF_END(tf, "QuickDNRmmx: ");
00305
00306 return 0;
00307 }
00308
00309
00310 int quickdnr2MMX(VideoFilter *f, VideoFrame *frame)
00311 {
00312 ThisFilter *tf = (ThisFilter *)f;
00313 const uint64_t sign_convert = 0x8080808080808080LL;
00314 int thr1[3], thr2[3], height[3];
00315 uint64_t *avg[3], *buf[3];
00316 int i, y;
00317
00318 TF_VARS;
00319
00320 TF_START;
00321
00322 if (!init_avg(tf, frame))
00323 return 0;
00324
00325 init_vars(tf, frame, thr1, thr2, height, (uint8_t**) avg, (uint8_t**) buf);
00326
00327 asm volatile("emms\n\t");
00328
00329 asm volatile("movq (%0), %%mm4" : : "r" (&sign_convert));
00330
00331 for (i = 0; i < 3; i++)
00332 {
00333 int sz = (height[i] * frame->pitches[i]) >> 3;
00334
00335 if (0 == i)
00336 asm volatile("movq (%0), %%mm5" : : "r" (&tf->Luma_threshold_mask1));
00337 else
00338 asm volatile("movq (%0), %%mm5" : : "r" (&tf->Chroma_threshold_mask1));
00339
00340 for (y = 0; y < sz; y++)
00341 {
00342 uint64_t *mask2 = (0 == i) ?
00343 &tf->Luma_threshold_mask2 : &tf->Chroma_threshold_mask2;
00344
00345 asm volatile(
00346 "movq (%0), %%mm0 \n\t"
00347 "movq (%1), %%mm1 \n\t"
00348 "movq %%mm0, %%mm2 \n\t"
00349 "movq %%mm1, %%mm3 \n\t"
00350 "movq %%mm1, %%mm6 \n\t"
00351 "movq %%mm1, %%mm7 \n\t"
00352
00353 "pcmpgtb %%mm0, %%mm1 \n\t"
00354 "psubb %%mm0, %%mm3 \n\t"
00355 "psubb %%mm7, %%mm0 \n\t"
00356 "pand %%mm1, %%mm3 \n\t"
00357 "pandn %%mm0,%%mm1 \n\t"
00358 "por %%mm1, %%mm3 \n\t"
00359
00360 "paddb %%mm4, %%mm3 \n\t"
00361 "pcmpgtb %%mm5, %%mm3 \n\t"
00362
00363 "movq %%mm2, %%mm0 \n\t"
00364 "movq %%mm7, %%mm1 \n\t"
00365
00366 "pcmpgtb %%mm0, %%mm1 \n\t"
00367 "psubb %%mm0, %%mm6 \n\t"
00368 "psubb %%mm7, %%mm0 \n\t"
00369 "pand %%mm1, %%mm6 \n\t"
00370 "pandn %%mm0,%%mm1 \n\t"
00371 "por %%mm1, %%mm6 \n\t"
00372
00373 "paddb %%mm4, %%mm6 \n\t"
00374 "pcmpgtb (%2), %%mm6 \n\t"
00375
00376 "movq %%mm2, %%mm0 \n\t"
00377
00378 "pavgb %%mm7, %%mm2 \n\t"
00379
00380 "pand %%mm6, %%mm2 \n\t"
00381 "pandn %%mm0,%%mm6 \n\t"
00382 "por %%mm2, %%mm6 \n\t"
00383
00384 "pand %%mm3, %%mm7 \n\t"
00385 "pandn %%mm6,%%mm3 \n\t"
00386 "por %%mm7, %%mm3 \n\t"
00387
00388 "movq %%mm3, (%0) \n\t"
00389 "movq %%mm3, (%1) \n\t"
00390 : :
00391 "r" (avg[i]),
00392 "r" (buf[i]),
00393 "r" (mask2)
00394 );
00395 buf[i]++;
00396 avg[i]++;
00397 }
00398 }
00399
00400 asm volatile("emms\n\t");
00401
00402
00403 for (i = 0; i < 3; i++)
00404 {
00405 int thr1[3], thr2[3], height[3];
00406 uint8_t *avg8[3], *buf8[3];
00407 int end, beg;
00408
00409 init_vars(tf, frame, thr1, thr2, height, avg8, buf8);
00410
00411 end = height[i] * frame->pitches[i];
00412 beg = end & ~0x7;
00413
00414 if (beg == end)
00415 continue;
00416
00417 for (y = beg; y < end; y++)
00418 {
00419 int t = abs(avg8[i][y] - buf8[i][y]);
00420 if (t < thr1[i])
00421 {
00422 if (t > thr2[i])
00423 avg8[i][y] = (avg8[i][y] + buf8[i][y]) >> 1;
00424 buf8[i][y] = avg8[i][y];
00425 }
00426 else
00427 {
00428 avg8[i][y] = buf8[i][y];
00429 }
00430 }
00431 }
00432
00433 TF_END(tf, "QuickDNR2mmx: ");
00434
00435 return 0;
00436 }
00437 #endif
00438
00439 void cleanup(VideoFilter *vf)
00440 {
00441 ThisFilter *tf = (ThisFilter*) vf;
00442
00443 if (tf->average)
00444 free(tf->average);
00445 }
00446
00447 VideoFilter *new_filter(VideoFrameType inpixfmt, VideoFrameType outpixfmt,
00448 int *width, int *height, char *options)
00449 {
00450 unsigned int Param1, Param2, Param3, Param4;
00451 int i, double_threshold = 1;
00452 ThisFilter *filter;
00453
00454 (void) width;
00455 (void) height;
00456 (void) i;
00457
00458 if (inpixfmt != FMT_YV12 || outpixfmt != FMT_YV12)
00459 {
00460 fprintf(stderr, "QuickDNR: attempt to initialize "
00461 "with unsupported format\n");
00462 return NULL;
00463 }
00464
00465 filter = malloc(sizeof(ThisFilter));
00466 if (filter == NULL)
00467 {
00468 fprintf(stderr, "Couldn't allocate memory for filter\n");
00469 return NULL;
00470 }
00471
00472 memset(filter, 0, sizeof(ThisFilter));
00473 filter->vf.cleanup = &cleanup;
00474 filter->Luma_threshold1 = LUMA_THRESHOLD1_DEFAULT;
00475 filter->Chroma_threshold1 = CHROMA_THRESHOLD1_DEFAULT;
00476 filter->Luma_threshold2 = LUMA_THRESHOLD2_DEFAULT;
00477 filter->Chroma_threshold2 = CHROMA_THRESHOLD2_DEFAULT;
00478 double_threshold = 1;
00479
00480 if (options)
00481 {
00482 int ret = sscanf(options, "%u:%u:%u:%u",
00483 &Param1, &Param2, &Param3, &Param4);
00484 switch (ret)
00485 {
00486 case 1:
00487
00488 filter->Luma_threshold1 = ((uint8_t) Param1) * 40 / 255;
00489 filter->Luma_threshold2 = ((uint8_t) Param1) * 4/255 > 2 ?
00490 2 : ((uint8_t) Param1) * 4/255;
00491 filter->Chroma_threshold1 = ((uint8_t) Param1) * 80 / 255;
00492 filter->Chroma_threshold2 = ((uint8_t) Param1) * 8/255 > 4 ?
00493 4 : ((uint8_t) Param1) * 8/255;
00494 break;
00495
00496 case 2:
00497 filter->Luma_threshold1 = (uint8_t) Param1;
00498 filter->Chroma_threshold1 = (uint8_t) Param2;
00499 double_threshold = 0;
00500 break;
00501
00502 case 4:
00503 filter->Luma_threshold1 = (uint8_t) Param1;
00504 filter->Luma_threshold2 = (uint8_t) Param2;
00505 filter->Chroma_threshold1 = (uint8_t) Param3;
00506 filter->Chroma_threshold2 = (uint8_t) Param4;
00507 break;
00508
00509 default:
00510 break;
00511 }
00512 }
00513
00514 filter->vf.filter = (double_threshold) ? &quickdnr2 : &quickdnr;
00515
00516 #ifdef MMX
00517 if (mm_support() > MM_MMXEXT)
00518 {
00519 filter->vf.filter = (double_threshold) ? &quickdnr2MMX : &quickdnrMMX;
00520 for (i = 0; i < 8; i++)
00521 {
00522
00523 filter->Luma_threshold_mask1 =
00524 (filter->Luma_threshold_mask1 << 8) +
00525 ((filter->Luma_threshold1 > 0x80) ?
00526 (filter->Luma_threshold1 - 0x80) :
00527 (filter->Luma_threshold1 + 0x80));
00528
00529 filter->Chroma_threshold_mask1 =
00530 (filter->Chroma_threshold_mask1 << 8) +
00531 ((filter->Chroma_threshold1 > 0x80) ?
00532 (filter->Chroma_threshold1 - 0x80) :
00533 (filter->Chroma_threshold1 + 0x80));
00534
00535 filter->Luma_threshold_mask2 =
00536 (filter->Luma_threshold_mask2 << 8) +
00537 ((filter->Luma_threshold2 > 0x80) ?
00538 (filter->Luma_threshold2 - 0x80) :
00539 (filter->Luma_threshold2 + 0x80));
00540
00541 filter->Chroma_threshold_mask2 =
00542 (filter->Chroma_threshold_mask2 << 8) +
00543 ((filter->Chroma_threshold2 > 0x80) ?
00544 (filter->Chroma_threshold2 - 0x80) :
00545 (filter->Chroma_threshold2 + 0x80));
00546 }
00547 }
00548 #endif
00549
00550 TF_INIT(filter);
00551
00552 #ifdef QUICKDNR_DEBUG
00553 fprintf(stderr, "DNR Loaded: 0x%X Params: %u %u \n"
00554 "Luma1: %3d 0x%X%X Luma2: 0x%X%X\n"
00555 "Chroma1: %3d %X%X Chroma2: 0x%X%X\n",
00556 mm_support(), Param1, Param2, filter->Luma_threshold1,
00557 ((int*)&filter->Luma_threshold_mask1)[1],
00558 ((int*)&filter->Luma_threshold_mask1)[0],
00559 ((int*)&filter->Luma_threshold_mask2)[1],
00560 ((int*)&filter->Luma_threshold_mask2)[0],
00561 filter->Chroma_threshold1,
00562 ((int*)&filter->Chroma_threshold_mask1)[1],
00563 ((int*)&filter->Chroma_threshold_mask1)[0],
00564 ((int*)&filter->Chroma_threshold_mask2)[1],
00565 ((int*)&filter->Chroma_threshold_mask2)[0]
00566 );
00567
00568 fprintf(stderr, "Options:%d:%d:%d:%d\n",
00569 filter->Luma_threshold1, filter->Luma_threshold2,
00570 filter->Chroma_threshold1, filter->Chroma_threshold2);
00571 #endif
00572
00573 return (VideoFilter*) filter;
00574 }
00575
00576 static FmtConv FmtList[] =
00577 {
00578 { FMT_YV12, FMT_YV12 },
00579 FMT_NULL
00580 };
00581
00582 FilterInfo filter_table[] =
00583 {
00584 {
00585 symbol: "new_filter",
00586 name: "quickdnr",
00587 descript: "removes noise with a fast single/double thresholded average filter",
00588 formats: FmtList,
00589 libname: NULL
00590 },
00591 FILT_NULL
00592 };