summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-08-10 18:44:52 +0200
committerwm4 <wm4@nowhere>2015-08-10 18:48:45 +0200
commite77bc570d79331d43f87e820f5be83e7722eadac (patch)
tree3509e9c667eaa8532ebb2239768222b77ff41cb4
parent031555fbe6cfdf6d0db3b0a5a316dd55efd75846 (diff)
downloadmpv-e77bc570d79331d43f87e820f5be83e7722eadac.tar.bz2
mpv-e77bc570d79331d43f87e820f5be83e7722eadac.tar.xz
vo_rpi: support display sync
This VO is special because it normally doesn't block on vsync, but can be made to do so. Supposedly the MMAL video output API merely sets a "current frame" field when sending an output frame, and the firmware will pick up whatever frame that field is set to at the time of a vsync.
-rw-r--r--video/out/vo_rpi.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c
index cd9a0aef17..28e8641a50 100644
--- a/video/out/vo_rpi.c
+++ b/video/out/vo_rpi.c
@@ -71,6 +71,7 @@ struct priv {
MMAL_COMPONENT_T *renderer;
bool renderer_enabled;
+ bool display_synced;
struct mp_image *next_image;
// for RAM input
@@ -78,6 +79,10 @@ struct priv {
atomic_bool update_display;
+ pthread_mutex_t vsync_mutex;
+ pthread_cond_t vsync_cond;
+ int64_t vsync_counter;
+
int background_layer;
int video_layer;
int osd_layer;
@@ -323,6 +328,16 @@ static int update_display_size(struct vo *vo)
return 0;
}
+static void wait_next_vsync(struct vo *vo)
+{
+ struct priv *p = vo->priv;
+ pthread_mutex_lock(&p->vsync_mutex);
+ int64_t old = p->vsync_counter;
+ while (old == p->vsync_counter)
+ pthread_cond_wait(&p->vsync_cond, &p->vsync_mutex);
+ pthread_mutex_unlock(&p->vsync_mutex);
+}
+
static void flip_page(struct vo *vo)
{
struct priv *p = vo->priv;
@@ -345,6 +360,9 @@ static void flip_page(struct vo *vo)
talloc_free(mpi);
}
}
+
+ if (p->display_synced)
+ wait_next_vsync(vo);
}
static void free_mmal_buffer(void *arg)
@@ -353,15 +371,26 @@ static void free_mmal_buffer(void *arg)
mmal_buffer_header_release(buffer);
}
-static void draw_image(struct vo *vo, mp_image_t *mpi)
+static void draw_frame(struct vo *vo, struct vo_frame *frame)
{
struct priv *p = vo->priv;
+ mp_image_t *mpi = NULL;
+ if (!frame->redraw && !frame->repeat)
+ mpi = mp_image_new_ref(frame->current);
+
talloc_free(p->next_image);
p->next_image = NULL;
- p->osd_pts = mpi->pts;
- update_osd(vo);
+ if (mpi)
+ p->osd_pts = mpi->pts;
+
+ // Redraw only if the OSD has meaningfully changed, which we assume it
+ // hasn't when a frame is merely repeated for display sync.
+ if (frame->redraw || !frame->repeat)
+ update_osd(vo);
+
+ p->display_synced = frame->display_synced;
if (vo->params->imgfmt != IMGFMT_MMAL) {
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(p->swpool->queue);
@@ -575,6 +604,16 @@ static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1,
vo_wakeup(vo);
}
+static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
+{
+ struct vo *vo = arg;
+ struct priv *p = vo->priv;
+ pthread_mutex_lock(&p->vsync_mutex);
+ p->vsync_counter += 1;
+ pthread_cond_signal(&p->vsync_cond);
+ pthread_mutex_unlock(&p->vsync_mutex);
+}
+
static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
@@ -602,6 +641,9 @@ static void uninit(struct vo *vo)
vc_dispmanx_display_close(p->display);
mmal_vc_deinit();
+
+ pthread_cond_destroy(&p->vsync_cond);
+ pthread_mutex_destroy(&p->vsync_mutex);
}
static int preinit(struct vo *vo)
@@ -637,6 +679,11 @@ static int preinit(struct vo *vo)
vc_tv_register_callback(tv_callback, vo);
+ pthread_mutex_init(&p->vsync_mutex, NULL);
+ pthread_cond_init(&p->vsync_cond, NULL);
+
+ vc_dispmanx_vsync_callback(p->display, vsync_callback, vo);
+
return 0;
fail:
@@ -658,7 +705,7 @@ const struct vo_driver video_out_rpi = {
.query_format = query_format,
.reconfig = reconfig,
.control = control,
- .draw_image = draw_image,
+ .draw_frame = draw_frame,
.flip_page = flip_page,
.uninit = uninit,
.priv_size = sizeof(struct priv),