From 2c2f85a93d054caee750f20e646b66fceb568c84 Mon Sep 17 00:00:00 2001 From: Amar Takhar Date: Sat, 14 Feb 2009 19:19:35 +0000 Subject: [PATCH] Add changes from http://greg.geekmind.org/mplayer/libass-snapshot-20090214.tar.gz * \be filter with [1,2,1] kernel (like vsfilter) * "decimal point" support, e.g. numbers with fractional parts are dealt with correctly * shadow without border * "compromise" fix for transparency + aa * misc fixes: \be and \blur radius and a memory leak * proper compositing of overlapping translucent outlines Originally committed to SVN as r2733. --- libass/ass_bitmap.c | 121 ++++++++++++++++++++---- libass/ass_bitmap.h | 8 +- libass/ass_render.c | 217 ++++++++++++++++++++++++++++++++++++-------- libass/ass_utils.c | 17 +++- libass/ass_utils.h | 1 + 5 files changed, 307 insertions(+), 57 deletions(-) diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 88ce84d87..95e47c649 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -39,10 +39,15 @@ struct ass_synth_priv_s { unsigned *g; unsigned *gt2; - + double radius; }; +struct ass_be_priv_s { + int size; + unsigned char *buf; +}; + static const unsigned int maxcolor = 255; static const unsigned base = 256; @@ -52,11 +57,14 @@ 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 + else { priv->radius = radius; + if (priv->g) free(priv->g); + if (priv->gt2) free(priv->gt2); + } priv->g_r = ceil(radius); priv->g_w = 2*priv->g_r+1; @@ -115,6 +123,7 @@ static void resize_tmp(ass_synth_priv_t* priv, int w, int h) ass_synth_priv_t* ass_synth_init(double radius) { ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t)); + priv->g = priv->gt2 = 0; generate_tables(priv, radius); return priv; } @@ -130,7 +139,7 @@ void ass_synth_done(ass_synth_priv_t* priv) free(priv); } -static bitmap_t* alloc_bitmap(int w, int h) +bitmap_t* alloc_bitmap(int w, int h) { bitmap_t* bm; bm = calloc(1, sizeof(bitmap_t)); @@ -242,7 +251,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 - c_g : 0; + o[x] = (c_o > c_g) ? c_o - c_g/2 : 0; s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF; } g += bm_g->w; @@ -254,12 +263,86 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o) return bm_s; } +// \be blur with [1,2,1] matrix +static void be_blur(unsigned char *buf, ass_be_priv_t* priv, int w, int h) { + unsigned int x, y; + unsigned int p; + unsigned char *tmp_buf = priv->buf; + const int wh = w*h; + + if (priv->size < wh) { + priv->buf = realloc(priv->buf, wh); + priv->size = wh; + tmp_buf = priv->buf; + printf("resized priv to %d bytes\n", wh); + } + memset(tmp_buf, 0, wh); + + for (y=0; y> 2; + tmp_buf[y*w+x] = p; + } + + for (x=0; x> 2; + buf[y*w+x] = p; + } + + //free(tmp_buf); +} + +/* +static void get_overlap(bitmap_t* a, bitmap_t* b) { + int left, top, bottom, right; + int old_left, old_top, old_w, old_h; + int cur_left, cur_top, cur_w, cur_h; + + // Calculate overlap as coordinates + left = (a->left > b->left) ? a->left : b-> left; + top = (a->top > b->top) ? a->top : b->top; + right = ((a->left+a->w) < (b->left+b->w)) ? + (a->left+a->w) : (b->left+b->w); + bottom = ((a->top+a->h) < (b->top+b->h)) ? + (a->top+a->h) : (b->top+b->h); + // Check whether overlap rect is valid + // Just return if it isn't... + if ((right <= left) || (bottom <= top)) + return; + printf("coord overlap %dx%d+%dx%d\n", left, top, right, bottom); + + // Translate into coordinates+width/height for each bitmap + old_left = left-(a->left); + old_top = top-(a->top); + old_w = right-left; + old_h = bottom-top; + printf("bitmap overlap %dx%d+%dx%d\n", old_left, old_top, old_w, old_h); +} +*/ + +ass_be_priv_t* ass_be_init(void) { + ass_be_priv_t* priv; + priv = malloc(sizeof(ass_be_priv_t)); + priv->size = 64*64; + priv->buf = malloc(64*64); + + return priv; +} + 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) + bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius, ass_be_priv_t* be_priv, bitmap_t** bm_oo) { - int bord = be ? (be+1) : 0; - bord = (blur_radius > 0.0) ? blur_radius : bord; + int bord = be ? (be/4+1) : 0; + blur_radius *= 2; + bord = (blur_radius > 0.0) ? (int)(blur_radius+3) : (int) bord; assert(bm_g && bm_o && bm_s); @@ -278,28 +361,34 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur, } } 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) { 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); + 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); + be_blur((*bm_o)->buffer, be_priv, (*bm_o)->w, (*bm_o)->h); + //(*bm_o)->top--; + //(*bm_o)->left--; + } 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); + be_blur((*bm_g)->buffer, be_priv, (*bm_g)->w, (*bm_g)->h); } - } else + } 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 5f45aae4b..a51e3c026 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -23,11 +23,15 @@ #ifndef LIBASS_BITMAP_H #define LIBASS_BITMAP_H +#define MAX_BOXBLUR 50 + #include #include FT_GLYPH_H typedef struct ass_synth_priv_s ass_synth_priv_t; +typedef struct ass_be_priv_s ass_be_priv_t; +ass_be_priv_t* ass_be_init(void); ass_synth_priv_t* ass_synth_init(double); void ass_synth_done(ass_synth_priv_t* priv); @@ -46,8 +50,10 @@ 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, 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); +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, ass_be_priv_t* be_priv, bitmap_t** bm_oo); void ass_free_bitmap(bitmap_t* bm); +bitmap_t* alloc_bitmap(int w, int h); + #endif /* LIBASS_BITMAP_H */ diff --git a/libass/ass_render.c b/libass/ass_render.c index b812ccd8b..44c5ddc0e 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -41,11 +41,13 @@ #include "ass_fontconfig.h" #include "ass_library.h" -#define MAX_GLYPHS 1000 -#define MAX_LINES 100 +#define MAX_GLYPHS 3000 +#define MAX_LINES 300 #define BE_RADIUS 1.5 #define BLUR_MAX_RADIUS 50.0 +#define NEAREST(x) ((int) (x + 0.5)) + static int last_render_id = 0; typedef struct ass_settings_s { @@ -83,12 +85,15 @@ struct ass_renderer_s { int render_id; ass_synth_priv_t* synth_priv; ass_synth_priv_t* synth_priv_blur; + ass_be_priv_t* be_priv; ass_image_t* images_root; // rendering result is stored here ass_image_t* prev_images_root; event_images_t* eimg; // temporary buffer for sorting rendered events int eimg_size; // allocated buffer size + + bitmap_t* bm_oo; // pointer to last rendered outline for compositing }; typedef enum {EF_NONE = 0, EF_KARAOKE, EF_KARAOKE_KF, EF_KARAOKE_KO} effect_t; @@ -116,7 +121,7 @@ typedef struct glyph_info_s { // int height; int be; // blur edges double blur; // gaussian blur - int shadow; + double shadow; double frx, fry, frz; // rotation bitmap_hash_key_t hash_key; @@ -132,6 +137,9 @@ typedef struct text_info_s { line_info_t lines[MAX_LINES]; int n_lines; int height; + // Free list for composited glyphs + void* free_list[MAX_GLYPHS]; + int free_count; } text_info_t; @@ -165,7 +173,7 @@ typedef struct render_context_s { uint32_t fade; // alpha from \fad char be; // blur edges double blur; // gaussian blur - int shadow; + double shadow; int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags effect_t effect_type; @@ -265,6 +273,8 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library) priv->synth_priv = ass_synth_init(BE_RADIUS); priv->synth_priv_blur = ass_synth_init(BLUR_MAX_RADIUS); + priv->be_priv = ass_be_init(); + priv->bm_oo = NULL; priv->library = library; priv->ftlibrary = ft; @@ -315,6 +325,8 @@ static ass_image_t* my_draw_bitmap(unsigned char* bitmap, int bitmap_w, int bitm img->color = color; img->dst_x = dst_x; img->dst_y = dst_y; + + //printf("img dest %dx%d\n", dst_x, dst_y); return img; } @@ -398,6 +410,74 @@ static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t c return tail; } +// Glyph compositing +static void render_overlap(ass_image_t** last_tail, ass_image_t** tail, void** free_list, int* free_count) { + int left, top, bottom, right; + int old_left, old_top, old_w, old_h; + int cur_left, cur_top, cur_w, cur_h; + int x, y, opos, cpos; + char m; + + int ax = (*last_tail)->dst_x; + int ay = (*last_tail)->dst_y; + int aw = (*last_tail)->w; + int ah = (*last_tail)->h; + int bx = (*tail)->dst_x; + int by = (*tail)->dst_y; + int bw = (*tail)->w; + int bh = (*tail)->h; + unsigned char* a; + unsigned char* b; + + // Calculate overlap as coordinates + left = (ax > bx) ? ax : bx; + top = (ay > by) ? ay : by; + right = ((ax+aw) < (bx+bw)) ? + (ax+aw) : (bx+bw); + bottom = ((ay+ah) < (by+bh)) ? + (ay+ah) : (by+bh); + // Check whether overlap rect is valid + if ((right <= left) || (bottom <= top)) + return; + //printf("coord overlap %dx%d+%dx%d\n", left, top, right, bottom); + + // Translate into coordinates+width/height for each bitmap + old_left = left-(ax); + old_top = top-(ay); + old_w = right-left; + old_h = bottom-top; + //printf("bitmap overlap %dx%d+%dx%d\n", old_left, old_top, old_w, old_h); + + cur_left = left-(bx); + cur_top = top-(by); + cur_w = right-left; + cur_h = bottom-top; + //printf("bitmap overlap %dx%d+%dx%d\n\n", cur_left, cur_top, cur_w, cur_h); + + // Allocate new bitmaps and copy over data + a = (*last_tail)->bitmap; + b = (*tail)->bitmap; + (*last_tail)->bitmap = malloc(aw*ah); + free_list[(*free_count)++] = (*last_tail)->bitmap; + (*tail)->bitmap = malloc(bw*bh); + free_list[(*free_count)++] = (*tail)->bitmap; + memcpy((*last_tail)->bitmap, a, aw*ah); + memcpy((*tail)->bitmap, b, bw*bh); + + // Composite overlapping area + for (y=0; y b[cpos]) ? + a[opos] : b[cpos]; + (*last_tail)->bitmap[opos] = 0; + (*tail)->bitmap[cpos] = m; + } +} + + /** * \brief Convert text_info_t struct to ass_image_t list * Splits glyphs in halves when needed (for \kf karaoke). @@ -409,14 +489,16 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) bitmap_t* bm; ass_image_t* head; ass_image_t** tail = &head; - + ass_image_t** last_tail = 0; + ass_image_t** here_tail = 0; + for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) continue; - pen_x = dst_x + info->pos.x + info->shadow; - pen_y = dst_y + info->pos.y + info->shadow; + pen_x = dst_x + info->pos.x + NEAREST(info->shadow); + pen_y = dst_y + info->pos.y + NEAREST(info->shadow); bm = info->bm_s; tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail); @@ -429,12 +511,23 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) pen_x = dst_x + info->pos.x; pen_y = dst_y + info->pos.y; + bm = info->bm_o; if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { // do nothing - } else + } else { + here_tail = tail; tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); + // Composite overlapping translucent outlines together + // Additional bitmaps not stored in cache are allocated for that + // These are put into a free list which gets freed either + // when a new frame starts or when the renderer is dealloc'd + if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) { + render_overlap(last_tail, here_tail, text_info->free_list, &text_info->free_count); + } + last_tail = here_tail; + } } for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; @@ -455,7 +548,6 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) } else tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail); } - *tail = 0; return head; } @@ -583,7 +675,7 @@ static void change_border(double border) if (border < 0) { if (render_context.style->BorderStyle == 1) { if (render_context.style->Outline == 0 && render_context.style->Shadow > 0) - border = 1.; + border = 0.0; //1.; else border = render_context.style->Outline; } else @@ -693,7 +785,7 @@ static char* parse_tag(char* p, double pwr) { skip('\\'); if ((*p == '}') || (*p == 0)) return p; - + // New tags introduced in vsfilter 2.39 if (mystrcmp(&p, "xbord")) { double val; @@ -740,7 +832,6 @@ static char* parse_tag(char* p, double pwr) { render_context.blur = val; } else render_context.blur = 0.0; - // ASS standard tags } else if (mystrcmp(&p, "fsc")) { char tp = *p++; @@ -785,18 +876,24 @@ static char* parse_tag(char* p, double pwr) { double x, y; double k; skip('('); - x1 = strtol(p, &p, 10); + //x1 = strtol(p, &p, 10); + mystrtoi(&p, 10, &x1); skip(','); - y1 = strtol(p, &p, 10); + //y1 = strtol(p, &p, 10); + mystrtoi(&p, 10, &y1); skip(','); - x2 = strtol(p, &p, 10); + //x2 = strtol(p, &p, 10); + mystrtoi(&p, 10, &x2); skip(','); - y2 = strtol(p, &p, 10); + //y2 = strtol(p, &p, 10); + mystrtoi(&p, 10, &y2); if (*p == ',') { skip(','); - t1 = strtoll(p, &p, 10); + //t1 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t1); skip(','); - t2 = strtoll(p, &p, 10); + //t2 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t2); mp_msg(MSGT_ASS, MSGL_DBG2, "movement6: (%d, %d) -> (%d, %d), (%" PRId64 " .. %" PRId64 ")\n", x1, y1, x2, y2, (int64_t)t1, (int64_t)t2); } else { @@ -890,9 +987,11 @@ static char* parse_tag(char* p, double pwr) { } else if (mystrcmp(&p, "pos")) { int v1, v2; skip('('); - v1 = strtol(p, &p, 10); + //v1 = strtol(p, &p, 10); + mystrtoi(&p, 10, &v1); skip(','); - v2 = strtol(p, &p, 10); + //v2 = strtol(p, &p, 10); + mystrtoi(&p, 10, &v2); skip(')'); mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2); if (render_context.evt_type != EVENT_POSITIONED) { @@ -906,9 +1005,11 @@ static char* parse_tag(char* p, double pwr) { long long t1, t2, t3, t4; if (*p == 'e') ++p; // either \fad or \fade skip('('); - a1 = strtol(p, &p, 10); + //a1 = strtol(p, &p, 10); + mystrtoi(&p, 10, &a1); skip(','); - a2 = strtol(p, &p, 10); + //a2 = strtol(p, &p, 10); + mystrtoi(&p, 10, &a2); if (*p == ')') { // 2-argument version (\fad, according to specs) // a1 and a2 are fade-in and fade-out durations @@ -923,24 +1024,31 @@ static char* parse_tag(char* p, double pwr) { // 6-argument version (\fade) // a1 and a2 (and a3) are opacity values skip(','); - a3 = strtol(p, &p, 10); + //a3 = strtol(p, &p, 10); + mystrtoi(&p, 10, &a3); skip(','); - t1 = strtoll(p, &p, 10); + //t1 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t1); skip(','); - t2 = strtoll(p, &p, 10); + //t2 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t2); skip(','); - t3 = strtoll(p, &p, 10); + //t3 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t3); skip(','); - t4 = strtoll(p, &p, 10); + //t4 = strtoll(p, &p, 10); + mystrtoll(&p, 10, &t4); } skip(')'); render_context.fade = interpolate_alpha(frame_context.time - render_context.event->Start, t1, t2, t3, t4, a1, a2, a3); } else if (mystrcmp(&p, "org")) { int v1, v2; skip('('); - v1 = strtol(p, &p, 10); + //v1 = strtol(p, &p, 10); + mystrtoi(&p, 10, &v1); skip(','); - v2 = strtol(p, &p, 10); + //v2 = strtol(p, &p, 10); + mystrtoi(&p, 10, &v2); skip(')'); mp_msg(MSGT_ASS, MSGL_DBG2, "org(%d, %d)\n", v1, v2); // render_context.evt_type = EVENT_POSITIONED; @@ -1046,7 +1154,7 @@ static char* parse_tag(char* p, double pwr) { if (mystrtoi(&p, 10, &val)) { // Clamp to 10, since high values need excessive CPU val = (val < 0) ? 0 : val; - val = (val > 10) ? 10 : val; + val = (val > 50) ? 10 : val; render_context.be = val; } else render_context.be = 0; @@ -1067,33 +1175,41 @@ static char* parse_tag(char* p, double pwr) { render_context.italic = render_context.style->Italic; update_font(); } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) { - int val = strtol(p, &p, 10); + //int val = strtol(p, &p, 10); + int val = 0; + mystrtoi(&p, 10, &val); render_context.effect_type = EF_KARAOKE_KF; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "ko")) { - int val = strtol(p, &p, 10); + //int val = strtol(p, &p, 10); + int val = 0; + mystrtoi(&p, 10, &val); render_context.effect_type = EF_KARAOKE_KO; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "k")) { - int val = strtol(p, &p, 10); + //int val = strtol(p, &p, 10); + int val = 0; + mystrtoi(&p, 10, &val); render_context.effect_type = EF_KARAOKE; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "shad")) { - int val; + int val = 0;; if (mystrtoi(&p, 10, &val)) render_context.shadow = val; else render_context.shadow = render_context.style->Shadow; } else if (mystrcmp(&p, "pbo")) { - (void)strtol(p, &p, 10); // ignored + //(void)strtol(p, &p, 10); // ignored + int val = 0; + mystrtoi(&p, 10, &val); } else if (mystrcmp(&p, "p")) { - int val; + int val = 0; if (!mystrtoi(&p, 10, &val)) val = 0; render_context.drawing_mode = !!val; @@ -1148,7 +1264,7 @@ static unsigned get_next_char(char** str) return ' '; } } - chr = utf8_get_char(&p); + chr = utf8_get_char((const char **) &p); *str = p; return chr; } @@ -1386,7 +1502,7 @@ static void get_bitmap_glyph(glyph_info_t* info) ass_renderer->synth_priv_blur, info->glyph, info->outline_glyph, &info->bm, &info->bm_o, - &info->bm_s, info->be, info->blur); + &info->bm_s, info->be, info->blur, ass_renderer->be_priv, &ass_renderer->bm_oo); if (error) info->symbol = 0; @@ -1402,6 +1518,21 @@ static void get_bitmap_glyph(glyph_info_t* info) FT_Done_Glyph(info->glyph); if (info->outline_glyph) FT_Done_Glyph(info->outline_glyph); + + /* + // Find outline overlap rectangle and composite glyphs together + if (ass_renderer->bm_oo) { + printf("current outline %dx%d+%dx%d\n", + info->bm_o->left, info->bm_o->top, + info->bm_o->w, info->bm_o->h); + printf("old outline %dx%d+%dx%d\n", + ass_renderer->bm_oo->left, ass_renderer->bm_oo->top, + ass_renderer->bm_oo->w, ass_renderer->bm_oo->h); + get_overlap(info->bm_o, ass_renderer->bm_oo); + printf("--\n"); + } + ass_renderer->bm_oo = info->bm_o; + */ } /** @@ -2047,7 +2178,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) center.x = x2scr(render_context.org_x); center.y = y2scr(render_context.org_y); } else { - int bx, by; + int bx = 0, by = 0; get_base_point(bbox, alignment, &bx, &by); center.x = device_x + bx; center.y = device_y + by; @@ -2195,14 +2326,21 @@ int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const cha */ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now) { + int i = 0; ass_renderer = priv; global_settings = &priv->settings; + if (!priv->settings.frame_width && !priv->settings.frame_height) return 1; // library not initialized if (track->n_events == 0) return 1; // nothing to do + + // Free composited images + while (text_info.free_count--) + free(text_info.free_list[i++]); + text_info.free_count = 0; frame_context.ass_priv = priv; frame_context.width = global_settings->frame_width; @@ -2231,6 +2369,7 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n priv->prev_images_root = priv->images_root; priv->images_root = 0; + return 0; } diff --git a/libass/ass_utils.c b/libass/ass_utils.c index d48685c63..47f638aea 100644 --- a/libass/ass_utils.c +++ b/libass/ass_utils.c @@ -32,8 +32,23 @@ int mystrtoi(char** p, int base, int* res) { + // NOTE: base argument is ignored, but not used anyway + double temp_res; char* start = *p; - *res = strtol(*p, p, base); + temp_res = strtod(*p, p); + *res = (int) (temp_res + 0.5); + //printf("read %f, rounded to %d\n", temp_res, *res); + if (*p != start) return 1; + else return 0; +} + +int mystrtoll(char** p, int base, long long* res) +{ + // NOTE: base argument is ignored, but not used anyway + double temp_res; + char* start = *p; + temp_res = strtod(*p, p); + *res = (long long) (temp_res + 0.5); if (*p != start) return 1; else return 0; } diff --git a/libass/ass_utils.h b/libass/ass_utils.h index d7501c485..fb751ffd2 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -26,6 +26,7 @@ #include int mystrtoi(char** p, int base, int* res); +int mystrtoll(char** p, int base, long long* res); int mystrtou32(char** p, int base, uint32_t* res); int mystrtod(char** p, double* res); int strtocolor(char** q, uint32_t* res);