diff options
author | Uoti Urpala <uau@mplayer2.org> | 2011-12-04 18:10:17 +0200 |
---|---|---|
committer | Uoti Urpala <uau@mplayer2.org> | 2011-12-06 02:55:13 +0200 |
commit | c9553ce82fdb80811196f40b9c1eaaa3b2351e01 (patch) | |
tree | 8a0068a1f2654637bcd90a9c8529016f568078d1 | |
parent | 421c840b3c061de89b426244fe75237a73f765de (diff) | |
download | mpv-c9553ce82fdb80811196f40b9c1eaaa3b2351e01.tar.bz2 mpv-c9553ce82fdb80811196f40b9c1eaaa3b2351e01.tar.xz |
vo: do final frame draw only near page flip
Separate passing a new frame to VOs using the new API into two steps.
The first, vo_draw_image(), happens after a new frame is available
from the filter chain. In constrast to old behavior, now the frame is
not actually rendered yet at this point (though possible slice draw
calls can already reach the VO before). The second step,
vo_new_frame_imminent(), happens when we're close enough to the
display time of the new frame that we'll commit to flipping it as the
next action and will not change the OSD over the previous frame any
more.
This new behavior fixes a previous problem with vo_vdpau and vo_gl in
the situation where the player is paused after decoding a new frame
but before flipping it; previously changing OSD in that state would
switch to the new frame as a side effect. It would also allow an easy
way to fix extra output files produced with something like "--vo=png
--frames=1" with precise seeking, but this is not done yet.
The code now relies on a new mp_image from the filter chain staying
valid even after the vf_vo put_image() call providing it returns. In
other words decoders/filters must not deallocate or otherwise
invalidate their output frame between passing it forward and returning
from the decode/filter call.
-rw-r--r-- | libvo/video_out.c | 20 | ||||
-rw-r--r-- | libvo/video_out.h | 4 | ||||
-rw-r--r-- | libvo/vo_vdpau.c | 38 | ||||
-rw-r--r-- | mplayer.c | 1 |
4 files changed, 51 insertions, 12 deletions
diff --git a/libvo/video_out.c b/libvo/video_out.c index e796784b1e..82cf0dbbfe 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -275,6 +275,11 @@ int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts) } vo->frame_loaded = true; vo->next_pts = pts; + // Guaranteed to support at least DRAW_IMAGE later + if (vo->driver->is_new) { + vo->waiting_mpi = mpi; + return 0; + } if (vo_control(vo, VOCTRL_DRAW_IMAGE, mpi) == VO_NOTIMPL) return -1; return 0; @@ -294,6 +299,7 @@ int vo_get_buffered_frame(struct vo *vo, bool eof) void vo_skip_frame(struct vo *vo) { + vo_control(vo, VOCTRL_SKIPFRAME, NULL); vo->frame_loaded = false; } @@ -310,6 +316,18 @@ int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int return vo->driver->draw_slice(vo, src, stride, w, h, x, y); } +void vo_new_frame_imminent(struct vo *vo) +{ + if (!vo->driver->is_new) + return; + if (vo->driver->buffer_frames) + vo_control(vo, VOCTRL_NEWFRAME, NULL); + else { + vo_control(vo, VOCTRL_DRAW_IMAGE, vo->waiting_mpi); + vo->waiting_mpi = NULL; + } +} + void vo_draw_osd(struct vo *vo, struct osd_state *osd) { if (!vo->config_ok) @@ -466,6 +484,8 @@ int vo_config(struct vo *vo, uint32_t width, uint32_t height, NULL, vo); vo->registered_fd = vo->event_fd; } + vo->frame_loaded = false; + vo->waiting_mpi = NULL; return ret; } diff --git a/libvo/video_out.h b/libvo/video_out.h index bd7b2e8fa5..a710f7de4a 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -63,6 +63,8 @@ enum mp_voctrl { VOCTRL_XOVERLAY_SET_COLORKEY, // mp_colorkey_t VOCTRL_XOVERLAY_SET_WIN, + VOCTRL_NEWFRAME, + VOCTRL_SKIPFRAME, VOCTRL_REDRAW_OSD, VOCTRL_ONTOP, @@ -258,6 +260,7 @@ struct vo { int config_count; // Total number of successful config calls bool frame_loaded; // Is there a next frame the VO could flip to? + struct mp_image *waiting_mpi; double next_pts; // pts value of the next frame if any double next_pts2; // optional pts of frame after that @@ -307,6 +310,7 @@ int vo_get_buffered_frame(struct vo *vo, bool eof); void vo_skip_frame(struct vo *vo); int vo_draw_frame(struct vo *vo, uint8_t *src[]); int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y); +void vo_new_frame_imminent(struct vo *vo); void vo_draw_osd(struct vo *vo, struct osd_state *osd); void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration); void vo_check_events(struct vo *vo); diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index be4540002b..f087f6cf38 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -80,7 +80,7 @@ /* number of video and output surfaces */ #define MAX_OUTPUT_SURFACES 15 #define MAX_VIDEO_SURFACES 50 -#define NUM_BUFFERED_VIDEO 4 +#define NUM_BUFFERED_VIDEO 5 /* number of palette entries */ #define PALETTE_SIZE 256 @@ -295,7 +295,7 @@ static int video_to_output_surface(struct vo *vo) &vc->out_rect_vid); } -static void get_buffered_frame(struct vo *vo, bool eof) +static int next_deint_queue_pos(struct vo *vo, bool eof) { struct vdpctx *vc = vo->priv; @@ -305,15 +305,23 @@ static void get_buffered_frame(struct vo *vo, bool eof) else dqp = vc->deint >= 2 ? dqp - 1 : dqp - 2 | 1; if (dqp < (eof ? 0 : 3)) - return; + return -1; + return dqp; +} + +static void set_next_frame_info(struct vo *vo, bool eof) +{ + struct vdpctx *vc = vo->priv; - dqp = FFMIN(dqp, 4); - vc->deint_queue_pos = dqp; + vo->frame_loaded = false; + int dqp = next_deint_queue_pos(vo, eof); + if (dqp < 0) + return; vo->frame_loaded = true; // Set pts values struct buffered_video_surface *bv = vc->buffered_video; - int idx = vc->deint_queue_pos >> 1; + int idx = dqp >> 1; if (idx == 0) { // no future frame/pts available vo->next_pts = bv[0].pts; vo->next_pts2 = MP_NOPTS_VALUE; @@ -327,7 +335,7 @@ static void get_buffered_frame(struct vo *vo, bool eof) intermediate_pts = (bv[idx].pts + bv[idx - 1].pts) / 2; else intermediate_pts = bv[idx].pts; - if (vc->deint_queue_pos & 1) { // first field + if (dqp & 1) { // first field vo->next_pts = bv[idx].pts; vo->next_pts2 = intermediate_pts; } else { @@ -335,8 +343,6 @@ static void get_buffered_frame(struct vo *vo, bool eof) vo->next_pts2 = bv[idx - 1].pts; } } - - video_to_output_surface(vo); } static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, @@ -358,8 +364,9 @@ static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, .pts = pts, }; - vc->deint_queue_pos += 2; - get_buffered_frame(vo, false); + vc->deint_queue_pos = FFMIN(vc->deint_queue_pos + 2, + NUM_BUFFERED_VIDEO * 2 - 3); + set_next_frame_info(vo, false); } static void forget_frames(struct vo *vo) @@ -1858,6 +1865,13 @@ static int control(struct vo *vo, uint32_t request, void *data) r->mt = r->mb = vc->border_y; return VO_TRUE; } + case VOCTRL_NEWFRAME: + vc->deint_queue_pos = next_deint_queue_pos(vo, true); + video_to_output_surface(vo); + return true; + case VOCTRL_SKIPFRAME: + vc->deint_queue_pos = next_deint_queue_pos(vo, true); + return true; case VOCTRL_REDRAW_OSD: video_to_output_surface(vo); draw_eosd(vo); @@ -1892,7 +1906,7 @@ const struct vo_driver video_out_vdpau = { .config = config, .control = control, .draw_image = draw_image, - .get_buffered_frame = get_buffered_frame, + .get_buffered_frame = set_next_frame_info, .draw_slice = draw_slice, .draw_osd = draw_osd, .flip_page_timed = flip_page_timed, @@ -3672,6 +3672,7 @@ static void run_playloop(struct MPContext *mpctx) current_module = "flip_page"; if (!frame_time_remaining && blit_frame) { + vo_new_frame_imminent(mpctx->video_out); struct sh_video *sh_video = mpctx->sh_video; mpctx->video_pts = sh_video->pts; update_subtitles(mpctx, sh_video->pts, mpctx->video_offset, false); |