Mercurial > mplayer.hg
diff libmpcodecs/vf_phase.c @ 12081:e34700c872ac
vf_phase filter by Ville Saari (114263 at foo dot bar dot org)
author | rfelker |
---|---|
date | Mon, 29 Mar 2004 04:39:04 +0000 |
parents | |
children | f60bc2314146 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpcodecs/vf_phase.c Mon Mar 29 04:39:04 2004 +0000 @@ -0,0 +1,283 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "../config.h" +#include "../mp_msg.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +#include "../libvo/fastmemcpy.h" + +enum mode { PROGRESSIVE, TOP_FIRST, BOTTOM_FIRST, + TOP_FIRST_ANALYZE, BOTTOM_FIRST_ANALYZE, + ANALYZE, FULL_ANALYZE, AUTO, AUTO_ANALYZE }; + +#define fixed_mode(p) ((p)<=BOTTOM_FIRST) + +struct vf_priv_s + { + enum mode mode; + int verbose; + unsigned char *buf[3]; + }; + +/* + * Copy fields from either current or buffered previous frame to the + * output and store the current frame unmodified to the buffer. + */ + +static void do_plane(unsigned char *to, unsigned char *from, + int w, int h, int ts, int fs, + unsigned char **bufp, enum mode mode) + { + unsigned char *buf, *end; + int top; + + if(!*bufp) + { + mode=PROGRESSIVE; + if(!(*bufp=malloc(h*w))) return; + } + + for(end=to+h*ts, buf=*bufp, top=1; to<end; from+=fs, to+=ts, buf+=w, top^=1) + { + memcpy(to, mode==(top?BOTTOM_FIRST:TOP_FIRST)?buf:from, w); + memcpy(buf, from, w); + } + } + +/* + * This macro interpolates the value of both fields at a point halfway + * between lines and takes the squared difference. In field resolution + * the point is a quarter pixel below a line in one field and a quarter + * pixel above a line in other. + * + * (the result is actually multiplied by 25) + */ + +#define diff(a, as, b, bs) (t=(*a-b[bs]<<2)+a[as<<1]-b[-bs], t*t) + +/* + * Find which field combination has the smallest average squared difference + * between the fields. + */ + +static enum mode analyze_plane(unsigned char *old, unsigned char *new, + int w, int h, int os, int ns, enum mode mode, + int verbose, int fields) + { + double bdiff, pdiff, tdiff, scale; + int bdif, tdif, pdif; + int top, t; + unsigned char *end, *rend; + + if(mode==AUTO) + mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST? + TOP_FIRST:BOTTOM_FIRST:PROGRESSIVE; + else if(mode==AUTO_ANALYZE) + mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST? + TOP_FIRST_ANALYZE:BOTTOM_FIRST_ANALYZE:FULL_ANALYZE; + + if(fixed_mode(mode)) + bdiff=pdiff=tdiff=65536.0; + else + { + bdiff=pdiff=tdiff=0.0; + + for(end=new+(h-2)*ns, new+=ns, old+=os, top=0; + new<end; new+=ns-w, old+=os-w, top^=1) + { + pdif=tdif=bdif=0; + + switch(mode) + { + case TOP_FIRST_ANALYZE: + if(top) + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + tdif+=diff(new, ns, old, os); + else + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + tdif+=diff(old, os, new, ns); + break; + + case BOTTOM_FIRST_ANALYZE: + if(top) + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + bdif+=diff(old, os, new, ns); + else + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + bdif+=diff(new, ns, old, os); + break; + + case ANALYZE: + if(top) + for(rend=new+w; new<rend; new++, old++) + tdif+=diff(new, ns, old, os), + bdif+=diff(old, os, new, ns); + else + for(rend=new+w; new<rend; new++, old++) + bdif+=diff(new, ns, old, os), + tdif+=diff(old, os, new, ns); + break; + + default: /* FULL_ANALYZE */ + if(top) + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + tdif+=diff(new, ns, old, os), + bdif+=diff(old, os, new, ns); + else + for(rend=new+w; new<rend; new++, old++) + pdif+=diff(new, ns, new, ns), + bdif+=diff(new, ns, old, os), + tdif+=diff(old, os, new, ns); + } + + pdiff+=(double)pdif; + tdiff+=(double)tdif; + bdiff+=(double)bdif; + } + + scale=1.0/(w*(h-3))/25.0; + pdiff*=scale; + tdiff*=scale; + bdiff*=scale; + + if(mode==TOP_FIRST_ANALYZE) + bdiff=65536.0; + else if(mode==BOTTOM_FIRST_ANALYZE) + tdiff=65536.0; + else if(mode==ANALYZE) + pdiff=65536.0; + + if(bdiff<pdiff && bdiff<tdiff) + mode=BOTTOM_FIRST; + else if(tdiff<pdiff && tdiff<bdiff) + mode=TOP_FIRST; + else + mode=PROGRESSIVE; + } + + if(verbose) + { + printf("%c", mode==BOTTOM_FIRST?'b':mode==TOP_FIRST?'t':'p'); + if(tdiff==65536.0) printf(" N/A "); else printf(" %8.2f", tdiff); + if(bdiff==65536.0) printf(" N/A "); else printf(" %8.2f", bdiff); + if(pdiff==65536.0) printf(" N/A "); else printf(" %8.2f", pdiff); + printf(" \n"); + } + + return mode; + } + +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi) + { + mp_image_t *dmpi; + int w; + enum mode mode; + + if(!(dmpi=vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, + mpi->w, mpi->h))) + return 0; + + w=dmpi->w; + if(!(dmpi->flags&MP_IMGFLAG_PLANAR)) + w*=dmpi->bpp/8; + + mode=vf->priv->mode; + + if(!vf->priv->buf[0]) + mode=PROGRESSIVE; + else + mode=analyze_plane(vf->priv->buf[0], mpi->planes[0], + w, dmpi->h, w, mpi->stride[0], mode, + vf->priv->verbose, mpi->fields); + + do_plane(dmpi->planes[0], mpi->planes[0], + w, dmpi->h, + dmpi->stride[0], mpi->stride[0], + &vf->priv->buf[0], mode); + + if(dmpi->flags&MP_IMGFLAG_PLANAR) + { + do_plane(dmpi->planes[1], mpi->planes[1], + dmpi->chroma_width, dmpi->chroma_height, + dmpi->stride[1], mpi->stride[1], + &vf->priv->buf[1], mode); + do_plane(dmpi->planes[2], mpi->planes[2], + dmpi->chroma_width, dmpi->chroma_height, + dmpi->stride[2], mpi->stride[2], + &vf->priv->buf[2], mode); + } + + return vf_next_put_image(vf, dmpi); + } + +static void uninit(struct vf_instance_s* vf) + { + free(vf->priv->buf[0]); + free(vf->priv->buf[1]); + free(vf->priv->buf[2]); + free(vf->priv); + } + +static int open(vf_instance_t *vf, char* args) + { + vf->put_image = put_image; + vf->uninit = uninit; + vf->default_reqs = VFCAP_ACCEPT_STRIDE; + + if(!(vf->priv = calloc(1, sizeof(struct vf_priv_s)))) + { + uninit(vf); + return 0; + } + + vf->priv->mode=AUTO_ANALYZE; + vf->priv->verbose=0; + + while(args && *args) + { + switch(*args) + { + case 't': vf->priv->mode=TOP_FIRST; break; + case 'a': vf->priv->mode=AUTO; break; + case 'b': vf->priv->mode=BOTTOM_FIRST; break; + case 'u': vf->priv->mode=ANALYZE; break; + case 'T': vf->priv->mode=TOP_FIRST_ANALYZE; break; + case 'A': vf->priv->mode=AUTO_ANALYZE; break; + case 'B': vf->priv->mode=BOTTOM_FIRST_ANALYZE; break; + case 'U': vf->priv->mode=FULL_ANALYZE; break; + case 'p': vf->priv->mode=PROGRESSIVE; break; + case 'v': vf->priv->verbose=1; break; + case ':': break; + + default: + uninit(vf); + return 0; /* bad args */ + } + + if(args=strchr(args, ':')) args++; + } + + return 1; + } + +vf_info_t vf_info_phase = + { + "phase shift fields", + "phase", + "Ville Saari", + "", + open, + NULL + };