From a3680d1b2d137461008d38486cdb2d5013291e61 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:11:03 +0200 Subject: [PATCH] client API: add a screenshot_raw command Requested. The wild code for setting up the mpv_node probably deserves to be cleaned up later. Fixes #1800. --- DOCS/man/input.rst | 9 +++++++++ input/cmd_list.c | 5 +++++ input/cmd_list.h | 1 + player/command.c | 39 +++++++++++++++++++++++++++++++++++++++ player/screenshot.c | 10 ++++++++++ player/screenshot.h | 3 +++ 6 files changed, 67 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 3c8c51e87b..e1c3a58421 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -631,6 +631,15 @@ Input Commands that are Possibly Subject to Change unseekable streams that are going out of sync. This command might be changed or removed in the future. +``screenshot_raw [subtitles|video|window]`` + Return a screenshot in memory. This can be used only through the client + API. The MPV_FORMAT_NODE_MAP returned by this command has the ``w``, ``h``, + ``stride`` fields set to obvious contents. A ``format`` field is set to + ``bgr0`` by default. This format is organized as ``B8G8R8X8`` (where ``B`` + is the LSB). The contents of the padding ``X`` is undefined. The ``data`` + field is of type MPV_FORMAT_BYTE_ARRAY with the actual image data. The image + is freed as soon as the result node is freed. + Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``get_property`` (deprecated), ``ao_reload`` (experimental/internal). diff --git a/input/cmd_list.c b/input/cmd_list.c index 9005121985..acd8ae72a1 100644 --- a/input/cmd_list.c +++ b/input/cmd_list.c @@ -119,6 +119,11 @@ const struct mp_cmd_def mp_cmds[] = { {"window", 1}, {"subtitles", 2})), }}, + { MP_CMD_SCREENSHOT_RAW, "screenshot_raw", { + OARG_CHOICE(2, ({"video", 0}, + {"window", 1}, + {"subtitles", 2})), + }}, { MP_CMD_LOADFILE, "loadfile", { ARG_STRING, OARG_CHOICE(0, ({"replace", 0}, diff --git a/input/cmd_list.h b/input/cmd_list.h index 52dc6426fa..e9418d4429 100644 --- a/input/cmd_list.h +++ b/input/cmd_list.h @@ -48,6 +48,7 @@ enum mp_command_type { MP_CMD_OSD, MP_CMD_SCREENSHOT, MP_CMD_SCREENSHOT_TO_FILE, + MP_CMD_SCREENSHOT_RAW, MP_CMD_LOADFILE, MP_CMD_LOADLIST, MP_CMD_PLAYLIST_CLEAR, diff --git a/player/command.c b/player/command.c index 376f2b6bed..d210398946 100644 --- a/player/command.c +++ b/player/command.c @@ -4040,6 +4040,22 @@ static bool check_property_autorepeat(char *property, struct MPContext *mpctx) return true; } +static struct mpv_node *add_map_entry(struct mpv_node *dst, const char *key) +{ + struct mpv_node_list *list = dst->u.list; + assert(dst->format == MPV_FORMAT_NODE_MAP && dst->u.list); + MP_TARRAY_GROW(list, list->values, list->num); + MP_TARRAY_GROW(list, list->keys, list->num); + list->keys[list->num] = talloc_strdup(list, key); + return &list->values[list->num++]; +} + +#define ADD_MAP_INT(dst, name, i) (*add_map_entry(dst, name) = \ + (struct mpv_node){ .format = MPV_FORMAT_INT64, .u.int64 = (i) }); + +#define ADD_MAP_CSTR(dst, name, s) (*add_map_entry(dst, name) = \ + (struct mpv_node){ .format = MPV_FORMAT_STRING, .u.string = (s) }); + int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res) { struct command_ctx *cmdctx = mpctx->command_ctx; @@ -4552,6 +4568,29 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, msg_osd); break; + case MP_CMD_SCREENSHOT_RAW: { + if (!res) + return -1; + struct mp_image *img = screenshot_get_rgb(mpctx, cmd->args[0].v.i); + if (!img) + return -1; + struct mpv_node_list *info = talloc_zero(NULL, struct mpv_node_list); + talloc_steal(info, img); + *res = (mpv_node){ .format = MPV_FORMAT_NODE_MAP, .u.list = info }; + ADD_MAP_INT(res, "w", img->w); + ADD_MAP_INT(res, "h", img->h); + ADD_MAP_INT(res, "stride", img->stride[0]); + ADD_MAP_CSTR(res, "format", "bgr0"); + struct mpv_byte_array *ba = talloc_ptrtype(info, ba); + *ba = (struct mpv_byte_array){ + .data = img->planes[0], + .size = img->stride[0] * img->h, + }; + *add_map_entry(res, "data") = + (struct mpv_node){.format = MPV_FORMAT_BYTE_ARRAY, .u.ba = ba,}; + break; + } + case MP_CMD_RUN: { char *args[MP_CMD_MAX_ARGS + 1] = {0}; for (int n = 0; n < cmd->nargs; n++) diff --git a/player/screenshot.c b/player/screenshot.c index f722b9561f..a47de292d5 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -357,6 +357,16 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode) return image; } +struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode) +{ + struct mp_image *mpi = screenshot_get(mpctx, mode); + if (!mpi) + return NULL; + struct mp_image *res = convert_image(mpi, IMGFMT_BGR0, mpctx->log); + talloc_free(mpi); + return res; +} + void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, bool osd) { diff --git a/player/screenshot.h b/player/screenshot.h index 84b7ef4f58..9ebe9ef76e 100644 --- a/player/screenshot.h +++ b/player/screenshot.h @@ -39,6 +39,9 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame, void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, bool osd); +// mode is the same as in screenshot_request() +struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode); + // Called by the playback core code when a new frame is displayed. void screenshot_flip(struct MPContext *mpctx);