summaryrefslogtreecommitdiffstats
path: root/player/screenshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/screenshot.c')
-rw-r--r--player/screenshot.c132
1 files changed, 95 insertions, 37 deletions
diff --git a/player/screenshot.c b/player/screenshot.c
index e731e02e21..aa637e6e63 100644
--- a/player/screenshot.c
+++ b/player/screenshot.c
@@ -19,8 +19,9 @@
#include <string.h>
#include <time.h>
-#include "config.h"
+#include <libavcodec/avcodec.h>
+#include "common/global.h"
#include "osdep/io.h"
#include "mpv_talloc.h"
@@ -48,6 +49,7 @@
typedef struct screenshot_ctx {
struct MPContext *mpctx;
+ struct mp_log *log;
// Command to repeat in each-frame mode.
struct mp_cmd *each_frame;
@@ -62,6 +64,7 @@ void screenshot_init(struct MPContext *mpctx)
*mpctx->screenshot_ctx = (screenshot_ctx) {
.mpctx = mpctx,
.frameno = 1,
+ .log = mp_log_new(mpctx, mpctx->log, "screenshot")
};
}
@@ -74,7 +77,8 @@ static char *stripext(void *talloc_ctx, const char *s)
}
static bool write_screenshot(struct mp_cmd_ctx *cmd, struct mp_image *img,
- const char *filename, struct image_writer_opts *opts)
+ const char *filename, struct image_writer_opts *opts,
+ bool overwrite)
{
struct MPContext *mpctx = cmd->mpctx;
struct image_writer_opts *gopts = mpctx->opts->screenshot_image_opts;
@@ -85,7 +89,7 @@ static bool write_screenshot(struct mp_cmd_ctx *cmd, struct mp_image *img,
mp_core_unlock(mpctx);
bool ok = img && write_image(img, &opts_copy, filename, mpctx->global,
- mpctx->log);
+ mpctx->screenshot_ctx->log, overwrite);
mp_core_lock(mpctx);
@@ -163,7 +167,7 @@ static char *create_fname(struct MPContext *mpctx, char *template,
goto error_exit;
char fmtstr[] = {'%', '0', digits, 'd', '\0'};
res = talloc_asprintf_append(res, fmtstr, *frameno);
- if (*frameno < 100000 - 1) {
+ if (*frameno < INT_MAX - 1) {
(*frameno) += 1;
(*sequence) += 1;
}
@@ -291,7 +295,7 @@ static char *gen_fname(struct mp_cmd_ctx *cmd, const char *file_ext)
return NULL;
}
- char *dir = ctx->mpctx->opts->screenshot_directory;
+ char *dir = ctx->mpctx->opts->screenshot_dir;
if (dir && dir[0]) {
void *t = fname;
dir = mp_get_user_path(t, ctx->mpctx->global, dir);
@@ -321,53 +325,101 @@ static char *gen_fname(struct mp_cmd_ctx *cmd, const char *file_ext)
}
}
-static void add_subs(struct MPContext *mpctx, struct mp_image *image)
+static void add_osd(struct MPContext *mpctx, struct mp_image *image, int mode)
{
- struct mp_osd_res res = osd_res_from_image_params(&image->params);
- osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
- OSD_DRAW_SUB_ONLY, image);
+ bool window = mode == MODE_FULL_WINDOW;
+ struct mp_osd_res res = window ? osd_get_vo_res(mpctx->video_out->osd) :
+ osd_res_from_image_params(&image->params);
+ if (mode == MODE_SUBTITLES || window) {
+ osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
+ OSD_DRAW_SUB_ONLY, image);
+ }
+ if (window) {
+ osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
+ OSD_DRAW_OSD_ONLY, image);
+ }
}
static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
bool high_depth)
{
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;
- bool need_add_subs = mode == MODE_SUBTITLES;
-
- if (mpctx->video_out && mpctx->video_out->config_ok) {
- vo_wait_frame(mpctx->video_out); // important for each-frame mode
-
- struct voctrl_screenshot ctrl = {
- .scaled = mode == MODE_FULL_WINDOW,
- .subs = mode != 0,
- .osd = mode == MODE_FULL_WINDOW,
- .high_bit_depth = high_depth &&
- mpctx->opts->screenshot_image_opts->high_bit_depth,
- };
+
+ if (!mpctx->video_out || !mpctx->video_out->config_ok)
+ return NULL;
+
+ vo_wait_frame(mpctx->video_out); // important for each-frame mode
+
+ bool use_sw = mpctx->opts->screenshot_sw;
+ bool window = mode == MODE_FULL_WINDOW;
+ struct voctrl_screenshot ctrl = {
+ .scaled = window,
+ .subs = mode != 0,
+ .osd = window,
+ .high_bit_depth = high_depth && imgopts->high_bit_depth,
+ .native_csp = image_writer_flexible_csp(imgopts),
+ };
+ if (!use_sw)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &ctrl);
- image = ctrl.res;
- if (image)
- need_add_subs = false;
-
- if (!image && mode != MODE_FULL_WINDOW)
- image = vo_get_current_frame(mpctx->video_out);
- if (!image) {
- vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image);
- mode = MODE_FULL_WINDOW;
- }
+ image = ctrl.res;
+
+ if (!use_sw && !image && window)
+ vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image);
+
+ if (!image) {
+ use_sw = true;
+ MP_VERBOSE(mpctx->screenshot_ctx, "Falling back to software screenshot.\n");
+ image = vo_get_current_frame(mpctx->video_out);
}
- if (image && (image->fmt.flags & MP_IMGFLAG_HWACCEL)) {
+ // vo_get_current_frame() can return a hardware frame, which we have to download first.
+ if (image && image->fmt.flags & MP_IMGFLAG_HWACCEL) {
struct mp_image *nimage = mp_image_hw_download(image, NULL);
talloc_free(image);
+ if (!nimage)
+ return NULL;
image = nimage;
}
- if (image && need_add_subs)
- add_subs(mpctx, image);
+ if (use_sw && image && window) {
+ if (mp_image_crop_valid(&image->params) &&
+ (mp_rect_w(image->params.crop) != image->w ||
+ mp_rect_h(image->params.crop) != image->h))
+ {
+ struct mp_image *nimage = mp_image_new_ref(image);
+ if (!nimage) {
+ MP_ERR(mpctx->screenshot_ctx, "mp_image_new_ref failed!\n");
+ return NULL;
+ }
+ mp_image_crop_rc(nimage, image->params.crop);
+ talloc_free(image);
+ image = nimage;
+ }
+ struct mp_osd_res res = osd_get_vo_res(mpctx->video_out->osd);
+ struct mp_osd_res image_res = osd_res_from_image_params(&image->params);
+ if (!osd_res_equals(res, image_res)) {
+ struct mp_image *nimage = mp_image_alloc(image->imgfmt, res.w, res.h);
+ if (!nimage) {
+ talloc_free(image);
+ return NULL;
+ }
+ struct mp_sws_context *sws = mp_sws_alloc(NULL);
+ mp_sws_scale(sws, nimage, image);
+ talloc_free(image);
+ talloc_free(sws);
+ image = nimage;
+ }
+ }
+ if (!image)
+ return NULL;
+
+ if (use_sw && mode != 0)
+ add_osd(mpctx, image, mode);
+ mp_image_params_guess_csp(&image->params);
return image;
}
@@ -445,7 +497,7 @@ void cmd_screenshot_to_file(void *p)
cmd->success = false;
return;
}
- cmd->success = write_screenshot(cmd, image, filename, &opts);
+ cmd->success = write_screenshot(cmd, image, filename, &opts, true);
talloc_free(image);
}
@@ -453,6 +505,7 @@ 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;
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;
@@ -484,8 +537,13 @@ void cmd_screenshot(void *p)
if (image) {
char *filename = gen_fname(cmd, image_writer_file_ext(opts));
- if (filename)
- cmd->success = write_screenshot(cmd, image, filename, NULL);
+ if (filename) {
+ cmd->success = write_screenshot(cmd, image, filename, NULL, false);
+ if (cmd->success) {
+ node_init(res, MPV_FORMAT_NODE_MAP, NULL);
+ node_map_add_string(res, "filename", filename);
+ }
+ }
talloc_free(filename);
} else {
mp_cmd_msg(cmd, MSGL_ERR, "Taking screenshot failed.");