summaryrefslogtreecommitdiffstats
path: root/player/playloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/playloop.c')
-rw-r--r--player/playloop.c121
1 files changed, 92 insertions, 29 deletions
diff --git a/player/playloop.c b/player/playloop.c
index ed4f57dd5c..18a51f33d0 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -28,6 +28,7 @@
#include "options/options.h"
#include "common/common.h"
#include "common/encode.h"
+#include "options/m_config.h"
#include "options/m_property.h"
#include "common/playlist.h"
#include "input/input.h"
@@ -50,26 +51,66 @@
#include "client.h"
#include "command.h"
-// Wait until mp_input_wakeup(mpctx->input) is called, since the last time
-// mp_wait_events() was called. (But see mp_process_input().)
-void mp_wait_events(struct MPContext *mpctx, double sleeptime)
+// Wait until mp_wakeup_core() is called, since the last time
+// mp_wait_events() was called.
+void mp_wait_events(struct MPContext *mpctx)
{
- mp_input_wait(mpctx->input, sleeptime);
+ if (mpctx->sleeptime > 0)
+ MP_STATS(mpctx, "start sleep");
+
+ mpctx->in_dispatch = true;
+
+ mp_dispatch_queue_process(mpctx->dispatch, mpctx->sleeptime);
+
+ while (mpctx->suspend_count)
+ mp_dispatch_queue_process(mpctx->dispatch, 100);
+
+ mpctx->in_dispatch = false;
+ mpctx->sleeptime = INFINITY;
+
+ if (mpctx->sleeptime > 0)
+ MP_STATS(mpctx, "end sleep");
+}
+
+// Set the timeout used when the playloop goes to sleep. This means the
+// playloop will re-run as soon as the timeout elapses (or earlier).
+// mp_set_timeout(c, 0) is essentially equivalent to mp_wakeup_core(c).
+void mp_set_timeout(struct MPContext *mpctx, double sleeptime)
+{
+ mpctx->sleeptime = MPMIN(mpctx->sleeptime, sleeptime);
+
+ // Can't adjust timeout if called from mp_dispatch_queue_process().
+ if (mpctx->in_dispatch && isfinite(sleeptime))
+ mp_wakeup_core(mpctx);
+}
+
+// Cause the playloop to run. This can be called from any thread. If called
+// from within the playloop itself, it will be run immediately again, instead
+// of going to sleep in the next mp_wait_events().
+void mp_wakeup_core(struct MPContext *mpctx)
+{
+ mp_dispatch_interrupt(mpctx->dispatch);
+}
+
+// Opaque callback variant of mp_wakeup_core().
+void mp_wakeup_core_cb(void *ctx)
+{
+ struct MPContext *mpctx = ctx;
+ mp_wakeup_core(mpctx);
}
// Process any queued input, whether it's user input, or requests from client
// API threads. This also resets the "wakeup" flag used with mp_wait_events().
void mp_process_input(struct MPContext *mpctx)
{
- mp_dispatch_queue_process(mpctx->dispatch, 0);
for (;;) {
mp_cmd_t *cmd = mp_input_read_cmd(mpctx->input);
if (!cmd)
break;
run_command(mpctx, cmd, NULL);
mp_cmd_free(cmd);
- mp_dispatch_queue_process(mpctx->dispatch, 0);
}
+ mp_set_timeout(mpctx, mp_input_get_delay(mpctx->input));
}
double get_relative_time(struct MPContext *mpctx)
@@ -84,8 +125,7 @@ void pause_player(struct MPContext *mpctx)
{
mpctx->opts->pause = 1;
- if (mpctx->video_out)
- vo_control(mpctx->video_out, VOCTRL_RESTORE_SCREENSAVER, NULL);
+ update_screensaver_state(mpctx);
if (mpctx->paused)
goto end;
@@ -101,6 +141,8 @@ void pause_player(struct MPContext *mpctx)
if (mpctx->video_out)
vo_set_paused(mpctx->video_out, true);
+ mp_wakeup_core(mpctx);
+
end:
mp_notify(mpctx, mpctx->opts->pause ? MPV_EVENT_PAUSE : MPV_EVENT_UNPAUSE, 0);
}
@@ -109,8 +151,7 @@ void unpause_player(struct MPContext *mpctx)
{
mpctx->opts->pause = 0;
- if (mpctx->video_out && mpctx->opts->stop_screensaver)
- vo_control(mpctx->video_out, VOCTRL_KILL_SCREENSAVER, NULL);
+ update_screensaver_state(mpctx);
if (!mpctx->paused)
goto end;
@@ -126,12 +167,25 @@ void unpause_player(struct MPContext *mpctx)
if (mpctx->video_out)
vo_set_paused(mpctx->video_out, false);
+ mp_wakeup_core(mpctx);
+
(void)get_relative_time(mpctx); // ignore time that passed during pause
end:
mp_notify(mpctx, mpctx->opts->pause ? MPV_EVENT_PAUSE : MPV_EVENT_UNPAUSE, 0);
}
+void update_screensaver_state(struct MPContext *mpctx)
+{
+ if (!mpctx->video_out)
+ return;
+
+ bool saver_state = mpctx->opts->pause || !mpctx->opts->stop_screensaver ||
+ !mpctx->playback_initialized;
+ vo_control(mpctx->video_out, saver_state ? VOCTRL_RESTORE_SCREENSAVER
+ : VOCTRL_KILL_SCREENSAVER, NULL);
+}
+
void add_step_frame(struct MPContext *mpctx, int dir)
{
if (!mpctx->vo_chain)
@@ -297,7 +351,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
mpctx->stop_play = KEEP_PLAYING;
mpctx->start_timestamp = mp_time_sec();
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
mp_notify(mpctx, MPV_EVENT_SEEK, NULL);
mp_notify(mpctx, MPV_EVENT_TICK, NULL);
@@ -314,6 +368,8 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
{
struct seek_params *seek = &mpctx->seek;
+ mp_wakeup_core(mpctx);
+
if (mpctx->stop_play == AT_END_OF_FILE)
mpctx->stop_play = KEEP_PLAYING;
@@ -520,7 +576,7 @@ static void handle_osd_redraw(struct MPContext *mpctx)
// Don't redraw immediately during a seek (makes it significantly slower).
bool use_video = mpctx->vo_chain && !mpctx->vo_chain->is_coverart;
if (use_video && mp_time_sec() - mpctx->start_timestamp < 0.1) {
- mpctx->sleeptime = MPMIN(mpctx->sleeptime, 0.1);
+ mp_set_timeout(mpctx, 0.1);
return;
}
bool want_redraw = osd_query_and_reset_want_redraw(mpctx->osd) ||
@@ -528,7 +584,7 @@ static void handle_osd_redraw(struct MPContext *mpctx)
if (!want_redraw)
return;
vo_redraw(mpctx->video_out);
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
}
static void handle_pause_on_low_cache(struct MPContext *mpctx)
@@ -564,7 +620,7 @@ static void handle_pause_on_low_cache(struct MPContext *mpctx)
unpause_player(mpctx);
force_update = true;
}
- mpctx->sleeptime = MPMIN(mpctx->sleeptime, 0.2);
+ mp_set_timeout(mpctx, 0.2);
} else {
if (opts->cache_pausing && s.underrun) {
bool prev_paused_user = opts->pause;
@@ -589,10 +645,8 @@ static void handle_pause_on_low_cache(struct MPContext *mpctx)
mpctx->next_cache_update = busy ? now + 0.25 : 0;
force_update = true;
}
- if (mpctx->next_cache_update > 0) {
- mpctx->sleeptime =
- MPMIN(mpctx->sleeptime, mpctx->next_cache_update - now);
- }
+ if (mpctx->next_cache_update > 0)
+ mp_set_timeout(mpctx, mpctx->next_cache_update - now);
}
if (mpctx->cache_buffer != cache_buffer) {
@@ -628,7 +682,7 @@ static void handle_heartbeat_cmd(struct MPContext *mpctx)
mpctx->next_heartbeat = now + opts->heartbeat_interval;
(void)system(opts->heartbeat_cmd);
}
- mpctx->sleeptime = MPMIN(mpctx->sleeptime, mpctx->next_heartbeat - now);
+ mp_set_timeout(mpctx, mpctx->next_heartbeat - now);
}
}
@@ -651,7 +705,7 @@ static void handle_cursor_autohide(struct MPContext *mpctx)
}
if (mpctx->mouse_timer > now) {
- mpctx->sleeptime = MPMIN(mpctx->sleeptime, mpctx->mouse_timer - now);
+ mp_set_timeout(mpctx, mpctx->mouse_timer - now);
} else {
mouse_cursor_visible = false;
}
@@ -662,7 +716,7 @@ static void handle_cursor_autohide(struct MPContext *mpctx)
if (opts->cursor_autohide_delay == -2)
mouse_cursor_visible = false;
- if (opts->cursor_autohide_fs && !opts->vo.fullscreen)
+ if (opts->cursor_autohide_fs && !opts->vo->fullscreen)
mouse_cursor_visible = true;
if (mouse_cursor_visible != mpctx->mouse_cursor_visible)
@@ -678,6 +732,14 @@ static void handle_vo_events(struct MPContext *mpctx)
mp_notify(mpctx, MP_EVENT_WIN_RESIZE, NULL);
if (events & VO_EVENT_WIN_STATE)
mp_notify(mpctx, MP_EVENT_WIN_STATE, NULL);
+ if (events & VO_EVENT_FULLSCREEN_STATE) {
+ // The only purpose of this is to update the fullscreen flag on the
+ // playloop side if it changes "from outside" on the VO.
+ int fs = mpctx->opts->vo->fullscreen;
+ vo_control(vo, VOCTRL_GET_FULLSCREEN, &fs);
+ m_config_set_option_raw_direct(mpctx->mconfig,
+ m_config_get_co(mpctx->mconfig, bstr0("fullscreen")), &fs, 0);
+ }
}
static void handle_sstep(struct MPContext *mpctx)
@@ -813,6 +875,9 @@ int handle_force_window(struct MPContext *mpctx, bool force)
.input_ctx = mpctx->input,
.osd = mpctx->osd,
.encode_lavc_ctx = mpctx->encode_lavc_ctx,
+ .opengl_cb_context = mpctx->gl_cb_ctx,
+ .wakeup_cb = mp_wakeup_core_cb,
+ .wakeup_ctx = mpctx,
};
mpctx->video_out = init_best_video_out(mpctx->global, &ex);
if (!mpctx->video_out)
@@ -895,7 +960,7 @@ static void handle_playback_restart(struct MPContext *mpctx)
if (mpctx->video_status == STATUS_READY) {
mpctx->video_status = STATUS_PLAYING;
get_relative_time(mpctx);
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
}
if (mpctx->audio_status == STATUS_READY) {
@@ -933,7 +998,7 @@ static void handle_playback_restart(struct MPContext *mpctx)
}
}
mpctx->playing_msg_shown = true;
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
mpctx->ab_loop_clip = mpctx->playback_pts < opts->ab_loop[1];
MP_VERBOSE(mpctx, "playback restart complete\n");
}
@@ -1013,7 +1078,7 @@ void run_playloop(struct MPContext *mpctx)
if (mpctx->lavfi) {
if (lavfi_process(mpctx->lavfi))
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
if (lavfi_has_failed(mpctx->lavfi))
mpctx->stop_play = AT_END_OF_FILE;
}
@@ -1047,8 +1112,7 @@ void run_playloop(struct MPContext *mpctx)
handle_osd_redraw(mpctx);
- mp_wait_events(mpctx, mpctx->sleeptime);
- mpctx->sleeptime = 1e9; // infinite for all practical purposes
+ mp_wait_events(mpctx);
handle_pause_on_low_cache(mpctx);
@@ -1064,8 +1128,7 @@ void run_playloop(struct MPContext *mpctx)
void mp_idle(struct MPContext *mpctx)
{
handle_dummy_ticks(mpctx);
- mp_wait_events(mpctx, mpctx->sleeptime);
- mpctx->sleeptime = 100.0;
+ mp_wait_events(mpctx);
mp_process_input(mpctx);
handle_command_updates(mpctx);
handle_cursor_autohide(mpctx);
@@ -1085,7 +1148,7 @@ void idle_loop(struct MPContext *mpctx)
if (need_reinit) {
uninit_audio_out(mpctx);
handle_force_window(mpctx, true);
- mpctx->sleeptime = 0;
+ mp_wakeup_core(mpctx);
mp_notify(mpctx, MPV_EVENT_IDLE, NULL);
need_reinit = false;
}