diff options
Diffstat (limited to 'video/out/vo_opengl_cb.c')
-rw-r--r-- | video/out/vo_opengl_cb.c | 108 |
1 files changed, 90 insertions, 18 deletions
diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index a689a1dcbe..b49f3fdb9d 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -39,6 +39,9 @@ * here to transfer the video frames somehow. */ +#define FRAME_DROP_POP 0 // drop the oldest frame in queue +#define FRAME_DROP_CLEAR 1 // drop all frames in queue + struct vo_priv { struct vo *vo; @@ -47,6 +50,8 @@ struct vo_priv { // Immutable after VO init int use_gl_debug; struct gl_video_opts *renderer_opts; + int frame_queue_size; + int frame_drop_mode; }; struct mpv_opengl_cb_context { @@ -60,7 +65,9 @@ struct mpv_opengl_cb_context { mpv_opengl_cb_update_fn update_cb; void *update_cb_ctx; struct mp_image *waiting_frame; - struct mp_image *next_frame; + struct mp_image **frame_queue; + int queued_frames; + uint64_t dropped_frames; struct mp_image_params img_params; bool reconfigured; struct mp_rect wnd; @@ -90,6 +97,53 @@ struct mpv_opengl_cb_context { struct vo *active; }; +static void update(struct vo_priv *p); + +// all queue manipulation functions shold be called under locked state + +static struct mp_image *frame_queue_pop(struct mpv_opengl_cb_context *ctx) +{ + if (ctx->queued_frames == 0) + return NULL; + struct mp_image *ret = ctx->frame_queue[0]; + MP_TARRAY_REMOVE_AT(ctx->frame_queue, ctx->queued_frames, 0); + return ret; +} + +static void frame_queue_drop(struct mpv_opengl_cb_context *ctx) +{ + talloc_free(frame_queue_pop(ctx)); + ctx->dropped_frames++; +} + +static void frame_queue_clear(struct mpv_opengl_cb_context *ctx) +{ + for (int i = 0; i < ctx->queued_frames; i++) + talloc_free(ctx->frame_queue[i]); + talloc_free(ctx->frame_queue); + ctx->frame_queue = NULL; + ctx->dropped_frames += ctx->queued_frames; + ctx->queued_frames = 0; +} + +static void frame_queue_push(struct mpv_opengl_cb_context *ctx, struct mp_image *mpi) +{ + MP_TARRAY_APPEND(ctx, ctx->frame_queue, ctx->queued_frames, mpi); +} + +static void frame_queue_shrink(struct mpv_opengl_cb_context *ctx, int size) +{ + while (ctx->queued_frames > size) + frame_queue_drop(ctx); +} + +static void forget_frames(struct mpv_opengl_cb_context *ctx) +{ + frame_queue_clear(ctx); + mp_image_unrefp(&ctx->waiting_frame); + ctx->dropped_frames = 0; +} + static void free_ctx(void *ptr) { mpv_opengl_cb_context *ctx = ptr; @@ -185,7 +239,9 @@ int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx) { // Bring down the decoder etc., which still might be using the hwdec // context. Setting initialized=false guarantees it can't come back. + pthread_mutex_lock(&ctx->lock); + forget_frames(ctx); ctx->initialized = false; pthread_mutex_unlock(&ctx->lock); @@ -252,6 +308,7 @@ int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4]) gl_video_set_options(ctx->renderer, opts->renderer_opts); ctx->gl->debug_context = opts->use_gl_debug; gl_video_set_debug(ctx->renderer, opts->use_gl_debug); + frame_queue_shrink(ctx, opts->frame_queue_size); } ctx->reconfigured = false; ctx->update_new_opts = false; @@ -265,8 +322,7 @@ int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4]) ctx->eq_changed = false; ctx->eq = *eq; - struct mp_image *mpi = ctx->next_frame; - ctx->next_frame = NULL; + struct mp_image *mpi = frame_queue_pop(ctx); pthread_mutex_unlock(&ctx->lock); @@ -277,6 +333,11 @@ int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4]) gl_video_unset_gl_state(ctx->renderer); + pthread_mutex_lock(&ctx->lock); + if (vo && ctx->queued_frames > 0) + update(vo->priv); + pthread_mutex_unlock(&ctx->lock); + return 0; } @@ -302,8 +363,13 @@ static void flip_page(struct vo *vo) struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); - mp_image_unrefp(&p->ctx->next_frame); - p->ctx->next_frame = p->ctx->waiting_frame; + if (p->ctx->queued_frames >= p->frame_queue_size) { + if (p->frame_drop_mode == FRAME_DROP_CLEAR) + frame_queue_clear(p->ctx); + else // FRAME_DROP_POP mode + frame_queue_shrink(p->ctx, p->frame_queue_size - 1); + } + frame_queue_push(p->ctx, p->ctx->waiting_frame); p->ctx->waiting_frame = NULL; update(p); pthread_mutex_unlock(&p->ctx->lock); @@ -326,7 +392,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags) struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); - mp_image_unrefp(&p->ctx->next_frame); + forget_frames(p->ctx); p->ctx->img_params = *params; p->ctx->reconfigured = true; pthread_mutex_unlock(&p->ctx->lock); @@ -334,6 +400,19 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags) return 0; } +// list of options which can be changed at runtime +#define OPT_BASE_STRUCT struct vo_priv +static const struct m_option change_opts[] = { + OPT_FLAG("debug", use_gl_debug, 0), + OPT_INTRANGE("frame-queue-size", frame_queue_size, 0, 1, 100, OPTDEF_INT(1)), + OPT_CHOICE("frame-drop-mode", frame_drop_mode, 0, + ({"pop", FRAME_DROP_POP}, + {"clear", FRAME_DROP_CLEAR})), + OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), + {0} +}; +#undef OPT_BASE_STRUCT + static bool reparse_cmdline(struct vo_priv *p, char *args) { struct m_config *cfg = NULL; @@ -341,16 +420,6 @@ static bool reparse_cmdline(struct vo_priv *p, char *args) int r = 0; pthread_mutex_lock(&p->ctx->lock); - - // list of options which can be changed at runtime -#define OPT_BASE_STRUCT struct vo_priv - static const struct m_option change_opts[] = { - OPT_FLAG("debug", use_gl_debug, 0), - OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), - {0} - }; -#undef OPT_BASE_STRUCT - const struct vo_priv *vodef = p->vo->driver->priv_defaults; cfg = m_config_new(NULL, p->vo->log, sizeof(*opts), vodef, change_opts); opts = cfg->optstruct; @@ -426,8 +495,7 @@ 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); + forget_frames(p->ctx); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; @@ -462,6 +530,10 @@ static int preinit(struct vo *vo) #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(1)), + OPT_CHOICE("frame-drop-mode", frame_drop_mode, 0, + ({"pop", FRAME_DROP_POP}, + {"clear", FRAME_DROP_CLEAR})), OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), {0}, }; |