diff --git a/player/screenshot.c b/player/screenshot.c index 2a1aaf6746..702e2dd766 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -337,7 +337,7 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode) vo_wait_frame(mpctx->video_out); // important for each-frame mode if (mode != MODE_FULL_WINDOW) - vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &image); + image = vo_get_current_frame(mpctx->video_out); if (!image) { vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image); mode = MODE_FULL_WINDOW; diff --git a/video/mp_image.c b/video/mp_image.c index cf17429d89..269db4b2b0 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -252,6 +252,9 @@ void mp_image_steal_data(struct mp_image *dst, struct mp_image *src) // while img is left untouched. struct mp_image *mp_image_new_ref(struct mp_image *img) { + if (!img) + return NULL; + if (!img->refcount) return mp_image_new_copy(img); diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 2eeb86f353..bc1e04b0e6 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -2188,12 +2188,6 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } -struct mp_image *gl_video_download_image(struct gl_video *p) -{ - struct video_image *vimg = &p->image; - return vimg->mpi ? mp_image_new_ref(vimg->mpi) : NULL; -} - static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) { struct gl_video *p = ctx; diff --git a/video/out/gl_video.h b/video/out/gl_video.h index f62a292785..195ab40902 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -72,7 +72,6 @@ void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b); void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d); void gl_video_upload_image(struct gl_video *p, struct mp_image *img); void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t); -struct mp_image *gl_video_download_image(struct gl_video *p); void gl_video_resize(struct gl_video *p, struct mp_rect *window, struct mp_rect *src, struct mp_rect *dst, struct mp_osd_res *osd, bool vflip); diff --git a/video/out/vo.c b/video/out/vo.c index 36bd2a9c2e..11690afb67 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -135,7 +135,8 @@ struct vo_internal { int64_t drop_count; bool dropped_frame; // the previous frame was dropped - struct mp_image *dropped_image; // used to possibly redraw the dropped frame + + struct mp_image *current_frame; // last frame queued to the VO int64_t wakeup_pts; // time at which to pull frame from decoder @@ -333,6 +334,8 @@ static void run_reconfig(void *p) int flags = *(int *)pp[2]; int *ret = pp[3]; + struct vo_internal *in = vo->in; + vo->dwidth = params->d_w; vo->dheight = params->d_h; @@ -347,7 +350,11 @@ static void run_reconfig(void *p) talloc_free(vo->params); vo->params = NULL; } - forget_frames(vo); // implicitly synchronized + + pthread_mutex_lock(&in->lock); + mp_image_unrefp(&in->current_frame); + forget_frames(vo); + pthread_mutex_unlock(&in->lock); update_display_fps(vo); } @@ -388,7 +395,7 @@ static void forget_frames(struct vo *vo) in->hasframe_rendered = false; in->drop_count = 0; mp_image_unrefp(&in->frame_queued); - mp_image_unrefp(&in->dropped_image); + // don't unref current_frame; we always want to be able to redraw it } #ifndef __MINGW32__ @@ -555,7 +562,8 @@ static bool render_frame(struct vo *vo) if (in->vsync_timed && !in->hasframe) goto nothing_done; - mp_image_unrefp(&in->dropped_image); + if (img) + mp_image_setrefp(&in->current_frame, img); in->rendering = true; in->frame_queued = NULL; @@ -598,7 +606,7 @@ static bool render_frame(struct vo *vo) } if (in->dropped_frame) { - in->dropped_image = img; + talloc_free(img); } else { in->hasframe_rendered = true; pthread_mutex_unlock(&in->lock); @@ -679,20 +687,21 @@ static void do_redraw(struct vo *vo) pthread_mutex_lock(&in->lock); in->request_redraw = false; in->want_redraw = false; - bool skip = !in->paused && in->dropped_frame; - struct mp_image *img = in->dropped_image; - if (!skip) { - in->dropped_image = NULL; + bool force_full_redraw = in->dropped_frame; + struct mp_image *img = NULL; + if (vo->config_ok) + img = mp_image_new_ref(in->current_frame); + if (img) in->dropped_frame = false; - } pthread_mutex_unlock(&in->lock); - if (!vo->config_ok || skip) + if (!img) return; - if (img) { + if (force_full_redraw) { vo->driver->draw_image(vo, img); } else { + talloc_free(img); if (vo->driver->control(vo, VOCTRL_REDRAW_FRAME, NULL) < 1) return; } @@ -749,6 +758,7 @@ static void *vo_thread(void *ptr) wait_vo(vo, wait_until); } forget_frames(vo); // implicitly synchronized + mp_image_unrefp(&in->current_frame); vo->driver->uninit(vo); return NULL; } @@ -920,6 +930,15 @@ int vo_query_and_reset_events(struct vo *vo, int events) return r; } +struct mp_image *vo_get_current_frame(struct vo *vo) +{ + struct vo_internal *in = vo->in; + pthread_mutex_lock(&in->lock); + struct mp_image *r = mp_image_new_ref(vo->in->current_frame); + pthread_mutex_unlock(&in->lock); + return r; +} + /** * \brief lookup an integer in a table, table must have 0 as the last key * \param key key to search for diff --git a/video/out/vo.h b/video/out/vo.h index 9ae489e2cd..e5eccd3f86 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -97,9 +97,7 @@ enum mp_voctrl { // imgfmt/w/h/d_w/d_h can be omitted for convenience. VOCTRL_GET_COLORSPACE, // struct mp_image_params* - // Retrieve original image. - VOCTRL_SCREENSHOT, // struct mp_image** - // Retrieve window contents. + // Retrieve window contents. (Normal screenshots use vo_get_current_frame().) VOCTRL_SCREENSHOT_WIN, // struct mp_image** VOCTRL_SET_COMMAND_LINE, // char** @@ -319,6 +317,7 @@ void vo_increment_drop_count(struct vo *vo, int64_t n); void vo_query_formats(struct vo *vo, uint8_t *list); void vo_event(struct vo *vo, int event); int vo_query_and_reset_events(struct vo *vo, int events); +struct mp_image *vo_get_current_frame(struct vo *vo); void vo_set_flip_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed); int64_t vo_get_vsync_interval(struct vo *vo); diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c index 5b4fb7856a..88eb619b8a 100644 --- a/video/out/vo_direct3d.c +++ b/video/out/vo_direct3d.c @@ -225,7 +225,6 @@ static void d3d_clear_video_textures(d3d_priv *priv); static bool resize_d3d(d3d_priv *priv); static void uninit(struct vo *vo); static void flip_page(struct vo *vo); -static mp_image_t *get_screenshot(d3d_priv *priv); static mp_image_t *get_window_screenshot(d3d_priv *priv); static void draw_osd(struct vo *vo); static bool change_d3d_backbuffer(d3d_priv *priv); @@ -1260,9 +1259,6 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_TRUE; case VOCTRL_GET_PANSCAN: return VO_TRUE; - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(priv); - return VO_TRUE; case VOCTRL_SCREENSHOT_WIN: *(struct mp_image **)data = get_window_screenshot(priv); return VO_TRUE; @@ -1445,29 +1441,6 @@ done: talloc_free(mpi); } -static mp_image_t *get_screenshot(d3d_priv *priv) -{ - if (!priv->d3d_device) - return NULL; - - if (!priv->have_image) - return NULL; - - if (!priv->vo->params) - return NULL; - - struct mp_image buffer; - if (!get_video_buffer(priv, &buffer)) - return NULL; - - struct mp_image *image = mp_image_new_copy(&buffer); - if (image) - mp_image_set_attributes(image, priv->vo->params); - - d3d_unlock_video_objects(priv); - return image; -} - static mp_image_t *get_window_screenshot(d3d_priv *priv) { D3DDISPLAYMODE mode; diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 618ed90aff..0cd8d49343 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -349,15 +349,10 @@ static int control(struct vo *vo, uint32_t request, void *data) mpgl_unlock(p->glctx); return VO_TRUE; case VOCTRL_SCREENSHOT_WIN: - case VOCTRL_SCREENSHOT: - { mpgl_lock(p->glctx); - *(struct mp_image **)data = request == VOCTRL_SCREENSHOT - ? gl_video_download_image(p->renderer) - : glGetWindowScreenshot(p->gl); + *(struct mp_image **)data = glGetWindowScreenshot(p->gl); mpgl_unlock(p->glctx); return true; - } case VOCTRL_GET_HWDEC_INFO: { struct mp_hwdec_info **arg = data; *arg = &p->hwdec_info; diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index a974305b85..cee0bc1d46 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -64,7 +64,6 @@ struct mpv_opengl_cb_context { mpv_opengl_cb_update_fn update_cb; void *update_cb_ctx; struct mp_image *waiting_frame; - struct mp_image *displayed_frame; struct mp_image **frame_queue; int queued_frames; struct mp_image_params img_params; @@ -358,7 +357,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) pthread_mutex_lock(&p->ctx->lock); mp_image_setrefp(&p->ctx->waiting_frame, mpi); - mp_image_setrefp(&p->ctx->displayed_frame, mpi); talloc_free(mpi); pthread_mutex_unlock(&p->ctx->lock); } @@ -488,12 +486,6 @@ static int control(struct vo *vo, uint32_t request, void *data) update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; - case VOCTRL_SCREENSHOT: { - pthread_mutex_lock(&p->ctx->lock); - *(struct mp_image **)data = mp_image_new_ref(p->ctx->displayed_frame); - pthread_mutex_unlock(&p->ctx->lock); - return VO_TRUE; - } case VOCTRL_SET_COMMAND_LINE: { char *arg = data; return reparse_cmdline(p, arg); @@ -514,7 +506,6 @@ static void uninit(struct vo *vo) pthread_mutex_lock(&p->ctx->lock); forget_frames(p->ctx); - mp_image_unrefp(&p->ctx->displayed_frame); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c index 9b7605643a..9a06f2e3c4 100644 --- a/video/out/vo_sdl.c +++ b/video/out/vo_sdl.c @@ -172,7 +172,6 @@ struct priv { SDL_Texture *tex; int tex_swapped; struct mp_image_params params; - mp_image_t *ssmpi; struct mp_rect src_rect; struct mp_rect dst_rect; struct mp_osd_res osd_res; @@ -638,7 +637,6 @@ static void uninit(struct vo *vo) { struct priv *vc = vo->priv; destroy_renderer(vo); - talloc_free(vc->ssmpi); SDL_QuitSubSystem(SDL_INIT_VIDEO); talloc_free(vc); } @@ -913,9 +911,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) mp_image_copy(&texmpi, mpi); SDL_UnlockTexture(vc->tex); - - talloc_free(vc->ssmpi); - vc->ssmpi = mpi; } SDL_Rect src, dst; @@ -941,12 +936,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) draw_osd(vo); } -static struct mp_image *get_screenshot(struct vo *vo) -{ - struct priv *vc = vo->priv; - return vc->ssmpi ? mp_image_new_ref(vc->ssmpi) : NULL; -} - static struct mp_image *get_window_screenshot(struct vo *vo) { struct priv *vc = vo->priv; @@ -1018,9 +1007,6 @@ static int control(struct vo *vo, uint32_t request, void *data) struct voctrl_get_equalizer_args *args = data; return get_eq(vo, args->name, args->valueptr); } - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(vo); - return true; case VOCTRL_SCREENSHOT_WIN: *(struct mp_image **)data = get_window_screenshot(vo); return true; diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 1c4b016e6b..de2c975823 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -298,14 +298,6 @@ static void draw_image(struct vo *vo, struct mp_image *mpi) draw_osd(vo); } -static struct mp_image *get_screenshot(struct priv *p) -{ - struct mp_image *hwimg = p->output_surfaces[p->visible_surface]; - if (!hwimg) - return NULL; - return mp_image_new_ref(hwimg); -} - static void free_subpicture(struct priv *p, struct vaapi_osd_image *img) { if (img->image.image_id != VA_INVALID_ID) @@ -541,9 +533,6 @@ static int control(struct vo *vo, uint32_t request, void *data) p->output_surface = p->visible_surface; draw_osd(vo); return true; - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(p); - return true; case VOCTRL_GET_PANSCAN: return VO_TRUE; case VOCTRL_SET_PANSCAN: diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 1a1287c1d7..528756c05f 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -1049,18 +1049,10 @@ static int control(struct vo *vo, uint32_t request, void *data) forget_frames(vo, true); return true; case VOCTRL_SCREENSHOT_WIN: - case VOCTRL_SCREENSHOT: - { if (!status_ok(vo)) return false; - if (request == VOCTRL_SCREENSHOT_WIN) { - *(struct mp_image **)data = get_window_screenshot(vo); - } else { - *(struct mp_image **)data = - vc->current_image ? mp_image_new_ref(vc->current_image) : NULL; - } + *(struct mp_image **)data = get_window_screenshot(vo); return true; - } case VOCTRL_GET_PREF_DEINT: *(int *)data = vc->deint; return true; diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c index ed23f8af3d..9da24ddf3e 100644 --- a/video/out/vo_wayland.c +++ b/video/out/vo_wayland.c @@ -268,14 +268,6 @@ static bool redraw_frame(struct priv *p) return true; } -static mp_image_t *get_screenshot(struct priv *p) -{ - if (!p->original_image) - return NULL; - - return mp_image_new_ref(p->original_image); -} - static bool resize(struct priv *p) { struct vo_wayland_state *wl = p->wl; @@ -689,9 +681,6 @@ static int control(struct vo *vo, uint32_t request, void *data) } case VOCTRL_REDRAW_FRAME: return redraw_frame(p); - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(p); - return true; case VOCTRL_GET_RECENT_FLIP_TIME: { *(int64_t*) data = p->recent_flip_time; diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c index 32d9b731fd..aa578d4883 100644 --- a/video/out/vo_x11.c +++ b/video/out/vo_x11.c @@ -423,16 +423,6 @@ static struct mp_image get_x_buffer(struct priv *p, int buf_index) return img; } -static mp_image_t *get_screenshot(struct vo *vo) -{ - struct priv *p = vo->priv; - - if (!p->original_image) - return NULL; - - return mp_image_new_ref(p->original_image); -} - static void wait_for_completion(struct vo *vo, int max_outstanding) { #if HAVE_SHM && HAVE_XEXT @@ -619,9 +609,6 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_REDRAW_FRAME: draw_image(vo, p->original_image); return true; - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(vo); - return true; } int events = 0; diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index e506fc9359..11c6efc26e 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -648,15 +648,6 @@ static void flip_page(struct vo *vo) XSync(vo->x11->display, False); } -static mp_image_t *get_screenshot(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - if (!ctx->original_image) - return NULL; - - return mp_image_new_ref(ctx->original_image); -} - // Note: REDRAW_FRAME can call this with NULL. static void draw_image(struct vo *vo, mp_image_t *mpi) { @@ -839,9 +830,6 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_REDRAW_FRAME: draw_image(vo, ctx->original_image); return true; - case VOCTRL_SCREENSHOT: - *(struct mp_image **)data = get_screenshot(vo); - return true; } int events = 0; int r = vo_x11_control(vo, &events, request, data);