mirror of
https://github.com/mpv-player/mpv
synced 2025-02-18 05:37:04 +00:00
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 vf_priv_s {
|
||||||
struct vo *vo;
|
struct vo *vo;
|
||||||
bool prev_visibility;
|
|
||||||
double scale_ratio;
|
double scale_ratio;
|
||||||
};
|
};
|
||||||
#define video_out (vf->priv->vo)
|
#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;
|
vf->priv->scale_ratio = (double) d_width / d_height * height / width;
|
||||||
|
|
||||||
// force EOSD change detection reset
|
|
||||||
vf->priv->prev_visibility = false;
|
|
||||||
|
|
||||||
return 1;
|
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;
|
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: {
|
case VFCTRL_DRAW_EOSD: {
|
||||||
struct osd_state *osd = data;
|
struct osd_state *osd = data;
|
||||||
osd->dim = (struct mp_eosd_res){0};
|
osd->dim = (struct mp_eosd_res){0};
|
||||||
if (!video_out->config_ok ||
|
if (!video_out->config_ok ||
|
||||||
vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true) {
|
vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true)
|
||||||
vf->priv->prev_visibility = false;
|
|
||||||
return CONTROL_FALSE;
|
return CONTROL_FALSE;
|
||||||
}
|
|
||||||
osd->normal_scale = 1;
|
osd->normal_scale = 1;
|
||||||
osd->vsfilter_scale = vf->priv->scale_ratio;
|
osd->vsfilter_scale = vf->priv->scale_ratio;
|
||||||
osd->unscaled = vf->default_caps & VFCAP_EOSD_UNSCALED;
|
osd->unscaled = vf->default_caps & VFCAP_EOSD_UNSCALED;
|
||||||
struct sub_bitmaps images;
|
struct sub_bitmaps images;
|
||||||
sub_get_bitmaps(osd, &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;
|
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;
|
ASS_Image *p;
|
||||||
struct eosd_surface *sfc = &state->surface;
|
struct eosd_surface *sfc = &state->surface;
|
||||||
|
|
||||||
*out_need_reposition = false;
|
*out_need_reposition = imgs->bitmap_pos_id != state->last_bitmap_pos_id;
|
||||||
*out_need_upload = false;
|
*out_need_upload = imgs->bitmap_id != state->last_bitmap_id;
|
||||||
*out_need_reallocate = false;
|
*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.
|
// eosd_reinit() was probably called, force full reupload.
|
||||||
if (state->targets_count == 0 && img)
|
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
|
return; // Nothing changed, no need to redraw
|
||||||
|
|
||||||
state->targets_count = 0;
|
state->targets_count = 0;
|
||||||
@ -167,7 +168,7 @@ void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs,
|
|||||||
if (!img)
|
if (!img)
|
||||||
return; // There's nothing to render!
|
return; // There's nothing to render!
|
||||||
|
|
||||||
if (change_state == 1)
|
if (!(*out_need_upload))
|
||||||
goto eosd_skip_upload;
|
goto eosd_skip_upload;
|
||||||
|
|
||||||
*out_need_upload = true;
|
*out_need_upload = true;
|
||||||
|
@ -58,6 +58,8 @@ struct eosd_packer {
|
|||||||
uint32_t max_surface_height;
|
uint32_t max_surface_height;
|
||||||
|
|
||||||
int *scratch;
|
int *scratch;
|
||||||
|
int last_bitmap_id;
|
||||||
|
int last_bitmap_pos_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct eosd_packer *eosd_packer_create(void *talloc_ctx);
|
struct eosd_packer *eosd_packer_create(void *talloc_ctx);
|
||||||
|
@ -186,6 +186,8 @@ struct vdpctx {
|
|||||||
} *eosd_targets, osd_targets[MAX_OLD_OSD_BITMAPS][2];
|
} *eosd_targets, osd_targets[MAX_OLD_OSD_BITMAPS][2];
|
||||||
int eosd_targets_size;
|
int eosd_targets_size;
|
||||||
int eosd_render_count;
|
int eosd_render_count;
|
||||||
|
int bitmap_id;
|
||||||
|
int bitmap_pos_id;
|
||||||
|
|
||||||
// Video equalizer
|
// Video equalizer
|
||||||
struct mp_csp_equalizer video_eq;
|
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;
|
vc->vdp_device = VDP_INVALID_HANDLE;
|
||||||
talloc_free(vc->osd_surface.packer);
|
talloc_free(vc->osd_surface.packer);
|
||||||
talloc_free(vc->eosd_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){
|
vc->osd_surface = vc->eosd_surface = (struct eosd_bitmap_surface){
|
||||||
.surface = VDP_INVALID_HANDLE,
|
.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;
|
struct eosd_bitmap_surface *sfc = &vc->eosd_surface;
|
||||||
bool need_upload = false;
|
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
|
return; // Nothing changed and we still have the old data
|
||||||
|
|
||||||
vc->eosd_render_count = 0;
|
vc->eosd_render_count = 0;
|
||||||
@ -1007,7 +1010,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
|
|||||||
if (!imgs->imgs)
|
if (!imgs->imgs)
|
||||||
return; // There's nothing to render!
|
return; // There's nothing to render!
|
||||||
|
|
||||||
if (imgs->changed == 1)
|
if (imgs->bitmap_id == vc->bitmap_id)
|
||||||
goto eosd_skip_upload;
|
goto eosd_skip_upload;
|
||||||
|
|
||||||
need_upload = true;
|
need_upload = true;
|
||||||
@ -1069,6 +1072,8 @@ eosd_skip_upload:
|
|||||||
target->dest.y1 = p->h + p->dst_y;
|
target->dest.y1 = p->h + p->dst_y;
|
||||||
vc->eosd_render_count++;
|
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,
|
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)
|
if (sh->sd_driver->init(sh, osd) < 0)
|
||||||
return;
|
return;
|
||||||
osd->sh_sub = sh;
|
osd->sh_sub = sh;
|
||||||
osd->changed_outside_sd = true;
|
osd->bitmap_id = ++osd->bitmap_pos_id;
|
||||||
sh->initialized = true;
|
sh->initialized = true;
|
||||||
sh->active = 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;
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (osd->sh_sub->sd_driver->get_bitmaps)
|
if (osd->sh_sub->sd_driver->get_bitmaps)
|
||||||
osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, res);
|
osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, res);
|
||||||
if (osd->changed_outside_sd)
|
osd->bitmap_id = res->bitmap_id;
|
||||||
res->changed = 2;
|
osd->bitmap_pos_id = res->bitmap_pos_id;
|
||||||
osd->changed_outside_sd = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sub_reset(struct sh_sub *sh, struct osd_state *osd)
|
void sub_reset(struct sh_sub *sh, struct osd_state *osd)
|
||||||
|
@ -12,7 +12,7 @@ typedef struct mp_eosd_res {
|
|||||||
|
|
||||||
typedef struct sub_bitmaps {
|
typedef struct sub_bitmaps {
|
||||||
struct ass_image *imgs;
|
struct ass_image *imgs;
|
||||||
int changed;
|
int bitmap_id, bitmap_pos_id;
|
||||||
} mp_eosd_images_t;
|
} mp_eosd_images_t;
|
||||||
|
|
||||||
static inline bool is_text_sub(int type)
|
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;
|
ASS_Renderer *renderer = osd->ass_renderer;
|
||||||
mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled);
|
mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled);
|
||||||
ass_set_aspect_ratio(renderer, scale, 1);
|
ass_set_aspect_ratio(renderer, scale, 1);
|
||||||
|
int changed;
|
||||||
res->imgs = ass_render_frame(renderer, ctx->ass_track,
|
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)
|
static void reset(struct sh_sub *sh, struct osd_state *osd)
|
||||||
|
@ -63,7 +63,8 @@ struct osd_state {
|
|||||||
struct ass_library *ass_library;
|
struct ass_library *ass_library;
|
||||||
struct ass_renderer *ass_renderer;
|
struct ass_renderer *ass_renderer;
|
||||||
struct sh_sub *sh_sub;
|
struct sh_sub *sh_sub;
|
||||||
bool changed_outside_sd;
|
int bitmap_id;
|
||||||
|
int bitmap_pos_id;
|
||||||
double sub_pts;
|
double sub_pts;
|
||||||
double sub_offset;
|
double sub_offset;
|
||||||
struct mp_eosd_res dim;
|
struct mp_eosd_res dim;
|
||||||
|
Loading…
Reference in New Issue
Block a user