diff options
Diffstat (limited to 'libass')
-rw-r--r-- | libass/ass_bitmap.c | 225 | ||||
-rw-r--r-- | libass/ass_bitmap.h | 43 | ||||
-rw-r--r-- | libass/ass_cache.c | 22 | ||||
-rw-r--r-- | libass/ass_cache.h | 6 | ||||
-rw-r--r-- | libass/ass_cache_template.h | 41 | ||||
-rw-r--r-- | libass/ass_parse.c | 1 | ||||
-rw-r--r-- | libass/ass_render.c | 745 | ||||
-rw-r--r-- | libass/ass_render.h | 76 | ||||
-rw-r--r-- | libass/ass_shaper.c | 29 | ||||
-rw-r--r-- | libass/ass_utils.c | 32 | ||||
-rw-r--r-- | libass/ass_utils.h | 1 |
11 files changed, 885 insertions, 336 deletions
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index dcc2f2b..ad00df2 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -27,24 +27,11 @@ #include "ass_utils.h" #include "ass_bitmap.h" - -struct ass_synth_priv { - int tmp_w, tmp_h; - unsigned *tmp; - - int g_r; - int g_w; - - double *g0; - unsigned *g; - unsigned *gt2; - - double radius; -}; +#include "ass_render.h" static const unsigned base = 256; -static int generate_tables(ASS_SynthPriv *priv, double radius) +int generate_tables(ASS_SynthPriv *priv, double radius) { double A = log(1.0 / base) / (radius * radius * 2); int mx, i; @@ -103,7 +90,7 @@ static int generate_tables(ASS_SynthPriv *priv, double radius) return 0; } -static void resize_tmp(ASS_SynthPriv *priv, int w, int h) +void resize_tmp(ASS_SynthPriv *priv, int w, int h) { if (priv->tmp_w >= w && priv->tmp_h >= h) return; @@ -135,12 +122,17 @@ void ass_synth_done(ASS_SynthPriv *priv) free(priv); } -static Bitmap *alloc_bitmap(int w, int h) +Bitmap *alloc_bitmap(int w, int h) { Bitmap *bm; - unsigned s = w; // XXX: alignment + + uintptr_t alignment_offset = (w > 31) ? 31 : ((w > 15) ? 15 : 0); + unsigned s = (w + alignment_offset) & ~alignment_offset; bm = malloc(sizeof(Bitmap)); - bm->buffer = calloc(s, h); + bm->buffer_ptr = malloc(s * h + alignment_offset + 32); + bm->buffer = (unsigned char*) + (((uintptr_t)bm->buffer_ptr + alignment_offset) & ~alignment_offset); + memset(bm->buffer, 0, s * h + 32); bm->w = w; bm->h = h; bm->stride = s; @@ -151,11 +143,11 @@ static Bitmap *alloc_bitmap(int w, int h) void ass_free_bitmap(Bitmap *bm) { if (bm) - free(bm->buffer); + free(bm->buffer_ptr); free(bm); } -static Bitmap *copy_bitmap(const Bitmap *src) +Bitmap *copy_bitmap(const Bitmap *src) { Bitmap *dst = alloc_bitmap(src->w, src->h); dst->left = src->left; @@ -220,7 +212,7 @@ Bitmap *outline_to_bitmap(ASS_Library *library, FT_Library ftlib, * The glyph bitmap is subtracted from outline bitmap. This way looks much * better in some cases. */ -static void fix_outline(Bitmap *bm_g, Bitmap *bm_o) +void fix_outline(Bitmap *bm_g, Bitmap *bm_o) { int x, y; const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; @@ -253,7 +245,7 @@ static void fix_outline(Bitmap *bm_g, Bitmap *bm_o) * \brief Shift a bitmap by the fraction of a pixel in x and y direction * expressed in 26.6 fixed point */ -static void shift_bitmap(Bitmap *bm, int shift_x, int shift_y) +void shift_bitmap(Bitmap *bm, int shift_x, int shift_y) { int x, y, b; int w = bm->w; @@ -305,9 +297,9 @@ static void shift_bitmap(Bitmap *bm, int shift_x, int shift_y) /* * Gaussian blur. An fast pure C implementation from MPlayer. */ -static void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, - int width, int height, int stride, - unsigned *m2, int r, int mwidth) +void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, + int width, int height, int stride, + unsigned *m2, int r, int mwidth) { int x, y; @@ -427,36 +419,72 @@ static void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, /** * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel * This blur is the same as the one employed by vsfilter. + * Pure C implementation. */ -static void be_blur(Bitmap *bm) +void be_blur_c(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride, + uint16_t *tmp) { - int w = bm->w; - int h = bm->h; - int s = bm->stride; - unsigned char *buf = bm->buffer; - unsigned int x, y; - unsigned int old_sum, new_sum; - - for (y = 0; y < h; y++) { - old_sum = 2 * buf[y * s]; - for (x = 0; x < w - 1; x++) { - new_sum = buf[y * s + x] + buf[y * s + x + 1]; - buf[y * s + x] = (old_sum + new_sum) >> 2; - old_sum = new_sum; + unsigned short *col_pix_buf = tmp; + unsigned short *col_sum_buf = tmp + w * sizeof(unsigned short); + unsigned x, y, old_pix, old_sum, new_sum, temp1, temp2; + unsigned char *src, *dst; + memset(col_pix_buf, 0, w * sizeof(unsigned short)); + memset(col_sum_buf, 0, w * sizeof(unsigned short)); + { + y = 0; + src=buf+y*stride; + + x = 2; + old_pix = src[x-1]; + old_sum = old_pix + src[x-2]; + for ( ; x < w; x++) { + temp1 = src[x]; + temp2 = old_pix + temp1; + old_pix = temp1; + temp1 = old_sum + temp2; + old_sum = temp2; + col_pix_buf[x] = temp1; + } + } + new_sum = 2 * buf[y * stride + w - 1]; + buf[y * stride + w - 1] = (old_sum + new_sum) >> 2; + { + x = 2; + old_pix = src[x-1]; + old_sum = old_pix + src[x-2]; + for ( ; x < w; x++) { + temp1 = src[x]; + temp2 = old_pix + temp1; + old_pix = temp1; + temp1 = old_sum + temp2; + old_sum = temp2; + + temp2 = col_pix_buf[x] + temp1; + col_pix_buf[x] = temp1; + col_sum_buf[x] = temp2; } - new_sum = 2 * buf[y * s + w - 1]; - buf[y * s + w - 1] = (old_sum + new_sum) >> 2; } - for (x = 0; x < w; x++) { - old_sum = 2 * buf[x]; - for (y = 0; y < h - 1; y++) { - new_sum = buf[y * s + x] + buf[(y + 1) * s + x]; - buf[y * s + x] = (old_sum + new_sum) >> 2; - old_sum = new_sum; + for (y = 2; y < h; y++) { + src=buf+y*stride; + dst=buf+(y-1)*stride; + + x = 2; + old_pix = src[x-1]; + old_sum = old_pix + src[x-2]; + for ( ; x < w; x++) { + temp1 = src[x]; + temp2 = old_pix + temp1; + old_pix = temp1; + temp1 = old_sum + temp2; + old_sum = temp2; + + temp2 = col_pix_buf[x] + temp1; + col_pix_buf[x] = temp1; + dst[x-1] = (col_sum_buf[x] + temp2) >> 4; + col_sum_buf[x] = temp2; } - new_sum = 2 * buf[(h - 1) * s + x]; - buf[(h - 1) * s + x] = (old_sum + new_sum) >> 2; } } @@ -489,46 +517,69 @@ int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur, } } - // Apply box blur (multiple passes, if requested) - while (be--) { - if (*bm_o) - be_blur(*bm_o); - if (!*bm_o || border_style == 3) - be_blur(*bm_g); - } + return 0; +} - // Apply gaussian blur - if (blur_radius > 0.0) { - if (*bm_o) - resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h); - if (!*bm_o || border_style == 3) - resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h); - generate_tables(priv_blur, blur_radius); - if (*bm_o) - ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp, - (*bm_o)->w, (*bm_o)->h, (*bm_o)->stride, - priv_blur->gt2, priv_blur->g_r, priv_blur->g_w); - if (!*bm_o || border_style == 3) - ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp, - (*bm_g)->w, (*bm_g)->h, (*bm_g)->stride, - priv_blur->gt2, priv_blur->g_r, priv_blur->g_w); +/** + * \brief Add two bitmaps together at a given position + * Uses additive blending, clipped to [0,255]. Pure C implementation. + */ +void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width) +{ + unsigned out; + uint8_t* end = dst + dst_stride * height; + while (dst < end) { + for (unsigned j = 0; j < width; ++j) { + out = dst[j] + src[j]; + dst[j] = FFMIN(out, 255); + } + dst += dst_stride; + src += src_stride; } +} - // Create shadow and fix outline as needed - if (*bm_o && border_style != 3) { - *bm_s = copy_bitmap(*bm_o); - fix_outline(*bm_g, *bm_o); - } else if (*bm_o && border_visible) { - *bm_s = copy_bitmap(*bm_o); - } else if (*bm_o) { - *bm_s = *bm_o; - *bm_o = 0; - } else - *bm_s = copy_bitmap(*bm_g); - - assert(bm_s); +void sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width) +{ + unsigned out; + uint8_t* end = dst + dst_stride * height; + while (dst < end) { + for (unsigned j = 0; j < width; ++j) { + out = dst[j] - src[j]; + dst[j] = FFMAX(out, 0); + } + dst += dst_stride; + src += src_stride; + } +} - shift_bitmap(*bm_s, shadow_offset.x, shadow_offset.y); +void restride_bitmap_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t width, intptr_t height) +{ + uint8_t* end = dst + dst_stride * height; + while (dst < end) { + memcpy(dst, src, width); + dst += dst_stride; + src += src_stride; + } +} - return 0; +void mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src1, intptr_t src1_stride, + uint8_t *src2, intptr_t src2_stride, + intptr_t w, intptr_t h) +{ + uint8_t* end = src1 + src1_stride * h; + while (src1 < end) { + for (unsigned x = 0; x < w; ++x) { + dst[x] = (src1[x] * src2[x] + 255) >> 8; + } + dst += dst_stride; + src1 += src1_stride; + src2 += src2_stride; + } } diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 53be7af..b51c1bf 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -24,7 +24,19 @@ #include "ass.h" -typedef struct ass_synth_priv ASS_SynthPriv; +typedef struct ass_synth_priv { + int tmp_w, tmp_h; + unsigned *tmp; + + int g_r; + int g_w; + + double *g0; + unsigned *g; + unsigned *gt2; + + double radius; +} ASS_SynthPriv; ASS_SynthPriv *ass_synth_init(double); void ass_synth_done(ASS_SynthPriv *priv); @@ -33,11 +45,14 @@ typedef struct { int left, top; int w, h; // width, height int stride; - unsigned char *buffer; // w x h buffer + unsigned char *buffer; // h * stride buffer + unsigned char *buffer_ptr; // unaligned pointer (for free()) } Bitmap; Bitmap *outline_to_bitmap(ASS_Library *library, FT_Library ftlib, FT_Outline *outline, int bord); + +Bitmap *alloc_bitmap(int w, int h); /** * \brief perform glyph rendering * \param glyph original glyph @@ -55,5 +70,29 @@ int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur, int border_style, int border_visible); void ass_free_bitmap(Bitmap *bm); +void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, + int width, int height, int stride, + unsigned *m2, int r, int mwidth); +void be_blur_c(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride, + uint16_t *tmp); +void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width); +void sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width); +void restride_bitmap_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t width, intptr_t height); +void mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src1, intptr_t src1_stride, + uint8_t *src2, intptr_t src2_stride, + intptr_t w, intptr_t h); +void shift_bitmap(Bitmap *bm, int shift_x, int shift_y); +void fix_outline(Bitmap *bm_g, Bitmap *bm_o); +void resize_tmp(ASS_SynthPriv *priv, int w, int h); +int generate_tables(ASS_SynthPriv *priv, double radius); +Bitmap *copy_bitmap(const Bitmap *src); #endif /* LIBASS_BITMAP_H */ diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 8234e5f..6baa924 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -125,12 +125,28 @@ static unsigned bitmap_compare (void *a, void *b, size_t key_size) static void composite_destruct(void *key, void *value) { CompositeHashValue *v = value; - free(v->a); - free(v->b); + CompositeHashKey *k = key; + if (v->bm) + ass_free_bitmap(v->bm); + if (v->bm_o) + ass_free_bitmap(v->bm_o); + if (v->bm_s) + ass_free_bitmap(v->bm_s); + free(k->str); free(key); free(value); } +static size_t composite_size(void *value, size_t value_size) +{ + CompositeHashValue *val = value; + if (val->bm_o) + return val->bm_o->w * val->bm_o->h * 3; + else if (val->bm) + return val->bm->w * val->bm->h * 3; + return 0; +} + // outline cache static unsigned outline_hash(void *key, size_t key_size) @@ -349,6 +365,6 @@ Cache *ass_bitmap_cache_create(void) Cache *ass_composite_cache_create(void) { return ass_cache_create(composite_hash, composite_compare, - composite_destruct, (ItemSize)NULL, sizeof(CompositeHashKey), + composite_destruct, composite_size, sizeof(CompositeHashKey), sizeof(CompositeHashValue)); } diff --git a/libass/ass_cache.h b/libass/ass_cache.h index 7375f04..677b705 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -35,8 +35,10 @@ typedef struct { } BitmapHashValue; typedef struct { - unsigned char *a; - unsigned char *b; + Bitmap *bm; + Bitmap *bm_o; + Bitmap *bm_s; + FT_Vector pos; } CompositeHashValue; typedef struct { diff --git a/libass/ass_cache_template.h b/libass/ass_cache_template.h index 3d8185f..8f7f2af 100644 --- a/libass/ass_cache_template.h +++ b/libass/ass_cache_template.h @@ -123,21 +123,36 @@ END(DrawingHashKey) // Cache for composited bitmaps START(composite, composite_hash_key) - GENERIC(int, aw) - GENERIC(int, ah) - GENERIC(int, bw) - GENERIC(int, bh) - GENERIC(int, ax) - GENERIC(int, ay) - GENERIC(int, bx) - GENERIC(int, by) - GENERIC(int, as) - GENERIC(int, bs) - GENERIC(unsigned char *, a) - GENERIC(unsigned char *, b) + GENERIC(unsigned, w) + GENERIC(unsigned, h) + GENERIC(unsigned, o_w) + GENERIC(unsigned, o_h) + GENERIC(int, is_drawing) + GENERIC(unsigned, chars) + GENERIC(int, be) + GENERIC(double, blur) + GENERIC(int, border_style) + GENERIC(int, has_border) + GENERIC(double, border_x) + GENERIC(double, border_y) + GENERIC(double, shadow_x) + GENERIC(double, shadow_y) + GENERIC(double, frx) + GENERIC(double, fry) + GENERIC(double, frz) + GENERIC(double, fax) + GENERIC(double, fay) + GENERIC(double, scale_x) + GENERIC(double, scale_y) + GENERIC(double, hspacing) + GENERIC(unsigned, italic) + GENERIC(unsigned, bold) + GENERIC(int, flags) + GENERIC(unsigned, has_outline) + FTVECTOR(advance) + STRING(str) END(CompositeHashKey) - #undef START #undef GENERIC #undef STRING diff --git a/libass/ass_parse.c b/libass/ass_parse.c index c3292c9..fe40e69 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -983,6 +983,7 @@ void process_karaoke_effects(ASS_Renderer *render_priv) cur2->effect_type = s1->effect_type; cur2->effect_timing = x - d6_to_int(cur2->pos.x); } + s1->effect = 1; } } } diff --git a/libass/ass_render.c b/libass/ass_render.c index 12f5701..e6e6052 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -20,6 +20,7 @@ #include <assert.h> #include <math.h> +#include <string.h> #include "ass_render.h" #include "ass_parse.h" @@ -27,9 +28,12 @@ #define MAX_GLYPHS_INITIAL 1024 #define MAX_LINES_INITIAL 64 +#define MAX_BITMAPS_INITIAL 16 +#define MAX_STR_LENGTH_INITIAL 64 #define SUBPIXEL_MASK 63 #define SUBPIXEL_ACCURACY 7 + ASS_Renderer *ass_renderer_init(ASS_Library *library) { int error; @@ -59,15 +63,25 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library) priv->ftlibrary = ft; // images_root and related stuff is zero-filled in calloc + priv->add_bitmaps_func = add_bitmaps_c; + priv->sub_bitmaps_func = sub_bitmaps_c; + priv->mul_bitmaps_func = mul_bitmaps_c; + priv->be_blur_func = be_blur_c; + priv->restride_bitmap_func = restride_bitmap_c; + priv->cache.font_cache = ass_font_cache_create(); priv->cache.bitmap_cache = ass_bitmap_cache_create(); priv->cache.composite_cache = ass_composite_cache_create(); priv->cache.outline_cache = ass_outline_cache_create(); priv->cache.glyph_max = GLYPH_CACHE_MAX; priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE; + priv->cache.composite_max_size = COMPOSITE_CACHE_MAX_SIZE; + priv->text_info.max_bitmaps = MAX_BITMAPS_INITIAL; priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; priv->text_info.max_lines = MAX_LINES_INITIAL; + priv->text_info.n_bitmaps = 0; + priv->text_info.combined_bitmaps = calloc(MAX_BITMAPS_INITIAL, sizeof(CombinedBitmapInfo)); priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo)); priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); @@ -129,6 +143,8 @@ void ass_renderer_done(ASS_Renderer *render_priv) free(render_priv->text_info.glyphs); free(render_priv->text_info.lines); + free(render_priv->text_info.combined_bitmaps); + free(render_priv->settings.default_font); free(render_priv->settings.default_family); @@ -415,109 +431,6 @@ render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y, return tail; } -/** - * \brief Replace the bitmap buffer in ASS_Image with a copy - * \param img ASS_Image to operate on - * \return pointer to old bitmap buffer - */ -static unsigned char *clone_bitmap_buffer(ASS_Image *img) -{ - unsigned char *old_bitmap = img->bitmap; - int size = img->stride * (img->h - 1) + img->w; - img->bitmap = malloc(size); - memcpy(img->bitmap, old_bitmap, size); - return old_bitmap; -} - -/** - * \brief Calculate overlapping area of two consecutive bitmaps and in case they - * overlap, blend them together - * Mainly useful for translucent glyphs and especially borders, to avoid the - * luminance adding up where they overlap (which looks ugly) - */ -static void -render_overlap(ASS_Renderer *render_priv, ASS_Image **last_tail, - ASS_Image **tail) -{ - int left, top, bottom, right; - int old_left, old_top, w, h, cur_left, cur_top; - int x, y, opos, cpos; - char m; - CompositeHashKey hk; - CompositeHashValue *hv; - CompositeHashValue chv; - int ax = (*last_tail)->dst_x; - int ay = (*last_tail)->dst_y; - int aw = (*last_tail)->w; - int as = (*last_tail)->stride; - int ah = (*last_tail)->h; - int bx = (*tail)->dst_x; - int by = (*tail)->dst_y; - int bw = (*tail)->w; - int bs = (*tail)->stride; - int bh = (*tail)->h; - unsigned char *a; - unsigned char *b; - - if ((*last_tail)->bitmap == (*tail)->bitmap) - return; - - if ((*last_tail)->color != (*tail)->color) - return; - - // Calculate overlap 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); - if ((right <= left) || (bottom <= top)) - return; - old_left = left - ax; - old_top = top - ay; - w = right - left; - h = bottom - top; - cur_left = left - bx; - cur_top = top - by; - - // Query cache - hk.a = (*last_tail)->bitmap; - hk.b = (*tail)->bitmap; - hk.aw = aw; - hk.ah = ah; - hk.bw = bw; - hk.bh = bh; - hk.ax = ax; - hk.ay = ay; - hk.bx = bx; - hk.by = by; - hk.as = as; - hk.bs = bs; - hv = ass_cache_get(render_priv->cache.composite_cache, &hk); - if (hv) { - (*last_tail)->bitmap = hv->a; - (*tail)->bitmap = hv->b; - return; - } - // Allocate new bitmaps and copy over data - a = clone_bitmap_buffer(*last_tail); - b = clone_bitmap_buffer(*tail); - - // Blend overlapping area - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - opos = (old_top + y) * (as) + (old_left + x); - cpos = (cur_top + y) * (bs) + (cur_left + x); - m = FFMIN(a[opos] + b[cpos], 0xff); - (*last_tail)->bitmap[opos] = 0; - (*tail)->bitmap[cpos] = m; - } - - // Insert bitmaps into the cache - chv.a = (*last_tail)->bitmap; - chv.b = (*tail)->bitmap; - ass_cache_put(render_priv->cache.composite_cache, &hk, &chv); -} - static void free_list_add(ASS_Renderer *render_priv, void *object) { if (!render_priv->free_head) { @@ -594,7 +507,7 @@ blend_vector_error: // Iterate through bitmaps and blend/clip them for (cur = head; cur; cur = cur->next) { - int left, top, right, bottom, apos, bpos, y, x, w, h; + int left, top, right, bottom, w, h; int ax, ay, aw, ah, as; int bx, by, bw, bh, bs; int aleft, atop, bleft, btop; @@ -628,43 +541,48 @@ blend_vector_error: if (render_priv->state.clip_drawing_mode) { // Inverse clip if (ax + aw < bx || ay + ah < by || ax > bx + bw || - ay > by + bh) { + ay > by + bh || !h || !w) { continue; } // Allocate new buffer and add to free list - nbuffer = malloc(as * ah); + nbuffer = malloc(as * ah + 0x1F); if (!nbuffer) goto blend_vector_exit; free_list_add(render_priv, nbuffer); + nbuffer = (unsigned char*)(((uintptr_t)nbuffer + 0x1F) & ~0x1F); // Blend together - memcpy(nbuffer, abuffer, as * (ah - 1) + aw); - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - apos = (atop + y) * as + aleft + x; - bpos = (btop + y) * bs + bleft + x; - nbuffer[apos] = FFMAX(0, abuffer[apos] - bbuffer[bpos]); - } + memcpy(nbuffer, abuffer, ((ah - 1) * as) + aw); + render_priv->sub_bitmaps_func(nbuffer + atop * as + aleft, as, + bbuffer + btop * bs + bleft, bs, + h, w); } else { // Regular clip if (ax + aw < bx || ay + ah < by || ax > bx + bw || - ay > by + bh) { - cur->w = cur->h = 0; + ay > by + bh || !h || !w) { + cur->w = cur->h = cur->stride = 0; continue; } // Allocate new buffer and add to free list - nbuffer = calloc(as, ah); + uintptr_t alignment_offset = (w > 15) ? 15 : ((w > 7) ? 7 : 0); + unsigned ns = (w + alignment_offset) & ~alignment_offset; + nbuffer = malloc(ns * h + alignment_offset); if (!nbuffer) goto blend_vector_exit; free_list_add(render_priv, nbuffer); + nbuffer = (unsigned char*) + (((uintptr_t)nbuffer + alignment_offset) & ~alignment_offset); // Blend together - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - apos = (atop + y) * as + aleft + x; - bpos = (btop + y) * bs + bleft + x; - nbuffer[apos] = (abuffer[apos] * bbuffer[bpos] + 255) >> 8; - } + render_priv->mul_bitmaps_func(nbuffer, ns, + abuffer + atop * as + aleft, as, + bbuffer + btop * bs + bleft, bs, + w, h); + cur->dst_x += aleft; + cur->dst_y += atop; + cur->w = w; + cur->h = h; + cur->stride = ns; } cur->bitmap = nbuffer; } @@ -674,8 +592,10 @@ blend_vector_exit: render_priv->state.clip_drawing = 0; } -#define IS_SKIP_SYMBOL(x) ((x) == 0 || (x) == '\n' || (x) == '\r') - +static inline int is_skip_symbol(uint32_t x) +{ + return (x == 0 || x == '\n' || x == '\r'); +} /** * \brief Convert TextInfo struct to ASS_Image list * Splits glyphs in halves when needed (for \kf karaoke). @@ -687,118 +607,102 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y) Bitmap *bm; ASS_Image *head; ASS_Image **tail = &head; - ASS_Image **last_tail = 0; - ASS_Image **here_tail = 0; TextInfo *text_info = &render_priv->text_info; - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if (IS_SKIP_SYMBOL(info->symbol) || !info->bm_s - || (info->shadow_x == 0 && info->shadow_y == 0) || info->skip) + for (i = 0; i < text_info->n_bitmaps; ++i) { + CombinedBitmapInfo *info = &text_info->combined_bitmaps[i]; + if (!info->bm_s || (info->shadow_x == 0 && info->shadow_y == 0)) continue; - while (info) { - if (!info->bm_s) { - info = info->next; - continue; - } - - pen_x = - dst_x + (info->pos.x >> 6) + - (int) (info->shadow_x * render_priv->border_scale); - pen_y = - dst_y + (info->pos.y >> 6) + - (int) (info->shadow_y * render_priv->border_scale); - bm = info->bm_s; - - here_tail = tail; - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0, - 1000000, tail, IMAGE_TYPE_SHADOW); - - if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0)) - render_overlap(render_priv, last_tail, here_tail); - last_tail = here_tail; + pen_x = + dst_x + info->pos.x + + (int) (info->shadow_x * render_priv->border_scale); + pen_y = + dst_y + info->pos.y + + (int) (info->shadow_y * render_priv->border_scale); + bm = info->bm_s; - info = info->next; - } + tail = + render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0, + 1000000, tail, IMAGE_TYPE_SHADOW); } - last_tail = 0; - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if (IS_SKIP_SYMBOL(info->symbol) || !info->bm_o - || info->skip) + for (i = 0; i < text_info->n_bitmaps; ++i) { + CombinedBitmapInfo *info = &text_info->combined_bitmaps[i]; + if (!info->bm_o) continue; - while (info) { - if (!info->bm_o) { - info = info->next; - continue; - } - - pen_x = dst_x + (info->pos.x >> 6); - pen_y = dst_y + (info->pos.y >> 6); - bm = info->bm_o; - - if ((info->effect_type == EF_KARAOKE_KO) - && (info->effect_timing <= (info->bbox.xMax >> 6))) { - // do nothing - } else { - here_tail = tail; - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[2], - 0, 1000000, tail, IMAGE_TYPE_OUTLINE); - if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) - render_overlap(render_priv, last_tail, here_tail); + pen_x = dst_x + info->pos.x; + pen_y = dst_y + info->pos.y; + bm = info->bm_o; - last_tail = here_tail; - } - info = info->next; + if ((info->effect_type == EF_KARAOKE_KO) + && (info->effect_timing <= info->first_pos_x)) { + // do nothing + } else { + tail = + render_glyph(render_priv, bm, pen_x, pen_y, info->c[2], + 0, 1000000, tail, IMAGE_TYPE_OUTLINE); } } - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if (IS_SKIP_SYMBOL(info->symbol) || !info->bm - || info->skip) + for (i = 0; i < text_info->n_bitmaps; ++i) { + CombinedBitmapInfo *info = &text_info->combined_bitmaps[i]; + if (!info->bm) continue; - while (info) { - if (!info->bm) { - info = info->next; - continue; - } + pen_x = dst_x + info->pos.x; + pen_y = dst_y + info->pos.y; + bm = info->bm; - pen_x = dst_x + (info->pos.x >> 6); - pen_y = dst_y + (info->pos.y >> 6); - bm = info->bm; - - if ((info->effect_type == EF_KARAOKE) - || (info->effect_type == EF_KARAOKE_KO)) { - if (info->effect_timing > (info->bbox.xMax >> 6)) - tail = - render_glyph(render_priv, bm, pen_x, pen_y, - info->c[0], 0, 1000000, tail, IMAGE_TYPE_CHARACTER); - else - tail = - render_glyph(render_priv, bm, pen_x, pen_y, - info->c[1], 0, 1000000, tail, IMAGE_TYPE_CHARACTER); - } else if (info->effect_type == EF_KARAOKE_KF) { + if ((info->effect_type == EF_KARAOKE) + || (info->effect_type == EF_KARAOKE_KO)) { + if (info->effect_timing > info->first_pos_x) tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], - info->c[1], info->effect_timing, tail, IMAGE_TYPE_CHARACTER); - } else + render_glyph(render_priv, bm, pen_x, pen_y, + info->c[0], 0, 1000000, tail, IMAGE_TYPE_CHARACTER); + else tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], - 0, 1000000, tail, IMAGE_TYPE_CHARACTER); - info = info->next; - } + render_glyph(render_priv, bm, pen_x, pen_y, + info->c[1], 0, 1000000, tail, IMAGE_TYPE_CHARACTER); + } else if (info->effect_type == EF_KARAOKE_KF) { + tail = + render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], + info->c[1], info->effect_timing, tail, IMAGE_TYPE_CHARACTER); + } else + tail = + render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], + 0, 1000000, tail, IMAGE_TYPE_CHARACTER); } *tail = 0; blend_vector_clip(render_priv, head); + for (ASS_Image* cur = head; cur; cur = cur->next) { + unsigned w = cur->w, + h = cur->h, + s = cur->stride; + if(w + 31 < (unsigned)cur->stride){ // Larger value? Play with this. + // Allocate new buffer and add to free list + uintptr_t alignment_offset = (w > 31) ? 31 : ((w > 15) ? 15 : 0); + unsigned ns = (w + alignment_offset) & ~alignment_offset; + uint8_t* nbuffer = malloc(ns * cur->h + alignment_offset); < |