forked from mia/Aegisub
Impliment changes from http://greg.geekmind.org/mplayer/mplayer-libass-fixes.patch
from: http://greg.geekmind.org/mplayer/mplayer-libass-fixes.txt * adds stubs for most features introduced in vsfilter 2.39 * implements \blur and \be > 1 * corrects fix_outline_and_shadow for transparency + aa * first-tag-wins for \pos and \move Originally committed to SVN as r2724.
This commit is contained in:
parent
f85ad3c81f
commit
372a5c6a1f
4 changed files with 117 additions and 31 deletions
|
@ -39,11 +39,12 @@ struct ass_synth_priv_s {
|
||||||
|
|
||||||
unsigned *g;
|
unsigned *g;
|
||||||
unsigned *gt2;
|
unsigned *gt2;
|
||||||
|
|
||||||
|
double radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int maxcolor = 255;
|
static const unsigned int maxcolor = 255;
|
||||||
static const unsigned base = 256;
|
static const unsigned base = 256;
|
||||||
static const double blur_radius = 1.5;
|
|
||||||
|
|
||||||
static int generate_tables(ass_synth_priv_t* priv, double radius)
|
static int generate_tables(ass_synth_priv_t* priv, double radius)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +53,11 @@ static int generate_tables(ass_synth_priv_t* priv, double radius)
|
||||||
double volume_diff, volume_factor = 0;
|
double volume_diff, volume_factor = 0;
|
||||||
unsigned volume;
|
unsigned volume;
|
||||||
|
|
||||||
|
if (priv->radius == radius)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
priv->radius = radius;
|
||||||
|
|
||||||
priv->g_r = ceil(radius);
|
priv->g_r = ceil(radius);
|
||||||
priv->g_w = 2*priv->g_r+1;
|
priv->g_w = 2*priv->g_r+1;
|
||||||
|
|
||||||
|
@ -106,10 +112,10 @@ static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
|
||||||
priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
|
priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
|
||||||
}
|
}
|
||||||
|
|
||||||
ass_synth_priv_t* ass_synth_init(void)
|
ass_synth_priv_t* ass_synth_init(double radius)
|
||||||
{
|
{
|
||||||
ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
|
ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
|
||||||
generate_tables(priv, blur_radius);
|
generate_tables(priv, radius);
|
||||||
return priv;
|
return priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +242,7 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
|
||||||
unsigned char c_g, c_o;
|
unsigned char c_g, c_o;
|
||||||
c_g = g[x];
|
c_g = g[x];
|
||||||
c_o = o[x];
|
c_o = o[x];
|
||||||
o[x] = (c_o > c_g) ? c_o : 0;
|
o[x] = (c_o > c_g) ? c_o - c_g : 0;
|
||||||
s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
|
s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
|
||||||
}
|
}
|
||||||
g += bm_g->w;
|
g += bm_g->w;
|
||||||
|
@ -248,10 +254,12 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
|
||||||
return bm_s;
|
return bm_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph,
|
int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur,
|
||||||
bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be)
|
FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g,
|
||||||
|
bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius)
|
||||||
{
|
{
|
||||||
const int bord = be ? ceil(blur_radius) : 0;
|
int bord = be ? (be+1) : 0;
|
||||||
|
bord = (blur_radius > 0.0) ? blur_radius : bord;
|
||||||
|
|
||||||
assert(bm_g && bm_o && bm_s);
|
assert(bm_g && bm_o && bm_s);
|
||||||
|
|
||||||
|
@ -269,16 +277,28 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_gly
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*bm_o)
|
if (*bm_o) {
|
||||||
resize_tmp(priv, (*bm_o)->w, (*bm_o)->h);
|
resize_tmp(priv, (*bm_o)->w, (*bm_o)->h);
|
||||||
|
resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
|
||||||
|
}
|
||||||
resize_tmp(priv, (*bm_g)->w, (*bm_g)->h);
|
resize_tmp(priv, (*bm_g)->w, (*bm_g)->h);
|
||||||
|
resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
|
||||||
|
|
||||||
if (be) {
|
if (be) {
|
||||||
|
while (be--) {
|
||||||
if (*bm_o)
|
if (*bm_o)
|
||||||
blur((*bm_o)->buffer, priv->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
|
blur((*bm_o)->buffer, priv->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
|
||||||
else
|
else
|
||||||
blur((*bm_g)->buffer, priv->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
|
blur((*bm_g)->buffer, priv->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
if (blur_radius > 0.0) {
|
||||||
|
generate_tables(priv_blur, blur_radius);
|
||||||
|
if (*bm_o)
|
||||||
|
blur((*bm_o)->buffer, priv_blur->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
|
||||||
|
else
|
||||||
|
blur((*bm_g)->buffer, priv_blur->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
|
||||||
|
}
|
||||||
|
|
||||||
if (*bm_o)
|
if (*bm_o)
|
||||||
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
|
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
typedef struct ass_synth_priv_s ass_synth_priv_t;
|
typedef struct ass_synth_priv_s ass_synth_priv_t;
|
||||||
|
|
||||||
ass_synth_priv_t* ass_synth_init(void);
|
ass_synth_priv_t* ass_synth_init(double);
|
||||||
void ass_synth_done(ass_synth_priv_t* priv);
|
void ass_synth_done(ass_synth_priv_t* priv);
|
||||||
|
|
||||||
typedef struct bitmap_s {
|
typedef struct bitmap_s {
|
||||||
|
@ -46,7 +46,7 @@ typedef struct bitmap_s {
|
||||||
* \param bm_g out: pointer to the bitmap of glyph shadow is returned here
|
* \param bm_g out: pointer to the bitmap of glyph shadow is returned here
|
||||||
* \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
|
* \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
|
||||||
*/
|
*/
|
||||||
int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be);
|
int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius);
|
||||||
|
|
||||||
void ass_free_bitmap(bitmap_t* bm);
|
void ass_free_bitmap(bitmap_t* bm);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ typedef struct bitmap_hash_key_s {
|
||||||
unsigned outline; // border width, 16.16 fixed point value
|
unsigned outline; // border width, 16.16 fixed point value
|
||||||
int bold, italic;
|
int bold, italic;
|
||||||
char be; // blur edges
|
char be; // blur edges
|
||||||
|
double blur; // gaussian blur
|
||||||
|
|
||||||
unsigned scale_x, scale_y; // 16.16
|
unsigned scale_x, scale_y; // 16.16
|
||||||
int frx, fry, frz; // signed 16.16
|
int frx, fry, frz; // signed 16.16
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
#define MAX_GLYPHS 1000
|
#define MAX_GLYPHS 1000
|
||||||
#define MAX_LINES 100
|
#define MAX_LINES 100
|
||||||
|
#define BE_RADIUS 1.5
|
||||||
|
#define BLUR_MAX_RADIUS 50.0
|
||||||
|
|
||||||
static int last_render_id = 0;
|
static int last_render_id = 0;
|
||||||
|
|
||||||
|
@ -80,6 +82,7 @@ struct ass_renderer_s {
|
||||||
ass_settings_t settings;
|
ass_settings_t settings;
|
||||||
int render_id;
|
int render_id;
|
||||||
ass_synth_priv_t* synth_priv;
|
ass_synth_priv_t* synth_priv;
|
||||||
|
ass_synth_priv_t* synth_priv_blur;
|
||||||
|
|
||||||
ass_image_t* images_root; // rendering result is stored here
|
ass_image_t* images_root; // rendering result is stored here
|
||||||
ass_image_t* prev_images_root;
|
ass_image_t* prev_images_root;
|
||||||
|
@ -112,6 +115,7 @@ typedef struct glyph_info_s {
|
||||||
int asc, desc; // font max ascender and descender
|
int asc, desc; // font max ascender and descender
|
||||||
// int height;
|
// int height;
|
||||||
int be; // blur edges
|
int be; // blur edges
|
||||||
|
double blur; // gaussian blur
|
||||||
int shadow;
|
int shadow;
|
||||||
double frx, fry, frz; // rotation
|
double frx, fry, frz; // rotation
|
||||||
|
|
||||||
|
@ -160,6 +164,7 @@ typedef struct render_context_s {
|
||||||
char detect_collisions;
|
char detect_collisions;
|
||||||
uint32_t fade; // alpha from \fad
|
uint32_t fade; // alpha from \fad
|
||||||
char be; // blur edges
|
char be; // blur edges
|
||||||
|
double blur; // gaussian blur
|
||||||
int shadow;
|
int shadow;
|
||||||
int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags
|
int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags
|
||||||
|
|
||||||
|
@ -258,7 +263,8 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library)
|
||||||
goto ass_init_exit;
|
goto ass_init_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->synth_priv = ass_synth_init();
|
priv->synth_priv = ass_synth_init(BE_RADIUS);
|
||||||
|
priv->synth_priv_blur = ass_synth_init(BLUR_MAX_RADIUS);
|
||||||
|
|
||||||
priv->library = library;
|
priv->library = library;
|
||||||
priv->ftlibrary = ft;
|
priv->ftlibrary = ft;
|
||||||
|
@ -688,7 +694,55 @@ static char* parse_tag(char* p, double pwr) {
|
||||||
if ((*p == '}') || (*p == 0))
|
if ((*p == '}') || (*p == 0))
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
if (mystrcmp(&p, "fsc")) {
|
// New tags introduced in vsfilter 2.39
|
||||||
|
if (mystrcmp(&p, "xbord")) {
|
||||||
|
double val;
|
||||||
|
if (mystrtod(&p, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\xbord%.2f\n", val);
|
||||||
|
} else if (mystrcmp(&p, "ybord")) {
|
||||||
|
double val;
|
||||||
|
if (mystrtod(&p, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\ybord%.2f\n", val);
|
||||||
|
} else if (mystrcmp(&p, "xshad")) {
|
||||||
|
int val;
|
||||||
|
if (mystrtoi(&p, 10, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\xshad%d\n", val);
|
||||||
|
} else if (mystrcmp(&p, "yshad")) {
|
||||||
|
int val;
|
||||||
|
if (mystrtoi(&p, 10, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\yshad%d\n", val);
|
||||||
|
} else if (mystrcmp(&p, "fax")) {
|
||||||
|
int val;
|
||||||
|
if (mystrtoi(&p, 10, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\fax%d\n", val);
|
||||||
|
} else if (mystrcmp(&p, "fay")) {
|
||||||
|
int val;
|
||||||
|
if (mystrtoi(&p, 10, &val))
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\fay%d\n", val);
|
||||||
|
} else if (mystrcmp(&p, "iclip")) {
|
||||||
|
int x0, y0, x1, y1;
|
||||||
|
int res = 1;
|
||||||
|
skip('(');
|
||||||
|
res &= mystrtoi(&p, 10, &x0);
|
||||||
|
skip(',');
|
||||||
|
res &= mystrtoi(&p, 10, &y0);
|
||||||
|
skip(',');
|
||||||
|
res &= mystrtoi(&p, 10, &x1);
|
||||||
|
skip(',');
|
||||||
|
res &= mystrtoi(&p, 10, &y1);
|
||||||
|
skip(')');
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "stub: \\iclip(%d,%d,%d,%d)\n", x0, y0, x1, y1);
|
||||||
|
} else if (mystrcmp(&p, "blur")) {
|
||||||
|
double val;
|
||||||
|
if (mystrtod(&p, &val)) {
|
||||||
|
val = (val < 0) ? 0 : val;
|
||||||
|
val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val;
|
||||||
|
render_context.blur = val;
|
||||||
|
} else
|
||||||
|
render_context.blur = 0.0;
|
||||||
|
|
||||||
|
// ASS standard tags
|
||||||
|
} else if (mystrcmp(&p, "fsc")) {
|
||||||
char tp = *p++;
|
char tp = *p++;
|
||||||
double val;
|
double val;
|
||||||
if (tp == 'x') {
|
if (tp == 'x') {
|
||||||
|
@ -760,10 +814,12 @@ static char* parse_tag(char* p, double pwr) {
|
||||||
else k = ((double)(t - t1)) / delta_t;
|
else k = ((double)(t - t1)) / delta_t;
|
||||||
x = k * (x2 - x1) + x1;
|
x = k * (x2 - x1) + x1;
|
||||||
y = k * (y2 - y1) + y1;
|
y = k * (y2 - y1) + y1;
|
||||||
|
if (render_context.evt_type != EVENT_POSITIONED) {
|
||||||
render_context.pos_x = x;
|
render_context.pos_x = x;
|
||||||
render_context.pos_y = y;
|
render_context.pos_y = y;
|
||||||
render_context.detect_collisions = 0;
|
render_context.detect_collisions = 0;
|
||||||
render_context.evt_type = EVENT_POSITIONED;
|
render_context.evt_type = EVENT_POSITIONED;
|
||||||
|
}
|
||||||
} else if (mystrcmp(&p, "frx")) {
|
} else if (mystrcmp(&p, "frx")) {
|
||||||
double val;
|
double val;
|
||||||
if (mystrtod(&p, &val)) {
|
if (mystrtod(&p, &val)) {
|
||||||
|
@ -839,10 +895,12 @@ static char* parse_tag(char* p, double pwr) {
|
||||||
v2 = strtol(p, &p, 10);
|
v2 = strtol(p, &p, 10);
|
||||||
skip(')');
|
skip(')');
|
||||||
mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2);
|
mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2);
|
||||||
|
if (render_context.evt_type != EVENT_POSITIONED) {
|
||||||
render_context.evt_type = EVENT_POSITIONED;
|
render_context.evt_type = EVENT_POSITIONED;
|
||||||
render_context.detect_collisions = 0;
|
render_context.detect_collisions = 0;
|
||||||
render_context.pos_x = v1;
|
render_context.pos_x = v1;
|
||||||
render_context.pos_y = v2;
|
render_context.pos_y = v2;
|
||||||
|
}
|
||||||
} else if (mystrcmp(&p, "fad")) {
|
} else if (mystrcmp(&p, "fad")) {
|
||||||
int a1, a2, a3;
|
int a1, a2, a3;
|
||||||
long long t1, t2, t3, t4;
|
long long t1, t2, t3, t4;
|
||||||
|
@ -985,9 +1043,12 @@ static char* parse_tag(char* p, double pwr) {
|
||||||
reset_render_context();
|
reset_render_context();
|
||||||
} else if (mystrcmp(&p, "be")) {
|
} else if (mystrcmp(&p, "be")) {
|
||||||
int val;
|
int val;
|
||||||
if (mystrtoi(&p, 10, &val))
|
if (mystrtoi(&p, 10, &val)) {
|
||||||
render_context.be = val ? 1 : 0;
|
// Clamp to 10, since high values need excessive CPU
|
||||||
else
|
val = (val < 0) ? 0 : val;
|
||||||
|
val = (val > 10) ? 10 : val;
|
||||||
|
render_context.be = val;
|
||||||
|
} else
|
||||||
render_context.be = 0;
|
render_context.be = 0;
|
||||||
} else if (mystrcmp(&p, "b")) {
|
} else if (mystrcmp(&p, "b")) {
|
||||||
int b;
|
int b;
|
||||||
|
@ -1181,6 +1242,7 @@ static void reset_render_context(void)
|
||||||
render_context.scale_y = render_context.style->ScaleY;
|
render_context.scale_y = render_context.style->ScaleY;
|
||||||
render_context.hspacing = render_context.style->Spacing;
|
render_context.hspacing = render_context.style->Spacing;
|
||||||
render_context.be = 0;
|
render_context.be = 0;
|
||||||
|
render_context.blur = 0.0;
|
||||||
render_context.shadow = render_context.style->Shadow;
|
render_context.shadow = render_context.style->Shadow;
|
||||||
render_context.frx = render_context.fry = 0.;
|
render_context.frx = render_context.fry = 0.;
|
||||||
render_context.frz = M_PI * render_context.style->Angle / 180.;
|
render_context.frz = M_PI * render_context.style->Angle / 180.;
|
||||||
|
@ -1321,9 +1383,10 @@ static void get_bitmap_glyph(glyph_info_t* info)
|
||||||
|
|
||||||
// render glyph
|
// render glyph
|
||||||
error = glyph_to_bitmap(ass_renderer->synth_priv,
|
error = glyph_to_bitmap(ass_renderer->synth_priv,
|
||||||
|
ass_renderer->synth_priv_blur,
|
||||||
info->glyph, info->outline_glyph,
|
info->glyph, info->outline_glyph,
|
||||||
&info->bm, &info->bm_o,
|
&info->bm, &info->bm_o,
|
||||||
&info->bm_s, info->be);
|
&info->bm_s, info->be, info->blur);
|
||||||
if (error)
|
if (error)
|
||||||
info->symbol = 0;
|
info->symbol = 0;
|
||||||
|
|
||||||
|
@ -1815,6 +1878,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
|
||||||
text_info.glyphs[text_info.length].effect_timing = render_context.effect_timing;
|
text_info.glyphs[text_info.length].effect_timing = render_context.effect_timing;
|
||||||
text_info.glyphs[text_info.length].effect_skip_timing = render_context.effect_skip_timing;
|
text_info.glyphs[text_info.length].effect_skip_timing = render_context.effect_skip_timing;
|
||||||
text_info.glyphs[text_info.length].be = render_context.be;
|
text_info.glyphs[text_info.length].be = render_context.be;
|
||||||
|
text_info.glyphs[text_info.length].blur = render_context.blur;
|
||||||
text_info.glyphs[text_info.length].shadow = render_context.shadow;
|
text_info.glyphs[text_info.length].shadow = render_context.shadow;
|
||||||
text_info.glyphs[text_info.length].frx = render_context.frx;
|
text_info.glyphs[text_info.length].frx = render_context.frx;
|
||||||
text_info.glyphs[text_info.length].fry = render_context.fry;
|
text_info.glyphs[text_info.length].fry = render_context.fry;
|
||||||
|
@ -1839,6 +1903,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
|
||||||
text_info.glyphs[text_info.length].hash_key.ch = code;
|
text_info.glyphs[text_info.length].hash_key.ch = code;
|
||||||
text_info.glyphs[text_info.length].hash_key.advance = shift;
|
text_info.glyphs[text_info.length].hash_key.advance = shift;
|
||||||
text_info.glyphs[text_info.length].hash_key.be = render_context.be;
|
text_info.glyphs[text_info.length].hash_key.be = render_context.be;
|
||||||
|
text_info.glyphs[text_info.length].hash_key.blur = render_context.blur;
|
||||||
|
|
||||||
text_info.length++;
|
text_info.length++;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue