summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author11rcombs <rodger.combs@gmail.com>2014-01-25 19:06:12 -0600
committer11rcombs <rodger.combs@gmail.com>2014-01-25 19:09:15 -0600
commit5dd56af2f97419ce5a72d1dab2e9c19b34c1dd57 (patch)
tree1997f519ae3d5f75a76a3cee3dd95034e513210a
parentfa3b6fa3ee1de42232f0513539af2464a3c9203a (diff)
downloadlibass-5dd56af2f97419ce5a72d1dab2e9c19b34c1dd57.tar.bz2
libass-5dd56af2f97419ce5a72d1dab2e9c19b34c1dd57.tar.xz
Combine bitmaps before applying blur and shadow
-rw-r--r--libass/ass_bitmap.c225
-rw-r--r--libass/ass_bitmap.h43
-rw-r--r--libass/ass_cache.c22
-rw-r--r--libass/ass_cache.h6
-rw-r--r--libass/ass_cache_template.h41
-rw-r--r--libass/ass_parse.c1
-rw-r--r--libass/ass_render.c745
-rw-r--r--libass/ass_render.h76
-rw-r--r--libass/ass_shaper.c29
-rw-r--r--libass/ass_utils.c32
-rw-r--r--libass/ass_utils.h1
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);
+ if (!nbuffer) continue;
+ free_list_add(render_priv, nbuffer);
+ nbuffer = (unsigned char*)
+ (((uintptr_t)nbuffer + alignment_offset) & ~alignment_offset);
+