diff options
author | wm4 <wm4@nowhere> | 2015-07-01 19:22:40 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2015-07-01 22:37:46 +0200 |
commit | 41ad9d8924cad07948ee7c2eaff9d0fa1be0b044 (patch) | |
tree | 97ffd8a66c1863f0f0a9c9c0c5b26b768da44be8 /video/out/vo.c | |
parent | 7faa80ace82f89036f6bb46e9539cc4a0cdce25c (diff) | |
download | mpv-41ad9d8924cad07948ee7c2eaff9d0fa1be0b044.tar.bz2 mpv-41ad9d8924cad07948ee7c2eaff9d0fa1be0b044.tar.xz |
video: pass future frames to VO
Now the VO can request a number of future frames with the last parameter
of vo_set_queue_params(). This will be helpful to fix the interpolation
code.
Note that the first frame (after playback start or seeking) will usually
not have any future frames (to make seeking fast). Near the end of the
file, the number of future frames will become lower as well.
Diffstat (limited to 'video/out/vo.c')
-rw-r--r-- | video/out/vo.c | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/video/out/vo.c b/video/out/vo.c index 954a9a4c67..68af6a38c8 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -146,6 +146,9 @@ struct vo_internal { bool rendering; // true if an image is being rendered struct mp_image *frame_queued; // the image that should be rendered + struct mp_image *future_frames[VO_MAX_FUTURE_FRAMES]; + int num_future_frames; + int req_future_frames; // VO's requested value of num_future_frames int64_t frame_pts; // realtime of intended display int64_t frame_duration; // realtime frame duration (for framedrop) @@ -410,6 +413,23 @@ int vo_control(struct vo *vo, uint32_t request, void *data) } // must be called locked +// transfers ownership of frames[] items to the VO +static void set_future_frames(struct vo *vo, struct mp_image **frames) +{ + struct vo_internal *in = vo->in; + for (int n = 0; n < in->num_future_frames; n++) + talloc_free(in->future_frames[n]); + in->num_future_frames = 0; + for (int n = 0; frames && frames[n]; n++) { + if (n < in->req_future_frames) { + in->future_frames[in->num_future_frames++] = frames[n]; + } else { + talloc_free(frames[n]); + } + } +} + +// must be called locked static void forget_frames(struct vo *vo) { struct vo_internal *in = vo->in; @@ -417,6 +437,7 @@ static void forget_frames(struct vo *vo) in->hasframe_rendered = false; in->drop_count = 0; mp_image_unrefp(&in->frame_queued); + set_future_frames(vo, NULL); // don't unref current_frame; we always want to be able to redraw it } @@ -530,18 +551,22 @@ bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts) // Direct the VO thread to put the currently queued image on the screen. // vo_is_ready_for_frame() must have returned true before this call. -// Ownership of the image is handed to the vo. -void vo_queue_frame(struct vo *vo, struct mp_image *image, +// images[0] is the frame to draw, images[n+1] are future frames (NULL +// terminated). Ownership of all the images is handed to the vo. +void vo_queue_frame(struct vo *vo, struct mp_image **images, int64_t pts_us, int64_t duration) { struct vo_internal *in = vo->in; pthread_mutex_lock(&in->lock); + struct mp_image *image = images[0]; + assert(image); assert(vo->config_ok && !in->frame_queued); in->hasframe = true; in->frame_queued = image; in->frame_pts = pts_us; in->frame_duration = duration; in->wakeup_pts = in->vsync_timed ? 0 : in->frame_pts + MPMAX(duration, 0); + set_future_frames(vo, images + 1); wakeup_locked(vo); pthread_mutex_unlock(&in->lock); } @@ -674,6 +699,13 @@ static bool render_frame(struct vo *vo) } else { in->rendering = true; in->hasframe_rendered = true; + int num_future_frames = in->num_future_frames; + in->num_future_frames = 0; + struct mp_image *future_frames[VO_MAX_FUTURE_FRAMES]; + for (int n = 0; n < num_future_frames; n++) { + future_frames[n] = in->future_frames[n]; + in->future_frames[n] = NULL; + } pthread_mutex_unlock(&in->lock); mp_input_wakeup(vo->input_ctx); // core can queue new video now @@ -684,6 +716,9 @@ static bool render_frame(struct vo *vo) .pts = pts, .next_vsync = next_vsync, .prev_vsync = prev_vsync, + .frame = img, + .num_future_frames = num_future_frames, + .future_frames = future_frames, }; vo->driver->draw_image_timed(vo, img, &t); } else { @@ -714,6 +749,8 @@ static bool render_frame(struct vo *vo) pthread_mutex_lock(&in->lock); in->dropped_frame = drop; in->rendering = false; + for (int n = 0; n < num_future_frames; n++) + talloc_free(future_frames[n]); } if (in->dropped_frame) { @@ -947,14 +984,27 @@ const char *vo_get_window_title(struct vo *vo) // flip_page[_timed] will be called offset_us microseconds too early. // (For vo_vdpau, which does its own timing.) // Setting vsync_timed to true redraws as fast as possible. +// num_future_frames set the requested number of future frames in +// struct frame_timing. // (For vo_opengl smoothmotion.) -void vo_set_flip_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed) +void vo_set_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed, + int num_future_frames) { struct vo_internal *in = vo->in; pthread_mutex_lock(&in->lock); in->flip_queue_offset = offset_us; in->vsync_timed = vsync_timed; + in->req_future_frames = MPMIN(num_future_frames, VO_MAX_FUTURE_FRAMES); + pthread_mutex_unlock(&in->lock); +} + +int vo_get_num_future_frames(struct vo *vo) +{ + struct vo_internal *in = vo->in; + pthread_mutex_lock(&in->lock); + int res = in->req_future_frames; pthread_mutex_unlock(&in->lock); + return res; } // to be called from the VO thread only |