sub: reimplement -spugauss as --sub-gauss

Apparently the -spugauss option was popular. The code originally
implementing this is gone (scaler stuff in spudec.c). Reimplement it
using libswscale to scale and blur image subtitles if the --sub-gauss
option is set.

The code does some rather lazy padding to allow the blur to spread
pixels past the original image bounding box. (This problem exists with
normal bilinear scaling too, but is barely noticable.)

Technically, this doesn't just blur subtitles, but anything RGBA (or
indexed) that enters the OSD rendering path. But only image subtitles
produce these OSD formats currently, so no explicit check is done to
prevent blurring in other cases.
This commit is contained in:
wm4 2012-11-25 00:06:16 +01:00
parent 2bd7f980ac
commit 24bfa82a91
9 changed files with 97 additions and 7 deletions

View File

@ -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

View File

@ -1882,6 +1882,13 @@
*NOTE*: <rate> > 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.

View File

@ -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),

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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