summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-09-13 14:23:08 +0200
committerwm4 <wm4@nowhere>2014-09-13 16:09:51 +0200
commit2e91d44e2031c299de0d879e2656024d701c27da (patch)
treefdbe4903705bff3d6a21c42f08eb7e4b31e5cf07 /input
parent2dd819705dcbeb4a20c0d6123082f9662cfa2ae4 (diff)
downloadmpv-2e91d44e2031c299de0d879e2656024d701c27da.tar.bz2
mpv-2e91d44e2031c299de0d879e2656024d701c27da.tar.xz
stream: redo playback abort handling
This mechanism originates from MPlayer's way of dealing with blocking network, but it's still useful. On opening and closing, mpv waits for network synchronously, and also some obscure commands and use-cases can lead to such blocking. In these situations, the stream is asynchronously forced to stop by "interrupting" it. The old design interrupting I/O was a bit broken: polling with a callback, instead of actively interrupting it. Change the direction of this. There is no callback anymore, and the player calls mp_cancel_trigger() to force the stream to return. libavformat (via stream_lavf.c) has the old broken design, and fixing it would require fixing libavformat, which won't happen so quickly. So we have to keep that part. But everything above the stream layer is prepared for a better design, and more sophisticated methods than mp_cancel_test() could be easily introduced. There's still one problem: commands are still run in the central playback loop, which we assume can block on I/O in the worst case. That's not a problem yet, because we simply mark some commands as being able to stop playback of the current file ("quit" etc.), so input.c could abort playback as soon as such a command is queued. But there are also commands abort playback only conditionally, and the logic for that is in the playback core and thus "unreachable". For example, "playlist_next" aborts playback only if there's a next file. We don't want it to always abort playback. As a quite ugly hack, abort playback only if at least 2 abort commands are queued - this pretty much happens only if the core is frozen and doesn't react to input.
Diffstat (limited to 'input')
-rw-r--r--input/input.c18
-rw-r--r--input/input.h6
2 files changed, 15 insertions, 9 deletions
diff --git a/input/input.c b/input/input.c
index 776bcaf6fb..3e9b40d158 100644
--- a/input/input.c
+++ b/input/input.c
@@ -156,6 +156,8 @@ struct input_ctx {
int num_sources;
struct cmd_queue cmd_queue;
+
+ struct mp_cancel *cancel;
};
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
@@ -243,10 +245,10 @@ static int queue_count_cmds(struct cmd_queue *queue)
return res;
}
-static bool queue_has_abort_cmds(struct cmd_queue *queue)
+static bool has_abort_cmds(struct input_ctx *ictx)
{
bool ret = false;
- for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next)
+ for (struct mp_cmd *cmd = ictx->cmd_queue.first; cmd; cmd = cmd->queue_next)
if (mp_input_is_abort_cmd(cmd)) {
ret = true;
break;
@@ -556,8 +558,8 @@ static bool key_updown_ok(enum mp_command_type cmd)
static bool should_drop_cmd(struct input_ctx *ictx, struct mp_cmd *cmd)
{
struct cmd_queue *queue = &ictx->cmd_queue;
- return (queue_count_cmds(queue) >= ictx->key_fifo_size &&
- (!mp_input_is_abort_cmd(cmd) || queue_has_abort_cmds(queue)));
+ return queue_count_cmds(queue) >= ictx->key_fifo_size &&
+ !mp_input_is_abort_cmd(cmd);
}
static struct mp_cmd *resolve_key(struct input_ctx *ictx, int code)
@@ -796,6 +798,9 @@ int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd)
{
input_lock(ictx);
if (cmd) {
+ // Abort only if there are going to be at least 2 commands in the queue.
+ if (ictx->cancel && mp_input_is_abort_cmd(cmd) && has_abort_cmds(ictx))
+ mp_cancel_trigger(ictx->cancel);
queue_add_tail(&ictx->cmd_queue, cmd);
mp_input_wakeup(ictx);
}
@@ -1304,12 +1309,11 @@ void mp_input_uninit(struct input_ctx *ictx)
talloc_free(ictx);
}
-bool mp_input_check_interrupt(struct input_ctx *ictx)
+void mp_input_set_cancel(struct input_ctx *ictx, struct mp_cancel *cancel)
{
input_lock(ictx);
- bool res = queue_has_abort_cmds(&ictx->cmd_queue);
+ ictx->cancel = cancel;
input_unlock(ictx);
- return res;
}
bool mp_input_use_alt_gr(struct input_ctx *ictx)
diff --git a/input/input.h b/input/input.h
index 56544a99ee..7096ae62cb 100644
--- a/input/input.h
+++ b/input/input.h
@@ -228,8 +228,10 @@ void mp_input_wakeup(struct input_ctx *ictx);
void mp_input_wakeup_nolock(struct input_ctx *ictx);
-// Interruptible usleep: (used by demux)
-bool mp_input_check_interrupt(struct input_ctx *ictx);
+// Used to asynchronously abort playback. Needed because the core still can
+// block on network in some situations.
+struct mp_cancel;
+void mp_input_set_cancel(struct input_ctx *ictx, struct mp_cancel *cancel);
// If this returns true, use Right Alt key as Alt Gr to produce special
// characters. If false, count Right Alt as the modifier Alt key.