summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-08-09 22:59:36 +0200
committerwm4 <wm4@nowhere>2013-08-12 00:50:28 +0200
commit689a25003fc8098e5fdfbb2faefc0e18365d3acb (patch)
tree1735960be82a994c75549e4c5c45a88f1bc9ea8c /sub
parent8fe4790ec8945cae52ea7600312f54e1dbdf8162 (diff)
downloadmpv-689a25003fc8098e5fdfbb2faefc0e18365d3acb.tar.bz2
mpv-689a25003fc8098e5fdfbb2faefc0e18365d3acb.tar.xz
sub: support straight alpha additionally to premultiplied alpha
This is for VAAPI support. VAAPI does not support premultiplied alpha for OSD. (Normally, we prefer premultiplied, because it has better behavior on scaling.) I'm not sure whether blending in the ASS->RGBA part is correct and I didn't test it extensively.
Diffstat (limited to 'sub')
-rw-r--r--sub/img_convert.c87
-rw-r--r--sub/img_convert.h2
-rw-r--r--sub/sub.c12
-rw-r--r--sub/sub.h6
4 files changed, 91 insertions, 16 deletions
diff --git a/sub/img_convert.c b/sub/img_convert.c
index 9a5d1bf42b..3196340c7a 100644
--- a/sub/img_convert.c
+++ b/sub/img_convert.c
@@ -56,13 +56,14 @@ static void rgba_to_premultiplied_rgba(uint32_t *colors, size_t count)
}
}
-bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+static bool conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs,
+ bool straight_alpha)
{
struct sub_bitmaps src = *imgs;
if (src.format != SUBBITMAP_INDEXED)
return false;
- imgs->format = SUBBITMAP_RGBA;
+ imgs->format = straight_alpha ? SUBBITMAP_RGBA_STR : SUBBITMAP_RGBA;
talloc_free(c->parts);
imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts);
@@ -71,7 +72,8 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
struct sub_bitmap *s = &src.parts[n];
struct osd_bmp_indexed sb = *(struct osd_bmp_indexed *)s->bitmap;
- rgba_to_premultiplied_rgba(sb.palette, 256);
+ if (imgs->format == SUBBITMAP_RGBA)
+ rgba_to_premultiplied_rgba(sb.palette, 256);
*d = *s;
struct mp_image *image = mp_image_alloc(IMGFMT_BGRA, s->w, s->h);
@@ -89,11 +91,21 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
return true;
}
+bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+{
+ return conv_idx_to_rgba(c, imgs, false);
+}
+
+bool osd_conv_idx_to_rgba_str(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+{
+ return conv_idx_to_rgba(c, imgs, 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)
+ if (src.format != SUBBITMAP_RGBA && src.format != SUBBITMAP_RGBA_STR)
return false;
talloc_free(c->parts);
@@ -165,8 +177,8 @@ bool osd_conv_idx_to_gray(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
return true;
}
-static void draw_ass_rgba(unsigned char *src, int src_w, int src_h,
- int src_stride, unsigned char *dst, size_t dst_stride,
+static void draw_ass_rgba(uint8_t *src, int src_w, int src_h,
+ int src_stride, uint8_t *dst, size_t dst_stride,
int dst_x, int dst_y, uint32_t color)
{
const unsigned int r = (color >> 24) & 0xff;
@@ -198,7 +210,41 @@ static void draw_ass_rgba(unsigned char *src, int src_w, int src_h,
}
}
-bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+static void draw_ass_rgba_str(uint8_t *src, int src_w, int src_h,
+ int src_stride, uint8_t *dst, size_t dst_stride,
+ int dst_x, int dst_y, uint32_t color)
+{
+ const unsigned int r = (color >> 24) & 0xff;
+ const unsigned int g = (color >> 16) & 0xff;
+ const unsigned int b = (color >> 8) & 0xff;
+ const unsigned int a = 0xff - (color & 0xff);
+
+ dst += dst_y * dst_stride + dst_x * 4;
+
+ for (int y = 0; y < src_h; y++, dst += dst_stride, src += src_stride) {
+ uint32_t *dstrow = (uint32_t *) dst;
+ for (int x = 0; x < src_w; x++) {
+ const unsigned int v = src[x];
+ int rr = (r * v);
+ int gg = (g * v);
+ int bb = (b * v);
+ int aa = (a * v);
+ uint32_t dstpix = dstrow[x];
+ unsigned int dstb = dstpix & 0xFF;
+ unsigned int dstg = (dstpix >> 8) & 0xFF;
+ unsigned int dstr = (dstpix >> 16) & 0xFF;
+ unsigned int dsta = (dstpix >> 24) & 0xFF;
+ dstb = (bb + dstb * (255 - aa)) / 255;
+ dstg = (gg + dstg * (255 - aa)) / 255;
+ dstr = (rr + dstr * (255 - aa)) / 255;
+ dsta = (aa + dsta * (255 - aa)) / 255;
+ dstrow[x] = dstb | (dstg << 8) | (dstr << 16) | (dsta << 24);
+ }
+ }
+}
+
+static bool conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs,
+ bool straight_alpha)
{
struct sub_bitmaps src = *imgs;
if (src.format != SUBBITMAP_LIBASS)
@@ -208,7 +254,7 @@ bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
struct mp_rect bb_list[MP_SUB_BB_LIST_MAX];
int num_bb = mp_get_sub_bb_list(&src, bb_list, MP_SUB_BB_LIST_MAX);
- imgs->format = SUBBITMAP_RGBA;
+ imgs->format = straight_alpha ? SUBBITMAP_RGBA_STR : SUBBITMAP_RGBA;
imgs->parts = c->part;
imgs->num_parts = num_bb;
@@ -251,16 +297,33 @@ bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
s->y > bb.y1 || s->y + s->h < bb.y0)
continue;
- draw_ass_rgba(s->bitmap, s->w, s->h, s->stride,
- bmp->bitmap, bmp->stride,
- s->x - bb.x0, s->y - bb.y0,
- s->libass.color);
+ if (imgs->format == SUBBITMAP_RGBA_STR) {
+ draw_ass_rgba(s->bitmap, s->w, s->h, s->stride,
+ bmp->bitmap, bmp->stride,
+ s->x - bb.x0, s->y - bb.y0,
+ s->libass.color);
+ } else {
+ draw_ass_rgba_str(s->bitmap, s->w, s->h, s->stride,
+ bmp->bitmap, bmp->stride,
+ s->x - bb.x0, s->y - bb.y0,
+ s->libass.color);
+ }
}
}
return true;
}
+bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+{
+ return conv_ass_to_rgba(c, imgs, false);
+}
+
+bool osd_conv_ass_to_rgba_str(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+{
+ return conv_ass_to_rgba(c, imgs, true);
+}
+
bool mp_sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb)
{
struct mp_rect bb = {INT_MAX, INT_MAX, INT_MIN, INT_MIN};
diff --git a/sub/img_convert.h b/sub/img_convert.h
index 383a2c8003..3b739a4a38 100644
--- a/sub/img_convert.h
+++ b/sub/img_convert.h
@@ -12,7 +12,9 @@ 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_idx_to_rgba_str(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
+bool osd_conv_ass_to_rgba_str(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);
diff --git a/sub/sub.c b/sub/sub.c
index a5ff9e2593..0e297e3bf8 100644
--- a/sub/sub.c
+++ b/sub/sub.c
@@ -202,13 +202,23 @@ 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[1], out_imgs);
- if (out_imgs->format == SUBBITMAP_RGBA && opts->sub_gauss != 0.0f)
+ if (formats[SUBBITMAP_RGBA_STR] && out_imgs->format == SUBBITMAP_INDEXED)
+ cached |= osd_conv_idx_to_rgba_str(obj->cache[1], out_imgs);
+
+ if ((out_imgs->format == SUBBITMAP_RGBA ||
+ out_imgs->format == SUBBITMAP_RGBA_STR)
+ && 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);
+ if (formats[SUBBITMAP_RGBA_STR] && out_imgs->format == SUBBITMAP_LIBASS)
+ cached |= osd_conv_ass_to_rgba_str(obj->cache[3], out_imgs);
+
if (cached)
obj->cached = *out_imgs;
}
diff --git a/sub/sub.h b/sub/sub.h
index 3cb140565c..3463022c88 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -25,11 +25,12 @@
#include "mpvcore/m_option.h"
-// NOTE: VOs must support at least SUBBITMAP_RGBA.
+// NOTE: VOs must support at least SUBBITMAP_RGBA or SUBBITMAP_RGBA_STR.
enum sub_bitmap_format {
SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0
SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color)
SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), scaled, premultiplied alpha
+ SUBBITMAP_RGBA_STR, // like RGBA, but straight (not premultiplied) alpha
SUBBITMAP_INDEXED, // scaled, bitmap points to osd_bmp_indexed
SUBBITMAP_COUNT
@@ -38,8 +39,7 @@ enum sub_bitmap_format {
// For SUBBITMAP_INDEXED
struct osd_bmp_indexed {
uint8_t *bitmap;
- // Each entry is like a pixel in SUBBITMAP_RGBA format, but using straight
- // alpha.
+ // Each entry is like a pixel in SUBBITMAP_RGBA_STR format.
uint32_t palette[256];
};