changeset 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 1abbfe730adc
children f705b0777572
files DOCS/man/en/mplayer.1 libmpcodecs/Makefile libmpcodecs/vf.c libmpcodecs/vf_phase.c
diffstat 4 files changed, 332 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Sun Mar 28 22:03:37 2004 +0000
+++ b/DOCS/man/en/mplayer.1	Mon Mar 29 04:39:04 2004 +0000
@@ -3136,6 +3136,52 @@
 Currently only libmpeg2 exports the needed flags.
 If used on material that does not set them, the filter does nothing.
 .TP
+.B phase=[t|b|p|a|u|T|B|A|U][:v]
+Delay interlaced video by one field time so that the field order
+changes.
+The intended use is to fix PAL movies that have been captured with the
+opposite field order to the film-to-video transfer.
+The options are:
+.RSs
+.IPs t
+Capture field order top-first, transfer bottom-first.
+Filter will delay the bottom field.
+.IPs b
+Capture bottom-first, transfer top-first.
+Filter will delay the top field.
+.IPs p
+Capture and transfer with the same field order.
+This mode only exists for the documentation of the other options to refer to,
+but if you actually select it, the filter will faithfully do nothing ;-)
+.IPs a
+Capture field order determined automatically by field flags, transfer opposite.
+Filter selects among t and b modes on a frame by frame basis using field flags.
+If no field information is available, then this works just like u.
+.IPs u
+Capture unknown or varying, transfer opposite.
+Filter selects among t and b on a frame by frame basis by analyzing the
+images and selecting the alternative that produces best match between the
+fields.
+.IPs T
+Capture top-first, transfer unknown or varying.
+Filter selects among t and p using image analysis.
+.IPs B
+Capture bottom-first, transfer unknown or varying.
+Filter selects among b and p using image analysis.
+.IPs A
+Capture determined by field flags, transfer unknown or varying.
+Filter selects among t, b and p using field flags and image analysis.
+If no field information is available, then this works just like U.
+This is the default mode.
+.IPs U
+Both capture and transfer unknown or varying.
+Filter selects among t, b and p using image analysis only.
+.IPs v
+Verbose operation.
+Prints the selected mode for each frame and the average squared difference
+between fields for t, b, and p alternatives.
+.RE
+.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
--- a/libmpcodecs/Makefile	Sun Mar 28 22:03:37 2004 +0000
+++ b/libmpcodecs/Makefile	Mon Mar 29 04:39:04 2004 +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_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
--- a/libmpcodecs/vf.c	Sun Mar 28 22:03:37 2004 +0000
+++ b/libmpcodecs/vf.c	Mon Mar 29 04:39:04 2004 +0000
@@ -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
 };
 
--- /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
+   };