summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-09-30 22:27:37 +0200
committerwm4 <wm4@nowhere>2013-10-05 22:46:55 +0200
commitae9a3e33aafaa0d708d54e2c42a563e45dadb0f7 (patch)
treedcdd7a4ee2e1b6456c69b02a90a15fad410fbff3
parentfd49edccf811de0d6c61f30d8b2b524f8df93b36 (diff)
downloadmpv-ae9a3e33aafaa0d708d54e2c42a563e45dadb0f7.tar.bz2
mpv-ae9a3e33aafaa0d708d54e2c42a563e45dadb0f7.tar.xz
command: add commands for displaying overlays
Requested by github issue #255. Does not work where mmap is not available (i.e. Windows).
-rw-r--r--DOCS/man/en/input.rst71
-rw-r--r--mpvcore/command.c141
-rw-r--r--mpvcore/command.h1
-rw-r--r--mpvcore/input/input.c5
-rw-r--r--mpvcore/input/input.h3
-rw-r--r--mpvcore/mplayer.c2
-rw-r--r--sub/sub.c5
-rw-r--r--sub/sub.h3
8 files changed, 227 insertions, 4 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
index a0014c51bd..c2ba45a61c 100644
--- a/DOCS/man/en/input.rst
+++ b/DOCS/man/en/input.rst
@@ -325,6 +325,77 @@ Input Commands that are Possibly Subject to Change
``disable_section "<section>"``
Disable the named input section. Undoes ``enable_section``.
+``overlay_add <id> <x> <y> "<file>" <offset> "<fmt>" <w> <h> <stride>``
+ Add an OSD overlay sourced from raw data. This might be useful for scripts
+ and applications controlling mpv, and which want to display things on top
+ of the video window.
+
+ Overlays are usually displayed in screen resolution, but with some VOs,
+ 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.)
+
+ ``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.)
+
+ ``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).
+
+ ``offset`` is the offset of the first pixel in the source file. It is
+ passed directly to ``mmap`` and is subject to certain restrictions
+ (see ``man mmap`` for details). In particular, this value has to be a
+ multiple of the system's page size.
+
+ ``fmt`` is a string identifying the image format. Currently, only ``bgra``
+ is defined. This format has 4 bytes per pixels, with 8 bits per component.
+ The least significant 8 bits are blue, and the most significant 8 bits
+ are alpha (in little endian, the components are B-G-R-A, with B as first
+ byte). This uses premultiplied alpha: every color component is already
+ multiplied with the alpha component. This means the numeric value of each
+ component is equal to or smaller than the alpha component. (Violating this
+ rule will lead to different results with different VOs: numeric overflows
+ resulting from blending broken alpha values is considered something that
+ shouldn't happen, and consequently implementations don't ensure that you
+ get predictable behavior in this case.)
+
+ ``w``, ``h``, and ``stride`` specify the size of the overlay. ``w`` is the
+ visible width of the overlay, while ``stride`` gives the width in bytes in
+ memory. In the simple case, and with the ``bgra`` format, ``stride==4*w``.
+ In general, the total amount of memory accessed is ``stride * h``.
+ (Technically, the minimum size would be ``stride * (h - 1) + w * 4``, but
+ for simplicity, the player will access all ``stride * h`` bytes.)
+
+ .. admonition:: Warning
+
+ 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.
+
+``overlay_remove <id>``
+ Remove an overlay added with ``overlay_add`` and the same ID. Does nothing
+ if no overlay with this ID exists.
+
Undocumented commands: ``tv_start_scan``, ``tv_step_channel``, ``tv_step_norm``,
``tv_step_chanlist``, ``tv_set_channel``, ``tv_last_channel``, ``tv_set_freq``,
``tv_step_freq``, ``tv_set_norm``, ``dvb_set_channel``, ``radio_step_channel``,
diff --git a/mpvcore/command.c b/mpvcore/command.c
index e1c7e6e79e..038e58bc8d 100644
--- a/mpvcore/command.c
+++ b/mpvcore/command.c
@@ -65,11 +65,21 @@
#include "stream/stream_dvd.h"
#endif
#include "screenshot.h"
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
#include "mpvcore/mp_core.h"
#include "mp_lua.h"
+struct command_ctx {
+ int events;
+
+#define OVERLAY_MAX_ID 64
+ void *overlay_map[OVERLAY_MAX_ID];
+};
+
static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
const char *cmd, const char *arg);
static int set_filters(struct MPContext *mpctx, enum stream_type mediatype,
@@ -2227,6 +2237,113 @@ static int edit_filters_osd(struct MPContext *mpctx, enum stream_type mediatype,
return r;
}
+#ifdef HAVE_SYS_MMAN_H
+
+static int ext2_sub_find(struct MPContext *mpctx, int id)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct sub_bitmaps *sub = &mpctx->osd->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 osd_state *osd = mpctx->osd;
+ struct sub_bitmaps *sub = &osd->external2;
+ struct sub_bitmap b = {0};
+ MP_TARRAY_APPEND(osd, sub->parts, sub->num_parts, b);
+ return sub->num_parts - 1;
+}
+
+static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
+ char *file, int offset, char *fmt, int w, int h,
+ int stride)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct osd_state *osd = mpctx->osd;
+ if (strcmp(fmt, "bgra") != 0) {
+ MP_ERR(mpctx, "overlay_add: unsupported OSD format '%s'\n", fmt);
+ return -1;
+ }
+ if (id < 0 || id >= OVERLAY_MAX_ID) {
+ MP_ERR(mpctx, "overlay_add: invalid id %d\n", id);
+ return -1;
+ }
+ int fd = -1;
+ bool close_fd = true;
+ if (file[0] == '@') {
+ char *end;
+ fd = strtol(&file[1], &end, 10);
+ if (!file[1] || end[0])
+ fd = -1;
+ close_fd = false;
+ } else {
+ fd = open(file, O_RDONLY | O_BINARY);
+ }
+ void *p = mmap(NULL, h * stride, PROT_READ, MAP_SHARED, fd, offset);
+ if (fd >= 0 && close_fd)
+ close(fd);
+ if (!p) {
+ MP_ERR(mpctx, "overlay_add: could not open or map '%s'\n", file);
+ return -1;
+ }
+ int index = ext2_sub_find(mpctx, id);
+ if (index < 0)
+ index = ext2_sub_alloc(mpctx);
+ if (index < 0) {
+ munmap(p, h * stride);
+ return -1;
+ }
+ cmd->overlay_map[id] = p;
+ osd->external2.parts[index] = (struct sub_bitmap) {
+ .bitmap = p,
+ .stride = stride,
+ .x = x, .y = y,
+ .w = w, .h = h,
+ .dw = w, .dh = h,
+ };
+ osd->external2.bitmap_id = osd->external2.bitmap_pos_id = 1;
+ osd->external2.format = SUBBITMAP_RGBA;
+ osd->want_redraw = true;
+ return 0;
+}
+
+static void overlay_remove(struct MPContext *mpctx, int id)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct osd_state *osd = mpctx->osd;
+ int index = ext2_sub_find(mpctx, id);
+ if (index >= 0) {
+ struct sub_bitmaps *sub = &osd->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;
+ }
+}
+
+static void overlay_uninit(struct MPContext *mpctx)
+{
+ for (int id = 0; id < OVERLAY_MAX_ID; id++)
+ overlay_remove(mpctx, id);
+}
+
+#else
+
+static void overlay_uninit(struct MPContext *mpctx){}
+
+#endif
+
void run_command(MPContext *mpctx, mp_cmd_t *cmd)
{
struct MPOpts *opts = mpctx->opts;
@@ -2775,6 +2892,19 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
break;
+#ifdef HAVE_SYS_MMAN_H
+ case MP_CMD_OVERLAY_ADD:
+ overlay_add(mpctx,
+ cmd->args[0].v.i, cmd->args[1].v.i, cmd->args[2].v.i,
+ cmd->args[3].v.s, cmd->args[4].v.i, cmd->args[5].v.s,
+ cmd->args[6].v.i, cmd->args[7].v.i, cmd->args[8].v.i);
+ break;
+
+ case MP_CMD_OVERLAY_REMOVE:
+ overlay_remove(mpctx, cmd->args[0].v.i);
+ break;
+#endif
+
case MP_CMD_COMMAND_LIST: {
for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
run_command(mpctx, sub);
@@ -2802,13 +2932,16 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
}
-struct command_ctx {
- int events;
-};
+void command_uninit(struct MPContext *mpctx)
+{
+ overlay_uninit(mpctx);
+ talloc_free(mpctx->command_ctx);
+ mpctx->command_ctx = NULL;
+}
void command_init(struct MPContext *mpctx)
{
- mpctx->command_ctx = talloc_zero(mpctx, struct command_ctx);
+ mpctx->command_ctx = talloc_zero(NULL, struct command_ctx);
}
// Notify that a property might have changed.
diff --git a/mpvcore/command.h b/mpvcore/command.h
index dfdc066ac7..d3469fc131 100644
--- a/mpvcore/command.h
+++ b/mpvcore/command.h
@@ -23,6 +23,7 @@ struct MPContext;
struct mp_cmd;
void command_init(struct MPContext *mpctx);
+void command_uninit(struct MPContext *mpctx);
void run_command(struct MPContext *mpctx, struct mp_cmd *cmd);
char *mp_property_expand_string(struct MPContext *mpctx, const char *str);
diff --git a/mpvcore/input/input.c b/mpvcore/input/input.c
index c78447c4bf..4ce7fe0156 100644
--- a/mpvcore/input/input.c
+++ b/mpvcore/input/input.c
@@ -232,6 +232,11 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_SCRIPT_DISPATCH, "script_dispatch", { ARG_STRING, ARG_INT } },
+ { MP_CMD_OVERLAY_ADD, "overlay_add",
+ { ARG_INT, ARG_INT, ARG_INT, ARG_STRING, ARG_INT, ARG_STRING, ARG_INT,
+ ARG_INT, ARG_INT }},
+ { MP_CMD_OVERLAY_REMOVE, "overlay_remove", { ARG_INT } },
+
{0}
};
diff --git a/mpvcore/input/input.h b/mpvcore/input/input.h
index 33c269c1a7..dc308ff9f6 100644
--- a/mpvcore/input/input.h
+++ b/mpvcore/input/input.h
@@ -89,6 +89,9 @@ enum mp_command_type {
/// Internal for Lua scripts
MP_CMD_SCRIPT_DISPATCH,
+ MP_CMD_OVERLAY_ADD,
+ MP_CMD_OVERLAY_REMOVE,
+
// Internal
MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p
};
diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c
index b82e6a9e5d..4d3f24d057 100644
--- a/mpvcore/mplayer.c
+++ b/mpvcore/mplayer.c
@@ -563,6 +563,8 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx,
cocoa_set_input_context(NULL);
#endif
+ command_uninit(mpctx);
+
mp_input_uninit(mpctx->input);
osd_free(mpctx->osd);
diff --git a/sub/sub.c b/sub/sub.c
index cc4a76c065..9be61bd1d3 100644
--- a/sub/sub.c
+++ b/sub/sub.c
@@ -163,6 +163,11 @@ static void render_object(struct osd_state *osd, struct osd_object *obj,
sub_pts -= osd->video_offset - opts->sub_delay;
sub_get_bitmaps(osd->dec_sub, obj->vo_res, sub_pts, out_imgs);
}
+ } else if (obj->type == OSDTYPE_EXTERNAL2) {
+ if (osd->external2.format) {
+ *out_imgs = osd->external2;
+ osd->external2.bitmap_id = osd->external2.bitmap_pos_id = 0;
+ }
} else {
osd_object_get_bitmaps(osd, obj, out_imgs);
}
diff --git a/sub/sub.h b/sub/sub.h
index 1118fec5c1..64e10193ea 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -91,6 +91,7 @@ enum mp_osdtype {
OSDTYPE_OSD,
OSDTYPE_EXTERNAL,
+ OSDTYPE_EXTERNAL2,
MAX_OSD_PARTS
};
@@ -144,6 +145,8 @@ struct osd_state {
// OSDTYPE_EXTERNAL
char *external;
int external_res_x, external_res_y;
+ // OSDTYPE_EXTERNAL2
+ struct sub_bitmaps external2;
// OSDTYPE_SUB
struct dec_sub *dec_sub;