1
mirror of https://github.com/mpv-player/mpv synced 2024-09-09 01:16:56 +02:00

sub: never decode subs to old OSD format

Instead, sd_lavc.c and spudec.c (the two image sub decoders) always
output indexed/paletted images. For this purpose, add SUBBITMAP_INDEXED,
and convert the subs to RGBA in img_convert.c instead. If a VO is used
that supports the old OSD format only, the indexed bitmaps are converted
to the old OSD format by abusing spudec.c in a similar way sd_lavc.c
used to do.

The main reason why spudec.c is used is because the images must not only
be converted to the old format, but also properly scaled, cropped, and
aligned (the asm code in libvo/osd.c requires this alignment).

Remove support for the old format (packed variant) from the OpenGL VOs.
(The packed formats were how the actual OSD format was handled in some
GPU-driven VOs for a while.)

Remove all conversions from old to new formats. Now all subtitle
decoders and OSD renderers produce the new formats only.

Add an evil hack to convert the new format (scaled+indexed bitmaps) to
the old format. It creates a new spudec instance to convert images to
grayscale and to scale them. This is temporary for VOs which don't
support new OSD formats yet (vo_xv, vo_x11, vo_lavc).
This commit is contained in:
wm4 2012-10-04 17:16:47 +02:00
parent cc05910f16
commit 3ad918bbc6
12 changed files with 187 additions and 181 deletions

View File

@ -33,20 +33,16 @@ struct osd_fmt_entry {
static const int blend_factors[SUBBITMAP_COUNT][2] = {
[SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[SUBBITMAP_RGBA] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[SUBBITMAP_OLD] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
};
static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = {
[SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE},
[SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE},
[SUBBITMAP_OLD] = {GL_RG, GL_RG, GL_UNSIGNED_BYTE},
};
static const struct osd_fmt_entry osd_to_gl_legacy_formats[SUBBITMAP_COUNT] = {
[SUBBITMAP_LIBASS] = {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE},
[SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE},
[SUBBITMAP_OLD] =
{GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE},
};
struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy)

View File

@ -252,7 +252,6 @@ static const struct fmt_entry mp_to_gl_formats[] = {
static const char *osd_shaders[SUBBITMAP_COUNT] = {
[SUBBITMAP_LIBASS] = "frag_osd_libass",
[SUBBITMAP_RGBA] = "frag_osd_rgba",
[SUBBITMAP_OLD] = "frag_osd_old",
};

View File

@ -66,17 +66,6 @@ void main() {
out_color = texture(texture1, texcoord);
}
#!section frag_osd_old
uniform sampler2D texture1;
uniform vec4 osd_color;
in vec2 texcoord;
out vec4 out_color;
void main() {
out_color = texture(texture1, texcoord).rrrg * osd_color;
}
#!section frag_video
uniform sampler2D texture1;
uniform sampler2D texture2;

View File

@ -63,9 +63,6 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_render_params *params,
{
struct MPOpts *opts = osd->opts;
// temporary hack
osd->support_rgba = params->support_rgba;
*res = (struct sub_bitmaps) {0};
if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) {
/* Change ID in case we just switched from visible subtitles

View File

@ -15,8 +15,6 @@ struct sub_render_params {
struct mp_eosd_res dim;
double normal_scale;
double vsfilter_scale;
bool support_rgba;
};
static inline bool is_text_sub(int type)

View File

@ -25,14 +25,16 @@
#include "img_convert.h"
#include "sub.h"
#include "spudec.h"
struct osd_conv_cache {
struct sub_bitmap part;
struct sub_bitmap *parts;
// for osd_conv_cache_alloc_old_p() (SUBBITMAP_PLANAR)
int allocated, stride;
struct old_osd_planar bmp;
// for osd_conv_cache_alloc_bmp() (various other formats)
unsigned char *packed;
// for osd_conv_idx_to_old_p(), a spudec.c handle
void *spudec;
};
static int osd_conv_cache_destroy(void *p)
@ -40,6 +42,8 @@ static int osd_conv_cache_destroy(void *p)
struct osd_conv_cache *c = p;
av_free(c->bmp.bitmap);
av_free(c->bmp.alpha);
if (c->spudec)
spudec_free(c->spudec);
return 0;
}
@ -73,21 +77,6 @@ static void osd_conv_cache_alloc_old_p(struct osd_conv_cache *c, int w, int h)
};
}
static void osd_conv_cache_alloc_bmp(struct osd_conv_cache *c, int w, int h,
int bpp)
{
size_t size = talloc_get_size(c->packed);
size_t new_size = w * bpp * h;
if (new_size > size)
c->packed = talloc_realloc(c, c->packed, unsigned char, new_size);
c->part = (struct sub_bitmap) {
.bitmap = c->packed,
.stride = w * bpp,
.w = w, .h = h,
.dw = w, .dh = h,
};
}
static void draw_alpha_ass_to_old(unsigned char *src, int src_w, int src_h,
int src_stride, unsigned char *dst_a,
unsigned char *dst_i, size_t dst_stride,
@ -177,80 +166,99 @@ bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
return true;
}
// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_RGBA
bool osd_conv_old_p_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
{
struct sub_bitmaps src = *imgs;
if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1)
if (src.format != SUBBITMAP_INDEXED)
return false;
imgs->format = SUBBITMAP_RGBA;
imgs->num_parts = 0;
imgs->parts = NULL;
talloc_free(c->parts);
imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts);
if (src.num_parts == 0)
return true;
for (int n = 0; n < src.num_parts; n++) {
struct sub_bitmap *d = &imgs->parts[n];
struct sub_bitmap *s = &src.parts[n];
struct osd_bmp_indexed *sb = s->bitmap;
struct sub_bitmap *s = &src.parts[0];
struct old_osd_planar *p = s->bitmap;
*d = *s;
d->stride = s->w * 4;
d->bitmap = talloc_size(c->parts, s->h * d->stride);
osd_conv_cache_alloc_bmp(c, s->w, s->h, 4);
for (int y = 0; y < s->h; y++) {
unsigned char *y_src = p->bitmap + s->stride * y;
unsigned char *y_srca = p->alpha + s->stride * y;
unsigned char *cur = c->packed + y * s->w * 4;
for (int x = 0; x < s->w; x++) {
// This is incorrect, as input is premultiplied alpha, but output
// has to be non-premultiplied. However, this code is for
// compatibility with spudec.c only, and DVD subtitles have
// binary transparency only - the rendered result will be the same.
cur[x*4+0] = cur[x*4+1] = cur[x*4+2] = y_src[x];
cur[x*4+3] = -y_srca[x];
uint32_t *palette = sb->palette;
uint32_t *outbmp = d->bitmap;
for (int y = 0; y < s->h; y++) {
uint8_t *inbmp = sb->bitmap + y * s->stride;
for (int x = 0; x < s->w; x++)
*outbmp++ = palette[*inbmp++];
}
}
c->part.x = s->x;
c->part.y = s->y;
imgs->parts = &c->part;
imgs->num_parts = 1;
return true;
}
// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_OLD
bool osd_conv_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
bool osd_conv_idx_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs,
int screen_w, int screen_h)
{
struct sub_bitmaps src = *imgs;
if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1)
if (src.format != SUBBITMAP_INDEXED)
return false;
imgs->format = SUBBITMAP_OLD;
imgs->format = SUBBITMAP_OLD_PLANAR;
imgs->num_parts = 0;
imgs->parts = NULL;
if (src.num_parts == 0)
return true;
struct sub_bitmap *s = &src.parts[0];
struct old_osd_planar *p = s->bitmap;
// assume they are all evenly scaled (and size 0 is not possible)
// could put more effort into it to reduce rounding errors, but it doesn't
// make much sense anyway
struct sub_bitmap *s0 = &src.parts[0];
double scale_x = (double)s0->w / s0->dw;
double scale_y = (double)s0->h / s0->dh;
double scale = FFMIN(scale_x, scale_y);
osd_conv_cache_alloc_bmp(c, s->w, s->h, 2);
int xmin, ymin, xmax, ymax;
for (int y = 0; y < s->h; y++) {
unsigned char *y_src = p->bitmap + s->stride * y;
unsigned char *y_srca = p->alpha + s->stride * y;
unsigned char *cur = c->packed + y * s->w * 2;
for (int x = 0; x < s->w; x++) {
cur[x*2+0] = y_src[x];
cur[x*2+1] = -y_srca[x];
}
xmin = ymin = INT_MAX;
xmax = ymax = INT_MIN;
for (int n = 0; n < src.num_parts; n++) {
struct sub_bitmap *s = &src.parts[n];
int sx = s->x * scale;
int sy = s->y * scale;
xmin = FFMIN(xmin, sx);
ymin = FFMIN(ymin, sy);
xmax = FFMAX(xmax, sx + s->w);
ymax = FFMAX(ymax, sy + s->h);
}
c->part.x = s->x;
c->part.y = s->y;
int w = xmax - xmin;
int h = ymax - ymin;
imgs->parts = &c->part;
imgs->num_parts = 1;
struct spu_packet_t *packet = spudec_packet_create(xmin, ymin, w, h);
if (!packet)
return false;
spudec_packet_clear(packet);
for (int n = 0; n < src.num_parts; n++) {
struct sub_bitmap *s = &src.parts[n];
struct osd_bmp_indexed *sb = s->bitmap;
int sx = s->x * scale;
int sy = s->y * scale;
assert(sx >= xmin);
assert(sy >= ymin);
assert(sx - xmin + s->w <= w);
assert(sy - ymin + s->h <= h);
// assumes sub-images are not overlapping
spudec_packet_fill(packet, sb->bitmap, s->stride, sb->palette,
sx - xmin, sy - ymin, s->w, s->h);
}
if (!c->spudec)
c->spudec = spudec_new_scaled(NULL, 0, 0, NULL, 0);
spudec_packet_send(c->spudec, packet, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
spudec_set_res(c->spudec, screen_w * scale, screen_h * scale);
spudec_heartbeat(c->spudec, 0);
spudec_get_bitmap(c->spudec, screen_w, screen_h, imgs);
imgs->render_index = src.render_index;
imgs->bitmap_id = src.bitmap_id;
imgs->bitmap_pos_id = src.bitmap_pos_id;
return true;
}

View File

@ -10,8 +10,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_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
bool osd_conv_old_p_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
bool osd_conv_idx_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs,
int screen_w, int screen_h);
#endif

View File

@ -16,6 +16,7 @@
*/
#include <stdlib.h>
#include <assert.h>
#include <libavcodec/avcodec.h>
@ -23,61 +24,21 @@
#include "mp_msg.h"
#include "libmpdemux/stheader.h"
#include "sd.h"
#include "spudec.h"
// Current code still pushes subs directly to global spudec
#include "dec_sub.h"
#include "sub.h"
struct sd_lavc_priv {
AVCodecContext *avctx;
AVSubtitle sub;
bool have_sub;
int count;
struct sub_bitmap *inbitmaps;
struct sub_bitmap *outbitmaps;
struct osd_bmp_indexed *imgs;
bool bitmaps_changed;
double endpts;
};
static void old_avsub_to_spudec(AVSubtitleRect **rects, int num_rects,
double pts, double endpts)
{
int i, xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN;
struct spu_packet_t *packet;
if (num_rects == 1) {
spudec_set_paletted(vo_spudec,
rects[0]->pict.data[0],
rects[0]->pict.linesize[0],
rects[0]->pict.data[1],
rects[0]->x,
rects[0]->y,
rects[0]->w,
rects[0]->h,
pts,
endpts);
return;
}
for (i = 0; i < num_rects; i++) {
xmin = FFMIN(xmin, rects[i]->x);
ymin = FFMIN(ymin, rects[i]->y);
xmax = FFMAX(xmax, rects[i]->x + rects[i]->w);
ymax = FFMAX(ymax, rects[i]->y + rects[i]->h);
}
packet = spudec_packet_create(xmin, ymin, xmax - xmin, ymax - ymin);
if (!packet)
return;
spudec_packet_clear(packet);
for (i = 0; i < num_rects; i++)
spudec_packet_fill(packet,
rects[i]->pict.data[0],
rects[i]->pict.linesize[0],
rects[i]->pict.data[1],
rects[i]->x - xmin,
rects[i]->y - ymin,
rects[i]->w,
rects[i]->h);
spudec_packet_send(vo_spudec, packet, pts, endpts);
}
static void guess_resolution(char type, int *w, int *h)
{
if (type == 'v') {
@ -143,8 +104,13 @@ static void clear(struct sd_lavc_priv *priv)
talloc_free(priv->inbitmaps);
talloc_free(priv->outbitmaps);
priv->inbitmaps = priv->outbitmaps = NULL;
talloc_free(priv->imgs);
priv->imgs = NULL;
priv->bitmaps_changed = true;
priv->endpts = MP_NOPTS_VALUE;
if (priv->have_sub)
avsubtitle_free(&priv->sub);
priv->have_sub = false;
}
static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
@ -166,6 +132,8 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
if (res < 0 || !got_sub)
return;
priv->sub = sub;
priv->have_sub = true;
if (pts != MP_NOPTS_VALUE) {
if (sub.end_display_time > sub.start_display_time)
duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
@ -174,39 +142,27 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
double endpts = MP_NOPTS_VALUE;
if (pts != MP_NOPTS_VALUE && duration >= 0)
endpts = pts + duration;
if (vo_spudec && sub.num_rects == 0)
spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, pts, endpts);
if (sub.num_rects > 0) {
switch (sub.rects[0]->type) {
case SUBTITLE_BITMAP:
if (!osd->support_rgba) {
if (!vo_spudec)
vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height,
NULL, 0);
old_avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts);
vo_osd_changed(OSDTYPE_SPU);
break;
}
priv->inbitmaps = talloc_array(priv, struct sub_bitmap,
sub.num_rects);
priv->imgs = talloc_array(priv, struct osd_bmp_indexed,
sub.num_rects);
for (int i = 0; i < sub.num_rects; i++) {
struct AVSubtitleRect *r = sub.rects[i];
struct sub_bitmap *b = &priv->inbitmaps[i];
uint32_t *outbmp = talloc_size(priv->inbitmaps,
r->w * r->h * 4);
b->bitmap = outbmp;
b->stride = r->w * 4;
struct osd_bmp_indexed *img = &priv->imgs[i];
img->bitmap = r->pict.data[0];
assert(r->nb_colors > 0);
assert(r->nb_colors * 4 <= sizeof(img->palette));
memcpy(img->palette, r->pict.data[1], r->nb_colors * 4);
b->bitmap = img;
b->stride = r->pict.linesize[0];
b->w = r->w;
b->h = r->h;
b->x = r->x;
b->y = r->y;
uint8_t *inbmp = r->pict.data[0];
uint32_t *palette = (uint32_t *) r->pict.data[1];
for (int y = 0; y < r->h; y++) {
for (int x = 0; x < r->w; x++)
*outbmp++ = palette[*inbmp++];
inbmp += r->pict.linesize[0] - r->w;
};
}
priv->count = sub.num_rects;
priv->endpts = endpts;
@ -217,7 +173,6 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
break;
}
}
avsubtitle_free(&sub);
}
static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
@ -229,8 +184,6 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
if (priv->endpts != MP_NOPTS_VALUE && (params->pts >= priv->endpts ||
params->pts < priv->endpts - 300))
clear(priv);
if (!params->support_rgba)
return;
if (priv->bitmaps_changed && priv->count > 0)
priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps,
talloc_get_size(priv->inbitmaps));
@ -257,7 +210,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
else if (pos_changed)
res->bitmap_pos_id++;
priv->bitmaps_changed = false;
res->format = SUBBITMAP_RGBA;
res->format = SUBBITMAP_INDEXED;
res->scaled = xscale != 1 || yscale != 1;
}
@ -274,6 +227,7 @@ static void uninit(struct sh_sub *sh)
{
struct sd_lavc_priv *priv = sh->context;
clear(priv);
avcodec_close(priv->avctx);
av_free(priv->avctx);
talloc_free(priv);

View File

@ -127,6 +127,7 @@ typedef struct {
struct sub_bitmap borrowed_sub_part;
struct old_osd_planar borrowed_sub_image;
struct osd_bmp_indexed borrowed_bmp;
} spudec_handle_t;
static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
@ -760,6 +761,50 @@ void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res)
}
}
void spudec_get_indexed(void *this, struct mp_eosd_res *dim,
struct sub_bitmaps *res)
{
spudec_handle_t *spu = this;
*res = (struct sub_bitmaps) { .format = SUBBITMAP_INDEXED };
struct sub_bitmap *part = &spu->borrowed_sub_part;
res->parts = part;
if (spudec_visible(spu)) {
struct osd_bmp_indexed *bmp = &spu->borrowed_bmp;
part->bitmap = bmp;
bmp->bitmap = spu->pal_image;
part->stride = spu->pal_width;
part->w = spu->pal_width;
part->h = spu->pal_height;
double xscale = (double) (dim->w - dim->ml - dim->mr) / spu->orig_frame_width;
double yscale = (double) (dim->h - dim->mt - dim->mb) / spu->orig_frame_height;
part->x = spu->pal_start_col * xscale + dim->ml;
part->y = spu->pal_start_row * yscale + dim->mt;
part->dw = part->w * xscale;
part->dh = part->h * yscale;
res->num_parts = 1;
memset(bmp->palette, 0, sizeof(bmp->palette));
for (int i = 0; i < 4; ++i) {
int alpha = spu->alpha[i];
// extend 4 -> 8 bit
alpha |= alpha << 4;
if (spu->custom && (spu->cuspal[i] >> 31) != 0)
alpha = 0;
int color = spu->custom ? spu->cuspal[i] :
spu->global_palette[spu->palette[i]];
int y = (color >> 16) & 0xff;
int u = (color >> 8) & 0xff;
int v = color & 0xff;
// stolen from some site, likely incorrect
int b = 1.164 * (y - 16) + 2.018 * (u - 128);
int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128);
int r = 1.164 * (y - 16) + 1.596 * (v - 128);
#define CL(x) FFMAX(FFMIN((x), 255), 0)
bmp->palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16);
#undef CL
}
}
}
void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
{
spudec_handle_t *spu = this;
@ -1325,6 +1370,14 @@ void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigne
return this;
}
void spudec_set_res(void *this, unsigned int frame_width, unsigned int frame_height)
{
spudec_handle_t *spu = this;
// intentionally do not apply resolution heuristics
spu->orig_frame_width = frame_width;
spu->orig_frame_height = frame_height;
}
void *spudec_new(unsigned int *palette)
{
return spudec_new_scaled(palette, 0, 0, NULL, 0);

View File

@ -22,14 +22,17 @@
#include <stdint.h>
struct sub_bitmaps;
struct mp_eosd_res;
void spudec_heartbeat(void *this, unsigned int pts100);
void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100);
void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx);
void spudec_draw_scaled(void *this, unsigned int dxs, unsigned int dys, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx);
void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res);
void spudec_get_indexed(void *this, struct mp_eosd_res *dim, struct sub_bitmaps *res);
int spudec_apply_palette_crop(void *this, uint32_t palette, int sx, int ex, int sy, int ey);
void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len);
void spudec_set_res(void *this, unsigned int frame_width, unsigned int frame_height);
void *spudec_new(unsigned int *palette);
void spudec_free(void *this);
void spudec_reset(void *this); // called after seek

View File

@ -172,8 +172,10 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj,
if (obj->type == OSDTYPE_SPU) {
*out_imgs = (struct sub_bitmaps) {0};
if (spu_visible(osd, obj))
spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs);
if (spu_visible(osd, obj)) {
//spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs);
spudec_get_indexed(vo_spudec, &osd->res, out_imgs);
}
// Normal change-detection (sub. dec. calls vo_osd_changed(OSDTYPE_SPU))
if (obj->force_redraw) {
out_imgs->bitmap_id++;
@ -183,9 +185,6 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj,
struct sub_render_params p = *sub_params;
if (p.pts != MP_NOPTS_VALUE)
p.pts += sub_delay - osd->sub_offset;
p.support_rgba = formats[SUBBITMAP_RGBA];
sub_get_bitmaps(osd, &p, out_imgs);
} else {
osd_object_get_bitmaps(osd, obj, out_imgs);
@ -204,7 +203,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj,
&& formats[obj->cached.format])
{
*out_imgs = obj->cached;
return true;
return out_imgs->num_parts > 0;
}
out_imgs->render_index = obj->type;
@ -212,22 +211,22 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj,
out_imgs->bitmap_pos_id = obj->vo_bitmap_pos_id;
if (formats[out_imgs->format])
return true;
return out_imgs->num_parts > 0;
bool cached = false; // do we have a copy of all the image data?
if ((formats[SUBBITMAP_OLD_PLANAR] || formats[SUBBITMAP_OLD])
&& out_imgs->format == SUBBITMAP_LIBASS)
if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_INDEXED) {
cached |= osd_conv_idx_to_rgba(obj->cache[0], out_imgs);
}
if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_INDEXED)
{
cached |= osd_conv_ass_to_old_p(obj->cache[0], out_imgs);
cached |= osd_conv_idx_to_old_p(obj->cache[1], out_imgs,
osd->res.w, osd->res.h);
}
if (formats[SUBBITMAP_OLD] && out_imgs->format == SUBBITMAP_OLD_PLANAR) {
cached |= osd_conv_old_p_to_old(obj->cache[1], out_imgs);
}
if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_OLD_PLANAR) {
cached |= osd_conv_old_p_to_rgba(obj->cache[2], out_imgs);
if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_LIBASS) {
cached |= osd_conv_ass_to_old_p(obj->cache[2], out_imgs);
}
if (cached)
@ -238,7 +237,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj,
obj->type, out_imgs->format);
return false;
}
return true;
return out_imgs->num_parts > 0;
}
// This is a hack to render the first subtitle OSD object, which is not empty.
@ -290,7 +289,6 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd)
.dim = dim,
.normal_scale = 1,
.vsfilter_scale = (double) asp.prew / asp.preh * asp.orgh / asp.orgw,
.support_rgba = formats[SUBBITMAP_RGBA],
};
for (int n = 0; n < MAX_OSD_PARTS; n++) {

View File

@ -30,13 +30,20 @@ struct sub_render_params;
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, can be scaled
SUBBITMAP_OLD, // I8A8 (monochrome), premultiplied alpha
SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), can be scaled
SUBBITMAP_INDEXED, // scaled, bitmap points to osd_bmp_indexed
SUBBITMAP_OLD_PLANAR, // like previous, but bitmap points to old_osd_planar
SUBBITMAP_COUNT
};
// For SUBBITMAP_INDEXED
struct osd_bmp_indexed {
uint8_t *bitmap;
// Each entry is like a pixel in SUBBITMAP_RGBA format
uint32_t palette[256];
};
// For SUBBITMAP_OLD_PANAR
struct old_osd_planar {
unsigned char *bitmap;
@ -46,9 +53,10 @@ struct old_osd_planar {
struct sub_bitmap {
void *bitmap;
int stride;
// Note: not clipped, going outside the screen area is allowed
// (except for SUBBITMAP_LIBASS, which is always clipped)
int w, h;
int x, y;
// Note: not clipped, going outside the screen area is allowed
int dw, dh;
union {
@ -59,10 +67,14 @@ struct sub_bitmap {
};
struct sub_bitmaps {
int render_index; // for VO cache state (limited by MAX_OSD_PARTS)
// For VO cache state (limited by MAX_OSD_PARTS)
int render_index;
enum sub_bitmap_format format;
bool scaled; // if false, dw==w && dh==h
// If false, dw==w && dh==h.
// SUBBITMAP_LIBASS is never scaled.
bool scaled;
struct sub_bitmap *parts;
int num_parts;
@ -120,8 +132,6 @@ struct osd_state {
double sub_offset;
double vo_sub_pts;
bool support_rgba;
bool render_subs_in_filter;
struct mp_eosd_res res;