static int control(struct vo *vo, uint32_t request, void *data) { struct vo_priv *p = vo->priv; switch (request) { case VOCTRL_GET_PANSCAN: return VO_TRUE; case VOCTRL_REDRAW_FRAME: pthread_mutex_lock(&p->ctx->lock); update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_SET_PANSCAN: pthread_mutex_lock(&p->ctx->lock); copy_vo_opts(vo); p->ctx->force_update = true; update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_SET_COMMAND_LINE: { char *arg = data; return reparse_cmdline(p, arg); } case VOCTRL_GET_HWDEC_INFO: { struct mp_hwdec_info **arg = data; *arg = p->ctx ? &p->ctx->hwdec_info : NULL; return true; } } return VO_NOTIMPL; }
static int control(struct vo *vo, uint32_t request, void *data) { struct vo_priv *p = vo->priv; switch (request) { case VOCTRL_GET_PANSCAN: return VO_TRUE; case VOCTRL_GET_EQUALIZER: { struct voctrl_get_equalizer_args *args = data; pthread_mutex_lock(&p->ctx->lock); bool r = mp_csp_equalizer_get(&p->ctx->eq, args->name, args->valueptr) >= 0; pthread_mutex_unlock(&p->ctx->lock); return r ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_SET_EQUALIZER: { struct voctrl_set_equalizer_args *args = data; pthread_mutex_lock(&p->ctx->lock); bool r = mp_csp_equalizer_set(&p->ctx->eq, args->name, args->value) >= 0; if (r) { p->ctx->eq_changed = true; update(p); } pthread_mutex_unlock(&p->ctx->lock); return r ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_REDRAW_FRAME: pthread_mutex_lock(&p->ctx->lock); update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_SET_PANSCAN: pthread_mutex_lock(&p->ctx->lock); copy_vo_opts(vo); p->ctx->force_update = true; update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_SET_COMMAND_LINE: { char *arg = data; return reparse_cmdline(p, arg); } case VOCTRL_GET_HWDEC_INFO: { struct mp_hwdec_info **arg = data; *arg = p->ctx ? &p->ctx->hwdec_info : NULL; return true; } case VOCTRL_GET_RECENT_FLIP_TIME: { int r = VO_FALSE; pthread_mutex_lock(&p->ctx->lock); if (p->ctx->recent_flip) { *(int64_t *)data = p->ctx->recent_flip; r = VO_TRUE; } pthread_mutex_unlock(&p->ctx->lock); return r; } } return VO_NOTIMPL; }
static void uninit(struct vo *vo) { struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); mp_image_unrefp(&p->ctx->next_frame); mp_image_unrefp(&p->ctx->waiting_frame); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; pthread_mutex_unlock(&p->ctx->lock); } static int preinit(struct vo *vo) { struct vo_priv *p = vo->priv; p->vo = vo; p->ctx = vo->extra.opengl_cb_context; if (!p->ctx) { MP_FATAL(vo, "No context set.\n"); return -1; } pthread_mutex_lock(&p->ctx->lock); if (!p->ctx->initialized) { MP_FATAL(vo, "OpenGL context not initialized.\n"); pthread_mutex_unlock(&p->ctx->lock); return -1; } p->ctx->active = vo; p->ctx->reconfigured = true; assert(vo->osd == p->ctx->osd); copy_vo_opts(vo); pthread_mutex_unlock(&p->ctx->lock); return 0; } #define OPT_BASE_STRUCT struct vo_priv static const struct m_option options[] = { OPT_FLAG("debug", use_gl_debug, 0), OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), {0}, }; const struct vo_driver video_out_opengl_cb = { .description = "OpenGL Callbacks for libmpv", .name = "opengl-cb", .caps = VO_CAP_ROTATE90, .preinit = preinit, .query_format = query_format, .reconfig = reconfig, .control = control, .draw_image = draw_image, .flip_page = flip_page, .uninit = uninit, .priv_size = sizeof(struct vo_priv), .options = options, };
static int control(struct vo *vo, uint32_t request, void *data) { struct vo_priv *p = vo->priv; switch (request) { case VOCTRL_RESET: pthread_mutex_lock(&p->ctx->lock); forget_frames(p->ctx, false); p->ctx->reset = true; pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_PAUSE: vo->want_redraw = true; vo_wakeup(vo); return VO_TRUE; case VOCTRL_GET_PANSCAN: return VO_TRUE; case VOCTRL_GET_EQUALIZER: { struct voctrl_get_equalizer_args *args = data; pthread_mutex_lock(&p->ctx->lock); bool r = mp_csp_equalizer_get(&p->ctx->eq, args->name, args->valueptr) >= 0; pthread_mutex_unlock(&p->ctx->lock); return r ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_SET_EQUALIZER: { struct voctrl_set_equalizer_args *args = data; pthread_mutex_lock(&p->ctx->lock); bool r = mp_csp_equalizer_set(&p->ctx->eq, args->name, args->value) >= 0; if (r) { p->ctx->eq_changed = true; update(p); } pthread_mutex_unlock(&p->ctx->lock); return r ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_SET_PANSCAN: pthread_mutex_lock(&p->ctx->lock); copy_vo_opts(vo); p->ctx->force_update = true; update(p); pthread_mutex_unlock(&p->ctx->lock); return VO_TRUE; case VOCTRL_SET_COMMAND_LINE: { char *arg = data; return reparse_cmdline(p, arg); } case VOCTRL_GET_HWDEC_INFO: { struct mp_hwdec_info **arg = data; *arg = p->ctx ? &p->ctx->hwdec_info : NULL; return true; } } return VO_NOTIMPL; }
static void uninit(struct vo *vo) { struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); forget_frames(p->ctx, true); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; update(p); pthread_mutex_unlock(&p->ctx->lock); } static int preinit(struct vo *vo) { struct vo_priv *p = vo->priv; p->vo = vo; p->ctx = vo->extra.opengl_cb_context; if (!p->ctx) { MP_FATAL(vo, "No context set.\n"); return -1; } pthread_mutex_lock(&p->ctx->lock); if (!p->ctx->initialized) { MP_FATAL(vo, "OpenGL context not initialized.\n"); pthread_mutex_unlock(&p->ctx->lock); return -1; } p->ctx->active = vo; p->ctx->reconfigured = true; p->ctx->update_new_opts = true; copy_vo_opts(vo); pthread_mutex_unlock(&p->ctx->lock); return 0; } #define OPT_BASE_STRUCT struct vo_priv static const struct m_option options[] = { OPT_FLAG("debug", use_gl_debug, 0), OPT_INTRANGE("frame-queue-size", frame_queue_size, 0, 1, 100, OPTDEF_INT(2)), OPT_CHOICE("frame-drop-mode", frame_drop_mode, 0, ({"pop", FRAME_DROP_POP}, {"clear", FRAME_DROP_CLEAR},