summaryrefslogtreecommitdiffstats
path: root/video/out/vo.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-07-01 19:22:40 +0200
committerwm4 <wm4@nowhere>2015-07-01 22:37:46 +0200
commit41ad9d8924cad07948ee7c2eaff9d0fa1be0b044 (patch)
tree97ffd8a66c1863f0f0a9c9c0c5b26b768da44be8 /video/out/vo.c
parent7faa80ace82f89036f6bb46e9539cc4a0cdce25c (diff)
downloadmpv-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.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