changeset 9077:d430529c5b4b

Improvements to spudec (DVD/VobSub) subtitle code: - runtime selectable positioning, like with text subs - runtime selectable scaling/antialiasing algorithm - gaussian blur scaler (finally dvd/vobsub doesn't look like shit!)
author rfelker
date Fri, 24 Jan 2003 10:24:07 +0000
parents 92014b66ed3d
children 240e53cdce84
files DOCS/mplayer.1 cfg-common.h libvo/sub.h spudec.c
diffstat 4 files changed, 139 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/mplayer.1	Fri Jan 24 01:04:50 2003 +0000
+++ b/DOCS/mplayer.1	Fri Jan 24 10:24:07 2003 +0000
@@ -1047,6 +1047,36 @@
 .TP
 .B \-vobsubid <0-31>
 Specify the VobSub subtitle id.
+.TP
+.B \-spualign <-1\-2>
+Specify how spu (DVD/VobSub) subtitles should be aligned.
+Values are the same as for -subpos, with the extra choice -1 for original
+position.
+.TP
+.B \-spuaa <mode>
+Antialiasing/scaling mode for DVD/VobSub. A value of 16 may be added
+to mode in order to force scaling even when original and scaled frame
+size already match, for example to smooth subtitles with the gaussian
+blur. The available modes are:
+.PD 0
+.RSs
+.IPs 0
+none (fastest, very ugly)
+.IPs 1
+approximate (broken?)
+.IPs 2
+full (slow)
+.IPs 3
+bilinear (default, fast and not too bad)
+.IPs 4
+uses swscaler gaussian blur (looks very good)
+.RE
+.PD 1
+.
+.TP
+.B \-spugauss <0.0\-3.0>
+Variance parameter of gaussian used by -spuaa 4. Higher means more
+blur. The default is 1.0.
 
 
 .SH "AUDIO OUTPUT OPTIONS (MPLAYER ONLY)"
--- a/cfg-common.h	Fri Jan 24 01:04:50 2003 +0000
+++ b/cfg-common.h	Fri Jan 24 10:24:07 2003 +0000
@@ -192,6 +192,9 @@
  	{"subpos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL},
 	{"subalign", &sub_alignment, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
  	{"subwidth", &sub_width_p, CONF_TYPE_INT, CONF_RANGE, 10, 100, NULL},
+	{"spualign", &spu_alignment, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL},
+	{"spuaa", &spu_aamode, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL},
+	{"spugauss", &spu_gaussvar, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 3.0, NULL},
 #ifdef HAVE_FREETYPE
 	{"subfont-encoding", &subtitle_font_encoding, CONF_TYPE_STRING, 0, 0, 0, NULL},
  	{"subfont-text-scale", &text_font_scale_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0, 100, NULL},
--- a/libvo/sub.h	Fri Jan 24 01:04:50 2003 +0000
+++ b/libvo/sub.h	Fri Jan 24 10:24:07 2003 +0000
@@ -103,6 +103,9 @@
 extern int suboverlap_enabled;
 extern int sub_bg_color; /* subtitles background color */
 extern int sub_bg_alpha;
+extern int spu_alignment;
+extern int spu_aamode;
+extern float spu_gaussvar;
 
 //extern void vo_draw_text_osd(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
 //extern void vo_draw_text_progbar(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
--- a/spudec.c	Fri Jan 24 01:04:50 2003 +0000
+++ b/spudec.c	Fri Jan 24 10:24:07 2003 +0000
@@ -1,17 +1,3 @@
-/* Valid values for ANTIALIASING_ALGORITHM:
-  -1: bilinear (similiar to vobsub, fast and good quality)
-   0: none (fastest, most ugly)
-   1: approximate
-   2: full (slowest, best looking)
- */
-#define ANTIALIASING_ALGORITHM -1
-
-/* Valid values for SUBPOS:
-   0: leave the sub on it's original place
-   1: put the sub at the bottom of the picture
- */
-#define SUBPOS 0
-
 /* SPUdec.c
    Skeleton of function spudec_process_controll() is from xine sources.
    Further works:
@@ -34,14 +20,26 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#if ANTIALIASING_ALGORITHM == 2
 #include <math.h>
-#endif
 #include "libvo/video_out.h"
 #include "spudec.h"
+#include "postproc/swscale.h"
 
 #define MIN(a, b)	((a)<(b)?(a):(b))
 
+/* Valid values for spu_aamode:
+   0: none (fastest, most ugly)
+   1: approximate
+   2: full (slowest)
+   3: bilinear (similiar to vobsub, fast and not too bad)
+   4: uses swscaler gaussian (this is the only one that looks good)
+ */
+
+int spu_aamode = 3;
+int spu_alignment = -1;
+float spu_gaussvar = 1.0;
+extern int sub_pos;
+
 typedef struct packet_t packet_t;
 struct packet_t {
   unsigned char *data;
@@ -605,13 +603,33 @@
     unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
     bbox[0] = spu->start_col * scalex / 0x100;
     bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
-#if SUBPOS == 0
-    bbox[2] = spu->start_row * scaley / 0x100;
-    bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
-#elif SUBPOS == 1
-    bbox[3] = dys -1;
-    bbox[2] = bbox[3] -spu->height * scaley / 0x100;
-#endif
+    switch (spu_alignment) {
+    case 0:
+      bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
+      if (bbox[3] > dys) bbox[3] = dys;
+      bbox[2] = bbox[3] - spu->height * scaley / 0x100;
+      break;
+    case 1:
+      if (sub_pos < 50) {
+        bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
+        if (bbox[2] < 0) bbox[2] = 0;
+        bbox[3] = bbox[2] + spu->height;
+      } else {
+        bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
+        if (bbox[3] > dys) bbox[3] = dys;
+        bbox[2] = bbox[3] - spu->height * scaley / 0x100;
+      }
+      break;
+    case 2:
+      bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
+      if (bbox[2] < 0) bbox[2] = 0;
+      bbox[3] = bbox[2] + spu->height;
+      break;
+    default: /* -1 */
+      bbox[2] = spu->start_row * scaley / 0x100;
+      bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
+      break;
+    }
   }
 }
 /* transform mplayer's alpha value into an opacity value that is linear */
@@ -627,7 +645,6 @@
 }scale_pixel;
 
 
-#if ANTIALIASING_ALGORITHM == -1
 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
 {
   unsigned int t;
@@ -674,7 +691,32 @@
       spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
   }
 }
-#endif
+
+void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
+	unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
+{
+	SwsContext *ctx;
+	static SwsFilter filter;
+	static int firsttime = 1;
+	static float oldvar;
+	int i;
+
+	if (!firsttime && oldvar != spu_gaussvar) freeVec(filter.lumH);
+	if (firsttime) {
+		filter.lumH = filter.lumV =
+			filter.chrH = filter.chrV = getGaussianVec(spu_gaussvar, 3.0);
+		normalizeVec(filter.lumH, 1.0);
+		firsttime = 0;
+		oldvar = spu_gaussvar;
+	}
+	
+	ctx=getSwsContext(sw, sh, IMGFMT_Y800, dw, dh, IMGFMT_Y800, SWS_GAUSS, &filter, NULL);
+	ctx->swScale(ctx,&s1,&ss,0,sh,&d1,&ds);
+	for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
+	ctx->swScale(ctx,&s2,&ss,0,sh,&d2,&ds);
+	for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
+	freeSwsContext(ctx);
+}
 
 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
 {
@@ -682,8 +724,8 @@
   scale_pixel *table_x;
   scale_pixel *table_y;
   if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
-    if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
-	|| (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
+    if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
+	|| (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
       if (spu->image)
       {
 	draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
@@ -729,7 +771,13 @@
 	  if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
 	    goto nothing_to_do;
 	  }
-#if ANTIALIASING_ALGORITHM == -1
+	  switch(spu_aamode&15) {
+	  case 4:
+	  sws_spu_image(spu->scaled_image, spu->scaled_aimage,
+		  spu->scaled_width, spu->scaled_height, spu->scaled_stride,
+		  spu->image, spu->aimage, spu->width, spu->height, spu->stride);
+	  break;
+	  case 3:
 	  table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
 	  table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
 	  if (!table_x || !table_y) {
@@ -742,7 +790,8 @@
 	      scale_image(x, y, table_x, table_y, spu);
 	  free(table_x);
 	  free(table_y);
-#elif ANTIALIASING_ALGORITHM == 0
+	  break;
+	  case 0:
 	  /* no antialiasing */
 	  for (y = 0; y < spu->scaled_height; ++y) {
 	    int unscaled_y = y * 0x100 / scaley;
@@ -754,7 +803,8 @@
 	      spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
 	    }
 	  }
-#elif ANTIALIASING_ALGORITHM == 1
+	  break;
+	  case 1:
 	  {
 	    /* Intermediate antialiasing. */
 	    for (y = 0; y < spu->scaled_height; ++y) {
@@ -792,7 +842,8 @@
 	      }
 	    }
 	  }
-#else
+	  break;
+	  case 2:
 	  {
 	    /* Best antialiasing.  Very slow. */
 	    /* Any pixel (x, y) represents pixels from the original
@@ -959,17 +1010,33 @@
 	      }
 	    }
 	  }
-#endif
+	  }
 nothing_to_do:
 	  spu->scaled_frame_width = dxs;
 	  spu->scaled_frame_height = dys;
 	}
       }
       if (spu->scaled_image){
-#if SUBPOS == 1
-	/*set subs at the bottom, i don't like to put it at the very bottom, so -1 :)*/
-	spu->scaled_start_row = dys - spu->scaled_height - 1;
-#endif
+        switch (spu_alignment) {
+        case 0:
+          spu->scaled_start_row = dys*sub_pos/100;
+	  if (spu->scaled_start_row + spu->scaled_height > dys)
+	    spu->scaled_start_row = dys - spu->scaled_height;
+	  break;
+	case 1:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
+          if (sub_pos < 50) {
+	    if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+	  } else {
+	    if (spu->scaled_start_row + spu->scaled_height > dys)
+	      spu->scaled_start_row = dys - spu->scaled_height;
+	  }
+	  break;
+        case 2:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
+	  if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+	  break;
+	}
 	draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
 		   spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
 	spu->spu_changed = 0;