screenshot: add osd and scaled flags to screenshot commands

Currently, screenshot being scaled and the presence of OSD and subtitles
cannot be independently controlled. This adds osd and scaled flags to
screenshot commands that make it possible to e.g. take screenshots with
only OSD without subtitles, or take screenshots at scaled resolution
without OSD or subtitles.

The "window" flag is now an alias of scaled+subtitles+osd, and is kept
for convenience.
This commit is contained in:
nanahi
2025-10-05 13:00:01 -04:00
committed by Kacper Michajłow
parent be5e606377
commit d89add6eb2
4 changed files with 51 additions and 31 deletions

View File

@@ -0,0 +1 @@
add `scaled` and `osd` flags to screenshot commands

View File

@@ -1419,16 +1419,21 @@ Screenshot Commands
Multiple flags are available (some can be combined with ``+``):
<video>
Save the video image in its original resolution, without OSD or
subtitles. This is the default when no flag is specified, and it does
not need to be explicitly added when combined with other flags.
<scaled>
Save the video image in the current playback resolution.
<subtitles> (default)
Save the video image, in its original resolution, and with subtitles.
Save the video image with subtitles.
Some video outputs may still include the OSD in the output under certain
circumstances.
<video>
Like ``subtitles``, but typically without OSD or subtitles. The exact
behavior depends on the selected video output.
<osd>
Save the video image with OSD.
<window>
Save the contents of the mpv window. Typically scaled, with OSD and
subtitles. The exact behavior depends on the selected video output.
Save the contents of the mpv window, with OSD and subtitles.
This is an alias of ``scaled+subtitles+osd``.
<each-frame>
Take a screenshot each frame. Issue this command again to stop taking
screenshots. Note that you should disable frame-dropping when using
@@ -1436,6 +1441,9 @@ Screenshot Commands
frame was dropped. This flag can be combined with the other flags,
e.g. ``video+each-frame``.
The exact behaviors of all flags other than ``each-frame`` depend on the
selected video output.
Older mpv versions required passing ``single`` and ``each-frame`` as
second argument (and did not have flags). This syntax is still understood,
but deprecated and might be removed in the future.

View File

@@ -7347,11 +7347,14 @@ const struct mp_cmd_def mp_cmds[] = {
{ "screenshot", cmd_screenshot,
{
{"flags", OPT_FLAGS(v.i,
{"video", 4|0}, {"-", 4|0},
{"window", 4|1},
{"subtitles", 4|2},
{"each-frame", 8}),
OPTDEF_INT(4|2)},
{"video", 0},
{"scaled", 1},
{"subtitles", 2},
{"osd", 4},
{"each-frame", 8},
{"-", 0},
{"window", 1|2|4}),
OPTDEF_INT(2)},
// backwards compatibility
{"legacy", OPT_CHOICE(v.i,
{"unused", 0}, {"single", 0},
@@ -7365,8 +7368,10 @@ const struct mp_cmd_def mp_cmds[] = {
{"filename", OPT_STRING(v.s)},
{"flags", OPT_CHOICE(v.i,
{"video", 0},
{"window", 1},
{"subtitles", 2}),
{"scaled", 1},
{"subtitles", 2},
{"osd", 4},
{"window", 1|2|4}),
OPTDEF_INT(2)},
},
.spawn_thread = true,
@@ -7375,8 +7380,10 @@ const struct mp_cmd_def mp_cmds[] = {
{
{"flags", OPT_CHOICE(v.i,
{"video", 0},
{"window", 1},
{"subtitles", 2}),
{"scaled", 1},
{"subtitles", 2},
{"osd", 4},
{"window", 1|2|4}),
OPTDEF_INT(2)},
{"format", OPT_CHOICE(v.i,
{"bgr0", 0},

View File

@@ -43,8 +43,9 @@
#include "video/csputils.h"
#define MODE_FULL_WINDOW 1
#define MODE_SCALED 1
#define MODE_SUBTITLES 2
#define MODE_OSD 4
typedef struct screenshot_ctx {
struct MPContext *mpctx;
@@ -324,14 +325,13 @@ static char *gen_fname(struct mp_cmd_ctx *cmd, const char *file_ext)
static void add_osd(struct MPContext *mpctx, struct mp_image *image, int mode)
{
bool window = mode == MODE_FULL_WINDOW;
struct mp_osd_res res = window ? osd_get_vo_res(mpctx->video_out->osd) :
struct mp_osd_res res = (mode & MODE_SCALED) ? osd_get_vo_res(mpctx->video_out->osd) :
osd_res_from_image_params(&image->params);
if (mode == MODE_SUBTITLES || window) {
if (mode & MODE_SUBTITLES) {
osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
OSD_DRAW_SUB_ONLY, image);
}
if (window) {
if (mode & MODE_OSD) {
osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
OSD_DRAW_OSD_ONLY, image);
}
@@ -342,8 +342,8 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
{
struct mp_image *image = NULL;
const struct image_writer_opts *imgopts = mpctx->opts->screenshot_image_opts;
if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd))
mode = 0;
if ((mode & MODE_SUBTITLES) && osd_get_render_subs_in_filter(mpctx->osd))
mode &= ~MODE_SUBTITLES;
if (!mpctx->video_out || !mpctx->video_out->config_ok)
return NULL;
@@ -351,11 +351,13 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
vo_wait_frame(mpctx->video_out); // important for each-frame mode
bool use_sw = mpctx->opts->screenshot_sw;
bool window = mode == MODE_FULL_WINDOW;
bool scaled = mode & MODE_SCALED;
bool subs = mode & MODE_SUBTITLES;
bool osd = mode & MODE_OSD;
struct voctrl_screenshot ctrl = {
.scaled = window,
.subs = mode != 0,
.osd = window,
.scaled = scaled,
.subs = subs,
.osd = osd,
.high_bit_depth = high_depth && imgopts->high_bit_depth,
.native_csp = image_writer_flexible_csp(imgopts),
};
@@ -363,7 +365,9 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &ctrl);
image = ctrl.res;
if (!use_sw && !image && window)
// VOCTRL_SCREENSHOT_WIN gets the complete rendered image so it's only
// usable for scaled+sub+osd screenshots.
if (!use_sw && !image && scaled && subs && osd)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image);
if (!image) {
@@ -381,7 +385,7 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
image = nimage;
}
if (use_sw && image && window) {
if (use_sw && image && scaled) {
if (mp_image_crop_valid(&image->params) &&
(mp_rect_w(image->params.crop) != image->w ||
mp_rect_h(image->params.crop) != image->h))
@@ -506,14 +510,14 @@ void cmd_screenshot(void *p)
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;
struct mpv_node *res = &cmd->result;
int mode = cmd->args[0].v.i & 3;
int mode = cmd->args[0].v.i & 7;
bool each_frame_toggle = (cmd->args[0].v.i | cmd->args[1].v.i) & 8;
bool each_frame_mode = cmd->args[0].v.i & 16;
screenshot_ctx *ctx = mpctx->screenshot_ctx;
if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd))
mode = 0;
if ((mode & MODE_SUBTITLES) && osd_get_render_subs_in_filter(mpctx->osd))
mode &= ~MODE_SUBTITLES;
if (!each_frame_mode) {
if (each_frame_toggle) {