00001
00002
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005
00006 #ifdef HAVE_STDINT_H
00007 #include <stdint.h>
00008 #endif
00009
00010 #include <string.h>
00011 #include <math.h>
00012
00013 #include "libmythtv/filter.h"
00014 #include "libmythtv/frame.h"
00015
00016 #include "libmyth/mythconfig.h"
00017 #include "libavcodec/dsputil.h"
00018
00019 #include "libmyth/mythverbose.h"
00020
00021 #undef ABS
00022 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
00023 #define CLAMP(A,L,U) ((A)>(U)?(U):((A)<(L)?(L):(A)))
00024
00025 #ifdef MMX
00026 #include "i386/mmx.h"
00027
00028 static const mmx_t mm_cpool[] =
00029 {
00030 { 0x0000000000000000LL },
00031 };
00032
00033 #else
00034 #define mmx_t int
00035 #endif
00036
00037 typedef struct ThisFilter
00038 {
00039 VideoFilter vf;
00040
00041 int threshold;
00042 int skipchroma;
00043 int mm_flags;
00044 void (*filtfunc)(uint8_t*, uint8_t*, int, int, int);
00045 mmx_t threshold_low;
00046 mmx_t threshold_high;
00047 uint8_t *line;
00048 int linesize;
00049 TF_STRUCT;
00050 } ThisFilter;
00051
00052 void
00053 KDP (uint8_t *Plane, uint8_t *Line, int W, int H, int Threshold)
00054 {
00055 int X, Y;
00056 uint8_t *LineCur, *LineCur1U, *LineCur1D, *LineCur2D, tmp;
00057
00058 LineCur = Plane+W;
00059 LineCur1U = Plane;
00060 LineCur1D = Plane+2*W;
00061 LineCur2D = Plane+3*W;
00062
00063 for (X = 0; X < W ; X++)
00064 {
00065 Line[X] = LineCur[X];
00066 if (Threshold == 0 || ABS((int)LineCur[X]-(int)LineCur1U[X])
00067 > Threshold - 1)
00068 LineCur[X] = (LineCur1U[X] + LineCur1D[X]) / 2;
00069 }
00070 LineCur += 2 * W;
00071 LineCur1U += 2 * W;
00072 LineCur1D += 2 * W;
00073 LineCur2D += 2 * W;
00074 for (Y = 3; Y < H / 2 - 1; Y++)
00075 {
00076 for (X = 0; X < W; X++)
00077 {
00078 tmp = Line[X];
00079 Line[X] = LineCur[X];
00080 if (Threshold == 0 || ABS((int)LineCur[X] - (int)LineCur1U[X])
00081 > Threshold-1)
00082 LineCur[X] = CLAMP((LineCur1U[X] * 4 + LineCur1D[X] * 4
00083 + LineCur[X] * 2 - tmp - LineCur2D[X])
00084 / 8, 0, 255);
00085 }
00086 LineCur += 2 * W;
00087 LineCur1U += 2 * W;
00088 LineCur1D += 2 * W;
00089 LineCur2D += 2 * W;
00090 }
00091 for (X = 0; X < W; X++)
00092 if (Threshold == 0 || ABS((int)LineCur[X] - (int)LineCur1U[X])
00093 > Threshold - 1)
00094 LineCur[X] = LineCur1U[X];
00095 }
00096
00097 #ifdef MMX
00098 void
00099 KDP_MMX (uint8_t *Plane, uint8_t *Line, int W, int H, int Threshold)
00100 {
00101 int X, Y;
00102 uint8_t *LineCur, *LineCur1U, *LineCur1D, *LineCur2D, tmp;
00103 mmx_t mm_lthr = { w:{-Threshold,-Threshold,-Threshold,-Threshold} };
00104 mmx_t mm_hthr = { w:{Threshold-(Threshold>0),Threshold-(Threshold>0),
00105 Threshold-(Threshold>0),Threshold-(Threshold>0)} };
00106
00107 LineCur = Plane+W;
00108 LineCur1U = Plane;
00109 LineCur1D = Plane+2*W;
00110 LineCur2D = Plane+3*W;
00111
00112 for (X = 0; X < W - 7; X += 8)
00113 {
00114 movq_m2r (LineCur1U[X], mm0);
00115 movq_m2r (LineCur1U[X], mm1);
00116 movq_m2r (LineCur1D[X], mm2);
00117 movq_m2r (LineCur1D[X], mm3);
00118 movq_m2r (LineCur[X], mm4);
00119 movq_m2r (LineCur[X], mm5);
00120 punpcklbw_m2r (mm_cpool[0], mm0);
00121 punpckhbw_m2r (mm_cpool[0], mm1);
00122 punpcklbw_m2r (mm_cpool[0], mm2);
00123 punpckhbw_m2r (mm_cpool[0], mm3);
00124 movq_r2r (mm0, mm6);
00125 movq_r2r (mm1, mm7);
00126 punpcklbw_m2r (mm_cpool[0], mm4);
00127 punpckhbw_m2r (mm_cpool[0], mm5);
00128 paddw_r2r (mm2, mm0);
00129 paddw_r2r (mm3, mm1);
00130 psrlw_i2r (1, mm0);
00131 psrlw_i2r (1, mm1);
00132 psubw_r2r (mm6, mm4);
00133 psubw_r2r (mm7, mm5);
00134 packuswb_r2r (mm1,mm0);
00135 movq_r2r (mm4, mm6);
00136 movq_r2r (mm5, mm7);
00137 pcmpgtw_m2r (mm_lthr, mm4);
00138 pcmpgtw_m2r (mm_lthr, mm5);
00139 pcmpgtw_m2r (mm_hthr, mm6);
00140 pcmpgtw_m2r (mm_hthr, mm7);
00141 packsswb_r2r (mm5, mm4);
00142 packsswb_r2r (mm7, mm6);
00143 pxor_r2r (mm6, mm4);
00144 movq_r2r (mm4, mm5);
00145 pandn_r2r (mm0, mm4);
00146 pand_m2r (LineCur[X], mm5);
00147 por_r2r (mm4, mm5);
00148 movq_r2m (mm5, LineCur[X]);
00149 }
00150
00151 for (; X < W ; X++)
00152 {
00153 Line[X] = LineCur[X];
00154 if (Threshold == 0 || ABS((int)LineCur[X]-(int)LineCur1U[X])
00155 > Threshold - 1)
00156 LineCur[X] = (LineCur1U[X] + LineCur1D[X]) / 2;
00157 }
00158
00159 LineCur += 2 * W;
00160 LineCur1U += 2 * W;
00161 LineCur1D += 2 * W;
00162 LineCur2D += 2 * W;
00163 for (Y = 0; Y < H / 2 - 2; Y++)
00164 {
00165 for (X = 0; X < W - 7; X += 8)
00166 {
00167 movq_m2r (LineCur1U[X], mm0);
00168 movq_m2r (LineCur1U[X], mm1);
00169 movq_m2r (LineCur1D[X], mm2);
00170 movq_m2r (LineCur1D[X], mm3);
00171 movq_m2r (LineCur[X], mm4);
00172 movq_m2r (LineCur[X], mm5);
00173 punpcklbw_m2r (mm_cpool[0], mm0);
00174 punpckhbw_m2r (mm_cpool[0], mm1);
00175 punpcklbw_m2r (mm_cpool[0], mm2);
00176 punpckhbw_m2r (mm_cpool[0], mm3);
00177 movq_r2r (mm0, mm6);
00178 movq_r2r (mm1, mm7);
00179 paddw_r2r (mm2, mm0);
00180 paddw_r2r (mm3, mm1);
00181 movq_m2r (LineCur[X], mm2);
00182 movq_m2r (LineCur[X], mm3);
00183 psllw_i2r (2, mm0);
00184 psllw_i2r (2, mm1);
00185 punpcklbw_m2r (mm_cpool[0], mm2);
00186 punpckhbw_m2r (mm_cpool[0], mm3);
00187 psllw_i2r (1, mm2);
00188 psllw_i2r (1, mm3);
00189 paddw_r2r (mm2, mm0);
00190 paddw_r2r (mm3, mm1);
00191 movq_m2r (Line[X], mm2);
00192 movq_m2r (Line[X], mm3);
00193 punpcklbw_m2r (mm_cpool[0], mm2);
00194 punpckhbw_m2r (mm_cpool[0], mm3);
00195 movq_r2m (mm4, Line[X]);
00196 punpcklbw_m2r (mm_cpool[0], mm4);
00197 punpckhbw_m2r (mm_cpool[0], mm5);
00198 psubusw_r2r (mm2, mm0);
00199 psubusw_r2r (mm3, mm1);
00200 movq_m2r (LineCur2D[X], mm2);
00201 movq_m2r (LineCur2D[X], mm3);
00202 punpcklbw_m2r (mm_cpool[0], mm2);
00203 punpckhbw_m2r (mm_cpool[0], mm3);
00204 psubusw_r2r (mm2, mm0);
00205 psubusw_r2r (mm3, mm1);
00206 psrlw_i2r (3, mm0);
00207 psrlw_i2r (3, mm1);
00208 psubw_r2r (mm6, mm4);
00209 psubw_r2r (mm7, mm5);
00210 packuswb_r2r (mm1,mm0);
00211 movq_r2r (mm4, mm6);
00212 movq_r2r (mm5, mm7);
00213 pcmpgtw_m2r (mm_lthr, mm4);
00214 pcmpgtw_m2r (mm_lthr, mm5);
00215 pcmpgtw_m2r (mm_hthr, mm6);
00216 pcmpgtw_m2r (mm_hthr, mm7);
00217 packsswb_r2r (mm5, mm4);
00218 packsswb_r2r (mm7, mm6);
00219 pxor_r2r (mm6, mm4);
00220 movq_r2r (mm4, mm5);
00221 pandn_r2r (mm0, mm4);
00222 pand_m2r (LineCur[X], mm5);
00223 por_r2r (mm4, mm5);
00224 movq_r2m (mm5, LineCur[X]);
00225 }
00226
00227 for (; X < W; X++)
00228 {
00229 tmp = Line[X];
00230 Line[X] = LineCur[X];
00231 if (Threshold == 0 || ABS((int)LineCur[X] - (int)LineCur1U[X])
00232 > Threshold-1)
00233 LineCur[X] = CLAMP((LineCur1U[X] * 4 + LineCur1D[X] * 4
00234 + LineCur[X] * 2 - tmp - LineCur2D[X])
00235 / 8, 0, 255);
00236 }
00237 LineCur += 2 * W;
00238 LineCur1U += 2 * W;
00239 LineCur1D += 2 * W;
00240 LineCur2D += 2 * W;
00241 }
00242 for (X = 0; X < W; X++)
00243 if (Threshold == 0 || ABS((int)LineCur[X] - (int)LineCur1U[X])
00244 > Threshold - 1)
00245 LineCur[X] = LineCur1U[X];
00246 }
00247 #endif
00248
00249 static int
00250 KernelDeint (VideoFilter * f, VideoFrame * frame)
00251 {
00252 ThisFilter *filter = (ThisFilter *) f;
00253 TF_VARS;
00254
00255 if (frame->pitches[0] > filter->linesize)
00256 {
00257 if (filter->line)
00258 free(filter->line);
00259 filter->line = malloc(frame->pitches[0]);
00260 filter->linesize = frame->pitches[0];
00261 }
00262
00263 if (!filter->line)
00264 {
00265 VERBOSE(VB_GENERAL, "KernelDeint: failed to allocate line buffer");
00266 return -1;
00267 }
00268
00269 TF_START;
00270 {
00271 unsigned char *ybeg = frame->buf + frame->offsets[0];
00272 unsigned char *ubeg = frame->buf + frame->offsets[1];
00273 unsigned char *vbeg = frame->buf + frame->offsets[2];
00274 int cheight = (frame->codec == FMT_YV12) ?
00275 (frame->height >> 1) : frame->height;
00276
00277 (filter->filtfunc)(ybeg, filter->line, frame->pitches[0],
00278 frame->height, filter->threshold);
00279
00280 if (!filter->skipchroma)
00281 {
00282 (filter->filtfunc)(ubeg, filter->line, frame->pitches[1],
00283 cheight, filter->threshold);
00284 (filter->filtfunc)(vbeg, filter->line, frame->pitches[2],
00285 cheight, filter->threshold);
00286 }
00287 #ifdef MMX
00288 if (filter->mm_flags)
00289 emms();
00290 #endif
00291 }
00292 TF_END(filter, "KernelDeint: ");
00293 return 0;
00294 }
00295
00296 void
00297 CleanupKernelDeintFilter (VideoFilter * filter)
00298 {
00299 if (((ThisFilter *)filter)->line)
00300 free (((ThisFilter *)filter)->line);
00301 }
00302
00303 VideoFilter *
00304 NewKernelDeintFilter (VideoFrameType inpixfmt, VideoFrameType outpixfmt,
00305 int *width, int *height, char *options)
00306 {
00307 ThisFilter *filter;
00308 int numopts;
00309 (void) height;
00310
00311 if ( inpixfmt != outpixfmt ||
00312 (inpixfmt != FMT_YV12 && inpixfmt != FMT_YUV422P) )
00313 {
00314 VERBOSE(VB_GENERAL, "KernelDeint: valid format conversions are"
00315 " YV12->YV12 or YUV422P->YUV422P\n");
00316 return NULL;
00317 }
00318
00319 filter = (ThisFilter *) malloc (sizeof(ThisFilter));
00320 if (filter == NULL)
00321 {
00322 VERBOSE(VB_GENERAL,
00323 "KernelDeint: failed to allocate memory for filter");
00324 return NULL;
00325 }
00326
00327 numopts = options ? sscanf(options, "%d:%d", &(filter->threshold), &(filter->skipchroma)) : 0;
00328 if (numopts < 2)
00329 filter->skipchroma = 0;
00330 if (numopts < 1)
00331 filter->threshold = 12;
00332
00333 #ifdef MMX
00334 filter->mm_flags = mm_support();
00335 if (filter->mm_flags & MM_MMX)
00336 filter->filtfunc = &KDP_MMX;
00337 else
00338 #else
00339 filter->mm_flags = 0,
00340 #endif
00341 filter->filtfunc = &KDP;
00342
00343 filter->line = malloc(*width);
00344 filter->linesize = *width;
00345
00346 if (filter->line == NULL)
00347 {
00348 VERBOSE(VB_GENERAL, "KernelDeint: failed to allocate line buffer");
00349 free (filter);
00350 return NULL;
00351 }
00352 TF_INIT(filter);
00353
00354 filter->vf.filter = &KernelDeint;
00355 filter->vf.cleanup = &CleanupKernelDeintFilter;
00356 return (VideoFilter *) filter;
00357 }
00358
00359 static FmtConv FmtList[] =
00360 {
00361 { FMT_YV12, FMT_YV12 },
00362 { FMT_YUV422P, FMT_YUV422P },
00363 FMT_NULL
00364 };
00365
00366 FilterInfo filter_table[] =
00367 {
00368 {
00369 symbol: "NewKernelDeintFilter",
00370 name: "kerneldeint",
00371 descript: "combines data from several fields to deinterlace with less motion blur",
00372 formats: FmtList,
00373 libname: NULL
00374 },
00375 FILT_NULL
00376 };