summaryrefslogtreecommitdiffstats
path: root/video/out/vo.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/vo.c')
-rw-r--r--video/out/vo.c56
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