summaryrefslogtreecommitdiffstats
path: root/video/out/vo_opengl.c
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2014-11-23 20:06:05 +0100
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2015-01-23 09:14:41 +0100
commitc29ab5a46b2676d013e4294ee719d83f6bc469b6 (patch)
treea20afc45d995e23e8a4c82575ba93994aade311a /video/out/vo_opengl.c
parent86f4fcf1e2b7dc6a4aba343465a5bf153d37c7f9 (diff)
downloadmpv-c29ab5a46b2676d013e4294ee719d83f6bc469b6.tar.bz2
mpv-c29ab5a46b2676d013e4294ee719d83f6bc469b6.tar.xz
vo_opengl: add smoothmotion frame blending
SmoothMotion is a way to time and blend frames made popular by MadVR. It's intended behaviour is to remove stuttering caused by mismatches between the display refresh rate and the video fps, while preserving the video's original artistic qualities (no soap opera effect). It's supposed to make 24fps video playback on 60hz monitors as close as possible to a 24hz monitor. Instead of drawing a frame once once it's pts has passed the vsync time, we redraw at the display refresh rate, and if we detect the vsync is between two frames we interpolated them (depending on their position relative to the vsync). We actually interpolate as few frames as possible to avoid a blur effect as much as possible. For example, if we were to play back a 1fps video on a 60hz monitor, we would blend at most on 1 vsync for each frame (while the other 59 vsyncs would be rendered as is). Frame interpolation is always done before scaling and in linear light when possible (an ICC profile is used, or :srgb is used).
Diffstat (limited to 'video/out/vo_opengl.c')
-rw-r--r--video/out/vo_opengl.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c
index 058b305c2f..d3f1e7da7d 100644
--- a/video/out/vo_opengl.c
+++ b/video/out/vo_opengl.c
@@ -154,7 +154,8 @@ static void flip_page(struct vo *vo)
mpgl_unlock(p->glctx);
}
-static void draw_image(struct vo *vo, mp_image_t *mpi)
+static void draw_image_timed(struct vo *vo, mp_image_t *mpi,
+ struct frame_timing *t)
{
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
@@ -164,8 +165,9 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
mpgl_lock(p->glctx);
- gl_video_upload_image(p->renderer, mpi);
- gl_video_render_frame(p->renderer, 0);
+ if (mpi)
+ gl_video_upload_image(p->renderer, mpi);
+ gl_video_render_frame(p->renderer, 0, t);
// The playloop calls this last before waiting some time until it decides
// to call flip_page(). Tell OpenGL to start execution of the GPU commands
@@ -178,6 +180,11 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
mpgl_unlock(p->glctx);
}
+static void draw_image(struct vo *vo, mp_image_t *mpi)
+{
+ draw_image_timed(vo, mpi, NULL);
+}
+
static int query_format(struct vo *vo, int format)
{
struct gl_priv *p = vo->priv;
@@ -361,13 +368,21 @@ static int control(struct vo *vo, uint32_t request, void *data)
return true;
case VOCTRL_REDRAW_FRAME:
mpgl_lock(p->glctx);
- gl_video_render_frame(p->renderer, 0);
+ gl_video_render_frame(p->renderer, 0, NULL);
mpgl_unlock(p->glctx);
return true;
case VOCTRL_SET_COMMAND_LINE: {
char *arg = data;
return reparse_cmdline(p, arg);
}
+ case VOCTRL_GET_VSYNC_TIMED:
+ *(bool *)data = p->renderer_opts->smoothmotion;
+ return VO_TRUE;
+ case VOCTRL_RESET:
+ mpgl_lock(p->glctx);
+ gl_video_reset(p->renderer);
+ mpgl_unlock(p->glctx);
+ return true;
}
mpgl_lock(p->glctx);
@@ -474,6 +489,7 @@ const struct vo_driver video_out_opengl = {
.reconfig = reconfig,
.control = control,
.draw_image = draw_image,
+ .draw_image_timed = draw_image_timed,
.flip_page = flip_page,
.uninit = uninit,
.priv_size = sizeof(struct gl_priv),
@@ -489,6 +505,7 @@ const struct vo_driver video_out_opengl_hq = {
.reconfig = reconfig,
.control = control,
.draw_image = draw_image,
+ .draw_image_timed = draw_image_timed,
.flip_page = flip_page,
.uninit = uninit,
.priv_size = sizeof(struct gl_priv),