[MPlayer-dev-eng] [PATCH] New filter: vf_phase.c

Ville Saari 114263 at foo.bar.org
Sun Mar 28 04:38:56 CEST 2004


If film is converted to PAL video using top-first field dominance and then
captured using bottom-first field dominance or vice versa, then inherently
progressive material will have really terrible interlacing artifacts (twice
as strong as true interlaced video). Some PAL DVDs suffer from this.

I wrote a filter to fix this. It changes the field dominance of the video
by doing 180 degree phase shift to the interlace pattern. Or in other words
it delays the video by half a frame.

-- 
 Ville
-------------- next part --------------
diff -Naur main/DOCS/man/en/mplayer.1 patched/DOCS/man/en/mplayer.1
--- main/DOCS/man/en/mplayer.1	2004-03-28 04:12:48.000000000 +0300
+++ patched/DOCS/man/en/mplayer.1	2004-03-28 04:16:30.000000000 +0300
@@ -3136,6 +3136,37 @@
 Currently only libmpeg2 exports the needed flags.
 If used on material that does not set them, the filter does nothing.
 .TP
+.B phase[=options]
+Delay interlaced video by one field time so that the field dominance
+changes. The intended use is to fix PAL movies that have been captured
+with the opposite field dominance to the film-to-video transfer.
+The options are:
+.PD 0
+.RSs
+.IPs b
+Capture field dominance bottom-first, transfer top-first. Filter will
+delay the top field.
+.IPs t
+Capture top-first, transfer bottom-first. Filter will delay the bottom field.
+.IPs p
+Capture and transfer with the same field dominance. Filter will do nothing.
+.IPs B
+Capture bottom-first, transfer unknown or varying. Filter selects among
+b and p on a frame by frame basis by analyzing which alternative
+produces best match between the fields.
+.IPs T
+Capture top-first, transfer unknown or varying. Filter selects among
+t and p.
+.IPs u
+Both capture and transfer unknown or varying. Filter selects among
+t, b and p. This is the default.
+.IPs v
+Verbose operation. Prints the selected mode for each frame and the
+average difference between fields for each tested alternative. Only
+works with B, T or u modes.
+.RE
+.PD 1
+.TP
 .B telecine[=start]
 Apply 3:2 'telecine' process to increase framerate by 20%.
 This most likely will not work correctly with MPlayer, but it can
diff -Naur main/libmpcodecs/Makefile patched/libmpcodecs/Makefile
--- main/libmpcodecs/Makefile	2004-02-17 14:43:07.000000000 +0200
+++ patched/libmpcodecs/Makefile	2004-03-28 04:17:34.000000000 +0300
@@ -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_zrmjpeg.c vd_xanim.c vd_xvid.c vd_xvid4.c vd_libdv.c vd_qtvideo.c vd_theora.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_scale.c vf_format.c vf_noformat.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 vf_dsize.c vf_decimate.c vf_softpulldown.c vf_tinterlace.c vf_pullup.c pullup.c vf_framestep.c vf_tile.c vf_delogo.c vf_fil.c vf_hue.c vf_spp.c vf_yuvcsp.c vf_filmdint.c vf_kerndeint.c vf_rgbtest.c vf_qp.c
+VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c vf_scale.c vf_format.c vf_noformat.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 vf_dsize.c vf_decimate.c vf_softpulldown.c vf_tinterlace.c vf_pullup.c pullup.c vf_framestep.c vf_tile.c vf_delogo.c vf_fil.c vf_hue.c vf_spp.c vf_yuvcsp.c vf_filmdint.c vf_kerndeint.c vf_rgbtest.c vf_qp.c vf_phase.c
 ifeq ($(HAVE_FFPOSTPROCESS),yes)
 VFILTER_SRCS += vf_pp.c
 endif
diff -Naur main/libmpcodecs/vf.c patched/libmpcodecs/vf.c
--- main/libmpcodecs/vf.c	2004-02-26 16:41:42.000000000 +0200
+++ patched/libmpcodecs/vf.c	2004-03-28 04:18:15.000000000 +0300
@@ -87,6 +87,7 @@
 extern vf_info_t vf_info_kerndeint;
 extern vf_info_t vf_info_rgbtest;
 extern vf_info_t vf_info_qp;
+extern vf_info_t vf_info_phase;
 
 // list of available filters:
 static vf_info_t* filter_list[]={
@@ -167,6 +168,7 @@
 #ifdef USE_LIBAVCODEC
     &vf_info_qp,
 #endif
+    &vf_info_phase,
     NULL
 };
 
diff -Naur main/libmpcodecs/vf_phase.c patched/libmpcodecs/vf_phase.c
--- main/libmpcodecs/vf_phase.c	1970-01-01 02:00:00.000000000 +0200
+++ patched/libmpcodecs/vf_phase.c	2004-03-28 04:16:30.000000000 +0300
@@ -0,0 +1,261 @@
+#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, FULL_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)
+   {
+   double bdiff=0.0, pdiff=0.0, tdiff=0.0, scale;
+   int bdif, tdif, pdif;
+   int top, t;
+   unsigned char *end, *rend;
+
+   if(fixed_mode(mode)) /* no need to analyze */
+      return mode; 
+
+   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;
+
+      if(mode==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);
+	 }
+      else if(mode==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);
+	 }
+      else /* 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;
+  
+   if(bdiff<pdiff && bdiff<tdiff)
+      mode=BOTTOM_FIRST;
+   else if(tdiff<pdiff && tdiff<bdiff)
+      mode=TOP_FIRST;
+   else
+      mode=PROGRESSIVE;
+
+   if(verbose)
+      printf("%c %10.3f %10.3f %10.3f  \n",
+	     mode==BOTTOM_FIRST?'B':mode==TOP_FIRST?'T':'P',
+	     pdiff, tdiff, bdiff);
+
+   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(!fixed_mode(mode))
+      {
+      if(vf->priv->buf[0])
+	 mode=analyze_plane(vf->priv->buf[0], mpi->planes[0],
+			    w, dmpi->h, w, mpi->stride[0], mode,
+			    vf->priv->verbose);
+      else
+	 mode=PROGRESSIVE;
+      }
+
+   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);
+   }
+
+/*
+
+
+Video              Film to video transfer
+capture       top first bottom first  unknown
+             +----------+----------+----------+
+top first    |  mode=p  |  mode=t  |  mode=T  |
+             +----------+----------+----------+
+bottom first |  mode=b  |  mode=p  |  mode=B  |
+             +----------+----------+----------+
+unknown      |  mode=B  |  mode=T  |  mode=u  |
+             +----------+----------+----------+
+*/
+
+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=FULL_ANALYZE;
+   vf->priv->verbose=0;
+      
+   while(args && *args)
+      {
+      switch(*args)
+	 {
+	 case 'p': vf->priv->mode=PROGRESSIVE;          break;
+	 case 't': vf->priv->mode=TOP_FIRST;            break;
+	 case 'b': vf->priv->mode=BOTTOM_FIRST;         break;
+	 case 'T': vf->priv->mode=TOP_FIRST_ANALYZE;    break;
+	 case 'B': vf->priv->mode=BOTTOM_FIRST_ANALYZE; break;
+	 case 'u': vf->priv->mode=FULL_ANALYZE;         break;
+	 case 'v': vf->priv->verbose=1;                 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
+   };


More information about the MPlayer-dev-eng mailing list