summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrfelker <rfelker@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-03-29 04:39:04 +0000
committerrfelker <rfelker@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-03-29 04:39:04 +0000
commit9721b82d2d9ef1560bd6244d52ec403191cb2fc8 (patch)
tree17e9c1c1fc337bb9da243090296e8781d229f102
parentd37c2fad12e84a00e201d7da3350f6403c513984 (diff)
downloadmpv-9721b82d2d9ef1560bd6244d52ec403191cb2fc8.tar.bz2
mpv-9721b82d2d9ef1560bd6244d52ec403191cb2fc8.tar.xz
vf_phase filter by Ville Saari (114263 at foo dot bar dot org)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@12082 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r--DOCS/man/en/mplayer.146
-rw-r--r--libmpcodecs/Makefile2
-rw-r--r--libmpcodecs/vf.c2
-rw-r--r--libmpcodecs/vf_phase.c283
4 files changed, 332 insertions, 1 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index 4192d385f2..b7e9e08eb2 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -3136,6 +3136,52 @@ telecined, inserting this filter before them should make them more reliable.
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
diff --git a/libmpcodecs/Makefile b/libmpcodecs/Makefile
index 29e25c9efd..748dcbfc52 100644
--- a/libmpcodecs/Makefile
+++ b/libmpcodecs/Makefile
@@ -14,7 +14,7 @@ VIDEO_SRCS_NAT=vd_null.c vd_cinepak.c vd_raw.c vd_hmblck.c vd_fli.c vd_qtrle.c v
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 --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c
index ede20446b4..042dcc1705 100644
--- a/libmpcodecs/vf.c
+++ b/libmpcodecs/vf.c
@@ -87,6 +87,7 @@ extern vf_info_t vf_info_yuvcsp;
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 @@ static vf_info_t* filter_list[]={
#ifdef USE_LIBAVCODEC
&vf_info_qp,
#endif
+ &vf_info_phase,
NULL
};
diff --git a/libmpcodecs/vf_phase.c b/libmpcodecs/vf_phase.c
new file mode 100644
index 0000000000..67ad902153
--- /dev/null
+++ b/libmpcodecs/vf_phase.c
@@ -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
+ };