mirror of
https://github.com/mpv-player/mpv
synced 2025-01-29 11:12:56 +00:00
video/out: always support redrawing VO window at any point
Before, a VO could easily refuse to respond to VOCTRL_REDRAW_FRAME, which means the VO wouldn't redraw OSD and window contents, and the player would appear frozen to the user. This was a bit stupid, and makes dealing with some corner cases much harder (think of --keep-open, which was hard to implement, because the VO gets into this state if there are no new video frames after a seek reset). Change this, and require VOs to always react to VOCTRL_REDRAW_FRAME. There are two aspects of this: First, behavior after a (successful) vo_reconfig() call, but before any video frame has been displayed. Second, behavior after a vo_seek_reset(). For the first issue, we define that sending VOCTRL_REDRAW_FRAME after vo_reconfig() should clear the window with black. This requires minor changes to some VOs. In particular vaapi makes this horribly complicated, because OSD rendering is bound to a video surface. We create a black dummy surface for this purpose. The second issue is much simpler and works already with most VOs: they simply redraw whatever has been uploaded previously. The exception is vdpau, which has a complicated mechanism to track and filter video frames. The state associated with this mechanism is completely cleared with vo_seek_reset(), so implementing this to work as expected is not trivial. For now, we just clear the window with black.
This commit is contained in:
parent
94d6babb95
commit
ed9295c250
@ -179,6 +179,7 @@ struct gl_video {
|
||||
int plane_count;
|
||||
|
||||
struct video_image image;
|
||||
bool have_image;
|
||||
|
||||
struct fbotex indirect_fbo; // RGB target
|
||||
struct fbotex scale_sep_fbo; // first pass when doing 2 pass scaling
|
||||
@ -1353,6 +1354,11 @@ void gl_video_render_frame(struct gl_video *p)
|
||||
gl->Clear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if (!p->have_image) {
|
||||
gl->Clear(GL_COLOR_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Order of processing:
|
||||
// [indirect -> [scale_sep ->]] final
|
||||
|
||||
@ -1571,6 +1577,8 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
|
||||
}
|
||||
gl->ActiveTexture(GL_TEXTURE0);
|
||||
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
p->have_image = true;
|
||||
}
|
||||
|
||||
struct mp_image *gl_video_download_image(struct gl_video *p)
|
||||
@ -1579,7 +1587,7 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
|
||||
|
||||
struct video_image *vimg = &p->image;
|
||||
|
||||
if (!vimg->planes[0].gl_texture)
|
||||
if (!p->have_image || !vimg->planes[0].gl_texture)
|
||||
return NULL;
|
||||
|
||||
assert(p->image_format == p->image_params.imgfmt);
|
||||
@ -1991,6 +1999,8 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params)
|
||||
csp.levels_out = params->outputlevels;
|
||||
csp.format = params->colorspace;
|
||||
p->colorspace = csp;
|
||||
|
||||
p->have_image = false;
|
||||
}
|
||||
|
||||
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b)
|
||||
|
@ -202,7 +202,7 @@ void vo_queue_image(struct vo *vo, struct mp_image *mpi)
|
||||
|
||||
int vo_redraw_frame(struct vo *vo)
|
||||
{
|
||||
if (!vo->config_ok || !vo->hasframe)
|
||||
if (!vo->config_ok)
|
||||
return -1;
|
||||
if (vo_control(vo, VOCTRL_REDRAW_FRAME, NULL) == true) {
|
||||
vo->want_redraw = false;
|
||||
@ -214,7 +214,7 @@ int vo_redraw_frame(struct vo *vo)
|
||||
|
||||
bool vo_get_want_redraw(struct vo *vo)
|
||||
{
|
||||
if (!vo->config_ok || !vo->hasframe)
|
||||
if (!vo->config_ok)
|
||||
return false;
|
||||
return vo->want_redraw;
|
||||
}
|
||||
@ -289,7 +289,6 @@ void vo_seek_reset(struct vo *vo)
|
||||
{
|
||||
vo_control(vo, VOCTRL_RESET, NULL);
|
||||
vo->frame_loaded = false;
|
||||
vo->hasframe = false;
|
||||
mp_image_unrefp(&vo->waiting_mpi);
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,8 @@ typedef struct d3d_priv {
|
||||
|
||||
struct vo *vo;
|
||||
|
||||
bool have_image;
|
||||
|
||||
D3DLOCKED_RECT locked_rect; /**< The locked offscreen surface */
|
||||
RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed
|
||||
in fullscreen */
|
||||
@ -842,6 +844,9 @@ static uint32_t d3d_draw_frame(d3d_priv *priv)
|
||||
|
||||
IDirect3DDevice9_Clear(priv->d3d_device, 0, NULL, D3DCLEAR_TARGET, 0, 0, 0);
|
||||
|
||||
if (!priv->have_image)
|
||||
return VO_TRUE;
|
||||
|
||||
if (priv->use_textures) {
|
||||
|
||||
for (n = 0; n < priv->plane_count; n++) {
|
||||
@ -1271,6 +1276,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
|
||||
{
|
||||
d3d_priv *priv = vo->priv;
|
||||
|
||||
priv->have_image = false;
|
||||
|
||||
/* w32_common framework call. Creates window on the screen with
|
||||
* the given coordinates.
|
||||
*/
|
||||
@ -1412,6 +1419,8 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||
}
|
||||
}
|
||||
|
||||
priv->have_image = true;
|
||||
|
||||
d3d_draw_frame(priv);
|
||||
}
|
||||
|
||||
@ -1420,6 +1429,9 @@ static mp_image_t *get_screenshot(d3d_priv *priv)
|
||||
if (!priv->d3d_device)
|
||||
return NULL;
|
||||
|
||||
if (!priv->have_image)
|
||||
return NULL;
|
||||
|
||||
struct mp_image buffer;
|
||||
if (!get_video_buffer(priv, &buffer))
|
||||
return NULL;
|
||||
|
@ -91,6 +91,9 @@ struct priv {
|
||||
|
||||
struct va_surface_pool *pool;
|
||||
struct va_image_formats *va_image_formats;
|
||||
|
||||
struct va_surface *black_surface;
|
||||
|
||||
VAImageFormat *va_subpic_formats;
|
||||
unsigned int *va_subpic_flags;
|
||||
int va_num_subpic_formats;
|
||||
@ -119,6 +122,8 @@ static void free_video_specific(struct priv *p)
|
||||
{
|
||||
flush_output_surfaces(p);
|
||||
|
||||
va_surface_releasep(&p->black_surface);
|
||||
|
||||
for (int n = 0; n < MAX_OUTPUT_SURFACES; n++)
|
||||
mp_image_unrefp(&p->swdec_surfaces[n]);
|
||||
}
|
||||
@ -149,6 +154,8 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
free_video_specific(p);
|
||||
|
||||
vo_x11_config_vo_window(vo, NULL, vo->dx, vo->dy, vo->dwidth, vo->dheight,
|
||||
flags, "vaapi");
|
||||
|
||||
@ -173,10 +180,29 @@ static int query_format(struct vo *vo, uint32_t imgfmt)
|
||||
|
||||
static bool render_to_screen(struct priv *p, struct mp_image *mpi)
|
||||
{
|
||||
bool res = true;
|
||||
VAStatus status;
|
||||
|
||||
VASurfaceID surface = va_surface_id_in_mp_image(mpi);
|
||||
if (surface == VA_INVALID_ID) {
|
||||
if (!p->black_surface) {
|
||||
int w = p->image_params.w, h = p->image_params.h;
|
||||
// 4:2:0 should work everywhere
|
||||
int fmt = IMGFMT_420P;
|
||||
p->black_surface =
|
||||
va_surface_pool_get_by_imgfmt(p->pool, p->va_image_formats,
|
||||
fmt, w, h);
|
||||
if (p->black_surface) {
|
||||
struct mp_image *img = mp_image_alloc(fmt, w, h);
|
||||
mp_image_clear(img, 0, 0, w, h);
|
||||
if (!va_surface_upload(p->black_surface, img))
|
||||
va_surface_releasep(&p->black_surface);
|
||||
talloc_free(img);
|
||||
}
|
||||
}
|
||||
surface = va_surface_id(p->black_surface);
|
||||
}
|
||||
|
||||
int fields = mpi ? mpi->fields : 0;
|
||||
if (surface == VA_INVALID_ID)
|
||||
return false;
|
||||
|
||||
@ -199,9 +225,8 @@ static bool render_to_screen(struct priv *p, struct mp_image *mpi)
|
||||
}
|
||||
|
||||
int flags = va_get_colorspace_flag(p->image_params.colorspace) | p->scaling;
|
||||
if (p->deint && (mpi->fields & MP_IMGFIELD_INTERLACED)) {
|
||||
flags |= (mpi->fields & MP_IMGFIELD_TOP_FIRST) ?
|
||||
VA_BOTTOM_FIELD : VA_TOP_FIELD;
|
||||
if (p->deint && (fields & MP_IMGFIELD_INTERLACED)) {
|
||||
flags |= (fields & MP_IMGFIELD_TOP_FIRST) ? VA_BOTTOM_FIELD : VA_TOP_FIELD;
|
||||
} else {
|
||||
flags |= VA_FRAME_PICTURE;
|
||||
}
|
||||
@ -230,7 +255,7 @@ static bool render_to_screen(struct priv *p, struct mp_image *mpi)
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void flip_page(struct vo *vo)
|
||||
@ -505,7 +530,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||
return get_equalizer(p, eq->name, eq->valueptr);
|
||||
}
|
||||
case VOCTRL_REDRAW_FRAME:
|
||||
return redraw_frame(p);
|
||||
redraw_frame(p);
|
||||
return true;
|
||||
case VOCTRL_SCREENSHOT: {
|
||||
struct voctrl_screenshot_args *args = data;
|
||||
args->out_image = get_screenshot(p);
|
||||
|
@ -222,8 +222,15 @@ static int render_video_to_output_surface(struct vo *vo,
|
||||
struct vdp_functions *vdp = vc->vdp;
|
||||
VdpTime dummy;
|
||||
VdpStatus vdp_st;
|
||||
if (vc->deint_queue_pos < 0)
|
||||
if (vc->deint_queue_pos < 0) {
|
||||
// At least clear the screen if there is nothing to render
|
||||
int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
|
||||
vdp_st = vdp->output_surface_render_output_surface(output_surface,
|
||||
NULL, vc->black_pixel,
|
||||
NULL, NULL, NULL,
|
||||
flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct buffered_video_surface *bv = vc->buffered_video;
|
||||
unsigned int dp = vc->deint_queue_pos;
|
||||
|
@ -490,8 +490,10 @@ static int redraw_frame(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
if (!p->original_image)
|
||||
if (!p->original_image) {
|
||||
vo_x11_clear_background(vo, &(struct mp_rect){0, 0, vo->dwidth, vo->dheight});
|
||||
return false;
|
||||
}
|
||||
|
||||
draw_image(vo, p->original_image);
|
||||
return true;
|
||||
@ -628,7 +630,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||
resize(vo);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_REDRAW_FRAME:
|
||||
return redraw_frame(vo);
|
||||
redraw_frame(vo);
|
||||
return true;
|
||||
case VOCTRL_WINDOW_TO_OSD_COORDS: {
|
||||
// OSD is rendered into the scaled image
|
||||
float *c = data;
|
||||
|
@ -848,7 +848,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||
*cspc = ctx->cached_csp;
|
||||
return true;
|
||||
case VOCTRL_REDRAW_FRAME:
|
||||
return redraw_frame(vo);
|
||||
redraw_frame(vo);
|
||||
return true;
|
||||
case VOCTRL_SCREENSHOT: {
|
||||
struct voctrl_screenshot_args *args = data;
|
||||
args->out_image = get_screenshot(vo);
|
||||
|
@ -417,7 +417,7 @@ struct va_surface *va_surface_in_mp_image(struct mp_image *mpi)
|
||||
|
||||
VASurfaceID va_surface_id(const struct va_surface *surface)
|
||||
{
|
||||
return surface->id;
|
||||
return surface ? surface->id : VA_INVALID_ID;
|
||||
}
|
||||
|
||||
bool va_image_map(VADisplay display, VAImage *image, struct mp_image *mpi)
|
||||
|
Loading…
Reference in New Issue
Block a user