subs, vo: do sub bitmap change detection by comparing IDs

vo_vdpau and vo_gl cache the last subtitle bitmaps uploaded to video
card in case they stay the same over multiple frames. Detecting
whether the bitmaps have changed and should be re-uploaded was
somewhat fragile. Change the VO API to provide a bitmap ID which can
be compared with what the VO has to determine whether a new upload of
the bitmaps is needed.

Conflicts:
	libvo/vo_gl.c

Note: the changes for vo_gl.c were not merged. Instead, eosd_packer is
modified to use the new way of detecting EOSD changes. This takes care
of vo_gl, vo_gl3 and vo_direct3d, which all render EOSD. They don't
need to be updated in turn.
This commit is contained in:
Uoti Urpala 2012-08-28 19:12:27 +03:00 committed by wm4
parent 62ccf6c5cc
commit fd52cb65f4
8 changed files with 39 additions and 32 deletions

View File

@ -34,7 +34,6 @@
struct vf_priv_s {
struct vo *vo;
bool prev_visibility;
double scale_ratio;
};
#define video_out (vf->priv->vo)
@ -77,9 +76,6 @@ static int config(struct vf_instance *vf,
vf->priv->scale_ratio = (double) d_width / d_height * height / width;
// force EOSD change detection reset
vf->priv->prev_visibility = false;
return 1;
}
@ -121,27 +117,17 @@ static int control(struct vf_instance *vf, int request, void *data)
};
return vo_control(video_out, VOCTRL_GET_EQUALIZER, &param) == VO_TRUE;
}
case VFCTRL_INIT_EOSD: {
vf->priv->prev_visibility = false;
return CONTROL_TRUE;
}
case VFCTRL_DRAW_EOSD: {
struct osd_state *osd = data;
osd->dim = (struct mp_eosd_res){0};
if (!video_out->config_ok ||
vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true) {
vf->priv->prev_visibility = false;
vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true)
return CONTROL_FALSE;
}
osd->normal_scale = 1;
osd->vsfilter_scale = vf->priv->scale_ratio;
osd->unscaled = vf->default_caps & VFCAP_EOSD_UNSCALED;
struct sub_bitmaps images;
sub_get_bitmaps(osd, &images);
if (!vf->priv->prev_visibility)
images.changed = 2;
vf->priv->prev_visibility = true;
return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE;
}
}

View File

@ -147,17 +147,18 @@ void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs,
ASS_Image *p;
struct eosd_surface *sfc = &state->surface;
*out_need_reposition = false;
*out_need_upload = false;
*out_need_reposition = imgs->bitmap_pos_id != state->last_bitmap_pos_id;
*out_need_upload = imgs->bitmap_id != state->last_bitmap_id;
*out_need_reallocate = false;
int change_state = imgs->changed;
state->last_bitmap_pos_id = imgs->bitmap_pos_id;
state->last_bitmap_id = imgs->bitmap_id;
// eosd_reinit() was probably called, force full reupload.
if (state->targets_count == 0 && img)
change_state = 2;
*out_need_upload = true;
if (change_state == 0)
if (!(*out_need_reposition) && !(*out_need_upload))
return; // Nothing changed, no need to redraw
state->targets_count = 0;
@ -167,7 +168,7 @@ void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs,
if (!img)
return; // There's nothing to render!
if (change_state == 1)
if (!(*out_need_upload))
goto eosd_skip_upload;
*out_need_upload = true;

View File

@ -58,6 +58,8 @@ struct eosd_packer {
uint32_t max_surface_height;
int *scratch;
int last_bitmap_id;
int last_bitmap_pos_id;
};
struct eosd_packer *eosd_packer_create(void *talloc_ctx);

View File

@ -186,6 +186,8 @@ struct vdpctx {
} *eosd_targets, osd_targets[MAX_OLD_OSD_BITMAPS][2];
int eosd_targets_size;
int eosd_render_count;
int bitmap_id;
int bitmap_pos_id;
// Video equalizer
struct mp_csp_equalizer video_eq;
@ -812,6 +814,7 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
vc->vdp_device = VDP_INVALID_HANDLE;
talloc_free(vc->osd_surface.packer);
talloc_free(vc->eosd_surface.packer);
vc->bitmap_id = vc->bitmap_pos_id = 0;
vc->osd_surface = vc->eosd_surface = (struct eosd_bitmap_surface){
.surface = VDP_INVALID_HANDLE,
};
@ -999,7 +1002,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
struct eosd_bitmap_surface *sfc = &vc->eosd_surface;
bool need_upload = false;
if (imgs->changed == 0 && sfc->packer)
if (imgs->bitmap_pos_id == vc->bitmap_pos_id)
return; // Nothing changed and we still have the old data
vc->eosd_render_count = 0;
@ -1007,7 +1010,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
if (!imgs->imgs)
return; // There's nothing to render!
if (imgs->changed == 1)
if (imgs->bitmap_id == vc->bitmap_id)
goto eosd_skip_upload;
need_upload = true;
@ -1069,6 +1072,8 @@ eosd_skip_upload:
target->dest.y1 = p->h + p->dst_y;
vc->eosd_render_count++;
}
vc->bitmap_id = imgs->bitmap_id;
vc->bitmap_pos_id = imgs->bitmap_pos_id;
}
static void record_osd(void *ctx, int x0, int y0, int w, int h,

View File

@ -45,7 +45,7 @@ void sub_init(struct sh_sub *sh, struct osd_state *osd)
if (sh->sd_driver->init(sh, osd) < 0)
return;
osd->sh_sub = sh;
osd->changed_outside_sd = true;
osd->bitmap_id = ++osd->bitmap_pos_id;
sh->initialized = true;
sh->active = true;
}
@ -62,16 +62,23 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res)
{
struct MPOpts *opts = osd->opts;
*res = (struct sub_bitmaps){.imgs = NULL, .changed = 2};
*res = (struct sub_bitmaps){ .bitmap_id = osd->bitmap_id,
.bitmap_pos_id = osd->bitmap_pos_id };
if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) {
osd->changed_outside_sd = true;
/* Change ID in case we just switched from visible subtitles
* to current state. Hopefully, unnecessarily claiming that
* things may have changed is harmless for empty contents.
* Increase osd-> values ahead so that _next_ returned id
* is also guaranteed to differ from this one.
*/
res->bitmap_id = ++res->bitmap_pos_id;
osd->bitmap_id = osd->bitmap_pos_id += 2;
return;
}
if (osd->sh_sub->sd_driver->get_bitmaps)
osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, res);
if (osd->changed_outside_sd)
res->changed = 2;
osd->changed_outside_sd = false;
osd->bitmap_id = res->bitmap_id;
osd->bitmap_pos_id = res->bitmap_pos_id;
}
void sub_reset(struct sh_sub *sh, struct osd_state *osd)

View File

@ -12,7 +12,7 @@ typedef struct mp_eosd_res {
typedef struct sub_bitmaps {
struct ass_image *imgs;
int changed;
int bitmap_id, bitmap_pos_id;
} mp_eosd_images_t;
static inline bool is_text_sub(int type)

View File

@ -140,8 +140,13 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
ASS_Renderer *renderer = osd->ass_renderer;
mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled);
ass_set_aspect_ratio(renderer, scale, 1);
int changed;
res->imgs = ass_render_frame(renderer, ctx->ass_track,
osd->sub_pts * 1000 + .5, &res->changed);
osd->sub_pts * 1000 + .5, &changed);
if (changed == 2)
res->bitmap_id = ++res->bitmap_pos_id;
else if (changed)
res->bitmap_pos_id++;
}
static void reset(struct sh_sub *sh, struct osd_state *osd)

View File

@ -63,7 +63,8 @@ struct osd_state {
struct ass_library *ass_library;
struct ass_renderer *ass_renderer;
struct sh_sub *sh_sub;
bool changed_outside_sd;
int bitmap_id;
int bitmap_pos_id;
double sub_pts;
double sub_offset;
struct mp_eosd_res dim;