diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst index 2f012f7b1b..b46691c888 100644 --- a/DOCS/man/en/changes.rst +++ b/DOCS/man/en/changes.rst @@ -110,6 +110,7 @@ Command line switches --cursor-autohide-delay --cursor-autohide -sub-fuzziness --autosub-match -subfont-text-scale --sub-scale + -spugauss --sub-gauss =================================== =================================== input.conf and slave commands diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index e533618583..f0d9ddb57b 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -1882,6 +1882,13 @@ *NOTE*: > movie fps speeds the subtitles up for frame-based subtitle files and slows them down for time-based ones. +--sub-gauss=<0.0-3.0> + Apply gaussian blur to image subtitles (default: 0). This can help making + pixelated DVD/Vobsubs look nicer. A value other than 0 also switches to + software subtitle scaling. Might be slow. + + *NOTE*: never applied to text subtitles. + --sub-pos=<0-100> Specify the position of subtitles on the screen. The value is the vertical position of the subtitle in % of the screen height. diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index d9dcb56e6a..ded7245f83 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -506,6 +506,7 @@ const m_option_t common_opts[] = { {"autosub-match", &sub_match_fuzziness, CONF_TYPE_CHOICE, 0, M_CHOICES(({"exact", 0}, {"fuzzy", 1}, {"all", 2}))}, {"sub-pos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, + OPT_FLOATRANGE("sub-gauss", sub_gauss, 0, 0.0, 3.0), OPT_MAKE_FLAGS("ass", ass_enabled, 0), OPT_FLOATRANGE("sub-scale", sub_scale, 0, 0, 100), OPT_FLOATRANGE("ass-line-spacing", ass_line_spacing, 0, -1000, 1000), diff --git a/core/options.h b/core/options.h index 28bdd70e3c..58d6a64e70 100644 --- a/core/options.h +++ b/core/options.h @@ -113,6 +113,7 @@ typedef struct MPOpts { int sub_auto; struct osd_style_opts *osd_style; float sub_scale; + float sub_gauss; int ass_enabled; float ass_line_spacing; int ass_top_margin; diff --git a/sub/img_convert.c b/sub/img_convert.c index e2eded24c3..274a83d833 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -28,6 +28,7 @@ #include "video/img_format.h" #include "video/mp_image.h" #include "video/sws_utils.h" +#include "video/memcpy_pic.h" struct osd_conv_cache { struct sub_bitmap part; @@ -86,3 +87,44 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) } return true; } + +bool osd_conv_blur_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs, + double gblur) +{ + struct sub_bitmaps src = *imgs; + if (src.format != SUBBITMAP_RGBA) + return false; + + talloc_free(c->parts); + imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts); + + for (int n = 0; n < src.num_parts; n++) { + struct sub_bitmap *d = &imgs->parts[n]; + struct sub_bitmap *s = &src.parts[n]; + + // add a transparent padding border to reduce artifacts + int pad = 5; + struct mp_image *temp = alloc_mpi(s->w + pad * 2, s->h + pad * 2, + IMGFMT_BGRA); + 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 = alloc_mpi(d->w, d->h, IMGFMT_BGRA); + talloc_steal(c->parts, image); + d->stride = image->stride[0]; + d->bitmap = image->planes[0]; + + mp_image_sw_blur_scale(image, temp, gblur); + + talloc_free(temp); + } + return true; +} diff --git a/sub/img_convert.h b/sub/img_convert.h index c947c44f01..eab543051c 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -11,5 +11,7 @@ struct osd_conv_cache *osd_conv_cache_new(void); // These functions convert from one OSD format to another. On success, they copy // the converted image data into c, and change imgs to point to the data. bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs); +bool osd_conv_blur_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs, + double gblur); #endif diff --git a/sub/sub.c b/sub/sub.c index dd8c887b4c..66ee6ea42c 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -172,6 +172,8 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, const bool formats[SUBBITMAP_COUNT], struct sub_bitmaps *out_imgs) { + struct MPOpts *opts = osd->opts; + *out_imgs = (struct sub_bitmaps) {0}; if (!osd_res_equals(res, obj->vo_res)) @@ -222,6 +224,9 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_INDEXED) cached |= osd_conv_idx_to_rgba(obj->cache[0], out_imgs); + if (out_imgs->format == SUBBITMAP_RGBA && opts->sub_gauss != 0.0f) + cached |= osd_conv_blur_rgba(obj->cache[1], out_imgs, opts->sub_gauss); + if (cached) obj->cached = *out_imgs; } diff --git a/video/sws_utils.c b/video/sws_utils.c index 663a0e282a..7a1385cfac 100644 --- a/video/sws_utils.c +++ b/video/sws_utils.c @@ -171,12 +171,10 @@ static void to_gbrp(struct mp_image *dst, struct mp_image *src, talloc_free(temp); } -void mp_image_swscale(struct mp_image *dst, struct mp_image *src, - int my_sws_flags) -{ - if (dst->imgfmt == IMGFMT_GBRP) - return to_gbrp(dst, src, my_sws_flags); +static void mp_sws_set_conv(struct SwsContext *sws, struct mp_image *dst, + struct mp_image *src, int my_sws_flags) +{ enum PixelFormat s_fmt = imgfmt2pixfmt(src->imgfmt); if (src->imgfmt == IMGFMT_RGB8 || src->imgfmt == IMGFMT_BGR8) s_fmt = PIX_FMT_PAL8; @@ -195,8 +193,6 @@ void mp_image_swscale(struct mp_image *dst, struct mp_image *src, s_range = s_range && s_yuv; d_range = d_range && d_yuv; - struct SwsContext *sws = sws_alloc_context(); - av_opt_set_int(sws, "sws_flags", my_sws_flags, 0); av_opt_set_int(sws, "srcw", src->w, 0); @@ -210,6 +206,16 @@ void mp_image_swscale(struct mp_image *dst, struct mp_image *src, sws_setColorspaceDetails(sws, sws_getCoefficients(s_csp), s_range, sws_getCoefficients(d_csp), d_range, 0, 1 << 16, 1 << 16); +} + +void mp_image_swscale(struct mp_image *dst, struct mp_image *src, + int my_sws_flags) +{ + if (dst->imgfmt == IMGFMT_GBRP) + return to_gbrp(dst, src, my_sws_flags); + + struct SwsContext *sws = sws_alloc_context(); + mp_sws_set_conv(sws, dst, src, my_sws_flags); int res = sws_init_context(sws, NULL, NULL); assert(res >= 0); @@ -219,4 +225,26 @@ void mp_image_swscale(struct mp_image *dst, struct mp_image *src, sws_freeContext(sws); } +void mp_image_sw_blur_scale(struct mp_image *dst, struct mp_image *src, + float gblur) +{ + struct SwsContext *sws = sws_alloc_context(); + + int flags = SWS_LANCZOS | SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | + SWS_ACCURATE_RND | SWS_BITEXACT; + + mp_sws_set_conv(sws, dst, src, flags); + + SwsFilter *src_filter = sws_getDefaultFilter(gblur, gblur, 0, 0, 0, 0, 0); + + int res = sws_init_context(sws, src_filter, NULL); + assert(res >= 0); + + sws_scale(sws, (const uint8_t *const *) src->planes, src->stride, + 0, src->h, dst->planes, dst->stride); + sws_freeContext(sws); + + sws_freeFilter(src_filter); +} + // vim: ts=4 sw=4 et tw=80 diff --git a/video/sws_utils.h b/video/sws_utils.h index d9e22d763b..22d16edefb 100644 --- a/video/sws_utils.h +++ b/video/sws_utils.h @@ -23,6 +23,9 @@ bool mp_sws_supported_format(int imgfmt); void mp_image_swscale(struct mp_image *dst, struct mp_image *src, int my_sws_flags); +void mp_image_sw_blur_scale(struct mp_image *dst, struct mp_image *src, + float gblur); + #endif /* MP_SWS_UTILS_H */ // vim: ts=4 sw=4 et tw=80