changeset 6637:f47f12ba3b88

more scaling algos
author michael
date Thu, 04 Jul 2002 13:08:37 +0000
parents 1bb626b7a0fd
children 16f8f95e6c85
files libmpcodecs/vf_scale.c postproc/swscale.c postproc/swscale.h
diffstat 3 files changed, 123 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/vf_scale.c	Thu Jul 04 12:04:55 2002 +0000
+++ b/libmpcodecs/vf_scale.c	Thu Jul 04 13:08:37 2002 +0000
@@ -16,6 +16,7 @@
 struct vf_priv_s {
     int w,h;
     int v_chr_drop;
+    int param;
     unsigned int fmt;
     SwsContext *ctx;
 };
@@ -30,6 +31,16 @@
     IMGFMT_BGR24,
     IMGFMT_BGR16,
     IMGFMT_BGR15,
+    IMGFMT_BGR8,
+    IMGFMT_BGR4,
+    IMGFMT_BGR1,
+    IMGFMT_RGB32,
+    IMGFMT_RGB24,
+    IMGFMT_RGB16,
+    IMGFMT_RGB15,
+    IMGFMT_RGB8,
+    IMGFMT_RGB4,
+    IMGFMT_RGB1,
     IMGFMT_YV12,
     IMGFMT_I420,
     IMGFMT_IYUV,
@@ -112,6 +123,7 @@
     // new swscaler:
     swsGetFlagsAndFilterFromCmdLine(&int_sws_flags, &srcFilter, &dstFilter);
     int_sws_flags|= vf->priv->v_chr_drop << SWS_SRC_V_CHR_DROP_SHIFT;
+    int_sws_flags|= vf->priv->param      << SWS_PARAM_SHIFT;
     vf->priv->ctx=getSwsContext(width,height,
 	    (outfmt==IMGFMT_I420 || outfmt==IMGFMT_IYUV)?IMGFMT_YV12:outfmt,
 		  vf->priv->w,vf->priv->h,
@@ -195,10 +207,12 @@
     vf->priv->w=
     vf->priv->h=-1;
     vf->priv->v_chr_drop=0;
-    if(args) sscanf(args, "%d:%d:%d",
+    vf->priv->param=0;
+    if(args) sscanf(args, "%d:%d:%d:%d",
     &vf->priv->w,
     &vf->priv->h,
-    &vf->priv->v_chr_drop);
+    &vf->priv->v_chr_drop,
+    &vf->priv->param);
     mp_msg(MSGT_VFILTER,MSGL_V,"SwScale params: %d x %d (-1=no scaling)\n",
     vf->priv->w,
     vf->priv->h);
--- a/postproc/swscale.c	Thu Jul 04 12:04:55 2002 +0000
+++ b/postproc/swscale.c	Thu Jul 04 13:08:37 2002 +0000
@@ -958,6 +958,10 @@
 		case 4: *flags|= SWS_POINT; break;
 		case 5: *flags|= SWS_AREA; break;
 		case 6: *flags|= SWS_BICUBLIN; break;
+		case 7: *flags|= SWS_GAUSS; break;
+		case 8: *flags|= SWS_SINC; break;
+		case 9: *flags|= SWS_LANCZOS; break;
+		case 10:*flags|= SWS_SPLINE; break;
 		default:*flags|= SWS_BILINEAR; break;
 	}
 	
@@ -975,6 +979,16 @@
 	return getSwsContext(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flags, srcFilterParam, dstFilterParam);
 }
 
+static double getSplineCoeff(double a, double b, double c, double d, double dist)
+{
+//	printf("%f %f %f %f %f\n", a,b,c,d,dist);
+	if(dist<=1.0) 	return ((d*dist + c)*dist + b)*dist +a;
+	else		return getSplineCoeff(	0.0, 
+						 b+ 2.0*c + 3.0*d,
+						        c + 3.0*d,
+						-b- 3.0*c - 6.0*d,
+						dist-1.0);
+}
 
 static inline void initFilter(int16_t **outFilter, int16_t **filterPos, int *outFilterSize, int xInc,
 			      int srcW, int dstW, int filterAlign, int one, int flags,
@@ -1025,7 +1039,7 @@
 			xDstInSrc+= xInc;
 		}
 	}
-	else if(xInc <= (1<<16) || (flags&SWS_FAST_BILINEAR)) // upscale
+	else if((xInc <= (1<<16) && (flags&SWS_AREA)) || (flags&SWS_FAST_BILINEAR)) // bilinear upscale
 	{
 		int i;
 		int xDstInSrc;
@@ -1041,32 +1055,6 @@
 			int j;
 
 			(*filterPos)[i]= xx;
-			if((flags & SWS_BICUBIC) || (flags & SWS_X))
-			{
-				double d= ABS(((xx+1)<<16) - xDstInSrc)/(double)(1<<16);
-				double y1,y2,y3,y4;
-				double A= -0.6;
-				if(flags & SWS_BICUBIC){
-						// Equation is from VirtualDub
-					y1 = (        +     A*d -       2.0*A*d*d +       A*d*d*d);
-					y2 = (+ 1.0             -     (A+3.0)*d*d + (A+2.0)*d*d*d);
-					y3 = (        -     A*d + (2.0*A+3.0)*d*d - (A+2.0)*d*d*d);
-					y4 = (                  +           A*d*d -       A*d*d*d);
-				}else{
-						// cubic interpolation (derived it myself)
-					y1 = (    -2.0*d + 3.0*d*d - 1.0*d*d*d)/6.0;
-					y2 = (6.0 -3.0*d - 6.0*d*d + 3.0*d*d*d)/6.0;
-					y3 = (    +6.0*d + 3.0*d*d - 3.0*d*d*d)/6.0;
-					y4 = (    -1.0*d           + 1.0*d*d*d)/6.0;
-				}
-
-				filter[i*filterSize + 0]= y1;
-				filter[i*filterSize + 1]= y2;
-				filter[i*filterSize + 2]= y3;
-				filter[i*filterSize + 3]= y4;
-			}
-			else
-			{
 				//Bilinear upscale / linear interpolate / Area averaging
 				for(j=0; j<filterSize; j++)
 				{
@@ -1076,35 +1064,48 @@
 					filter[i*filterSize + j]= coeff;
 					xx++;
 				}
-			}
 			xDstInSrc+= xInc;
 		}
 	}
-	else // downscale
+	else
 	{
-		int xDstInSrc;
-		ASSERT(dstW <= srcW)
+		double xDstInSrc;
+		double sizeFactor, filterSizeInSrc;
+		const double xInc1= (double)xInc / (double)(1<<16);
+		int param= (flags&SWS_PARAM_MASK)>>SWS_PARAM_SHIFT;
 
-		if(flags&SWS_BICUBIC)	filterSize= (int)ceil(1 + 4.0*srcW / (double)dstW);
-		else if(flags&SWS_X)	filterSize= (int)ceil(1 + 4.0*srcW / (double)dstW);
-		else if(flags&SWS_AREA)	filterSize= (int)ceil(1 + 1.0*srcW / (double)dstW);
-		else /* BILINEAR */	filterSize= (int)ceil(1 + 2.0*srcW / (double)dstW);
-		filter= (double*)memalign(8, dstW*sizeof(double)*filterSize);
+		if     (flags&SWS_BICUBIC)	sizeFactor= 4.0;
+		else if(flags&SWS_X)		sizeFactor= 8.0;
+		else if(flags&SWS_AREA)		sizeFactor= 1.0; //downscale only, for upscale it is bilinear
+		else if(flags&SWS_GAUSS)	sizeFactor= 8.0;   // infinite ;)
+		else if(flags&SWS_LANCZOS)	sizeFactor= param ? 2.0*param : 6.0;
+		else if(flags&SWS_SINC)		sizeFactor= 100.0; // infinite ;)
+		else if(flags&SWS_SPLINE)	sizeFactor= 20.0;  // infinite ;)
+		else if(flags&SWS_BILINEAR)	sizeFactor= 2.0;
+		else ASSERT(0)
+		
+		if(xInc1 <= 1.0)	filterSizeInSrc= sizeFactor; // upscale
+		else			filterSizeInSrc= sizeFactor*srcW / (double)dstW;
 
-		xDstInSrc= xInc/2 - 0x8000;
+		filterSize= (int)ceil(1 + filterSizeInSrc); // will be reduced later if possible
+		if(filterSize > srcW-2) filterSize=srcW-2;
+
+		filter= (double*)memalign(16, dstW*sizeof(double)*filterSize);
+
+		xDstInSrc= xInc1 / 2.0 - 0.5;
 		for(i=0; i<dstW; i++)
 		{
-			int xx= (int)((double)xDstInSrc/(double)(1<<16) - (filterSize-1)*0.5 + 0.5);
+			int xx= (int)(xDstInSrc - (filterSize-1)*0.5 + 0.5);
 			int j;
 			(*filterPos)[i]= xx;
 			for(j=0; j<filterSize; j++)
 			{
-				double d= ABS((xx<<16) - xDstInSrc)/(double)xInc;
+				double d= ABS(xx - xDstInSrc)/filterSizeInSrc*sizeFactor;
 				double coeff;
-				if((flags & SWS_BICUBIC) || (flags & SWS_X))
+				if(flags & SWS_BICUBIC)
 				{
-					double A= -0.75;
-//					d*=2;
+					double A= param ? -param*0.01 : -0.60;
+					
 					// Equation is from VirtualDub
 					if(d<1.0)
 						coeff = (1.0 - (A+3.0)*d*d + (A+2.0)*d*d*d);
@@ -1113,22 +1114,62 @@
 					else
 						coeff=0.0;
 				}
+/*				else if(flags & SWS_X)
+				{
+					double p= param ? param*0.01 : 0.3;
+					coeff = d ? sin(d*PI)/(d*PI) : 1.0;
+					coeff*= pow(2.0, - p*d*d);
+				}*/
+				else if(flags & SWS_X)
+				{
+					double A= param ? param*0.1 : 1.0;
+					
+					if(d<1.0)
+						coeff = cos(d*PI);
+					else
+						coeff=-1.0;
+					if(coeff<0.0) 	coeff= -pow(-coeff, A);
+					else		coeff=  pow( coeff, A);
+					coeff= coeff*0.5 + 0.5;
+				}
 				else if(flags & SWS_AREA)
 				{
-					double srcPixelSize= (1<<16)/(double)xInc;
+					double srcPixelSize= 1.0/xInc1;
 					if(d + srcPixelSize/2 < 0.5) coeff= 1.0;
 					else if(d - srcPixelSize/2 < 0.5) coeff= (0.5-d)/srcPixelSize + 0.5;
 					else coeff=0.0;
 				}
-				else
+				else if(flags & SWS_GAUSS)
+				{
+					double p= param ? param*0.1 : 3.0;
+					coeff = pow(2.0, - p*d*d);
+				}
+				else if(flags & SWS_SINC)
+				{
+					coeff = d ? sin(d*PI)/(d*PI) : 1.0;
+				}
+				else if(flags & SWS_LANCZOS)
+				{
+					double p= param ? param : 3.0; 
+					coeff = d ? sin(d*PI)*sin(d*PI/p)/(d*d*PI*PI/p) : 1.0;
+					if(d>p) coeff=0;
+				}
+				else if(flags & SWS_BILINEAR)
 				{
 					coeff= 1.0 - d;
 					if(coeff<0) coeff=0;
 				}
+				else if(flags & SWS_SPLINE)
+				{
+					double p=-2.196152422706632;
+					coeff = getSplineCoeff(1.0, 0.0, p, -p-1.0, d);
+				}
+				else ASSERT(0)
+
 				filter[i*filterSize + j]= coeff;
 				xx++;
 			}
-			xDstInSrc+= xInc;
+			xDstInSrc+= xInc1;
 		}
 	}
 
@@ -2178,7 +2219,15 @@
 		else if(flags&SWS_AREA)
 			MSG_INFO("\nSwScaler: Area Averageing scaler, ");
 		else if(flags&SWS_BICUBLIN)
-			MSG_INFO("\nSwScaler: luma BICUBIC / chroma BILINEAR, ");
+			MSG_INFO("\nSwScaler: luma BICUBIC / chroma BILINEAR scaler, ");
+		else if(flags&SWS_GAUSS)
+			MSG_INFO("\nSwScaler: Gaussian scaler, ");
+		else if(flags&SWS_SINC)
+			MSG_INFO("\nSwScaler: Sinc scaler, ");
+		else if(flags&SWS_LANCZOS)
+			MSG_INFO("\nSwScaler: Lanczos scaler, ");
+		else if(flags&SWS_SPLINE)
+			MSG_INFO("\nSwScaler: Bicubic spline scaler, ");
 		else
 			MSG_INFO("\nSwScaler: ehh flags invalid?! ");
 
--- a/postproc/swscale.h	Thu Jul 04 12:04:55 2002 +0000
+++ b/postproc/swscale.h	Thu Jul 04 13:08:37 2002 +0000
@@ -24,18 +24,26 @@
 #define SWS_POINT    0x10
 #define SWS_AREA     0x20
 #define SWS_BICUBLIN 0x40
+#define SWS_GAUSS    0x80
+#define SWS_SINC     0x100
+#define SWS_LANCZOS  0x200
+#define SWS_SPLINE   0x400
 
-#define SWS_SRC_V_CHR_DROP_MASK		0x300
-#define SWS_SRC_V_CHR_DROP_SHIFT	8
+#define SWS_SRC_V_CHR_DROP_MASK		0x30000
+#define SWS_SRC_V_CHR_DROP_SHIFT	16
 
-//the following 4 flags are not completly implemented
+#define SWS_PARAM_MASK			0x3FC0000
+#define SWS_PARAM_SHIFT			18
+
+#define SWS_PRINT_INFO		0x1000
+
+//the following 3 flags are not completly implemented
 //internal chrominace subsamling info
 #define SWS_FULL_CHR_H_INT	0x2000
 //input subsampling info
 #define SWS_FULL_CHR_H_INP	0x4000
 #define SWS_DIRECT_BGR		0x8000
 
-#define SWS_PRINT_INFO 0x1000
 
 #define SWS_MAX_REDUCE_CUTOFF 0.002