changeset 9467:9fae4150ec43

experimental de-telecine filter. not documented or configurable yet, but defaults seem to work ok. may change drastically over the next few weeks. please test it an report results!
author rfelker
date Thu, 20 Feb 2003 03:16:41 +0000
parents 08c717b7b886
children 356963ad4784
files libmpcodecs/Makefile libmpcodecs/vf.c libmpcodecs/vf_detc.c
diffstat 3 files changed, 278 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/Makefile	Wed Feb 19 17:26:59 2003 +0000
+++ b/libmpcodecs/Makefile	Thu Feb 20 03:16:41 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
+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
 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
 
 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
--- a/libmpcodecs/vf.c	Wed Feb 19 17:26:59 2003 +0000
+++ b/libmpcodecs/vf.c	Thu Feb 20 03:16:41 2003 +0000
@@ -56,6 +56,7 @@
 extern vf_info_t vf_info_field;
 extern vf_info_t vf_info_denoise3d;
 extern vf_info_t vf_info_hqdn3d;
+extern vf_info_t vf_info_detc;
 
 char** vo_plugin_args=(char**) NULL;
 
@@ -105,6 +106,7 @@
     &vf_info_field,
     &vf_info_denoise3d,
     &vf_info_hqdn3d,
+    &vf_info_detc,
     NULL
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf_detc.c	Thu Feb 20 03:16:41 2003 +0000
@@ -0,0 +1,275 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "../libvo/fastmemcpy.h"
+
+struct metrics {
+	int even;
+	int odd;
+	int noise;
+	int temp;
+};
+
+struct vf_priv_s {
+	int frame;
+	int autosync;
+	int lastsync;
+	int lastdrop;
+	int oddfactor, noisefactor;
+	int resync;
+	struct metrics pm, hi, lo;
+	int prevscore;
+};
+
+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; i<height; i++)
+	{
+		memcpy(dst, src, bytesPerLine);
+		src+= srcStride;
+		dst+= dstStride;
+	}
+
+	return retval;
+}
+
+static void block_diffs(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
+{
+	int i, x, even=0, odd=0, noise=0, temp=0, sum=0;
+	for (i = 8; i; i--) {
+		for (x = 0; x < 16; x++) {
+			even += abs(new[x]-old[x]);
+			odd += abs(new[x+ns]-old[x+os]);
+			sum += new[x];
+			noise += new[x+ns];
+			temp += old[x+os];
+		}
+		old += 2*os; new += 2*ns;
+	}
+	m->even = even;
+	m->odd = odd;
+	m->noise = abs(noise-sum);
+	m->temp = abs(temp-sum);
+}
+
+
+static void diff_fields(struct metrics *m, unsigned char *old, unsigned char *new, int w, int h, int os, int ns)
+{
+	int x, y, me=0, mo=0, mn=0, mt=0;
+	struct metrics l;
+	for (y = 0; y < h-15; y += 16) {
+		for (x = 0; x < w-15; x += 16) {
+			block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns);
+			if (l.even > me) me = l.even;
+			if (l.odd > mo) mo = l.odd;
+			if (l.noise > mn) mn = l.noise;
+			if (l.temp > mt) mt = l.temp;
+		}
+	}
+	m->even = me;
+	m->odd = mo;
+	m->noise = mn;
+	m->temp = mt;
+}
+
+static status(int f, struct metrics *m, int s)
+{
+	mp_msg(MSGT_VFILTER, MSGL_V, "frame %d: e=%d o=%d n=%d t=%d s=%d\n",
+		f, m->even, m->odd, m->noise, m->temp, s);
+}
+
+static int put_image(struct vf_instance_s* vf, mp_image_t *mpi)
+{
+	struct vf_priv_s *p = vf->priv;
+	mp_image_t *dmpi;
+	int i;
+	struct metrics m;
+	int isdup, notdup;
+	int islaced, notlaced;
+	int tcstart, tcend;
+	int tcscore;
+
+	if (p->frame >= 0)
+		p->frame = (p->frame+1)%5;
+	
+	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);
+
+	diff_fields(&m, dmpi->planes[0], mpi->planes[0],
+		mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
+
+	isdup = m.even < p->lo.even;
+	notdup = m.even > p->hi.even;
+
+	tcscore = (m.odd > p->lo.odd) + (m.odd > p->hi.odd) + (m.odd > 4*m.even)
+		+ (m.noise > p->lo.noise) + (m.noise > p->hi.noise)
+		+ (m.noise > m.temp)
+		+ (m.even * p->pm.odd > m.odd * p->pm.even);
+
+	status(p->frame, &m, tcscore);
+	
+	vf->priv->pm = m;
+	vf->priv->prevscore = tcscore;
+	
+	switch (vf->priv->frame) {
+	case 0:
+	case 1:
+	case 2:
+		if (isdup && (tcscore > 3)) {
+			//status(p->frame, &m, tcscore);
+			mp_msg(MSGT_VFILTER, MSGL_V, "heavy lacing, trying to resync with telecine!\n");
+			vf->priv->frame = 3;
+			return 0;
+		} else if (tcscore > 5) {
+			//status(p->frame, &m, tcscore);
+			mp_msg(MSGT_VFILTER, MSGL_V, "laced scene change, trying to resync with telecine!\n");
+			vf->priv->frame = 3;
+			return 0;
+		}
+		break;
+	case 3:
+		if (notdup && (m.noise < p->hi.noise)) {
+			//status(p->frame, &m, tcscore);
+			mp_msg(MSGT_VFILTER, MSGL_V, "non-duplicate field; lost telecine tracking!\n");
+			vf->priv->frame = -1;
+		}
+		break;
+	case 4:
+		if (m.temp > p->hi.temp) { /* bad match */
+			//status(p->frame, &m, tcscore);
+			if (m.noise < p->hi.noise) {
+				mp_msg(MSGT_VFILTER, MSGL_V, "mismatched non-interlaced frame; lost telecine tracking!\n");
+				vf->priv->frame = -1;
+			} else {
+				mp_msg(MSGT_VFILTER, MSGL_V, "mismatched interlaced frame; trying to resync!\n");
+				vf->priv->frame = 3;
+			}
+		}
+		break;
+	default:
+		if (!notdup && (tcscore > 2)) {
+			//status(p->frame, &m, tcscore);
+			mp_msg(MSGT_VFILTER, MSGL_V, "caught the telecine start!\n");
+			vf->priv->frame = 3;
+		}
+		break;
+	}
+
+	if (vf->priv->frame < 3) {
+		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]);
+		}
+	} else if (vf->priv->frame == 3) {
+		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);
+		}
+		p->lastdrop = 0;
+		return 0;
+	} else {
+		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);
+		}
+	}
+	if (++p->lastdrop >= 5) {
+		mp_msg(MSGT_VFILTER, MSGL_V, "dropping frame!\n");
+		p->lastdrop = 0;
+		return 0;
+	}
+	return vf_next_put_image(vf, dmpi);
+}
+
+static int query_format(struct vf_instance_s* vf, unsigned int fmt)
+{
+	/* FIXME - figure out which other formats work */
+	switch (fmt) {
+	case IMGFMT_YV12:
+	case IMGFMT_IYUV:
+	case IMGFMT_I420:
+		return vf_next_query_format(vf, fmt);
+	}
+	return 0;
+}
+
+static int config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt)
+{
+	return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+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->config = config;
+	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));
+	if (args) sscanf(args, "%d:%d", &vf->priv->frame, &vf->priv->autosync);
+	p->frame = -1;
+	p->lastsync = 10;
+	p->lo.even = 1760;
+	p->hi.even = 2880;
+	p->lo.odd = 2560;
+	p->hi.odd = 10240;
+	p->lo.noise = 4480;
+	p->hi.noise = 10240;
+	p->lo.temp = 6400;
+	p->hi.temp = 12800;
+	vf->priv->oddfactor = 3;
+	vf->priv->noisefactor = 6;
+	return 1;
+}
+
+vf_info_t vf_info_detc = {
+    "de-telecine filter",
+    "detc",
+    "Rich Felker",
+    "",
+    open
+};
+
+