summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-08-20 14:46:38 +0200
committerwm4 <wm4@nowhere>2016-08-20 14:46:38 +0200
commitaf103aebd73609fa143b07805082a23525c8a306 (patch)
treec104ac9f6fcb1f17ae36d6a80b864271197ab2b3
parent969c0115220603b298ea31a2ebe4717ca966b0cc (diff)
downloadmpv-af103aebd73609fa143b07805082a23525c8a306.tar.bz2
mpv-af103aebd73609fa143b07805082a23525c8a306.tar.xz
player: update Windows playback state asynchronously
Doing this required synchronizing with the VO thread, which could lead to audio dropouts if the VO was frozen (which can happen in practice if e.g. an opengl_cb user is not doing what the API demands). Add a way to send asynchronous VOCTRLs, and use that for the playback state. In theory, it would be better to make this status update a several function and to "merge" several queued update, but that would be slightly more effort/code, and the update is so infrequent that the merging would never happen anyway. The change to vo_destroy() is to make sure all queued asynchronous reuqests are finished before making the vo_thread exit. Even though it's only used on MS Windows, it's run on any platform with any VO, which makes this worse.
-rw-r--r--player/misc.c4
-rw-r--r--video/out/vo.c36
-rw-r--r--video/out/vo.h1
3 files changed, 33 insertions, 8 deletions
diff --git a/player/misc.c b/player/misc.c
index bd65fb9d5b..c9e25a3966 100644
--- a/player/misc.c
+++ b/player/misc.c
@@ -149,8 +149,8 @@ void update_vo_playback_state(struct MPContext *mpctx)
if ((oldstate.playing && oldstate.taskbar_progress) ||
(newstate.playing && newstate.taskbar_progress))
{
- vo_control(mpctx->video_out,
- VOCTRL_UPDATE_PLAYBACK_STATE, &newstate);
+ vo_control_async(mpctx->video_out,
+ VOCTRL_UPDATE_PLAYBACK_STATE, &newstate);
}
mpctx->vo_playback_state = newstate;
}
diff --git a/video/out/vo.c b/video/out/vo.c
index 31eae5aef6..f31f55f378 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -297,12 +297,17 @@ autoprobe:
return NULL;
}
+static void terminate_vo(void *p)
+{
+ struct vo *vo = p;
+ struct vo_internal *in = vo->in;
+ in->terminate = true;
+}
+
void vo_destroy(struct vo *vo)
{
struct vo_internal *in = vo->in;
- mp_dispatch_lock(in->dispatch);
- vo->in->terminate = true;
- mp_dispatch_unlock(in->dispatch);
+ mp_dispatch_run(in->dispatch, terminate_vo, vo);
pthread_join(vo->in->thread, NULL);
dealloc_vo(vo);
}
@@ -537,20 +542,39 @@ static void run_control(void *p)
{
void **pp = p;
struct vo *vo = pp[0];
- int request = *(int *)pp[1];
+ int request = (intptr_t)pp[1];
void *data = pp[2];
int ret = vo->driver->control(vo, request, data);
- *(int *)pp[3] = ret;
+ if (pp[3])
+ *(int *)pp[3] = ret;
}
int vo_control(struct vo *vo, int request, void *data)
{
int ret;
- void *p[] = {vo, &request, data, &ret};
+ void *p[] = {vo, (void *)(intptr_t)request, data, &ret};
mp_dispatch_run(vo->in->dispatch, run_control, p);
return ret;
}
+// Run vo_control() without waiting for a reply.
+// (Only works for some VOCTRLs.)
+void vo_control_async(struct vo *vo, int request, void *data)
+{
+ void *p[4] = {vo, (void *)(intptr_t)request, NULL, NULL};
+ void **d = talloc_memdup(NULL, p, sizeof(p));
+
+ switch (request) {
+ case VOCTRL_UPDATE_PLAYBACK_STATE:
+ d[2] = ta_xdup_ptrtype(d, (struct voctrl_playback_state *)data);
+ break;
+ default:
+ abort(); // requires explicit support
+ }
+
+ mp_dispatch_enqueue_autofree(vo->in->dispatch, run_control, d);
+}
+
// must be called locked
static void forget_frames(struct vo *vo)
{
diff --git a/video/out/vo.h b/video/out/vo.h
index 8fdb2ed1e8..ed2fe94e37 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -342,6 +342,7 @@ struct vo *init_best_video_out(struct mpv_global *global, struct vo_extra *ex);
int vo_reconfig(struct vo *vo, struct mp_image_params *p);
int vo_control(struct vo *vo, int request, void *data);
+void vo_control_async(struct vo *vo, int request, void *data);
bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts);
void vo_queue_frame(struct vo *vo, struct vo_frame *frame);
void vo_wait_frame(struct vo *vo);