diff options
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 |