From e77bc570d79331d43f87e820f5be83e7722eadac Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 10 Aug 2015 18:44:52 +0200 Subject: 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. --- video/out/vo_rpi.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file 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), -- cgit v1.2.3