mirror of https://github.com/mpv-player/mpv
vf_screenshot: simplify
Instead of using a callback to "capture" the image next time the filter function is called, do it the other way around: on every filter invocation, create a reference to the image, and return it if a screenshot is requested. This also fixes the 1-frame delay when taking screenshots with the filter. This also allows simplifying screenshot.c.
This commit is contained in:
parent
b7cacf9165
commit
6e0b730044
|
@ -48,7 +48,6 @@ typedef struct screenshot_ctx {
|
|||
|
||||
int mode;
|
||||
int each_frame;
|
||||
int using_vf_screenshot;
|
||||
|
||||
int frameno;
|
||||
} screenshot_ctx;
|
||||
|
@ -234,16 +233,9 @@ static char *gen_fname(screenshot_ctx *ctx, const char *file_ext)
|
|||
}
|
||||
}
|
||||
|
||||
static struct mp_image *add_subs(struct MPContext *mpctx,
|
||||
struct mp_image *image)
|
||||
static void add_subs(struct MPContext *mpctx, struct mp_image *image)
|
||||
{
|
||||
if (!(image->flags & MP_IMGFLAG_ALLOCATED)) {
|
||||
struct mp_image *new_image = alloc_mpi(image->w, image->h,
|
||||
image->imgfmt);
|
||||
copy_mpi(new_image, image);
|
||||
vf_clone_mpi_attributes(new_image, image);
|
||||
image = new_image;
|
||||
}
|
||||
mp_image_make_writeable(image);
|
||||
|
||||
int d_w = image->display_w ? image->display_w : image->w;
|
||||
int d_h = image->display_h ? image->display_h : image->h;
|
||||
|
@ -259,8 +251,6 @@ static struct mp_image *add_subs(struct MPContext *mpctx,
|
|||
|
||||
osd_draw_on_image(mpctx->osd, res, mpctx->osd->vo_pts,
|
||||
OSD_DRAW_SUB_ONLY, image);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static void screenshot_save(struct MPContext *mpctx, struct mp_image *image,
|
||||
|
@ -270,31 +260,18 @@ static void screenshot_save(struct MPContext *mpctx, struct mp_image *image,
|
|||
|
||||
struct image_writer_opts *opts = mpctx->opts.screenshot_image_opts;
|
||||
|
||||
struct mp_image *new_image = image;
|
||||
if (with_subs)
|
||||
new_image = add_subs(mpctx, new_image);
|
||||
add_subs(mpctx, image);
|
||||
|
||||
char *filename = gen_fname(ctx, image_writer_file_ext(opts));
|
||||
if (filename) {
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, "*** screenshot '%s' ***\n", filename);
|
||||
if (!write_image(new_image, opts, filename))
|
||||
if (!write_image(image, opts, filename))
|
||||
mp_msg(MSGT_CPLAYER, MSGL_ERR, "\nError writing screenshot!\n");
|
||||
talloc_free(filename);
|
||||
}
|
||||
|
||||
if (new_image != image)
|
||||
free_mp_image(new_image);
|
||||
}
|
||||
|
||||
static void vf_screenshot_callback(void *pctx, struct mp_image *image)
|
||||
{
|
||||
struct MPContext *mpctx = (struct MPContext *)pctx;
|
||||
screenshot_ctx *ctx = mpctx->screenshot_ctx;
|
||||
screenshot_save(mpctx, image, ctx->mode == MODE_SUBTITLES);
|
||||
if (ctx->each_frame) {
|
||||
ctx->each_frame = false;
|
||||
screenshot_request(mpctx, ctx->mode, true);
|
||||
}
|
||||
talloc_free(image);
|
||||
}
|
||||
|
||||
static bool force_vf(struct MPContext *mpctx)
|
||||
|
@ -315,7 +292,6 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame)
|
|||
if (mpctx->video_out && mpctx->video_out->config_ok) {
|
||||
screenshot_ctx *ctx = mpctx->screenshot_ctx;
|
||||
|
||||
ctx->using_vf_screenshot = 0;
|
||||
|
||||
if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter)
|
||||
mode = 0;
|
||||
|
@ -332,26 +308,24 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame)
|
|||
|
||||
struct voctrl_screenshot_args args =
|
||||
{ .full_window = (mode == MODE_FULL_WINDOW) };
|
||||
if (!force_vf(mpctx)
|
||||
&& vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args) == true)
|
||||
{
|
||||
|
||||
if (!force_vf(mpctx))
|
||||
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args);
|
||||
|
||||
if (!args.out_image) {
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, "No VO support for taking"
|
||||
" screenshots, trying VFCTRL_SCREENSHOT!\n");
|
||||
struct vf_instance *vfilter = mpctx->sh_video->vfilter;
|
||||
vfilter->control(vfilter, VFCTRL_SCREENSHOT, &args);
|
||||
}
|
||||
|
||||
if (args.out_image) {
|
||||
if (args.has_osd)
|
||||
mode = 0;
|
||||
screenshot_save(mpctx, args.out_image, mode == MODE_SUBTITLES);
|
||||
free_mp_image(args.out_image);
|
||||
} else {
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, "No VO support for taking"
|
||||
" screenshots, trying VFCTRL_SCREENSHOT!\n");
|
||||
ctx->using_vf_screenshot = 1;
|
||||
struct vf_ctrl_screenshot cmd = {
|
||||
.image_callback = vf_screenshot_callback,
|
||||
.image_callback_ctx = mpctx,
|
||||
};
|
||||
struct vf_instance *vfilter = mpctx->sh_video->vfilter;
|
||||
if (vfilter->control(vfilter, VFCTRL_SCREENSHOT, &cmd) !=
|
||||
CONTROL_OK)
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO,
|
||||
"...failed (need --vf=screenshot?)\n");
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO,
|
||||
"...failed (need --vf=screenshot?)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -363,13 +337,6 @@ void screenshot_flip(struct MPContext *mpctx)
|
|||
if (!ctx->each_frame)
|
||||
return;
|
||||
|
||||
// screenshot_flip is called when the VO presents a new frame. vf_screenshot
|
||||
// can behave completely different (consider filters inserted between
|
||||
// vf_screenshot and vf_vo, that add or remove frames), so handle this case
|
||||
// somewhere else.
|
||||
if (ctx->using_vf_screenshot)
|
||||
return;
|
||||
|
||||
ctx->each_frame = false;
|
||||
screenshot_request(mpctx, ctx->mode, true);
|
||||
}
|
||||
|
|
|
@ -86,19 +86,13 @@ typedef struct vf_seteq {
|
|||
int value;
|
||||
} vf_equalizer_t;
|
||||
|
||||
struct vf_ctrl_screenshot {
|
||||
// When the screenshot is complete, pass it to this callback.
|
||||
void (*image_callback)(void *, mp_image_t *);
|
||||
void *image_callback_ctx;
|
||||
};
|
||||
|
||||
#define VFCTRL_QUERY_MAX_PP_LEVEL 4 // query max postprocessing level (if any)
|
||||
#define VFCTRL_SET_PP_LEVEL 5 // set postprocessing level
|
||||
#define VFCTRL_SET_EQUALIZER 6 // set color options (brightness,contrast etc)
|
||||
#define VFCTRL_GET_EQUALIZER 8 // get color options (brightness,contrast etc)
|
||||
#define VFCTRL_HWDEC_DECODER_RENDER 9 // vdpau hw decoding
|
||||
#define VFCTRL_HWDEC_ALLOC_SURFACE 10 // vdpau hw decoding
|
||||
#define VFCTRL_SCREENSHOT 14 // Take screenshot, arg is vf_ctrl_screenshot
|
||||
#define VFCTRL_SCREENSHOT 14 // Take screenshot, arg is voctrl_screenshot_args
|
||||
#define VFCTRL_INIT_OSD 15 // Filter OSD renderer present?
|
||||
#define VFCTRL_SET_DEINTERLACE 18 // Set deinterlacing status
|
||||
#define VFCTRL_GET_DEINTERLACE 19 // Get deinterlacing status
|
||||
|
|
|
@ -23,29 +23,25 @@
|
|||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "core/mp_msg.h"
|
||||
#include "talloc.h"
|
||||
|
||||
#include "video/img_format.h"
|
||||
#include "video/mp_image.h"
|
||||
#include "vf.h"
|
||||
#include "video/sws_utils.h"
|
||||
#include "video/fmt-conversion.h"
|
||||
#include "video/memcpy_pic.h"
|
||||
#include "video/out/vo.h"
|
||||
|
||||
#include <libswscale/swscale.h>
|
||||
#include "vf.h"
|
||||
|
||||
struct vf_priv_s {
|
||||
int display_w, display_h;
|
||||
void (*image_callback)(void *, mp_image_t *);
|
||||
void *image_callback_ctx;
|
||||
int shot;
|
||||
struct mp_image *current;
|
||||
};
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
static int config(struct vf_instance *vf,
|
||||
int width, int height, int d_width, int d_height,
|
||||
unsigned int flags, unsigned int outfmt)
|
||||
{
|
||||
mp_image_unrefp(&vf->priv->current);
|
||||
vf->priv->display_w = d_width;
|
||||
vf->priv->display_h = d_height;
|
||||
return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
|
||||
|
@ -53,57 +49,37 @@ static int config(struct vf_instance *vf,
|
|||
|
||||
static struct mp_image *filter(struct vf_instance *vf, struct mp_image *mpi)
|
||||
{
|
||||
if(vf->priv->shot) {
|
||||
vf->priv->shot=0;
|
||||
mp_image_t image = *mpi;
|
||||
image.flags &= ~MP_IMGFLAG_ALLOCATED;
|
||||
mp_image_copy_attributes(&image, mpi);
|
||||
mp_image_set_display_size(&image, vf->priv->display_w,
|
||||
vf->priv->display_h);
|
||||
vf->priv->image_callback(vf->priv->image_callback_ctx, &image);
|
||||
}
|
||||
|
||||
mp_image_unrefp(&vf->priv->current);
|
||||
vf->priv->current = talloc_steal(vf, mp_image_new_ref(mpi));
|
||||
mp_image_set_display_size(vf->priv->current, vf->priv->display_w,
|
||||
vf->priv->display_h);
|
||||
return mpi;
|
||||
}
|
||||
|
||||
static int control (vf_instance_t *vf, int request, void *data)
|
||||
{
|
||||
if(request==VFCTRL_SCREENSHOT) {
|
||||
struct vf_ctrl_screenshot *cmd = (struct vf_ctrl_screenshot *)data;
|
||||
vf->priv->image_callback = cmd->image_callback;
|
||||
vf->priv->image_callback_ctx = cmd->image_callback_ctx;
|
||||
vf->priv->shot=1;
|
||||
if (request == VFCTRL_SCREENSHOT && vf->priv->current) {
|
||||
struct voctrl_screenshot_args *args = data;
|
||||
args->out_image = mp_image_new_ref(vf->priv->current);
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return vf_next_control (vf, request, data);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
static int query_format(struct vf_instance *vf, unsigned int fmt)
|
||||
{
|
||||
enum PixelFormat av_format = imgfmt2pixfmt(fmt);
|
||||
|
||||
if (av_format != PIX_FMT_NONE && sws_isSupportedInput(av_format))
|
||||
if (mp_sws_supported_format(fmt))
|
||||
return vf_next_query_format(vf, fmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uninit(vf_instance_t *vf)
|
||||
{
|
||||
free(vf->priv);
|
||||
}
|
||||
|
||||
static int vf_open(vf_instance_t *vf, char *args)
|
||||
{
|
||||
vf->config=config;
|
||||
vf->control=control;
|
||||
vf->filter=filter;
|
||||
vf->query_format=query_format;
|
||||
vf->uninit=uninit;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
vf->priv->shot=0;
|
||||
vf->config = config;
|
||||
vf->control = control;
|
||||
vf->filter = filter;
|
||||
vf->query_format = query_format;
|
||||
vf->priv = talloc_zero(vf, struct vf_priv_s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -126,5 +102,3 @@ const vf_info_t vf_info_screenshot_force = {
|
|||
vf_open,
|
||||
NULL
|
||||
};
|
||||
|
||||
//===========================================================================//
|
||||
|
|
Loading…
Reference in New Issue