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!)


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9078 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
rfelker 2003-01-24 10:24:07 +00:00
parent c8091743e1
commit 3b285a0e3b
4 changed files with 139 additions and 36 deletions

View File

@ -1047,6 +1047,36 @@ This is the full pathname without extensions, i.e.\& without the '.idx',
.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)"

View File

@ -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},

View File

@ -103,6 +103,9 @@ extern int sub_visibility;
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));

139
spudec.c
View File

@ -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 @@ void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int
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 @@ typedef struct {
}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 @@ static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y
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 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
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 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
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 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
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 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
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 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
}
}
}
#else
break;
case 2:
{
/* Best antialiasing. Very slow. */
/* Any pixel (x, y) represents pixels from the original
@ -959,17 +1010,33 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra
}
}
}
#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;