diff libmpcodecs/pullup.c @ 15721:eec6ace22741

small change to field-matching metrics which hopefully makes a big improvement to results. inter-field comparison is now counterbalanced with intra-field total (vertical) variation. this means that areas of extreme high frequency content, which become aliased within individual fields, will not interfere with field matching. examples: white noise effects, small kanji, very small latin text, ... may still need tweaking. please report regressions. this change will likely be made optional in the future (right now it's enclosed in "if (1)"...
author rfelker
date Tue, 14 Jun 2005 05:33:34 +0000
parents 678f6aeb6754
children f580a7755ac5
line wrap: on
line diff
--- a/libmpcodecs/pullup.c	Mon Jun 13 20:40:29 2005 +0000
+++ b/libmpcodecs/pullup.c	Tue Jun 14 05:33:34 2005 +0000
@@ -147,6 +147,53 @@
 		);
 	return ret;
 }
+
+static int var_y_mmx(unsigned char *a, unsigned char *b, int s)
+{
+	int ret;
+	asm volatile (
+		"movl $3, %%ecx \n\t"
+		"pxor %%mm4, %%mm4 \n\t"
+		"pxor %%mm7, %%mm7 \n\t"
+		
+		".balign 16 \n\t"
+		"1: \n\t"
+		
+		"movq (%%esi), %%mm0 \n\t"
+		"movq (%%esi), %%mm2 \n\t"
+		"movq (%%esi,%%eax), %%mm1 \n\t"
+		"addl %%eax, %%esi \n\t"
+		"psubusb %%mm1, %%mm2 \n\t"
+		"psubusb %%mm0, %%mm1 \n\t"
+		"movq %%mm2, %%mm0 \n\t"
+		"movq %%mm1, %%mm3 \n\t"
+		"punpcklbw %%mm7, %%mm0 \n\t"
+		"punpcklbw %%mm7, %%mm1 \n\t"
+		"punpckhbw %%mm7, %%mm2 \n\t"
+		"punpckhbw %%mm7, %%mm3 \n\t"
+		"paddw %%mm0, %%mm4 \n\t"
+		"paddw %%mm1, %%mm4 \n\t"
+		"paddw %%mm2, %%mm4 \n\t"
+		"paddw %%mm3, %%mm4 \n\t"
+		
+		"decl %%ecx \n\t"
+		"jnz 1b \n\t"
+
+		"movq %%mm4, %%mm3 \n\t"
+		"punpcklwd %%mm7, %%mm4 \n\t"
+		"punpckhwd %%mm7, %%mm3 \n\t"
+		"paddd %%mm4, %%mm3 \n\t"
+		"movd %%mm3, %%eax \n\t"
+		"psrlq $32, %%mm3 \n\t"
+		"movd %%mm3, %%edx \n\t"
+		"addl %%edx, %%eax \n\t"
+		"emms \n\t"
+		: "=a" (ret)
+		: "S" (a), "a" (s)
+		: "%ecx", "%edx"
+		);
+	return 4*ret;
+}
 #endif
 #endif
 
@@ -195,6 +242,18 @@
 }
 #endif
 
+static int var_y(unsigned char *a, unsigned char *b, int s)
+{
+	int i, j, var=0;
+	for (i=3; i; i--) {
+		for (j=0; j<8; j++) {
+			var += ABS(a[j]-a[j+s]);
+		}
+		a+=s; b+=s;
+	}
+	return 4*var; /* match comb scaling */
+}
+
 
 
 
@@ -307,6 +366,7 @@
 {
 	f->diffs = calloc(c->metric_len, sizeof(int));
 	f->comb = calloc(c->metric_len, sizeof(int));
+	f->var = calloc(c->metric_len, sizeof(int));
 	/* add more metrics here as needed */
 }
 
@@ -357,6 +417,7 @@
 
 	compute_metric(c, f, parity, f->prev->prev, parity, c->diff, f->diffs);
 	compute_metric(c, parity?f->prev:f, 0, parity?f:f->prev, 1, c->comb, f->comb);
+	compute_metric(c, f, parity, f, -1, c->var, f->var);
 
 	/* Advance the circular list */
 	if (!c->first) c->first = c->head;
@@ -463,14 +524,32 @@
 		f->next->next->flags |= F_HAVE_AFFINITY;
 		return;
 	}
-	for (i = 0; i < c->metric_len; i++) {
-		l = f->comb[i] - f->next->comb[i];
-		if (l > max_l) max_l = l;
-		if (-l > max_r) max_r = -l;
+	if (1) {
+		for (i = 0; i < c->metric_len; i++) {
+			int lv = f->prev->var[i];
+			int rv = f->next->var[i];
+			int v = f->var[i];
+			int lc = f->comb[i] - (v+lv) + ABS(v-lv);
+			int rc = f->next->comb[i] - (v+rv) + ABS(v-rv);
+			lc = lc>0 ? lc : 0;
+			rc = rc>0 ? rc : 0;
+			l = lc - rc;
+			if (l > max_l) max_l = l;
+			if (-l > max_r) max_r = -l;
+		}
+		if (max_l + max_r < 64) return;
+		if (max_r > 6*max_l) f->affinity = -1;
+		else if (max_l > 6*max_r) f->affinity = 1;
+	} else {
+		for (i = 0; i < c->metric_len; i++) {
+			l = f->comb[i] - f->next->comb[i];
+			if (l > max_l) max_l = l;
+			if (-l > max_r) max_r = -l;
+		}
+		if (max_l + max_r < 64) return;
+		if (max_r > 2*max_l) f->affinity = -1;
+		else if (max_l > 2*max_r) f->affinity = 1;
 	}
-	if (max_l + max_r < 64) return;
-	if (max_r > 2*max_l) f->affinity = -1;
-	else if (max_l > 2*max_r) f->affinity = 1;
 }
 
 static void foo(struct pullup_context *c)
@@ -692,11 +771,13 @@
 	case PULLUP_FMT_Y:
 		c->diff = diff_y;
 		c->comb = licomb_y;
+		c->var = var_y;
 #ifdef ARCH_X86
 #ifdef HAVE_MMX
 		if (c->cpu & PULLUP_CPU_MMX) {
 			c->diff = diff_y_mmx;
 			c->comb = licomb_y_mmx;
+			c->var = var_y_mmx;
 		}
 #endif
 #endif