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