summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Oshmyan <chortos@inbox.lv>2014-03-13 03:15:18 +0000
committerOleg Oshmyan <chortos@inbox.lv>2015-02-10 04:42:35 +0200
commit0f367cc55086e46070e4c4cda9a1800176bed3c0 (patch)
treefac7afe0b15febf7ee5d30e8b5c44ba30ceeadbb
parent461ba65d18957aa20c686c22d4f73d930c602146 (diff)
downloadlibass-0f367cc55086e46070e4c4cda9a1800176bed3c0.tar.bz2
libass-0f367cc55086e46070e4c4cda9a1800176bed3c0.tar.xz
Calculate \be using [0..64] value range (like VSFilter)
To avoid banding in the output, the full [0..255] value range is restored before the last \be pass, which then uses the full range and hides the bands by virtue of being a blur. With this, our \be finally closely matches VSFilter's. The only visible difference (other than the lack of banding) is in clipping: we add proper padding and output the whole blurred image, while VSFilter does not add any padding and hence clips the blurred image too early.
-rw-r--r--libass/ass_bitmap.c63
-rw-r--r--libass/ass_bitmap.h4
2 files changed, 58 insertions, 9 deletions
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c
index 97fb26b..5f0991d 100644
--- a/libass/ass_bitmap.c
+++ b/libass/ass_bitmap.c
@@ -170,13 +170,23 @@ void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be,
unsigned stride = bm_o->stride;
unsigned char *buf = bm_o->buffer;
if(w && h){
- while(passes--){
- memset(tmp, 0, stride * 2);
- if(w < 16){
- be_blur_c(buf, w, h, stride, tmp);
- }else{
- priv_blur->be_blur_func(buf, w, h, stride, tmp);
+ if(passes > 1){
+ be_blur_pre(buf, w, h, stride);
+ while(--passes){
+ memset(tmp, 0, stride * 2);
+ if(w < 16){
+ be_blur_c(buf, w, h, stride, tmp);
+ }else{
+ priv_blur->be_blur_func(buf, w, h, stride, tmp);
+ }
}
+ be_blur_post(buf, w, h, stride);
+ }
+ memset(tmp, 0, stride * 2);
+ if(w < 16){
+ be_blur_c(buf, w, h, stride, tmp);
+ }else{
+ priv_blur->be_blur_func(buf, w, h, stride, tmp);
}
}
}
@@ -187,10 +197,16 @@ void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be,
unsigned stride = bm_g->stride;
unsigned char *buf = bm_g->buffer;
if(w && h){
- while(passes--){
- memset(tmp, 0, stride * 2);
- priv_blur->be_blur_func(buf, w, h, stride, tmp);
+ if(passes > 1){
+ be_blur_pre(buf, w, h, stride);
+ while(--passes){
+ memset(tmp, 0, stride * 2);
+ priv_blur->be_blur_func(buf, w, h, stride, tmp);
+ }
+ be_blur_post(buf, w, h, stride);
}
+ memset(tmp, 0, stride * 2);
+ priv_blur->be_blur_func(buf, w, h, stride, tmp);
}
}
}
@@ -704,6 +720,35 @@ void be_blur_c(uint8_t *buf, intptr_t w,
}
}
+void be_blur_pre(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
+{
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < w; ++x)
+ {
+ // This is equivalent to (value * 64 + 127) / 255 for all
+ // values from 0 to 256 inclusive. Assist vectorizing
+ // compilers by noting that all temporaries fit in 8 bits.
+ buf[y * stride + x] =
+ (uint8_t) ((buf[y * stride + x] >> 1) + 1) >> 1;
+ }
+ }
+}
+
+void be_blur_post(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
+{
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < w; ++x)
+ {
+ // This is equivalent to (value * 255 + 32) / 64 for all values
+ // from 0 to 96 inclusive, and we only care about 0 to 64.
+ uint8_t value = buf[y * stride + x];
+ buf[y * stride + x] = (value << 2) - (value > 32);
+ }
+ }
+}
+
int outline_to_bitmap2(ASS_Renderer *render_priv,
ASS_Outline *outline, ASS_Outline *border,
Bitmap **bm_g, Bitmap **bm_o)
diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h
index 9a36a3e..5014f51 100644
--- a/libass/ass_bitmap.h
+++ b/libass/ass_bitmap.h
@@ -72,6 +72,10 @@ void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2,
void be_blur_c(uint8_t *buf, intptr_t w,
intptr_t h, intptr_t stride,
uint16_t *tmp);
+void be_blur_pre(uint8_t *buf, intptr_t w,
+ intptr_t h, intptr_t stride);
+void be_blur_post(uint8_t *buf, intptr_t w,
+ intptr_t h, intptr_t stride);
void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
uint8_t *src, intptr_t src_stride,
intptr_t height, intptr_t width);