00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022
00023 #include "config.h"
00024 #include "mp_msg.h"
00025 #include "cpudetect.h"
00026
00027 #include "img_format.h"
00028 #include "mp_image.h"
00029 #include "vf.h"
00030
00031 #include "libvo/fastmemcpy.h"
00032
00033
00034 struct metrics {
00035
00036 int d, e, o;
00037
00038 int t, s, p;
00039 };
00040
00041 struct frameinfo {
00042
00043 struct metrics p, r, m;
00044 };
00045
00046 struct vf_priv_s {
00047 struct frameinfo fi[2];
00048 mp_image_t *dmpi;
00049 int first;
00050 int drop, lastdrop, dropnext;
00051 int inframes, outframes;
00052 };
00053
00054 enum {
00055 F_DROP,
00056 F_MERGE,
00057 F_NEXT,
00058 F_SHOW
00059 };
00060
00061 #if HAVE_MMX && HAVE_EBX_AVAILABLE
00062 static void block_diffs_MMX(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
00063 {
00064 int i;
00065 short out[24];
00066
00067 __asm__ (
00068 "movl $4, %%ecx \n\t"
00069 "pxor %%mm4, %%mm4 \n\t"
00070 "pxor %%mm5, %%mm5 \n\t"
00071 "pxor %%mm7, %%mm7 \n\t"
00072
00073 ASMALIGN(4)
00074 "1: \n\t"
00075
00076
00077 "movq (%%"REG_S"), %%mm0 \n\t"
00078 "movq (%%"REG_S"), %%mm2 \n\t"
00079 "add %%"REG_a", %%"REG_S" \n\t"
00080 "movq (%%"REG_D"), %%mm1 \n\t"
00081 "add %%"REG_b", %%"REG_D" \n\t"
00082 "psubusb %%mm1, %%mm2 \n\t"
00083 "psubusb %%mm0, %%mm1 \n\t"
00084 "movq %%mm2, %%mm0 \n\t"
00085 "movq %%mm1, %%mm3 \n\t"
00086 "punpcklbw %%mm7, %%mm0 \n\t"
00087 "punpcklbw %%mm7, %%mm1 \n\t"
00088 "punpckhbw %%mm7, %%mm2 \n\t"
00089 "punpckhbw %%mm7, %%mm3 \n\t"
00090 "paddw %%mm0, %%mm4 \n\t"
00091 "paddw %%mm1, %%mm4 \n\t"
00092 "paddw %%mm2, %%mm4 \n\t"
00093 "paddw %%mm3, %%mm4 \n\t"
00094
00095
00096 "movq (%%"REG_S"), %%mm0 \n\t"
00097 "movq (%%"REG_S"), %%mm2 \n\t"
00098 "add %%"REG_a", %%"REG_S" \n\t"
00099 "movq (%%"REG_D"), %%mm1 \n\t"
00100 "add %%"REG_b", %%"REG_D" \n\t"
00101 "psubusb %%mm1, %%mm2 \n\t"
00102 "psubusb %%mm0, %%mm1 \n\t"
00103 "movq %%mm2, %%mm0 \n\t"
00104 "movq %%mm1, %%mm3 \n\t"
00105 "punpcklbw %%mm7, %%mm0 \n\t"
00106 "punpcklbw %%mm7, %%mm1 \n\t"
00107 "punpckhbw %%mm7, %%mm2 \n\t"
00108 "punpckhbw %%mm7, %%mm3 \n\t"
00109 "paddw %%mm0, %%mm5 \n\t"
00110 "paddw %%mm1, %%mm5 \n\t"
00111 "paddw %%mm2, %%mm5 \n\t"
00112 "paddw %%mm3, %%mm5 \n\t"
00113
00114 "decl %%ecx \n\t"
00115 "jnz 1b \n\t"
00116 "movq %%mm4, (%%"REG_d") \n\t"
00117 "movq %%mm5, 8(%%"REG_d") \n\t"
00118 :
00119 : "S" (old), "D" (new), "a" (os), "b" (ns), "d" (out)
00120 : "memory"
00121 );
00122 m->e = out[0]+out[1]+out[2]+out[3];
00123 m->o = out[4]+out[5]+out[6]+out[7];
00124 m->d = m->e + m->o;
00125
00126 __asm__ (
00127
00128 "movl $4, %%ecx \n\t"
00129 "pxor %%mm4, %%mm4 \n\t"
00130 "pxor %%mm5, %%mm5 \n\t"
00131 "pxor %%mm6, %%mm6 \n\t"
00132
00133 ASMALIGN(4)
00134 "2: \n\t"
00135
00136 "movq (%%"REG_S"), %%mm0 \n\t"
00137 "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
00138 "add %%"REG_a", %%"REG_S" \n\t"
00139 "add %%"REG_a", %%"REG_S" \n\t"
00140 "movq (%%"REG_D"), %%mm2 \n\t"
00141 "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t"
00142 "add %%"REG_b", %%"REG_D" \n\t"
00143 "add %%"REG_b", %%"REG_D" \n\t"
00144 "punpcklbw %%mm7, %%mm0 \n\t"
00145 "punpcklbw %%mm7, %%mm1 \n\t"
00146 "punpcklbw %%mm7, %%mm2 \n\t"
00147 "punpcklbw %%mm7, %%mm3 \n\t"
00148 "paddw %%mm1, %%mm4 \n\t"
00149 "paddw %%mm1, %%mm5 \n\t"
00150 "paddw %%mm3, %%mm6 \n\t"
00151 "psubw %%mm0, %%mm4 \n\t"
00152 "psubw %%mm2, %%mm5 \n\t"
00153 "psubw %%mm2, %%mm6 \n\t"
00154
00155 "decl %%ecx \n\t"
00156 "jnz 2b \n\t"
00157
00158 "movq %%mm0, %%mm1 \n\t"
00159 "movq %%mm0, %%mm2 \n\t"
00160 "movq %%mm0, %%mm3 \n\t"
00161 "pcmpgtw %%mm4, %%mm1 \n\t"
00162 "pcmpgtw %%mm5, %%mm2 \n\t"
00163 "pcmpgtw %%mm6, %%mm3 \n\t"
00164 "pxor %%mm1, %%mm4 \n\t"
00165 "pxor %%mm2, %%mm5 \n\t"
00166 "pxor %%mm3, %%mm6 \n\t"
00167 "psubw %%mm1, %%mm4 \n\t"
00168 "psubw %%mm2, %%mm5 \n\t"
00169 "psubw %%mm3, %%mm6 \n\t"
00170 "movq %%mm4, (%%"REG_d") \n\t"
00171 "movq %%mm5, 16(%%"REG_d") \n\t"
00172 "movq %%mm6, 32(%%"REG_d") \n\t"
00173
00174 "mov %%"REG_a", %%"REG_c" \n\t"
00175 "shl $3, %%"REG_c" \n\t"
00176 "sub %%"REG_c", %%"REG_S" \n\t"
00177 "mov %%"REG_b", %%"REG_c" \n\t"
00178 "shl $3, %%"REG_c" \n\t"
00179 "sub %%"REG_c", %%"REG_D" \n\t"
00180
00181
00182 "movl $4, %%ecx \n\t"
00183 "pxor %%mm4, %%mm4 \n\t"
00184 "pxor %%mm5, %%mm5 \n\t"
00185 "pxor %%mm6, %%mm6 \n\t"
00186
00187 ASMALIGN(4)
00188 "3: \n\t"
00189
00190 "movq (%%"REG_S"), %%mm0 \n\t"
00191 "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
00192 "add %%"REG_a", %%"REG_S" \n\t"
00193 "add %%"REG_a", %%"REG_S" \n\t"
00194 "movq (%%"REG_D"), %%mm2 \n\t"
00195 "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t"
00196 "add %%"REG_b", %%"REG_D" \n\t"
00197 "add %%"REG_b", %%"REG_D" \n\t"
00198 "punpckhbw %%mm7, %%mm0 \n\t"
00199 "punpckhbw %%mm7, %%mm1 \n\t"
00200 "punpckhbw %%mm7, %%mm2 \n\t"
00201 "punpckhbw %%mm7, %%mm3 \n\t"
00202 "paddw %%mm1, %%mm4 \n\t"
00203 "paddw %%mm1, %%mm5 \n\t"
00204 "paddw %%mm3, %%mm6 \n\t"
00205 "psubw %%mm0, %%mm4 \n\t"
00206 "psubw %%mm2, %%mm5 \n\t"
00207 "psubw %%mm2, %%mm6 \n\t"
00208
00209 "decl %%ecx \n\t"
00210 "jnz 3b \n\t"
00211
00212 "movq %%mm0, %%mm1 \n\t"
00213 "movq %%mm0, %%mm2 \n\t"
00214 "movq %%mm0, %%mm3 \n\t"
00215 "pcmpgtw %%mm4, %%mm1 \n\t"
00216 "pcmpgtw %%mm5, %%mm2 \n\t"
00217 "pcmpgtw %%mm6, %%mm3 \n\t"
00218 "pxor %%mm1, %%mm4 \n\t"
00219 "pxor %%mm2, %%mm5 \n\t"
00220 "pxor %%mm3, %%mm6 \n\t"
00221 "psubw %%mm1, %%mm4 \n\t"
00222 "psubw %%mm2, %%mm5 \n\t"
00223 "psubw %%mm3, %%mm6 \n\t"
00224 "movq %%mm4, 8(%%"REG_d") \n\t"
00225 "movq %%mm5, 24(%%"REG_d") \n\t"
00226 "movq %%mm6, 40(%%"REG_d") \n\t"
00227
00228 "emms \n\t"
00229 :
00230 : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out)
00231 : "memory"
00232 );
00233 m->p = m->t = m->s = 0;
00234 for (i=0; i<8; i++) {
00235 m->p += out[i];
00236 m->t += out[8+i];
00237 m->s += out[16+i];
00238 }
00239
00240 }
00241 #endif
00242
00243
00244
00245 #define MAG(a) (((a)^((a)>>31))-((a)>>31))
00246
00247
00248
00249 #define LOWPASS(s) ((s)[0])
00250
00251
00252 static void block_diffs_C(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
00253 {
00254 int x, y, e=0, o=0, s=0, p=0, t=0;
00255 unsigned char *oldp, *newp;
00256 m->s = m->p = m->t = 0;
00257 for (x = 8; x; x--) {
00258 oldp = old++;
00259 newp = new++;
00260 s = p = t = 0;
00261 for (y = 4; y; y--) {
00262 e += MAG(newp[0]-oldp[0]);
00263 o += MAG(newp[ns]-oldp[os]);
00264 s += newp[ns]-newp[0];
00265 p += oldp[os]-oldp[0];
00266 t += oldp[os]-newp[0];
00267 oldp += os<<1;
00268 newp += ns<<1;
00269 }
00270 m->s += MAG(s);
00271 m->p += MAG(p);
00272 m->t += MAG(t);
00273 }
00274 m->e = e;
00275 m->o = o;
00276 m->d = e+o;
00277 }
00278
00279 static void (*block_diffs)(struct metrics *, unsigned char *, unsigned char *, int, int);
00280
00281 #define MAXUP(a,b) ((a) = ((a)>(b)) ? (a) : (b))
00282
00283 static void diff_planes(struct frameinfo *fi,
00284 unsigned char *old, unsigned char *new, int w, int h, int os, int ns)
00285 {
00286 int x, y;
00287 struct metrics l;
00288 struct metrics *peak=&fi->p, *rel=&fi->r, *mean=&fi->m;
00289 memset(peak, 0, sizeof(struct metrics));
00290 memset(rel, 0, sizeof(struct metrics));
00291 memset(mean, 0, sizeof(struct metrics));
00292 for (y = 0; y < h-7; y += 8) {
00293 for (x = 8; x < w-8-7; x += 8) {
00294 block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns);
00295 mean->d += l.d;
00296 mean->e += l.e;
00297 mean->o += l.o;
00298 mean->s += l.s;
00299 mean->p += l.p;
00300 mean->t += l.t;
00301 MAXUP(peak->d, l.d);
00302 MAXUP(peak->e, l.e);
00303 MAXUP(peak->o, l.o);
00304 MAXUP(peak->s, l.s);
00305 MAXUP(peak->p, l.p);
00306 MAXUP(peak->t, l.t);
00307 MAXUP(rel->e, l.e-l.o);
00308 MAXUP(rel->o, l.o-l.e);
00309 MAXUP(rel->s, l.s-l.t);
00310 MAXUP(rel->p, l.p-l.t);
00311 MAXUP(rel->t, l.t-l.p);
00312 MAXUP(rel->d, l.t-l.s);
00313 }
00314 }
00315 x = (w/8-2)*(h/8);
00316 mean->d /= x;
00317 mean->e /= x;
00318 mean->o /= x;
00319 mean->s /= x;
00320 mean->p /= x;
00321 mean->t /= x;
00322 }
00323
00324 static void diff_fields(struct frameinfo *fi, mp_image_t *old, mp_image_t *new)
00325 {
00326 diff_planes(fi, old->planes[0], new->planes[0],
00327 new->w, new->h, old->stride[0], new->stride[0]);
00328 }
00329
00330 static void stats(struct frameinfo *f)
00331 {
00332 mp_msg(MSGT_VFILTER, MSGL_V, " pd=%d re=%d ro=%d rp=%d rt=%d rs=%d rd=%d pp=%d pt=%d ps=%d\r",
00333 f->p.d, f->r.e, f->r.o, f->r.p, f->r.t, f->r.s, f->r.d, f->p.p, f->p.t, f->p.s);
00334 }
00335
00336 static int foo(struct vf_priv_s *p, mp_image_t *new, mp_image_t *cur)
00337 {
00338 struct frameinfo *f = p->fi;
00339
00340 f[0] = f[1];
00341 diff_fields(&f[1], cur, new);
00342 stats(&f[1]);
00343
00344
00345 if (p->dropnext) {
00346 p->dropnext = 0;
00347 return F_DROP;
00348 }
00349
00350
00351
00352
00353
00354
00355 if ((3*f[1].r.o < f[1].r.e) && (f[1].r.s < f[1].r.d)) {
00356 p->dropnext = 1;
00357 return F_NEXT;
00358 }
00359
00360
00361
00362 if (!( (3*f[0].r.e < f[0].r.o) ||
00363 ((2*f[0].r.d < f[0].r.s) && (f[0].r.s > 1200)) ||
00364 ((2*f[1].r.t < f[1].r.p) && (f[1].r.p > 1200)) ))
00365 return F_SHOW;
00366
00367
00368
00369
00370 if (((2*f[1].r.t < 3*f[1].r.p) && (f[1].r.t < 3600)) ||
00371 (f[1].r.t < 900) || (f[1].r.d < 900)) {
00372
00373
00374 if ((3*f[0].r.e < f[0].r.o) || (2*f[1].r.t < f[1].r.p)) {
00375 p->dropnext = 1;
00376 return F_MERGE;
00377 }
00378 }
00379 return F_DROP;
00380 }
00381
00382
00383
00384 static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field)
00385 {
00386 switch (field) {
00387 case 0:
00388 my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2,
00389 dmpi->stride[0]*2, mpi->stride[0]*2);
00390 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00391 my_memcpy_pic(dmpi->planes[1], mpi->planes[1],
00392 mpi->chroma_width, mpi->chroma_height/2,
00393 dmpi->stride[1]*2, mpi->stride[1]*2);
00394 my_memcpy_pic(dmpi->planes[2], mpi->planes[2],
00395 mpi->chroma_width, mpi->chroma_height/2,
00396 dmpi->stride[2]*2, mpi->stride[2]*2);
00397 }
00398 break;
00399 case 1:
00400 my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
00401 mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2,
00402 dmpi->stride[0]*2, mpi->stride[0]*2);
00403 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00404 my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1],
00405 mpi->planes[1]+mpi->stride[1],
00406 mpi->chroma_width, mpi->chroma_height/2,
00407 dmpi->stride[1]*2, mpi->stride[1]*2);
00408 my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2],
00409 mpi->planes[2]+mpi->stride[2],
00410 mpi->chroma_width, mpi->chroma_height/2,
00411 dmpi->stride[2]*2, mpi->stride[2]*2);
00412 }
00413 break;
00414 case 2:
00415 memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h,
00416 dmpi->stride[0], mpi->stride[0]);
00417 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00418 memcpy_pic(dmpi->planes[1], mpi->planes[1],
00419 mpi->chroma_width, mpi->chroma_height,
00420 dmpi->stride[1], mpi->stride[1]);
00421 memcpy_pic(dmpi->planes[2], mpi->planes[2],
00422 mpi->chroma_width, mpi->chroma_height,
00423 dmpi->stride[2], mpi->stride[2]);
00424 }
00425 break;
00426 }
00427 }
00428
00429 static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi)
00430 {
00431 struct vf_priv_s *p = vf->priv;
00432 int dropflag=0;
00433
00434 if (!p->dropnext) switch (p->drop) {
00435 case 0:
00436 dropflag = 0;
00437 break;
00438 case 1:
00439 dropflag = (++p->lastdrop >= 5);
00440 break;
00441 case 2:
00442 dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes);
00443 break;
00444 }
00445
00446 if (dropflag) {
00447
00448
00449 mp_msg(MSGT_VFILTER, MSGL_V, "!");
00450 p->lastdrop = 0;
00451 return 0;
00452 }
00453
00454 p->outframes++;
00455 return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
00456 }
00457
00458 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
00459 {
00460 int ret=0;
00461 struct vf_priv_s *p = vf->priv;
00462
00463 p->inframes++;
00464
00465 if (p->first) {
00466 p->first = 0;
00467 return 1;
00468 }
00469
00470 if (!p->dmpi) p->dmpi = vf_get_image(vf->next, mpi->imgfmt,
00471 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
00472 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
00473 mpi->width, mpi->height);
00474
00475 p->dmpi->qscale = mpi->qscale;
00476 p->dmpi->qstride = mpi->qstride;
00477 p->dmpi->qscale_type = mpi->qscale_type;
00478
00479 switch (foo(p, mpi, p->dmpi)) {
00480 case F_DROP:
00481 copy_image(p->dmpi, mpi, 2);
00482 ret = 0;
00483 p->lastdrop = 0;
00484 mp_msg(MSGT_VFILTER, MSGL_V, "DROP\n");
00485 break;
00486 case F_MERGE:
00487 copy_image(p->dmpi, mpi, 0);
00488 ret = do_put_image(vf, p->dmpi);
00489 copy_image(p->dmpi, mpi, 1);
00490 mp_msg(MSGT_VFILTER, MSGL_V, "MERGE\n");
00491 p->dmpi = NULL;
00492 break;
00493 case F_NEXT:
00494 copy_image(p->dmpi, mpi, 2);
00495 ret = do_put_image(vf, p->dmpi);
00496 mp_msg(MSGT_VFILTER, MSGL_V, "NEXT\n");
00497 p->dmpi = NULL;
00498 break;
00499 case F_SHOW:
00500 ret = do_put_image(vf, p->dmpi);
00501 copy_image(p->dmpi, mpi, 2);
00502 mp_msg(MSGT_VFILTER, MSGL_V, "OK\n");
00503 p->dmpi = NULL;
00504 break;
00505 }
00506 return ret;
00507 }
00508
00509 static int query_format(struct vf_instance *vf, unsigned int fmt)
00510 {
00511 switch (fmt) {
00512 case IMGFMT_YV12:
00513 case IMGFMT_IYUV:
00514 case IMGFMT_I420:
00515 return vf_next_query_format(vf, fmt);
00516 }
00517 return 0;
00518 }
00519
00520 static void uninit(struct vf_instance *vf)
00521 {
00522 free(vf->priv);
00523 }
00524
00525 static int vf_open(vf_instance_t *vf, char *args)
00526 {
00527 struct vf_priv_s *p;
00528 vf->put_image = put_image;
00529 vf->query_format = query_format;
00530 vf->uninit = uninit;
00531 vf->default_reqs = VFCAP_ACCEPT_STRIDE;
00532 vf->priv = p = calloc(1, sizeof(struct vf_priv_s));
00533 p->drop = 0;
00534 p->first = 1;
00535 if (args) sscanf(args, "%d", &p->drop);
00536 block_diffs = block_diffs_C;
00537 #if HAVE_MMX && HAVE_EBX_AVAILABLE
00538 if(gCpuCaps.hasMMX) block_diffs = block_diffs_MMX;
00539 #endif
00540 return 1;
00541 }
00542
00543 const vf_info_t vf_info_ivtc = {
00544 "inverse telecine, take 2",
00545 "ivtc",
00546 "Rich Felker",
00547 "",
00548 vf_open,
00549 NULL
00550 };