summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-07-25 14:22:40 +0200
committerwm4 <wm4@nowhere>2014-07-25 14:32:45 +0200
commitf24f960ec78552da3d0b143c4fb88a732e8e9e11 (patch)
tree88bba8ec8be9380f275781b4b4d7622cc49c25b0
parent08415933db8ede1ec27cb43654bc6fffdbd6ad93 (diff)
downloadmpv-f24f960ec78552da3d0b143c4fb88a732e8e9e11.tar.bz2
mpv-f24f960ec78552da3d0b143c4fb88a732e8e9e11.tar.xz
command: fix and simplify overlay_add
Actually free the old mmap region when readding an overlay of the same ID without removing it before. (This is explicitly documented as working.) Replace the OSD atomically. Before this commit, the overlays were removed and then readded to avoid synchronization problems. Simplify the code: now there is no weird mapping between index and ID. The OSD sub-bitmap list still needs to be prepared to skip unused IDs (since each sub-bitmap list entry must be in use), but the code for this is relatively separated now. Fixes issue #956.
-rw-r--r--player/command.c94
1 files changed, 44 insertions, 50 deletions
diff --git a/player/command.c b/player/command.c
index 2bcb4bcd0c..d0b310bade 100644
--- a/player/command.c
+++ b/player/command.c
@@ -78,9 +78,12 @@ struct command_ctx {
struct cycle_counter *cycle_counters;
int num_cycle_counters;
-#define OVERLAY_MAX_ID 64
- void *overlay_map[OVERLAY_MAX_ID];
- struct sub_bitmaps external2;
+ struct sub_bitmap *overlays;
+ int num_overlays;
+ // One of these is in use by the OSD; the other one exists so that the
+ // bitmap list can be manipulated without additional synchronization.
+ struct sub_bitmaps overlay_osd[2];
+ struct sub_bitmaps *overlay_osd_current;
};
static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
@@ -3126,29 +3129,23 @@ static int edit_filters_osd(struct MPContext *mpctx, enum stream_type mediatype,
#if HAVE_SYS_MMAN_H
-static int ext2_sub_find(struct MPContext *mpctx, int id)
+static void recreate_overlays(struct MPContext *mpctx)
{
struct command_ctx *cmd = mpctx->command_ctx;
- struct sub_bitmaps *sub = &cmd->external2;
- void *p = NULL;
- if (id >= 0 && id < OVERLAY_MAX_ID)
- p = cmd->overlay_map[id];
- if (sub && p) {
- for (int n = 0; n < sub->num_parts; n++) {
- if (sub->parts[n].bitmap == p)
- return n;
- }
- }
- return -1;
-}
-
-static int ext2_sub_alloc(struct MPContext *mpctx)
-{
- struct command_ctx *cmd = mpctx->command_ctx;
- struct sub_bitmaps *sub = &cmd->external2;
- struct sub_bitmap b = {0};
- MP_TARRAY_APPEND(cmd, sub->parts, sub->num_parts, b);
- return sub->num_parts - 1;
+ struct sub_bitmaps *new = &cmd->overlay_osd[0];
+ if (new == cmd->overlay_osd_current)
+ new += 1; // pick the unused one
+ new->format = SUBBITMAP_RGBA;
+ new->bitmap_id = new->bitmap_pos_id = 1;
+ // overlay array can have unused entries, but parts list must be "packed"
+ new->num_parts = 0;
+ for (int n = 0; n < cmd->num_overlays; n++) {
+ struct sub_bitmap *s = &cmd->overlays[n];
+ if (s->bitmap)
+ MP_TARRAY_APPEND(cmd, new->parts, new->num_parts, *s);
+ }
+ cmd->overlay_osd_current = new;
+ osd_set_external2(mpctx->osd, cmd->overlay_osd_current);
}
static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
@@ -3157,13 +3154,11 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
{
struct command_ctx *cmd = mpctx->command_ctx;
int r = -1;
- // Temporarily unmap them to avoid race condition with concurrent access.
- osd_set_external2(mpctx->osd, NULL);
if (strcmp(fmt, "bgra") != 0) {
MP_ERR(mpctx, "overlay_add: unsupported OSD format '%s'\n", fmt);
goto error;
}
- if (id < 0 || id >= OVERLAY_MAX_ID) {
+ if (id < 0 || id >= 64) { // arbitrary upper limit
MP_ERR(mpctx, "overlay_add: invalid id %d\n", id);
goto error;
}
@@ -3185,50 +3180,49 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
MP_ERR(mpctx, "overlay_add: could not open or map '%s'\n", file);
goto error;
}
- int index = ext2_sub_find(mpctx, id);
- if (index < 0)
- index = ext2_sub_alloc(mpctx);
- if (index < 0) {
- munmap(p, h * stride);
- goto error;
- }
- cmd->overlay_map[id] = p;
- cmd->external2.parts[index] = (struct sub_bitmap) {
+ MP_TARRAY_GROW(cmd, cmd->overlays, id);
+ while (cmd->num_overlays <= id)
+ cmd->overlays[cmd->num_overlays++].bitmap = NULL;
+ struct sub_bitmap *overlay = &cmd->overlays[id];
+ void *prev = overlay->bitmap;
+ size_t prev_size = overlay->stride * overlay->h;
+ *overlay = (struct sub_bitmap) {
.bitmap = p,
.stride = stride,
.x = x, .y = y,
.w = w, .h = h,
.dw = w, .dh = h,
};
- cmd->external2.bitmap_id = cmd->external2.bitmap_pos_id = 1;
- cmd->external2.format = SUBBITMAP_RGBA;
+ recreate_overlays(mpctx);
+ // unmap afterwards, to avoid unmapping while OSD uses the memory
+ if (prev)
+ munmap(prev, prev_size);
r = 0;
error:
- osd_set_external2(mpctx->osd, &cmd->external2);
return r;
}
static void overlay_remove(struct MPContext *mpctx, int id)
{
struct command_ctx *cmd = mpctx->command_ctx;
- osd_set_external2(mpctx->osd, NULL);
- int index = ext2_sub_find(mpctx, id);
- if (index >= 0) {
- struct sub_bitmaps *sub = &cmd->external2;
- struct sub_bitmap *part = &sub->parts[index];
- munmap(part->bitmap, part->h * part->stride);
- MP_TARRAY_REMOVE_AT(sub->parts, sub->num_parts, index);
- cmd->overlay_map[id] = NULL;
- sub->bitmap_id = sub->bitmap_pos_id = 1;
+ if (id >= 0 && id < cmd->num_overlays) {
+ struct sub_bitmap *overlay = &cmd->overlays[id];
+ if (overlay->bitmap) {
+ void *ptr = overlay->bitmap;
+ size_t ptr_size = overlay->h * overlay->stride;
+ overlay->bitmap = NULL; // remove
+ recreate_overlays(mpctx);
+ munmap(ptr, ptr_size);
+ }
}
- osd_set_external2(mpctx->osd, &cmd->external2);
}
static void overlay_uninit(struct MPContext *mpctx)
{
+ struct command_ctx *cmd = mpctx->command_ctx;
if (!mpctx->osd)
return;
- for (int id = 0; id < OVERLAY_MAX_ID; id++)
+ for (int id = 0; id < cmd->num_overlays; id++)
overlay_remove(mpctx, id);
osd_set_external2(mpctx->osd, NULL);
}