vo_xv, vo_x11: simplify OSD redrawing

In order to support OSD redrawing for vo_xv and vo_x11, draw_bmp.c
included an awkward "backup" mechanism to copy and restore image
regions that have been changed by OSD/subtitles.

Replace this by a much simpler mechanism: keep a reference to the
original image, and use that to restore the Xv/X framebuffers.

In the worst case, this may increase cache pressure and memory usage,
even if no OSD or subtitles are rendered. In practice, it seems to be
always faster.
This commit is contained in:
wm4 2012-12-22 17:50:15 +01:00
parent 1c65428d6f
commit 3d6d549dac
6 changed files with 40 additions and 180 deletions

View File

@ -512,127 +512,4 @@ void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst,
}
}
struct mp_draw_sub_backup
{
bool valid;
struct mp_image *image; // backed up image parts
struct line_ext *lines[MP_MAX_PLANES]; // backup range for each line
};
struct line_ext {
int x0, x1; // x1 is exclusive
};
struct mp_draw_sub_backup *mp_draw_sub_backup_new(void)
{
return talloc_zero(NULL, struct mp_draw_sub_backup);
}
// Signal that the full image is valid (nothing to backup).
void mp_draw_sub_backup_reset(struct mp_draw_sub_backup *backup)
{
backup->valid = true;
if (backup->image) {
for (int p = 0; p < MP_MAX_PLANES; p++) {
int h = backup->image->h;
for (int y = 0; y < h; y++) {
struct line_ext *ext = &backup->lines[p][y];
ext->x0 = ext->x1 = -1;
}
}
}
}
static void backup_realloc(struct mp_draw_sub_backup *backup,
struct mp_image *img)
{
if (backup->image && backup->image->imgfmt == img->imgfmt
&& backup->image->w == img->w && backup->image->h == img->h)
return;
talloc_free_children(backup);
backup->image = mp_image_alloc(img->imgfmt, img->w, img->h);
talloc_steal(backup, backup->image);
for (int p = 0; p < MP_MAX_PLANES; p++) {
backup->lines[p] = talloc_array(backup, struct line_ext,
backup->image->h);
}
mp_draw_sub_backup_reset(backup);
}
static void copy_line(struct mp_image *dst, struct mp_image *src,
int p, int plane_y, int x0, int x1)
{
int bits = dst->fmt.bpp[p];
int xs = p ? dst->chroma_x_shift : 0;
memcpy(dst->planes[p] + plane_y * dst->stride[p] + (x0 >> xs) * bits / 8,
src->planes[p] + plane_y * src->stride[p] + (x0 >> xs) * bits / 8,
((x1 - x0) >> xs) * bits / 8);
}
static void backup_rect(struct mp_draw_sub_backup *backup, struct mp_image *img,
int plane, struct mp_rect rc)
{
if (!align_bbox_for_swscale(img, &rc))
return;
int ys = plane ? img->chroma_y_shift : 0;
int yp = ys ? ((1 << ys) - 1) : 0;
for (int y = (rc.y0 >> ys); y < ((rc.y1 + yp) >> ys); y++) {
struct line_ext *ext = &backup->lines[plane][y];
if (ext->x0 == -1) {
copy_line(backup->image, img, plane, y, rc.x0, rc.x1);
ext->x0 = rc.x0;
ext->x1 = rc.x1;
} else {
if (rc.x0 < ext->x0) {
copy_line(backup->image, img, plane, y, rc.x0, ext->x0);
ext->x0 = rc.x0;
}
if (ext->x1 < rc.x1) {
copy_line(backup->image, img, plane, y, ext->x1, rc.x1);
ext->x1 = rc.x1;
}
}
}
}
void mp_draw_sub_backup_add(struct mp_draw_sub_backup *backup,
struct mp_image *img, struct sub_bitmaps *sbs)
{
backup_realloc(backup, img);
for (int p = 0; p < img->num_planes; p++) {
for (int i = 0; i < sbs->num_parts; ++i) {
struct sub_bitmap *sb = &sbs->parts[i];
struct mp_rect rc = {sb->x, sb->y, sb->x + sb->dw, sb->y + sb->dh};
backup_rect(backup, img, p, rc);
}
}
}
bool mp_draw_sub_backup_restore(struct mp_draw_sub_backup *backup,
struct mp_image *buffer)
{
if (!backup->image || backup->image->imgfmt != buffer->imgfmt
|| backup->image->w != buffer->w || backup->image->h != buffer->h
|| !backup->valid)
{
backup->valid = false;
return false;
}
struct mp_image *img = backup->image;
for (int p = 0; p < img->num_planes; p++) {
int ys = p ? img->chroma_y_shift : 0;
int yp = ys ? ((1 << ys) - 1) : 0;
int p_h = ((img->h + yp) >> ys);
for (int y = 0; y < p_h; y++) {
struct line_ext *ext = &backup->lines[p][y];
if (ext->x0 < ext->x1) {
copy_line(buffer, img, p, y, ext->x0, ext->x1);
}
}
}
return true;
}
// vim: ts=4 sw=4 et tw=80

View File

@ -12,14 +12,6 @@ void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst,
extern const bool mp_draw_sub_formats[SUBBITMAP_COUNT];
struct mp_draw_sub_backup;
struct mp_draw_sub_backup *mp_draw_sub_backup_new(void);
void mp_draw_sub_backup_add(struct mp_draw_sub_backup *backup,
struct mp_image *img, struct sub_bitmaps *sbs);
void mp_draw_sub_backup_reset(struct mp_draw_sub_backup *backup);
bool mp_draw_sub_backup_restore(struct mp_draw_sub_backup *backup,
struct mp_image *buffer);
#endif /* MPLAYER_DRAW_BMP_H */
// vim: ts=4 sw=4 et tw=80

View File

@ -275,7 +275,6 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
struct draw_on_image_closure {
struct osd_state *osd;
struct mp_image *dest;
struct mp_draw_sub_backup *bk;
struct mp_image_pool *pool;
bool changed;
};
@ -284,8 +283,6 @@ static void draw_on_image(void *ctx, struct sub_bitmaps *imgs)
{
struct draw_on_image_closure *closure = ctx;
struct osd_state *osd = closure->osd;
if (closure->bk)
mp_draw_sub_backup_add(closure->bk, closure->dest, imgs);
if (closure->pool) {
mp_image_pool_make_writeable(closure->pool, closure->dest);
} else {
@ -314,16 +311,7 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags,
struct mp_image_pool *pool, struct mp_image *dest)
{
struct draw_on_image_closure closure = {osd, dest, .pool = pool};
osd_draw(osd, res, video_pts, draw_flags, mp_draw_sub_formats,
&draw_on_image, &closure);
}
void osd_draw_on_image_bk(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags,
struct mp_draw_sub_backup *bk, struct mp_image *dest)
{
struct draw_on_image_closure closure = {osd, dest, bk};
struct draw_on_image_closure closure = {osd, dest, pool};
osd_draw(osd, res, video_pts, draw_flags, mp_draw_sub_formats,
&draw_on_image, &closure);
}

View File

@ -227,11 +227,6 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags,
struct mp_image_pool *pool, struct mp_image *dest);
struct mp_draw_sub_backup;
void osd_draw_on_image_bk(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags,
struct mp_draw_sub_backup *bk, struct mp_image *dest);
struct mp_rect;
bool sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb);

View File

@ -55,7 +55,7 @@ extern int sws_flags;
struct priv {
struct vo *vo;
struct mp_draw_sub_backup *osd_backup;
struct mp_image *original_image;
/* local data */
unsigned char *ImageData;
@ -268,6 +268,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
Colormap theCmap;
const struct fmt2Xfmtentry_s *fmte = fmt2Xfmt;
mp_image_unrefp(&p->original_image);
#ifdef CONFIG_XF86VM
int vm = flags & VOFLAG_MODESWITCHING;
#endif
@ -441,30 +443,21 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.video_par = vo->aspdat.par,
};
osd_draw_on_image_bk(osd, res, osd->vo_pts, 0, p->osd_backup, &img);
osd_draw_on_image(osd, res, osd->vo_pts, 0, &img);
}
static mp_image_t *get_screenshot(struct vo *vo)
{
struct priv *p = vo->priv;
struct mp_image img = get_x_buffer(p);
struct mp_image *res = mp_image_new_copy(&img);
mp_draw_sub_backup_restore(p->osd_backup, res);
if (!p->original_image)
return NULL;
struct mp_image *res = mp_image_new_ref(p->original_image);
mp_image_set_display_size(res, vo->aspdat.prew, vo->aspdat.preh);
return res;
}
static int redraw_frame(struct vo *vo)
{
struct priv *p = vo->priv;
struct mp_image img = get_x_buffer(p);
mp_draw_sub_backup_restore(p->osd_backup, &img);
return true;
}
static void flip_page(struct vo *vo)
{
struct priv *p = vo->priv;
@ -516,7 +509,19 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
}
sws_scale(p->swsContext, (const uint8_t **)mpi->planes, mpi->stride,
0, mpi->h, dst, dstStride);
mp_draw_sub_backup_reset(p->osd_backup);
mp_image_setrefp(&p->original_image, mpi);
}
static int redraw_frame(struct vo *vo)
{
struct priv *p = vo->priv;
if (!p->original_image)
return false;
draw_image(vo, p->original_image);
return true;
}
static int query_format(struct vo *vo, uint32_t format)
@ -551,6 +556,8 @@ static void uninit(struct vo *vo)
if (p->myximage)
freeMyXImage(p);
talloc_free(p->original_image);
#ifdef CONFIG_XF86VM
vo_vm_close(vo);
#endif
@ -571,8 +578,6 @@ static int preinit(struct vo *vo, const char *arg)
return ENOSYS;
}
p->osd_backup = talloc_steal(p, mp_draw_sub_backup_new());
if (!vo_init(vo))
return -1; // Can't open X11
return 0;

View File

@ -73,7 +73,7 @@ struct xvctx {
int total_buffers;
int visible_buf;
XvImage *xvimage[2];
struct mp_draw_sub_backup *osd_backup;
struct mp_image *original_image;
uint32_t image_width;
uint32_t image_height;
uint32_t image_format;
@ -159,6 +159,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
struct xvctx *ctx = vo->priv;
int i;
mp_image_unrefp(&ctx->original_image);
ctx->image_height = height;
ctx->image_width = width;
ctx->image_format = format;
@ -383,17 +385,19 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.video_par = vo->aspdat.par,
};
osd_draw_on_image_bk(osd, res, osd->vo_pts, 0, ctx->osd_backup, &img);
osd_draw_on_image(osd, res, osd->vo_pts, 0, &img);
}
static int redraw_frame(struct vo *vo)
{
struct xvctx *ctx = vo->priv;
struct mp_image img = get_xv_buffer(vo, ctx->visible_buf);
mp_draw_sub_backup_restore(ctx->osd_backup, &img);
ctx->current_buf = ctx->visible_buf;
if (!ctx->original_image)
return false;
struct mp_image img = get_xv_buffer(vo, ctx->visible_buf);
mp_image_copy(&img, ctx->original_image);
ctx->current_buf = ctx->visible_buf;
return true;
}
@ -414,12 +418,11 @@ static mp_image_t *get_screenshot(struct vo *vo)
{
struct xvctx *ctx = vo->priv;
struct mp_image img = get_xv_buffer(vo, ctx->visible_buf);
struct mp_image *res = mp_image_new_copy(&img);
mp_image_set_display_size(res, vo->aspdat.prew, vo->aspdat.preh);
// try to get an image without OSD
mp_draw_sub_backup_restore(ctx->osd_backup, res);
if (!ctx->original_image)
return NULL;
struct mp_image *res = mp_image_new_ref(ctx->original_image);
mp_image_set_display_size(res, vo->aspdat.prew, vo->aspdat.preh);
return res;
}
@ -430,7 +433,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
struct mp_image xv_buffer = get_xv_buffer(vo, ctx->current_buf);
mp_image_copy(&xv_buffer, mpi);
mp_draw_sub_backup_reset(ctx->osd_backup);
mp_image_setrefp(&ctx->original_image, mpi);
}
static int query_format(struct vo *vo, uint32_t format)
@ -454,6 +457,8 @@ static void uninit(struct vo *vo)
struct xvctx *ctx = vo->priv;
int i;
talloc_free(ctx->original_image);
ctx->visible_buf = -1;
if (ctx->ai)
XvFreeAdaptorInfo(ctx->ai);
@ -595,8 +600,6 @@ static int preinit(struct vo *vo, const char *arg)
ctx->fo = XvListImageFormats(x11->display, x11->xv_port,
(int *) &ctx->formats);
ctx->osd_backup = talloc_steal(ctx, mp_draw_sub_backup_new());
return 0;
error: