summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/input.rst32
-rw-r--r--player/command.c131
2 files changed, 109 insertions, 54 deletions
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 9c0cf922c4..c2f3c03dd3 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -561,29 +561,20 @@ Input Commands that are Possibly Subject to Change
the resolution is reduced to that of the video's. You can read the
``osd-width`` and ``osd-height`` properties. At least with ``--vo-xv`` and
anamorphic video (such as DVD), ``osd-par`` should be read as well, and the
- overlay should be aspect-compensated. (Future directions: maybe mpv should
- take care of some of these things automatically, but it's hard to tell
- where to draw the line.)
+ overlay should be aspect-compensated.
``id`` is an integer between 0 and 63 identifying the overlay element. The
ID can be used to add multiple overlay parts, update a part by using this
command with an already existing ID, or to remove a part with
``overlay-remove``. Using a previously unused ID will add a new overlay,
- while reusing an ID will update it. (Future directions: there should be
- something to ensure different programs wanting to create overlays don't
- conflict with each others, should that ever be needed.)
+ while reusing an ID will update it.
``x`` and ``y`` specify the position where the OSD should be displayed.
``file`` specifies the file the raw image data is read from. It can be
either a numeric UNIX file descriptor prefixed with ``@`` (e.g. ``@4``),
- or a filename. The file will be mapped into memory with ``mmap()``. Some VOs
- will pass the mapped pointer directly to display APIs (e.g. opengl or
- vdpau), so no actual copying is involved. Truncating the source file while
- the overlay is active will crash the player. You shouldn't change the data
- while the overlay is active, because the data is essentially accessed at
- random points. Instead, call ``overlay-add`` again (preferably with a
- different memory region to prevent tearing).
+ or a filename. The file will be mapped into memory with ``mmap()``,
+ copied, and unmapped before the command returns (changed in mpv 0.18.1).
It is also possible to pass a raw memory address for use as bitmap memory
by passing a memory address as integer prefixed with an ``&`` character.
@@ -616,15 +607,14 @@ Input Commands that are Possibly Subject to Change
(Technically, the minimum size would be ``stride * (h - 1) + w * 4``, but
for simplicity, the player will access all ``stride * h`` bytes.)
- .. admonition:: Warning
+ .. note::
- When updating the overlay, you should prepare a second shared memory
- region (e.g. make use of the offset parameter) and add this as overlay,
- instead of reusing the same memory every time. Otherwise, you might
- get the equivalent of tearing, when your application and mpv write/read
- the buffer at the same time. Also, keep in mind that mpv might access
- an overlay's memory at random times whenever it feels the need to do
- so, for example when redrawing the screen.
+ Before mpv 0.18.1, you had to do manual "double buffering" when updating
+ an overlay by replacing it with a different memory buffer. Since mpv
+ 0.18.1, the memory is simply copied and doesn't reference any of the
+ memory indicated by the command's arguments after the commend returns.
+ If you want to use this command before mpv 0.18.1, reads the old docs
+ to see how to handle this correctly.
``overlay-remove <id>``
Remove an overlay added with ``overlay-add`` and the same ID. Does nothing
diff --git a/player/command.c b/player/command.c
index bc48d8cf2d..caca0c32ec 100644
--- a/player/command.c
+++ b/player/command.c
@@ -60,6 +60,7 @@
#include "audio/filter/af.h"
#include "video/decode/dec_video.h"
#include "audio/decode/dec_audio.h"
+#include "video/out/bitmap_packer.h"
#include "options/path.h"
#include "screenshot.h"
@@ -88,7 +89,8 @@ struct command_ctx {
// 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;
+ int overlay_osd_current;
+ struct bitmap_packer *overlay_packer;
struct hook_handler **hooks;
int num_hooks;
@@ -98,9 +100,8 @@ struct command_ctx {
};
struct overlay {
- void *map_start;
- size_t map_size;
- struct sub_bitmap osd;
+ struct mp_image *source;
+ int x, y;
};
struct hook_handler {
@@ -4314,20 +4315,85 @@ static int edit_filters_osd(struct MPContext *mpctx, enum stream_type mediatype,
static void recreate_overlays(struct MPContext *mpctx)
{
struct command_ctx *cmd = mpctx->command_ctx;
- struct sub_bitmaps *new = &cmd->overlay_osd[0];
- if (new == cmd->overlay_osd_current)
- new += 1; // pick the unused one
+ int overlay_next = !cmd->overlay_osd_current;
+ struct sub_bitmaps *new = &cmd->overlay_osd[overlay_next];
new->format = SUBBITMAP_RGBA;
new->change_id = 1;
- // overlay array can have unused entries, but parts list must be "packed"
+
+ bool valid = false;
+
new->num_parts = 0;
for (int n = 0; n < cmd->num_overlays; n++) {
struct overlay *o = &cmd->overlays[n];
- if (o->osd.bitmap)
- MP_TARRAY_APPEND(cmd, new->parts, new->num_parts, o->osd);
+ if (o->source) {
+ struct mp_image *s = o->source;
+ struct sub_bitmap b = {
+ .bitmap = s->planes[0],
+ .stride = s->stride[0],
+ .w = s->w, .dw = s->w,
+ .h = s->h, .dh = s->h,
+ .x = o->x,
+ .y = o->y,
+ };
+ MP_TARRAY_APPEND(cmd, new->parts, new->num_parts, b);
+ }
+ }
+
+ if (!cmd->overlay_packer)
+ cmd->overlay_packer = talloc_zero(cmd, struct bitmap_packer);
+
+ cmd->overlay_packer->padding = 1; // assume bilinear scaling
+ packer_set_size(cmd->overlay_packer, new->num_parts);
+
+ for (int n = 0; n < new->num_parts; n++)
+ cmd->overlay_packer->in[n] = (struct pos){new->parts[n].w, new->parts[n].h};
+
+ if (packer_pack(cmd->overlay_packer) < 0 || new->num_parts == 0)
+ goto done;
+
+ struct pos bb[2];
+ packer_get_bb(cmd->overlay_packer, bb);
+
+ new->packed_w = bb[1].x;
+ new->packed_h = bb[1].y;
+
+ if (!new->packed || new->packed->w < new->packed_w ||
+ new->packed->h < new->packed_h)
+ {
+ talloc_free(new->packed);
+ new->packed = mp_image_alloc(IMGFMT_BGRA, cmd->overlay_packer->w,
+ cmd->overlay_packer->h);
+ if (!new->packed)
+ goto done;
+ }
+
+ // clear padding
+ mp_image_clear(new->packed, 0, 0, new->packed->w, new->packed->h);
+
+ for (int n = 0; n < new->num_parts; n++) {
+ struct sub_bitmap *b = &new->parts[n];
+ struct pos pos = cmd->overlay_packer->result[n];
+
+ int stride = new->packed->stride[0];
+ void *pdata = (uint8_t *)new->packed->planes[0] + pos.y * stride + pos.x * 4;
+ memcpy_pic(pdata, b->bitmap, b->w * 4, b->h, stride, b->stride);
+
+ b->bitmap = pdata;
+ b->stride = stride;
+
+ b->src_x = pos.x;
+ b->src_y = pos.y;
+ }
+
+ valid = true;
+done:
+ if (!valid) {
+ new->format = SUBBITMAP_EMPTY;
+ new->num_parts = 0;
}
- cmd->overlay_osd_current = new;
- osd_set_external2(mpctx->osd, cmd->overlay_osd_current);
+
+ osd_set_external2(mpctx->osd, new);
+ cmd->overlay_osd_current = overlay_next;
}
// Set overlay with the given ID to the contents as described by "new".
@@ -4342,17 +4408,11 @@ static void replace_overlay(struct MPContext *mpctx, int id, struct overlay *new
}
struct overlay *ptr = &cmd->overlays[id];
- struct overlay old = *ptr;
-
- if (!ptr->osd.bitmap && !new->osd.bitmap)
- return; // don't need to recreate or unmap
+ talloc_free(ptr->source);
*ptr = *new;
- recreate_overlays(mpctx);
- // Do this afterwards, so we never unmap while the OSD is using it.
- if (old.map_start && old.map_size)
- munmap(old.map_start, old.map_size);
+ recreate_overlays(mpctx);
}
static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
@@ -4368,18 +4428,17 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
MP_ERR(mpctx, "overlay_add: invalid id %d\n", id);
goto error;
}
- if (w < 0 || h < 0 || stride < w * 4 || (stride % 4)) {
+ if (w <= 0 || h <= 0 || stride < w * 4 || (stride % 4)) {
MP_ERR(mpctx, "overlay_add: inconsistent parameters\n");
goto error;
}
struct overlay overlay = {
- .osd = {
- .stride = stride,
- .x = x, .y = y,
- .w = w, .h = h,
- .dw = w, .dh = h,
- },
+ .source = mp_image_alloc(IMGFMT_BGRA, w, h),
+ .x = x,
+ .y = y,
};
+ if (!overlay.source)
+ goto error;
int fd = -1;
bool close_fd = true;
void *p = NULL;
@@ -4398,21 +4457,25 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
} else {
fd = open(file, O_RDONLY | O_BINARY | O_CLOEXEC);
}
+ int map_size = 0;
if (fd >= 0) {
- overlay.map_size = offset + h * stride;
- void *m = mmap(NULL, overlay.map_size, PROT_READ, MAP_SHARED, fd, 0);
+ map_size = offset + h * stride;
+ void *m = mmap(NULL, map_size, PROT_READ, MAP_SHARED, fd, 0);
if (close_fd)
close(fd);
- if (m && m != MAP_FAILED) {
- overlay.map_start = m;
+ if (m && m != MAP_FAILED)
p = m;
- }
}
if (!p) {
MP_ERR(mpctx, "overlay_add: could not open or map '%s'\n", file);
+ talloc_free(overlay.source);
goto error;
}
- overlay.osd.bitmap = (char *)p + offset;
+ memcpy_pic(overlay.source->planes[0], (char *)p + offset, w * 4, h,
+ overlay.source->stride[0], stride);
+ if (map_size)
+ munmap(p, map_size);
+
replace_overlay(mpctx, id, &overlay);
r = 0;
error:
@@ -4434,6 +4497,8 @@ static void overlay_uninit(struct MPContext *mpctx)
for (int id = 0; id < cmd->num_overlays; id++)
overlay_remove(mpctx, id);
osd_set_external2(mpctx->osd, NULL);
+ for (int n = 0; n < 2; n++)
+ mp_image_unrefp(&cmd->overlay_osd[n].packed);
}
struct cycle_counter {