summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-05-12 22:16:19 +0200
committerwm4 <wm4@nowhere>2015-05-12 22:16:19 +0200
commitee3de1a063c281c1c915f204756d518966afdd54 (patch)
treef7a6d67353b451e93637965e07e4739a17871a83
parent4d9255a5e1a1c5be805800070a79ef1bcc1a150a (diff)
downloadmpv-ee3de1a063c281c1c915f204756d518966afdd54.tar.bz2
mpv-ee3de1a063c281c1c915f204756d518966afdd54.tar.xz
vo_opengl_cb: add a "block" framedrop mode and make it default
(I have no idea why there are different modes.) Instead of risking to drop frames too early, give it some margin. Since there are situations this could deadlock, wait with a timeout. This can happen if e.g. the API user is refusing to render anything, or if uninitialization is happening.
-rw-r--r--DOCS/man/vo.rst6
-rw-r--r--video/out/vo_opengl_cb.c32
2 files changed, 31 insertions, 7 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 6e1d89fade..874e064145 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -898,13 +898,15 @@ Available video output drivers are:
``frame-queue-size=<1..100>``
The maximum count of frames which the frame queue can hold (default: 1)
- ``frame-drop-mode=<pop|clear>``
+ ``frame-drop-mode=<pop|clear|block>``
Select the behavior when the frame queue is full.
pop
- Drop the oldest frame in the frame queue. (default)
+ Drop the oldest frame in the frame queue.
clear
Drop all frames in the frame queue.
+ block
+ Wait for a short time, behave like ``clear`` on timeout. (default)
This also supports many of the suboptions the ``opengl`` VO has. Run
``mpv --vo=opengl-cb:help`` for a list.
diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c
index ad8487ebaf..77bf5ed025 100644
--- a/video/out/vo_opengl_cb.c
+++ b/video/out/vo_opengl_cb.c
@@ -39,6 +39,7 @@
#define FRAME_DROP_POP 0 // drop the oldest frame in queue
#define FRAME_DROP_CLEAR 1 // drop all frames in queue
+#define FRAME_DROP_BLOCK 2
struct vo_priv {
struct vo *vo;
@@ -57,6 +58,7 @@ struct mpv_opengl_cb_context {
struct mp_client_api *client_api;
pthread_mutex_t lock;
+ pthread_cond_t wakeup;
// --- Protected by lock
bool initialized;
@@ -104,6 +106,7 @@ static struct mp_image *frame_queue_pop(struct mpv_opengl_cb_context *ctx)
return NULL;
struct mp_image *ret = ctx->frame_queue[0];
MP_TARRAY_REMOVE_AT(ctx->frame_queue, ctx->queued_frames, 0);
+ pthread_cond_broadcast(&ctx->wakeup);
return ret;
}
@@ -114,6 +117,7 @@ static void frame_queue_drop(struct mpv_opengl_cb_context *ctx)
talloc_free(mpi);
if (ctx->active)
vo_increment_drop_count(ctx->active, 1);
+ pthread_cond_broadcast(&ctx->wakeup);
}
}
@@ -124,6 +128,7 @@ static void frame_queue_clear(struct mpv_opengl_cb_context *ctx)
talloc_free(ctx->frame_queue);
ctx->frame_queue = NULL;
ctx->queued_frames = 0;
+ pthread_cond_broadcast(&ctx->wakeup);
}
static void frame_queue_drop_all(struct mpv_opengl_cb_context *ctx)
@@ -132,21 +137,25 @@ static void frame_queue_drop_all(struct mpv_opengl_cb_context *ctx)
frame_queue_clear(ctx);
if (ctx->active && frames > 0)
vo_increment_drop_count(ctx->active, frames);
+ pthread_cond_broadcast(&ctx->wakeup);
}
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);
+ pthread_cond_broadcast(&ctx->wakeup);
}
static void frame_queue_shrink(struct mpv_opengl_cb_context *ctx, int size)
{
+ pthread_cond_broadcast(&ctx->wakeup);
while (ctx->queued_frames > size)
frame_queue_drop(ctx);
}
static void forget_frames(struct mpv_opengl_cb_context *ctx)
{
+ pthread_cond_broadcast(&ctx->wakeup);
frame_queue_clear(ctx);
mp_image_unrefp(&ctx->waiting_frame);
}
@@ -159,6 +168,7 @@ static void free_ctx(void *ptr)
// mpv_opengl_cb_uninit_gl() properly.
assert(!ctx->initialized);
+ pthread_cond_destroy(&ctx->wakeup);
pthread_mutex_destroy(&ctx->lock);
}
@@ -168,6 +178,7 @@ struct mpv_opengl_cb_context *mp_opengl_create(struct mpv_global *g,
mpv_opengl_cb_context *ctx = talloc_zero(NULL, mpv_opengl_cb_context);
talloc_set_destructor(ctx, free_ctx);
pthread_mutex_init(&ctx->lock, NULL);
+ pthread_cond_init(&ctx->wakeup, NULL);
ctx->gl = talloc_zero(ctx, GL);
@@ -374,11 +385,20 @@ static void flip_page(struct vo *vo)
struct vo_priv *p = vo->priv;
pthread_mutex_lock(&p->ctx->lock);
- if (p->ctx->queued_frames >= p->frame_queue_size) {
- if (p->frame_drop_mode == FRAME_DROP_CLEAR)
+ while (p->ctx->queued_frames >= p->frame_queue_size) {
+ switch (p->frame_drop_mode) {
+ case FRAME_DROP_CLEAR:
frame_queue_drop_all(p->ctx);
- else // FRAME_DROP_POP mode
+ break;
+ case FRAME_DROP_POP:
frame_queue_shrink(p->ctx, p->frame_queue_size - 1);
+ break;
+ case FRAME_DROP_BLOCK: ;
+ struct timespec ts = mp_rel_time_to_timespec(0.2);
+ if (pthread_cond_timedwait(&p->ctx->wakeup, &p->ctx->lock, &ts))
+ frame_queue_drop_all(p->ctx);
+ break;
+ }
}
frame_queue_push(p->ctx, p->ctx->waiting_frame);
p->ctx->waiting_frame = NULL;
@@ -418,7 +438,8 @@ static const struct m_option change_opts[] = {
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})),
+ {"clear", FRAME_DROP_CLEAR},
+ {"block", FRAME_DROP_BLOCK})),
OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0),
{0}
};
@@ -555,7 +576,8 @@ static const struct m_option options[] = {
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})),
+ {"clear", FRAME_DROP_CLEAR},
+ {"block", FRAME_DROP_BLOCK}), OPTDEF_INT(FRAME_DROP_BLOCK)),
OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0),
{0},
};