mirror of https://github.com/mpv-player/mpv
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:
parent
62ccf6c5cc
commit
fd52cb65f4
|
@ -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, ¶m) == 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue