# HG changeset patch # User rfelker # Date 1050716377 0 # Node ID 3548701a13fe138e168ae2f967bea459365ff7f4 # Parent 208fcee0aa2d818a2cbd7742b9e7727149343d61 1. new alternate approach to inverse telecine! much better! 2. interlaced 4:2:0 planar to 4:2:2 packer. makes it possible to watch interlaced movies without horrible chroma artifacts, provided you have an interlaced display device. diff -r 208fcee0aa2d -r 3548701a13fe libmpcodecs/Makefile --- a/libmpcodecs/Makefile Fri Apr 18 22:33:30 2003 +0000 +++ b/libmpcodecs/Makefile Sat Apr 19 01:39:37 2003 +0000 @@ -14,7 +14,7 @@ VIDEO_SRCS_OPT=vd_realvid.c vd_ffmpeg.c vd_dshow.c vd_dmo.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_xanim.c vd_xvid.c vd_libdv.c vd_qtvideo.c VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT) -VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c vf_pp.c vf_scale.c vf_format.c vf_yuy2.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_yvu9.c vf_rectangle.c vf_lavcdeint.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c +VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c vf_pp.c vf_scale.c vf_format.c vf_yuy2.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_yvu9.c vf_rectangle.c vf_lavcdeint.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c vf_ivtc.c vf_ilpack.c ENCODER_SRCS=ve.c ve_divx4.c ve_lavc.c ve_vfw.c ve_rawrgb.c ve_libdv.c ve_xvid.c ve_qtvideo.c ve_nuv.c NATIVE_SRCS=native/RTjpegN.c native/cinepak.c native/fli.c native/minilzo.c native/msvidc.c native/nuppelvideo.c native/qtrle.c native/qtrpza.c native/qtsmc.c native/roqav.c native/xa_gsm.c native/svq1.c diff -r 208fcee0aa2d -r 3548701a13fe libmpcodecs/vf.c --- a/libmpcodecs/vf.c Fri Apr 18 22:33:30 2003 +0000 +++ b/libmpcodecs/vf.c Sat Apr 19 01:39:37 2003 +0000 @@ -63,6 +63,8 @@ extern vf_info_t vf_info_detc; extern vf_info_t vf_info_telecine; extern vf_info_t vf_info_tfields; +extern vf_info_t vf_info_ivtc; +extern vf_info_t vf_info_ilpack; // list of available filters: static vf_info_t* filter_list[]={ @@ -117,6 +119,8 @@ &vf_info_detc, &vf_info_telecine, &vf_info_tfields, + &vf_info_ivtc, + &vf_info_ilpack, NULL }; diff -r 208fcee0aa2d -r 3548701a13fe libmpcodecs/vf_ilpack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpcodecs/vf_ilpack.c Sat Apr 19 01:39:37 2003 +0000 @@ -0,0 +1,169 @@ +#include +#include +#include +#include + +#include "../config.h" +#include "../mp_msg.h" +#include "../cpudetect.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +#include "../libvo/fastmemcpy.h" +#include "../postproc/rgb2rgb.h" + +#ifdef HAVE_MMX +static void pack_MMX(unsigned char *dst, unsigned char *y, + unsigned char *u, unsigned char *v, int w) +{ + int j; + asm ("" + "pxor %%mm0, %%mm0 \n\t" + ".balign 16 \n\t" + "1: \n\t" + "movq (%0), %%mm1 \n\t" + "movq (%0), %%mm2 \n\t" + "punpcklbw %%mm0, %%mm1 \n\t" + "punpckhbw %%mm0, %%mm2 \n\t" + + "movq (%1), %%mm3 \n\t" + "movq (%2), %%mm5 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" + "punpcklbw %%mm0, %%mm5 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm5, %%mm6 \n\t" + "punpcklwd %%mm0, %%mm3 \n\t" + "punpckhwd %%mm0, %%mm4 \n\t" + "punpcklwd %%mm0, %%mm5 \n\t" + "punpckhwd %%mm0, %%mm6 \n\t" + "pslld $8, %%mm3 \n\t" + "pslld $8, %%mm4 \n\t" + "pslld $24, %%mm5 \n\t" + "pslld $24, %%mm6 \n\t" + + "por %%mm3, %%mm1 \n\t" + "por %%mm4, %%mm2 \n\t" + "por %%mm5, %%mm1 \n\t" + "por %%mm6, %%mm2 \n\t" + + "addl $8, %0 \n\t" + "addl $4, %1 \n\t" + "addl $4, %2 \n\t" + "movq %%mm1, (%3) \n\t" + "movq %%mm2, 8(%3) \n\t" + "addl $16, %3 \n\t" + "decl %4 \n\t" + "jnz 1b \n\t" + : + : "r" (y), "r" (u), "r" (v), "r" (dst), "r" (w/8) + : "memory" + ); + for (j = (w&7)/2; j; j--) { + *dst++ = *y++; + *dst++ = *u++; + *dst++ = *y++; + *dst++ = *v++; + } + asm volatile ( "emms \n\t" ::: "memory" ); +} +#endif + +static void pack_C(unsigned char *dst, unsigned char *y, + unsigned char *u, unsigned char *v, int w) +{ + int j; + for (j = w/2; j; j--) { + *dst++ = *y++; + *dst++ = *u++; + *dst++ = *y++; + *dst++ = *v++; + } +} + +static void (*pack)(unsigned char *dst, unsigned char *y, + unsigned char *u, unsigned char *v, int w); + +static void ilpack(unsigned char *dst, unsigned char *src[3], + unsigned int dststride, unsigned int srcstride[3], int w, int h) +{ + int i; + unsigned char *y, *u, *v; + + y = src[0]; + u = src[1]; + v = src[2]; + + for (i=0; inext, IMGFMT_YUY2, + MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, + mpi->w, mpi->h); + + ilpack(dmpi->planes[0], mpi->planes, dmpi->stride[0], mpi->stride, mpi->w, mpi->h); + + return vf_next_put_image(vf,dmpi); +} + +static int config(struct vf_instance_s* vf, + int width, int height, int d_width, int d_height, + unsigned int flags, unsigned int outfmt) +{ + /* FIXME - also support UYVY output? */ + return vf_next_config(vf, width, height, d_width, d_height, flags, IMGFMT_YUY2); +} + + +static int query_format(struct vf_instance_s* vf, unsigned int fmt) +{ + /* FIXME - really any YUV 4:2:0 input format should work */ + switch (fmt) { + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + return vf_next_query_format(vf,IMGFMT_YUY2); + } + return 0; +} + +static int open(vf_instance_t *vf, char* args) +{ + vf->config=config; + vf->query_format=query_format; + vf->put_image=put_image; + + pack = pack_C; +#ifdef HAVE_MMX + if(gCpuCaps.hasMMX) pack = pack_MMX; +#endif + return 1; +} + +vf_info_t vf_info_ilpack = { + "4:2:0 planar -> 4:2:2 packed reinterlacer", + "ilpack", + "Richard Felker", + "", + open, + NULL +}; + diff -r 208fcee0aa2d -r 3548701a13fe libmpcodecs/vf_ivtc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpcodecs/vf_ivtc.c Sat Apr 19 01:39:37 2003 +0000 @@ -0,0 +1,523 @@ +#include +#include +#include + +#include "../config.h" +#include "../mp_msg.h" +#include "../cpudetect.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +#include "../libvo/fastmemcpy.h" + + +struct metrics { + /* difference: total, even lines, odd lines */ + int d, e, o; + /* noise: temporal, spacial (current), spacial (past) */ + int t, s, p; +}; + +struct frameinfo { + /* peak, relative, mean */ + struct metrics p, r, m; +}; + +struct vf_priv_s { + struct frameinfo fi[2]; + mp_image_t *dmpi; + int first; + int drop, lastdrop, dropnext; + int inframes, outframes; +}; + +enum { + F_DROP, + F_MERGE, + F_NEXT, + F_SHOW +}; + +static inline void *my_memcpy_pic(void * dst, void * src, int bytesPerLine, int height, int dstStride, int srcStride) +{ + int i; + void *retval=dst; + + for(i=0; ie = out[0]+out[1]+out[2]+out[3]; + m->o = out[4]+out[5]+out[6]+out[7]; + m->d = m->e + m->o; + + asm ("" + // First loop to measure first four columns + "movl $4, %%ecx \n\t" + "pxor %%mm4, %%mm4 \n\t" // Past spacial noise + "pxor %%mm5, %%mm5 \n\t" // Temporal noise + "pxor %%mm6, %%mm6 \n\t" // Current spacial noise + + ".balign 16 \n\t" + "2: \n\t" + + "movq (%%esi), %%mm0 \n\t" + "movq (%%esi,%%eax), %%mm1 \n\t" + "addl %%eax, %%esi \n\t" + "addl %%eax, %%esi \n\t" + "movq (%%edi), %%mm2 \n\t" + "movq (%%edi,%%ebx), %%mm3 \n\t" + "addl %%ebx, %%edi \n\t" + "addl %%ebx, %%edi \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm1 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm3 \n\t" + "paddw %%mm1, %%mm4 \n\t" + "paddw %%mm1, %%mm5 \n\t" + "paddw %%mm3, %%mm6 \n\t" + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm2, %%mm5 \n\t" + "psubw %%mm2, %%mm6 \n\t" + + "decl %%ecx \n\t" + "jnz 2b \n\t" + "movq %%mm4, (%%edx) \n\t" + "movq %%mm5, 16(%%edx) \n\t" + "movq %%mm6, 32(%%edx) \n\t" + + "movl %%eax, %%ecx \n\t" + "shll $3, %%ecx \n\t" + "subl %%ecx, %%esi \n\t" + "movl %%ebx, %%ecx \n\t" + "shll $3, %%ecx \n\t" + "subl %%ecx, %%edi \n\t" + + // Second loop for the last four columns + "movl $4, %%ecx \n\t" + "pxor %%mm4, %%mm4 \n\t" + "pxor %%mm5, %%mm5 \n\t" + "pxor %%mm6, %%mm6 \n\t" + + ".balign 16 \n\t" + "3: \n\t" + + "movq (%%esi), %%mm0 \n\t" + "movq (%%esi,%%eax), %%mm1 \n\t" + "addl %%eax, %%esi \n\t" + "addl %%eax, %%esi \n\t" + "movq (%%edi), %%mm2 \n\t" + "movq (%%edi,%%ebx), %%mm3 \n\t" + "addl %%ebx, %%edi \n\t" + "addl %%ebx, %%edi \n\t" + "punpckhbw %%mm7, %%mm0 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddw %%mm1, %%mm4 \n\t" + "paddw %%mm1, %%mm5 \n\t" + "paddw %%mm3, %%mm6 \n\t" + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm2, %%mm5 \n\t" + "psubw %%mm2, %%mm6 \n\t" + + "decl %%ecx \n\t" + "jnz 3b \n\t" + "movq %%mm4, 8(%%edx) \n\t" + "movq %%mm5, 24(%%edx) \n\t" + "movq %%mm6, 40(%%edx) \n\t" + + "emms \n\t" + : + : "S" (old), "D" (new), "a" (os), "b" (ns), "d" (out) + : "memory" + ); + m->p = m->t = m->s = 0; + for (i=0; i<8; i++) { + // FIXME: move abs() into the mmx code! + m->p += abs(out[i]); + m->t += abs(out[8+i]); + m->s += abs(out[16+i]); + } + //printf("e=%d o=%d d=%d p=%d t=%d s=%d\n", m->e, m->o, m->d, m->p, m->t, m->s); +} +#endif + +//#define MAG(a) ((a)*(a)) +#define MAG(a) (abs(a)) + +//#define LOWPASS(s) (((s)[-2] + 4*(s)[-1] + 6*(s)[0] + 4*(s)[1] + (s)[2])>>4) +//#define LOWPASS(s) (((s)[-1] + 2*(s)[0] + (s)[1])>>2) +#define LOWPASS(s) ((s)[0]) + + +static void block_diffs_C(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns) +{ + int x, y, e=0, o=0, s=0, p=0, t=0; + unsigned char *oldp, *newp; + m->s = m->p = m->t = 0; + for (x = 8; x; x--) { + oldp = old++; + newp = new++; + s = p = t = 0; + for (y = 4; y; y--) { + e += MAG(newp[0]-oldp[0]); + o += MAG(newp[ns]-oldp[os]); + s += newp[ns]-newp[0]; + p += oldp[os]-oldp[0]; + t += oldp[os]-newp[0]; + oldp += os<<1; + newp += ns<<1; + } + m->s += MAG(s); + m->p += MAG(p); + m->t += MAG(t); + } + m->e = e; + m->o = o; + m->d = e+o; +} + +static void (*block_diffs)(struct metrics *, unsigned char *, unsigned char *, int, int); + +#define MAXUP(a,b) ((a) = ((a)>(b)) ? (a) : (b)) + +static void diff_planes(struct frameinfo *fi, + unsigned char *old, unsigned char *new, int w, int h, int os, int ns) +{ + int x, y; + struct metrics l; + struct metrics *peak=&fi->p, *rel=&fi->r, *mean=&fi->m; + memset(peak, 0, sizeof(struct metrics)); + memset(rel, 0, sizeof(struct metrics)); + memset(mean, 0, sizeof(struct metrics)); + for (y = 0; y < h-7; y += 8) { + for (x = 8; x < w-8-7; x += 8) { + block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns); + mean->d += l.d; + mean->e += l.e; + mean->o += l.o; + mean->s += l.s; + mean->p += l.p; + mean->t += l.t; + MAXUP(peak->d, l.d); + MAXUP(peak->e, l.e); + MAXUP(peak->o, l.o); + MAXUP(peak->s, l.s); + MAXUP(peak->p, l.p); + MAXUP(peak->t, l.t); + MAXUP(rel->e, l.e-l.o); + MAXUP(rel->o, l.o-l.e); + MAXUP(rel->s, l.s-l.t); + MAXUP(rel->p, l.p-l.t); + MAXUP(rel->t, l.t-l.p); + MAXUP(rel->d, l.t-l.s); /* hack */ + } + } + x = (w/8-2)*(h/8); + mean->d /= x; + mean->e /= x; + mean->o /= x; + mean->s /= x; + mean->p /= x; + mean->t /= x; +} + +static void diff_fields(struct frameinfo *fi, mp_image_t *old, mp_image_t *new) +{ + diff_planes(fi, old->planes[0], new->planes[0], + new->w, new->h, old->stride[0], new->stride[0]); +} + +static void stats(struct frameinfo *f) +{ + 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", + 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); +} + +static int foo(struct vf_priv_s *p, mp_image_t *new, mp_image_t *cur) +{ + struct frameinfo *f = p->fi; + + f[0] = f[1]; + diff_fields(&f[1], cur, new); + stats(&f[1]); + + // Immediately drop this frame if it's already been used. + if (p->dropnext) { + p->dropnext = 0; + return F_DROP; + } + + // Sometimes a pulldown frame comes all by itself, so both + // its top and bottom field are duplicates from the adjacent + // two frames. We can just drop such a frame, but we + // immediately show the next frame instead to keep the frame + // drops evenly spaced during normal 3:2 pulldown sequences. + if ((3*f[1].r.o < f[1].r.e) && (f[1].r.s < f[1].r.d)) { + p->dropnext = 1; + return F_NEXT; + } + + // If none of these conditions hold, we will consider the frame + // progressive and just show it as-is. + if (!( (3*f[0].r.e < f[0].r.o) || + ((2*f[0].r.d < f[0].r.s) && (f[0].r.s > 1200)) || + ((2*f[1].r.t < f[1].r.p) && (f[1].r.p > 1200)) )) + return F_SHOW; + + // Otherwise, we have to decide whether to merge or drop. + // If the noise metric only increases minimally, we're off + // to a good start... + if (((2*f[1].r.t < 3*f[1].r.p) && (f[1].r.t < 3600)) || + (f[1].r.t < 900) || (f[1].r.d < 900)) { + // ...and if noise decreases or the duplicate even field + // is detected, we go ahead with the merge. + if ((3*f[0].r.e < f[0].r.o) || (2*f[1].r.t < f[1].r.p)) { + p->dropnext = 1; + return F_MERGE; + } + } + return F_DROP; +} + + + +static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field) +{ + switch (field) { + case 0: + my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, + dmpi->stride[0]*2, mpi->stride[0]*2); + if (mpi->flags & MP_IMGFLAG_PLANAR) { + my_memcpy_pic(dmpi->planes[1], mpi->planes[1], + mpi->chroma_width, mpi->chroma_height/2, + dmpi->stride[1]*2, mpi->stride[1]*2); + my_memcpy_pic(dmpi->planes[2], mpi->planes[2], + mpi->chroma_width, mpi->chroma_height/2, + dmpi->stride[2]*2, mpi->stride[2]*2); + } + break; + case 1: + my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], + mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, + dmpi->stride[0]*2, mpi->stride[0]*2); + if (mpi->flags & MP_IMGFLAG_PLANAR) { + my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], + mpi->planes[1]+mpi->stride[1], + mpi->chroma_width, mpi->chroma_height/2, + dmpi->stride[1]*2, mpi->stride[1]*2); + my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], + mpi->planes[2]+mpi->stride[2], + mpi->chroma_width, mpi->chroma_height/2, + dmpi->stride[2]*2, mpi->stride[2]*2); + } + break; + case 2: + memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, + dmpi->stride[0], mpi->stride[0]); + if (mpi->flags & MP_IMGFLAG_PLANAR) { + memcpy_pic(dmpi->planes[1], mpi->planes[1], + mpi->chroma_width, mpi->chroma_height, + dmpi->stride[1], mpi->stride[1]); + memcpy_pic(dmpi->planes[2], mpi->planes[2], + mpi->chroma_width, mpi->chroma_height, + dmpi->stride[2], mpi->stride[2]); + } + break; + } +} + +static int do_put_image(struct vf_instance_s* vf, mp_image_t *dmpi) +{ + struct vf_priv_s *p = vf->priv; + int dropflag; + + switch (p->drop && !p->dropnext) { + case 0: + dropflag = 0; + break; + case 1: + dropflag = (++p->lastdrop >= 5); + break; + case 2: + dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes); + break; + } + + if (dropflag) { + //mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n", + // p->outframes, p->inframes, (float)p->outframes/p->inframes); + mp_msg(MSGT_VFILTER, MSGL_V, "!"); + p->lastdrop = 0; + return 0; + } + + p->outframes++; + return vf_next_put_image(vf, dmpi); +} + +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi) +{ + int ret=0; + struct vf_priv_s *p = vf->priv; + + p->inframes++; + + if (p->first) { /* hack */ + p->first = 0; + return 1; + } + + if (!p->dmpi) p->dmpi = vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | + MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, + mpi->width, mpi->height); + /* FIXME -- not correct, off by one frame! */ + p->dmpi->qscale = mpi->qscale; + p->dmpi->qstride = mpi->qstride; + p->dmpi->qscale_type = mpi->qscale_type; + + switch (foo(p, mpi, p->dmpi)) { + case F_DROP: + copy_image(p->dmpi, mpi, 2); + ret = 0; + p->lastdrop = 0; + mp_msg(MSGT_VFILTER, MSGL_V, "DROP\n"); + break; + case F_MERGE: + copy_image(p->dmpi, mpi, 0); + ret = do_put_image(vf, p->dmpi); + copy_image(p->dmpi, mpi, 1); + mp_msg(MSGT_VFILTER, MSGL_V, "MERGE\n"); + p->dmpi = NULL; + break; + case F_NEXT: + copy_image(p->dmpi, mpi, 2); + ret = do_put_image(vf, p->dmpi); + mp_msg(MSGT_VFILTER, MSGL_V, "NEXT\n"); + p->dmpi = NULL; + break; + case F_SHOW: + ret = do_put_image(vf, p->dmpi); + copy_image(p->dmpi, mpi, 2); + mp_msg(MSGT_VFILTER, MSGL_V, "OK\n"); + p->dmpi = NULL; + break; + } + return ret; +} + +static int query_format(struct vf_instance_s* vf, unsigned int fmt) +{ + switch (fmt) { + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + return vf_next_query_format(vf, fmt); + } + return 0; +} + +static void uninit(struct vf_instance_s* vf) +{ + free(vf->priv); +} + +static int open(vf_instance_t *vf, char* args) +{ + struct vf_priv_s *p; + vf->put_image = put_image; + vf->query_format = query_format; + vf->uninit = uninit; + vf->default_reqs = VFCAP_ACCEPT_STRIDE; + vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); + p->drop = 0; + p->first = 1; + if (args) sscanf(args, "%d", &p->drop); + block_diffs = block_diffs_C; +#ifdef HAVE_MMX + if(gCpuCaps.hasMMX) block_diffs = block_diffs_MMX; +#endif + return 1; +} + +vf_info_t vf_info_ivtc = { + "inverse telecine, take 2", + "ivtc", + "Rich Felker", + "", + open, + NULL +}; + +