summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2022-02-27 00:01:13 +0300
committerOleg Oshmyan <chortos@inbox.lv>2022-11-16 16:05:43 +0200
commitb4deb8937aa1485106b402422791bd87fa98099e (patch)
tree7336eb693d2d910ba80c0f45277377e8e97ffffb /libass
parent194f0d298f3c9f3d1167aac694de7adc812a18a3 (diff)
downloadlibass-b4deb8937aa1485106b402422791bd87fa98099e.tar.bz2
libass-b4deb8937aa1485106b402422791bd87fa98099e.tar.xz
Support different Gaussian blur radii along the two axes
Diffstat (limited to 'libass')
-rw-r--r--libass/ass_bitmap.c6
-rw-r--r--libass/ass_bitmap.h4
-rw-r--r--libass/ass_blur.c43
-rw-r--r--libass/ass_cache_template.h3
-rw-r--r--libass/ass_render.c17
5 files changed, 41 insertions, 32 deletions
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c
index 527916f..3f62f82 100644
--- a/libass/ass_bitmap.c
+++ b/libass/ass_bitmap.c
@@ -88,14 +88,14 @@ static void be_blur_post(uint8_t *buf, intptr_t stride, intptr_t width, intptr_t
}
void ass_synth_blur(const BitmapEngine *engine, Bitmap *bm,
- int be, double blur_r2)
+ int be, double blur_r2x, double blur_r2y)
{
if (!bm->buffer)
return;
// Apply gaussian blur
- if (blur_r2 > 0.001)
- ass_gaussian_blur(engine, bm, blur_r2);
+ if (blur_r2x > 0.001 || blur_r2y > 0.001)
+ ass_gaussian_blur(engine, bm, blur_r2x, blur_r2y);
if (!be)
return;
diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h
index 90973e0..9f425cc 100644
--- a/libass/ass_bitmap.h
+++ b/libass/ass_bitmap.h
@@ -108,9 +108,9 @@ bool ass_outline_to_bitmap(struct render_context *state, Bitmap *bm,
ASS_Outline *outline1, ASS_Outline *outline2);
void ass_synth_blur(const BitmapEngine *engine, Bitmap *bm,
- int be, double blur_r2);
+ int be, double blur_r2x, double blur_r2y);
-bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2);
+bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2x, double r2y);
void ass_shift_bitmap(Bitmap *bm, int shift_x, int shift_y);
void ass_fix_outline(Bitmap *bm_g, Bitmap *bm_o);
diff --git a/libass/ass_blur.c b/libass/ass_blur.c
index efea0df..61c838e 100644
--- a/libass/ass_blur.c
+++ b/libass/ass_blur.c
@@ -529,17 +529,22 @@ static void find_best_method(BlurMethod *blur, double r2)
/**
* \brief Perform approximate gaussian blur
- * \param r2 in: desired standard deviation squared
+ * \param r2x in: desired standard deviation along X axis squared
+ * \param r2y in: desired standard deviation along Y axis squared
*/
-bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2)
+bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2x, double r2y)
{
- BlurMethod blur;
- find_best_method(&blur, r2);
+ BlurMethod blur_x, blur_y;
+ find_best_method(&blur_x, r2x);
+ if (r2y == r2x)
+ memcpy(&blur_y, &blur_x, sizeof(blur_y));
+ else find_best_method(&blur_y, r2y);
uint32_t w = bm->w, h = bm->h;
- int offset = ((2 * blur.radius + 9) << blur.level) - 5;
- uint32_t end_w = ((w + offset) & ~((1 << blur.level) - 1)) - 4;
- uint32_t end_h = ((h + offset) & ~((1 << blur.level) - 1)) - 4;
+ int offset_x = ((2 * blur_x.radius + 9) << blur_x.level) - 5;
+ int offset_y = ((2 * blur_y.radius + 9) << blur_y.level) - 5;
+ uint32_t end_w = ((w + offset_x) & ~((1 << blur_x.level) - 1)) - 4;
+ uint32_t end_h = ((h + offset_y) & ~((1 << blur_y.level) - 1)) - 4;
const int stripe_width = 1 << (engine->align_order - 1);
uint64_t size = (((uint64_t) end_w + stripe_width - 1) & ~(stripe_width - 1)) * end_h;
@@ -554,29 +559,30 @@ bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2)
int16_t *buf[2] = {tmp, tmp + size};
int index = 0;
- for (int i = 0; i < blur.level; i++) {
+ for (int i = 0; i < blur_y.level; i++) {
engine->shrink_vert(buf[index ^ 1], buf[index], w, h);
h = (h + 5) >> 1;
index ^= 1;
}
- for (int i = 0; i < blur.level; i++) {
+ for (int i = 0; i < blur_x.level; i++) {
engine->shrink_horz(buf[index ^ 1], buf[index], w, h);
w = (w + 5) >> 1;
index ^= 1;
}
- assert(blur.radius >= 4 && blur.radius <= 8);
- engine->blur_horz[blur.radius - 4](buf[index ^ 1], buf[index], w, h, blur.coeff);
- w += 2 * blur.radius;
+ assert(blur_x.radius >= 4 && blur_x.radius <= 8);
+ engine->blur_horz[blur_x.radius - 4](buf[index ^ 1], buf[index], w, h, blur_x.coeff);
+ w += 2 * blur_x.radius;
index ^= 1;
- engine->blur_vert[blur.radius - 4](buf[index ^ 1], buf[index], w, h, blur.coeff);
- h += 2 * blur.radius;
+ assert(blur_y.radius >= 4 && blur_y.radius <= 8);
+ engine->blur_vert[blur_y.radius - 4](buf[index ^ 1], buf[index], w, h, blur_y.coeff);
+ h += 2 * blur_y.radius;
index ^= 1;
- for (int i = 0; i < blur.level; i++) {
+ for (int i = 0; i < blur_x.level; i++) {
engine->expand_horz(buf[index ^ 1], buf[index], w, h);
w = 2 * w + 4;
index ^= 1;
}
- for (int i = 0; i < blur.level; i++) {
+ for (int i = 0; i < blur_y.level; i++) {
engine->expand_vert(buf[index ^ 1], buf[index], w, h);
h = 2 * h + 4;
index ^= 1;
@@ -587,9 +593,8 @@ bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2)
ass_aligned_free(tmp);
return false;
}
- offset = ((blur.radius + 4) << blur.level) - 4;
- bm->left -= offset;
- bm->top -= offset;
+ bm->left -= ((blur_x.radius + 4) << blur_x.level) - 4;
+ bm->top -= ((blur_y.radius + 4) << blur_y.level) - 4;
engine->stripe_pack(bm->buffer, bm->stride, buf[index], w, h);
ass_aligned_free(tmp);
diff --git a/libass/ass_cache_template.h b/libass/ass_cache_template.h
index fd4cdb6..8b07faa 100644
--- a/libass/ass_cache_template.h
+++ b/libass/ass_cache_template.h
@@ -104,7 +104,8 @@ END(BorderHashKey)
START(filter, filter_desc)
GENERIC(int, flags)
GENERIC(int, be)
- GENERIC(int, blur)
+ GENERIC(int, blur_x)
+ GENERIC(int, blur_y)
VECTOR(shadow)
END(FilterDesc)
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 1022989..f14a737 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -2538,14 +2538,16 @@ static void render_and_combine_glyphs(RenderContext *state,
filter->flags = flags;
filter->be = info->be;
- int32_t shadow_mask;
+ int32_t shadow_mask_x, shadow_mask_y;
double blur_scale = state->blur_scale * (2 / sqrt(log(256)));
- filter->blur = quantize_blur(info->blur * blur_scale, &shadow_mask);
+ // XXX: correct anamorphic blur radii
+ filter->blur_x = quantize_blur(info->blur * blur_scale, &shadow_mask_x);
+ filter->blur_y = quantize_blur(info->blur * blur_scale, &shadow_mask_y);
if (flags & FILTER_NONZERO_SHADOW) {
int32_t x = double_to_d6(info->shadow_x * state->border_scale_x);
int32_t y = double_to_d6(info->shadow_y * state->border_scale_y);
- filter->shadow.x = (x + (shadow_mask >> 1)) & ~shadow_mask;
- filter->shadow.y = (y + (shadow_mask >> 1)) & ~shadow_mask;
+ filter->shadow.x = (x + (shadow_mask_x >> 1)) & ~shadow_mask_x;
+ filter->shadow.y = (y + (shadow_mask_y >> 1)) & ~shadow_mask_y;
} else
filter->shadow.x = filter->shadow.y = 0;
@@ -2752,10 +2754,11 @@ size_t ass_composite_construct(void *key, void *value, void *priv)
}
int flags = k->filter.flags;
- double r2 = restore_blur(k->filter.blur);
+ double r2x = restore_blur(k->filter.blur_x);
+ double r2y = restore_blur(k->filter.blur_y);
if (!(flags & FILTER_NONZERO_BORDER) || (flags & FILTER_BORDER_STYLE_3))
- ass_synth_blur(render_priv->engine, &v->bm, k->filter.be, r2);
- ass_synth_blur(render_priv->engine, &v->bm_o, k->filter.be, r2);
+ ass_synth_blur(render_priv->engine, &v->bm, k->filter.be, r2x, r2y);
+ ass_synth_blur(render_priv->engine, &v->bm_o, k->filter.be, r2x, r2y);
if (!(flags & FILTER_FILL_IN_BORDER) && !(flags & FILTER_FILL_IN_SHADOW))
ass_fix_outline(&v->bm, &v->bm_o);