From 372a5c6a1fcc322d5ae4ecbe4603949b8a1bf0a6 Mon Sep 17 00:00:00 2001 From: "http://greg.geekmind.org/mplayer/mplayer-libass-fixes.txt" Date: Fri, 6 Feb 2009 05:58:22 +0000 Subject: [PATCH] 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. --- libass/ass_bitmap.c | 48 ++++++++++++++++------- libass/ass_bitmap.h | 4 +- libass/ass_cache.h | 1 + libass/ass_render.c | 95 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 117 insertions(+), 31 deletions(-) diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 3d85300d1..88ce84d87 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -39,11 +39,12 @@ struct ass_synth_priv_s { unsigned *g; unsigned *gt2; + + double radius; }; static const unsigned int maxcolor = 255; static const unsigned base = 256; -static const double blur_radius = 1.5; static int generate_tables(ass_synth_priv_t* priv, double radius) { @@ -51,6 +52,11 @@ static int generate_tables(ass_synth_priv_t* priv, double radius) int mx, i; double volume_diff, volume_factor = 0; unsigned volume; + + if (priv->radius == radius) + return 0; + else + priv->radius = radius; priv->g_r = ceil(radius); 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)); } -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)); - generate_tables(priv, blur_radius); + generate_tables(priv, radius); 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; c_g = g[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; } 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; } -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) { - 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); @@ -269,17 +277,29 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_gly return 1; } } - if (*bm_o) + if (*bm_o) { 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_blur, (*bm_g)->w, (*bm_g)->h); if (be) { - 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); - 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); - } - + while (be--) { + 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); + 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); + } + } 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) *bm_s = fix_outline_and_shadow(*bm_g, *bm_o); else diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 73f9de4df..5f45aae4b 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -28,7 +28,7 @@ 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); 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 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); diff --git a/libass/ass_cache.h b/libass/ass_cache.h index 5f6a2ddd9..fdb8a641c 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -42,6 +42,7 @@ typedef struct bitmap_hash_key_s { unsigned outline; // border width, 16.16 fixed point value int bold, italic; char be; // blur edges + double blur; // gaussian blur unsigned scale_x, scale_y; // 16.16 int frx, fry, frz; // signed 16.16 diff --git a/libass/ass_render.c b/libass/ass_render.c index 380690724..b812ccd8b 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -43,6 +43,8 @@ #define MAX_GLYPHS 1000 #define MAX_LINES 100 +#define BE_RADIUS 1.5 +#define BLUR_MAX_RADIUS 50.0 static int last_render_id = 0; @@ -80,6 +82,7 @@ struct ass_renderer_s { ass_settings_t settings; int render_id; 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* prev_images_root; @@ -112,6 +115,7 @@ typedef struct glyph_info_s { int asc, desc; // font max ascender and descender // int height; int be; // blur edges + double blur; // gaussian blur int shadow; double frx, fry, frz; // rotation @@ -160,6 +164,7 @@ typedef struct render_context_s { char detect_collisions; uint32_t fade; // alpha from \fad char be; // blur edges + double blur; // gaussian blur int shadow; 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; } - 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->ftlibrary = ft; @@ -687,8 +693,56 @@ static char* parse_tag(char* p, double pwr) { skip('\\'); if ((*p == '}') || (*p == 0)) 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++; double val; if (tp == 'x') { @@ -760,10 +814,12 @@ static char* parse_tag(char* p, double pwr) { else k = ((double)(t - t1)) / delta_t; x = k * (x2 - x1) + x1; y = k * (y2 - y1) + y1; - render_context.pos_x = x; - render_context.pos_y = y; - render_context.detect_collisions = 0; - render_context.evt_type = EVENT_POSITIONED; + if (render_context.evt_type != EVENT_POSITIONED) { + render_context.pos_x = x; + render_context.pos_y = y; + render_context.detect_collisions = 0; + render_context.evt_type = EVENT_POSITIONED; + } } else if (mystrcmp(&p, "frx")) { double val; if (mystrtod(&p, &val)) { @@ -839,10 +895,12 @@ static char* parse_tag(char* p, double pwr) { v2 = strtol(p, &p, 10); skip(')'); mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2); - render_context.evt_type = EVENT_POSITIONED; - render_context.detect_collisions = 0; - render_context.pos_x = v1; - render_context.pos_y = v2; + if (render_context.evt_type != EVENT_POSITIONED) { + render_context.evt_type = EVENT_POSITIONED; + render_context.detect_collisions = 0; + render_context.pos_x = v1; + render_context.pos_y = v2; + } } else if (mystrcmp(&p, "fad")) { int a1, a2, a3; long long t1, t2, t3, t4; @@ -985,9 +1043,12 @@ static char* parse_tag(char* p, double pwr) { reset_render_context(); } else if (mystrcmp(&p, "be")) { int val; - if (mystrtoi(&p, 10, &val)) - render_context.be = val ? 1 : 0; - else + if (mystrtoi(&p, 10, &val)) { + // Clamp to 10, since high values need excessive CPU + val = (val < 0) ? 0 : val; + val = (val > 10) ? 10 : val; + render_context.be = val; + } else render_context.be = 0; } else if (mystrcmp(&p, "b")) { int b; @@ -1181,6 +1242,7 @@ static void reset_render_context(void) render_context.scale_y = render_context.style->ScaleY; render_context.hspacing = render_context.style->Spacing; render_context.be = 0; + render_context.blur = 0.0; render_context.shadow = render_context.style->Shadow; render_context.frx = render_context.fry = 0.; 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 error = glyph_to_bitmap(ass_renderer->synth_priv, + ass_renderer->synth_priv_blur, info->glyph, info->outline_glyph, &info->bm, &info->bm_o, - &info->bm_s, info->be); + &info->bm_s, info->be, info->blur); if (error) 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_skip_timing = render_context.effect_skip_timing; 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].frx = render_context.frx; 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.advance = shift; 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++;