00001
00002
00003
00004
00005
00006
00007 #include <stdlib.h>
00008 #include <stdio.h>
00009
00010 #ifdef HAVE_STDINT_H
00011 #include <stdint.h>
00012 #endif
00013
00014 #include <string.h>
00015 #include <math.h>
00016
00017 #include "config.h"
00018 #include "filter.h"
00019 #include "frame.h"
00020 #include "dsputil.h"
00021
00022 #define PARAM1_DEFAULT 4.0
00023 #define PARAM2_DEFAULT 3.0
00024 #define PARAM3_DEFAULT 6.0
00025
00026 #define LowPass(Prev, Curr, Coef) (Curr + Coef[Prev - Curr])
00027
00028 #undef ABS
00029 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
00030
00031 #ifdef MMX
00032 #include "i386/mmx.h"
00033 static const mmx_t mz = { 0x0LL };
00034 #endif
00035
00036 typedef struct ThisFilter
00037 {
00038 VideoFilter vf;
00039
00040 int offsets[3];
00041 int pitches[3];
00042 int mm_flags;
00043 int line_size;
00044 int prev_size;
00045 uint8_t *line;
00046 uint8_t *prev;
00047 uint8_t coefs[4][512];
00048
00049 void (*filtfunc)(uint8_t*, uint8_t*, uint8_t*,
00050 int, int, uint8_t*, uint8_t*);
00051
00052 TF_STRUCT;
00053 } ThisFilter;
00054
00055 static void calc_coefs(uint8_t * Ct, double Dist25)
00056 {
00057 int i;
00058 double Gamma, Simil, C;
00059
00060 Gamma = log (0.25) / log (1.0 - Dist25 / 255.0);
00061
00062 for (i = -256; i <= 255; i++)
00063 {
00064 Simil = 1.0 - ABS (i) / 255.0;
00065 C = pow (Simil, Gamma) * (double) i;
00066 Ct[256 + i] = (C < 0) ? (C - 0.5) : (C + 0.5);
00067 }
00068 }
00069
00070 static void denoise(uint8_t *Frame,
00071 uint8_t *FramePrev,
00072 uint8_t *Line,
00073 int W, int H,
00074 uint8_t *Spatial, uint8_t *Temporal)
00075 {
00076 uint8_t prev;
00077 int X, Y;
00078 uint8_t *LineCur = Frame;
00079 uint8_t *LinePrev = FramePrev;
00080
00081 prev = Line[0] = Frame[0];
00082 Frame[0] = LowPass (FramePrev[0], Frame[1], Temporal);
00083 for (X = 1; X < W; X++)
00084 {
00085 prev = LowPass (prev, Frame[X], Spatial);
00086 Line[X] = prev;
00087 FramePrev[X] = Frame[X] = LowPass (FramePrev[X], prev, Temporal);
00088 }
00089
00090 for (Y = 1; Y < H; Y++)
00091 {
00092 LineCur += W;
00093 LinePrev += W;
00094 prev = LineCur[0];
00095 Line[0] = LowPass (Line[0], prev, Spatial);
00096 LineCur[0] = LowPass (LinePrev[0], Line[0], Temporal);
00097 for (X = 1; X < W; X++)
00098 {
00099 prev = LowPass (prev, LineCur[X], Spatial);
00100 Line[X] = LowPass (Line[X], prev, Spatial);
00101 LinePrev[X] = LineCur[X] = LowPass (LinePrev[X], Line[X], Temporal);
00102 }
00103 }
00104 }
00105
00106 #ifdef MMX
00107
00108 static void denoiseMMX(uint8_t *Frame,
00109 uint8_t *FramePrev,
00110 uint8_t *Line,
00111 int W, int H,
00112 uint8_t *Spatial, uint8_t *Temporal)
00113 {
00114 int X, i;
00115 uint8_t *LineCur = Frame;
00116 uint8_t *LinePrev = FramePrev;
00117 uint8_t *End = Frame + W * H;
00118 int16_t wbuf[16];
00119 uint8_t cbuf[16];
00120
00121 Line[0] = LineCur[0];
00122 for (X = 1; X < W; X++)
00123 Line[X] = LowPass (Line[X-1], LineCur[X], Spatial);
00124
00125 for (X = 0; X < W - 15; X += 16)
00126 {
00127 movq_m2r (LinePrev[X], mm0);
00128 movq_m2r (LinePrev[X+8], mm2);
00129 movq_m2r (Line[X], mm4);
00130 movq_m2r (Line[X+8], mm6);
00131 movq_r2r (mm0, mm1);
00132 movq_r2r (mm2, mm3);
00133 movq_r2r (mm4, mm5);
00134 movq_r2r (mm6, mm7);
00135
00136 punpcklbw_m2r(mz, mm0);
00137 punpckhbw_m2r(mz, mm1);
00138 punpcklbw_m2r(mz, mm2);
00139 punpckhbw_m2r(mz, mm3);
00140 punpcklbw_m2r(mz, mm4);
00141 punpckhbw_m2r(mz, mm5);
00142 punpcklbw_m2r(mz, mm6);
00143 punpckhbw_m2r(mz, mm7);
00144
00145 psubw_r2r (mm4, mm0);
00146 psubw_r2r (mm5, mm1);
00147 psubw_r2r (mm6, mm2);
00148 psubw_r2r (mm7, mm3);
00149
00150 movq_r2m (mm0, wbuf[0]);
00151 movq_r2m (mm1, wbuf[4]);
00152 movq_r2m (mm2, wbuf[8]);
00153 movq_r2m (mm3, wbuf[12]);
00154
00155 movq_m2r (Line[X], mm4);
00156 movq_m2r (Line[X+8], mm6);
00157
00158 for (i = 0; i < 16; i++)
00159 cbuf[i] = Temporal[wbuf[i]];
00160
00161 paddb_m2r (cbuf[0], mm4);
00162 paddb_m2r (cbuf[8], mm6);
00163 movq_r2m (mm4, LinePrev[X]);
00164 movq_r2m (mm6, LinePrev[X+8]);
00165 movq_r2m (mm4, LineCur[X]);
00166 movq_r2m (mm6, LineCur[X+8]);
00167 }
00168
00169 for (; X < W; X++)
00170 LineCur[X] = Line[X] = LowPass (LinePrev[X], Line[X], Temporal);
00171
00172 LineCur += W;
00173 LinePrev += W;
00174 while (LineCur < End)
00175 {
00176 for (X = 1; X < W; X++)
00177 LineCur[X] = LowPass (LineCur[X-1], LineCur[X], Spatial);
00178
00179 for (X = 0; X < W - 15; X += 16)
00180 {
00181 movq_m2r (Line[X], mm0);
00182 movq_m2r (Line[X+8], mm2);
00183 movq_m2r (LineCur[X], mm4);
00184 movq_m2r (LineCur[X+8], mm6);
00185 movq_r2r (mm0, mm1);
00186 movq_r2r (mm2, mm3);
00187 movq_r2r (mm4, mm5);
00188 movq_r2r (mm6, mm7);
00189
00190 punpcklbw_m2r(mz, mm0);
00191 punpckhbw_m2r(mz, mm1);
00192 punpcklbw_m2r(mz, mm2);
00193 punpckhbw_m2r(mz, mm3);
00194 punpcklbw_m2r(mz, mm4);
00195 punpckhbw_m2r(mz, mm5);
00196 punpcklbw_m2r(mz, mm6);
00197 punpckhbw_m2r(mz, mm7);
00198
00199 psubw_r2r (mm4, mm0);
00200 psubw_r2r (mm5, mm1);
00201 psubw_r2r (mm6, mm2);
00202 psubw_r2r (mm7, mm3);
00203
00204 movq_r2m (mm0, wbuf[0]);
00205 movq_r2m (mm1, wbuf[4]);
00206 movq_r2m (mm2, wbuf[8]);
00207 movq_r2m (mm3, wbuf[12]);
00208
00209 movq_m2r (LineCur[X], mm4);
00210 movq_m2r (LineCur[X+8], mm6);
00211
00212 for (i = 0; i < 16; i++)
00213 cbuf[i] = Spatial[wbuf[i]];
00214
00215 movq_m2r (LinePrev[X], mm0);
00216 movq_m2r (LinePrev[X+8], mm2);
00217 paddb_m2r (cbuf[0], mm4);
00218 paddb_m2r (cbuf[8], mm6);
00219 movq_r2m (mm4, Line[X]);
00220 movq_r2m (mm6, Line[X+8]);
00221
00222 movq_r2r (mm0, mm1);
00223 movq_r2r (mm2, mm3);
00224 movq_r2r (mm4, mm5);
00225 movq_r2r (mm6, mm7);
00226
00227 punpcklbw_m2r(mz, mm0);
00228 punpckhbw_m2r(mz, mm1);
00229 punpcklbw_m2r(mz, mm2);
00230 punpckhbw_m2r(mz, mm3);
00231 punpcklbw_m2r(mz, mm4);
00232 punpckhbw_m2r(mz, mm5);
00233 punpcklbw_m2r(mz, mm6);
00234 punpckhbw_m2r(mz, mm7);
00235
00236 psubw_r2r (mm4, mm0);
00237 psubw_r2r (mm5, mm1);
00238 psubw_r2r (mm6, mm2);
00239 psubw_r2r (mm7, mm3);
00240
00241 movq_r2m (mm0, wbuf[0]);
00242 movq_r2m (mm1, wbuf[4]);
00243 movq_r2m (mm2, wbuf[8]);
00244 movq_r2m (mm3, wbuf[12]);
00245
00246 movq_m2r (Line[X], mm4);
00247 movq_m2r (Line[X+8], mm6);
00248
00249 for (i = 0; i < 16; i++)
00250 cbuf[i] = Temporal[wbuf[i]];
00251
00252 paddb_m2r (cbuf[0], mm4);
00253 paddb_m2r (cbuf[8], mm6);
00254 movq_r2m (mm4, LinePrev[X]);
00255 movq_r2m (mm6, LinePrev[X+8]);
00256 movq_r2m (mm4, LineCur[X]);
00257 movq_r2m (mm6, LineCur[X+8]);
00258 }
00259
00260 for (; X < W; X++)
00261 {
00262 Line[X] = LowPass (Line[X], LineCur[X], Spatial);
00263 LineCur[X] = LinePrev[X] = LowPass (LinePrev[X], Line[X], Temporal);
00264 }
00265
00266 LineCur += W;
00267 LinePrev += W;
00268 }
00269 }
00270 #endif
00271
00272 static int alloc_line(ThisFilter *filter, int size)
00273 {
00274 if (filter->line_size >= size)
00275 return 1;
00276
00277 uint8_t *tmp = realloc(filter->line, size);
00278 if (!tmp)
00279 {
00280 fprintf(stderr, "Couldn't allocate memory for line buffer\n");
00281 return 0;
00282 }
00283
00284 filter->line = tmp;
00285 filter->line_size = size;
00286
00287 return 1;
00288 }
00289
00290 static int alloc_prev(ThisFilter *filter, int size)
00291 {
00292 if (filter->prev_size >= size)
00293 return 1;
00294
00295 uint8_t *tmp = realloc(filter->prev, size);
00296 if (!tmp)
00297 {
00298 fprintf(stderr, "Couldn't allocate memory for frame buffer\n");
00299 return 0;
00300 }
00301
00302 filter->prev = tmp;
00303 filter->prev_size = size;
00304
00305 return 1;
00306 }
00307
00308 static int imax(int a, int b) { return (a > b) ? a : b; }
00309
00310 static int init_buf(ThisFilter *filter, VideoFrame *frame)
00311 {
00312 if (!alloc_prev(filter, frame->size))
00313 return 0;
00314
00315 int sz = imax(imax(frame->pitches[0], frame->pitches[1]), frame->pitches[2]);
00316 if (!alloc_line(filter, sz))
00317 return 0;
00318
00319 if ((filter->prev_size != frame->size) ||
00320 (filter->offsets[0] != frame->offsets[0]) ||
00321 (filter->offsets[1] != frame->offsets[1]) ||
00322 (filter->offsets[2] != frame->offsets[2]) ||
00323 (filter->pitches[0] != frame->pitches[0]) ||
00324 (filter->pitches[1] != frame->pitches[1]) ||
00325 (filter->pitches[2] != frame->pitches[2]))
00326 {
00327 memcpy(filter->prev, frame->buf, frame->size);
00328 memcpy(filter->offsets, frame->offsets, sizeof(int) * 3);
00329 memcpy(filter->pitches, frame->pitches, sizeof(int) * 3);
00330 }
00331
00332 return 1;
00333 }
00334
00335 static int denoise3DFilter(VideoFilter *f, VideoFrame *frame)
00336 {
00337 ThisFilter *filter = (ThisFilter*) f;
00338 TF_VARS;
00339
00340 if (!init_buf(filter, frame))
00341 return -1;
00342
00343 TF_START;
00344
00345 #ifdef MMX
00346 if (filter->mm_flags & MM_MMX)
00347 emms();
00348 #endif
00349
00350 (filter->filtfunc)(frame->buf + frame->offsets[0],
00351 filter->prev + frame->offsets[0],
00352 filter->line, frame->pitches[0], frame->height,
00353 filter->coefs[0] + 256,
00354 filter->coefs[1] + 256);
00355
00356 (filter->filtfunc)(frame->buf + frame->offsets[1],
00357 filter->prev + frame->offsets[1],
00358 filter->line, frame->pitches[1], frame->height >> 1,
00359 filter->coefs[2] + 256,
00360 filter->coefs[3] + 256);
00361
00362 (filter->filtfunc)(frame->buf + frame->offsets[2],
00363 filter->prev + frame->offsets[2],
00364 filter->line, frame->pitches[2], frame->height >> 1,
00365 filter->coefs[2] + 256,
00366 filter->coefs[3] + 256);
00367 #ifdef MMX
00368 if (filter->mm_flags & MM_MMX)
00369 emms();
00370 #endif
00371
00372 TF_END(filter, "Denoise3D: ");
00373 return 0;
00374 }
00375
00376 void Denoise3DFilterCleanup(VideoFilter *filter)
00377 {
00378 if (((ThisFilter*)filter)->prev)
00379 free(((ThisFilter*)filter)->prev);
00380
00381 if (((ThisFilter*)filter)->line)
00382 free (((ThisFilter*)filter)->line);
00383 }
00384
00385 VideoFilter *NewDenoise3DFilter(VideoFrameType inpixfmt, VideoFrameType outpixfmt,
00386 int *width, int *height, char *options)
00387 {
00388 double LumSpac = PARAM1_DEFAULT;
00389 double LumTmp = PARAM3_DEFAULT;
00390 double ChromSpac = PARAM2_DEFAULT;
00391 double ChromTmp = 0.0;
00392 ThisFilter *filter;
00393
00394 (void) width;
00395 (void) height;
00396
00397 if (inpixfmt != FMT_YV12 || outpixfmt != FMT_YV12)
00398 {
00399 fprintf(stderr, "Denoise3D: attempt to initialize "
00400 "with unsupported format\n");
00401 return NULL;
00402 }
00403
00404 filter = malloc(sizeof (ThisFilter));
00405 if (filter == NULL)
00406 {
00407 fprintf (stderr, "Denoise3D: failed to allocate memory for filter\n");
00408 return NULL;
00409 }
00410
00411 memset(filter, 0, sizeof(ThisFilter));
00412
00413 filter->vf.filter = &denoise3DFilter;
00414 filter->vf.cleanup = &Denoise3DFilterCleanup;
00415 filter->filtfunc = &denoise;
00416
00417 #ifdef MMX
00418 filter->mm_flags = mm_support();
00419 if (filter->mm_flags & MM_MMX)
00420 filter->filtfunc = &denoiseMMX;
00421 #endif
00422
00423 TF_INIT(filter);
00424
00425 if (options)
00426 {
00427 double param1, param2, param3;
00428 switch (sscanf (options, "%lf:%lf:%lf", ¶m1, ¶m2, ¶m3))
00429 {
00430 case 0:
00431 default:
00432 break;
00433
00434 case 1:
00435 LumSpac = param1;
00436 LumTmp = PARAM3_DEFAULT * param1 / PARAM1_DEFAULT;
00437 ChromSpac = PARAM2_DEFAULT * param1 / PARAM1_DEFAULT;
00438 break;
00439
00440 case 2:
00441 LumSpac = param1;
00442 LumTmp = PARAM3_DEFAULT * param1 / PARAM1_DEFAULT;
00443 ChromSpac = param2;
00444 break;
00445
00446 case 3:
00447 LumSpac = param1;
00448 LumTmp = param3;
00449 ChromSpac = param2;
00450 break;
00451 }
00452 }
00453
00454 ChromTmp = LumTmp * ChromSpac / LumSpac;
00455
00456 calc_coefs(filter->coefs[0], LumSpac);
00457 calc_coefs(filter->coefs[1], LumTmp);
00458 calc_coefs(filter->coefs[2], ChromSpac);
00459 calc_coefs(filter->coefs[3], ChromTmp);
00460
00461 return (VideoFilter*) filter;
00462 }
00463
00464 static FmtConv FmtList[] =
00465 {
00466 { FMT_YV12, FMT_YV12 },
00467 FMT_NULL
00468 };
00469
00470 FilterInfo filter_table[] =
00471 {
00472 {
00473 symbol: "NewDenoise3DFilter",
00474 name: "denoise3d",
00475 descript: "removes noise with a spatial and temporal low-pass filter",
00476 formats: FmtList,
00477 libname: NULL
00478 },
00479 FILT_NULL
00480 };