diff --git a/sub/img_convert.c b/sub/img_convert.c index ebf9c209da..2015e49ca6 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -41,52 +41,25 @@ struct osd_conv_cache *osd_conv_cache_new(void) return talloc_zero(NULL, struct osd_conv_cache); } -bool osd_conv_blur_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs, - double gblur) +void mp_blur_rgba_sub_bitmap(struct sub_bitmap *d, double gblur) { - struct sub_bitmaps src = *imgs; - if (src.format != SUBBITMAP_RGBA) - return false; + struct mp_image *tmp1 = mp_image_alloc(IMGFMT_BGRA, d->w, d->h); + struct mp_image *tmp2 = mp_image_alloc(IMGFMT_BGRA, d->w, d->h); + if (tmp1 && tmp2) { // on OOM, skip region + struct mp_image s = {0}; + mp_image_setfmt(&s, IMGFMT_BGRA); + mp_image_set_size(&s, d->w, d->h); + s.stride[0] = d->stride; + s.planes[0] = d->bitmap; - talloc_free(c->parts); - imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts); + mp_image_copy(tmp1, &s); - for (int n = 0; n < src.num_parts; n++) { - struct sub_bitmap *d = &imgs->parts[n]; - struct sub_bitmap *s = &src.parts[n]; + mp_image_sw_blur_scale(tmp2, tmp1, gblur); - // add a transparent padding border to reduce artifacts - int pad = 5; - struct mp_image *temp = mp_image_alloc(IMGFMT_BGRA, s->w + pad * 2, - s->h + pad * 2); - if (!temp) - continue; // on OOM, skip region - memset_pic(temp->planes[0], 0, temp->w * 4, temp->h, temp->stride[0]); - uint8_t *p0 = temp->planes[0] + pad * 4 + pad * temp->stride[0]; - memcpy_pic(p0, s->bitmap, s->w * 4, s->h, temp->stride[0], s->stride); - - double sx = (double)s->dw / s->w; - double sy = (double)s->dh / s->h; - - d->x = s->x - pad * sx; - d->y = s->y - pad * sy; - d->w = d->dw = s->dw + pad * 2 * sx; - d->h = d->dh = s->dh + pad * 2 * sy; - struct mp_image *image = mp_image_alloc(IMGFMT_BGRA, d->w, d->h); - talloc_steal(c->parts, image); - if (image) { - d->stride = image->stride[0]; - d->bitmap = image->planes[0]; - - mp_image_sw_blur_scale(image, temp, gblur); - } else { - // on OOM, skip region - *d = *s; - } - - talloc_free(temp); + mp_image_copy(&s, tmp2); } - return true; + talloc_free(tmp1); + talloc_free(tmp2); } // If RGBA parts need scaling, scale them. diff --git a/sub/img_convert.h b/sub/img_convert.h index d5baadced2..a0020df497 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -5,6 +5,7 @@ struct osd_conv_cache; struct sub_bitmaps; +struct sub_bitmap; struct mp_rect; struct osd_conv_cache *osd_conv_cache_new(void); @@ -13,8 +14,7 @@ struct osd_conv_cache *osd_conv_cache_new(void); // the converted image data into c, and change imgs to point to the data. bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs); // Sub postprocessing -bool osd_conv_blur_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs, - double gblur); +void mp_blur_rgba_sub_bitmap(struct sub_bitmap *d, double gblur); bool osd_scale_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs); bool mp_sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb); diff --git a/sub/osd.c b/sub/osd.c index ea33961c9f..a0618aafd9 100644 --- a/sub/osd.c +++ b/sub/osd.c @@ -295,10 +295,6 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, bool cached = false; // do we have a copy of all the image data? - if (out_imgs->format == SUBBITMAP_RGBA && opts->sub_gauss != 0.0f) - cached |= osd_conv_blur_rgba(obj->cache[2], out_imgs, opts->sub_gauss); - - // Do this conversion last to not trigger gauss blurring for ASS if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_LIBASS) cached |= osd_conv_ass_to_rgba(obj->cache[3], out_imgs); diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index a5f093bb54..fca4b611bf 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -32,6 +32,7 @@ #include "options/options.h" #include "video/mp_image.h" #include "video/out/bitmap_packer.h" +#include "img_convert.h" #include "sd.h" #include "dec_sub.h" @@ -209,8 +210,14 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub) packer_set_size(priv->packer, avsub->num_rects); + // If we blur, we want a transparent region around the bitmap data to + // avoid "cut off" artifacts on the borders. + bool apply_blur = opts->sub_gauss != 0.0f; + int extend = apply_blur ? 5 : 0; // Assume consumers may use bilinear scaling on it (2x2 filter) - priv->packer->padding = 1; + int padding = 1 + extend; + + priv->packer->padding = padding; for (int i = 0; i < avsub->num_rects; i++) { struct AVSubtitleRect *r = avsub->rects[i]; @@ -278,11 +285,12 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub) memcpy(pal, data[1], r->nb_colors * 4); convert_pal(pal, 256, opts->sub_gray); - int padding = priv->packer->padding; - for (int y = 0; y < b->h + padding; y++) { + for (int y = -padding; y < b->h + padding; y++) { uint32_t *out = (uint32_t*)((char*)b->bitmap + y * b->stride); int start = 0; - if (y < b->h) { + for (int x = -padding; x < 0; x++) + out[x] = 0; + if (y >= 0 && y < b->h) { uint8_t *in = data[0] + y * linesize[0]; for (int x = 0; x < b->w; x++) *out++ = pal[*in++]; @@ -291,6 +299,15 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub) for (int x = start; x < b->w + padding; x++) *out++ = 0; } + + b->bitmap = (char*)b->bitmap - extend * b->stride - extend * 4; + b->x -= extend; + b->y -= extend; + b->w += extend * 2; + b->h += extend * 2; + + if (apply_blur) + mp_blur_rgba_sub_bitmap(b, opts->sub_gauss); } }