summaryrefslogtreecommitdiffstats
path: root/player/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/main.c')
-rw-r--r--player/main.c208
1 files changed, 132 insertions, 76 deletions
diff --git a/player/main.c b/player/main.c
index e0371cc5ca..c455a0641c 100644
--- a/player/main.c
+++ b/player/main.c
@@ -31,6 +31,7 @@
#include "osdep/priority.h"
#include "osdep/terminal.h"
#include "osdep/timer.h"
+#include "osdep/threads.h"
#include "common/av_log.h"
#include "common/codecs.h"
@@ -61,6 +62,7 @@
#include "video/out/vo.h"
#include "core.h"
+#include "client.h"
#include "lua.h"
#include "command.h"
#include "screenshot.h"
@@ -89,6 +91,8 @@
#endif
#endif
+static bool terminal_initialized;
+
const char mp_help_text[] =
"Usage: mpv [options] [url|path/]filename\n"
"\n"
@@ -113,11 +117,20 @@ void mp_print_version(struct mp_log *log, int always)
mp_msg(log, v, "\n");
}
-static MP_NORETURN void exit_player(struct MPContext *mpctx,
- enum exit_reason how)
+static void shutdown_clients(struct MPContext *mpctx)
{
- int rc;
- uninit_player(mpctx, INITIALIZED_ALL);
+ while (mpctx->clients && mp_clients_num(mpctx)) {
+ mp_client_broadcast_event(mpctx, MPV_EVENT_SHUTDOWN, NULL);
+ mp_dispatch_queue_process(mpctx->dispatch, 0);
+ mp_input_get_cmd(mpctx->input, 100, 1);
+ }
+ mp_clients_destroy(mpctx);
+}
+
+void mp_destroy(struct MPContext *mpctx)
+{
+ if (mpctx->initialized)
+ uninit_player(mpctx, INITIALIZED_ALL);
#if HAVE_ENCODING
encode_lavc_finish(mpctx->encode_lavc_ctx);
@@ -129,10 +142,7 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx,
#if HAVE_LUA
mp_lua_uninit(mpctx);
#endif
-
-#if HAVE_COCOA
- cocoa_set_input_context(NULL);
-#endif
+ shutdown_clients(mpctx);
command_uninit(mpctx);
@@ -141,14 +151,27 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx,
osd_free(mpctx->osd);
#if HAVE_LIBASS
- ass_library_done(mpctx->ass_library);
- mpctx->ass_library = NULL;
+ if (mpctx->ass_library)
+ ass_library_done(mpctx->ass_library);
#endif
if (mpctx->opts->use_terminal)
getch2_disable();
uninit_libav(mpctx->global);
+ mp_msg_uninit(mpctx->global);
+ talloc_free(mpctx);
+}
+
+static MP_NORETURN void exit_player(struct MPContext *mpctx,
+ enum exit_reason how)
+{
+ int rc;
+
+#if HAVE_COCOA
+ cocoa_set_input_context(NULL);
+#endif
+
if (how != EXIT_NONE) {
const char *reason;
switch (how) {
@@ -183,11 +206,7 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx,
}
}
- // must be last since e.g. mp_msg uses option values
- // that will be freed by this.
-
- mp_msg_uninit(mpctx->global);
- talloc_free(mpctx);
+ mp_destroy(mpctx);
#if HAVE_COCOA
terminate_cocoa_application();
@@ -284,8 +303,6 @@ static void osdep_preinit(int *p_argc, char ***p_argv)
if (pSetSearchPathMode)
pSetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
#endif
-
- mp_time_init();
}
static int cfg_include(void *ctx, char *filename, int flags)
@@ -294,14 +311,10 @@ static int cfg_include(void *ctx, char *filename, int flags)
return m_config_parse_config_file(mpctx->mconfig, filename, flags);
}
-static int mpv_main(int argc, char *argv[])
+struct MPContext *mp_create(void)
{
- osdep_preinit(&argc, &argv);
-
- if (argc >= 1) {
- argc--;
- argv++;
- }
+ mp_time_init();
+ GetCpuCaps(&gCpuCaps);
struct MPContext *mpctx = talloc(NULL, MPContext);
*mpctx = (struct MPContext){
@@ -309,6 +322,7 @@ static int mpv_main(int argc, char *argv[])
.term_osd_contents = talloc_strdup(mpctx, ""),
.osd_progbar = { .type = -1 },
.playlist = talloc_struct(mpctx, struct playlist, {0}),
+ .dispatch = mp_dispatch_create(mpctx),
};
mpctx->global = talloc_zero(mpctx, struct mpv_global);
@@ -331,68 +345,35 @@ static int mpv_main(int argc, char *argv[])
mpctx->mconfig->use_profiles = true;
mpctx->mconfig->is_toplevel = true;
- struct MPOpts *opts = mpctx->opts;
- mpctx->global->opts = opts;
+ mpctx->global->opts = mpctx->opts;
- char *verbose_env = getenv("MPV_VERBOSE");
- if (verbose_env)
- opts->verbose = atoi(verbose_env);
-
- // Preparse the command line
- m_config_preparse_command_line(mpctx->mconfig, mpctx->global, argc, argv);
-
- mp_msg_update_msglevels(mpctx->global);
-
- if (opts->use_terminal)
- terminal_init();
-
- init_libav(mpctx->global);
- GetCpuCaps(&gCpuCaps);
screenshot_init(mpctx);
mpctx->mixer = mixer_init(mpctx, mpctx->global);
command_init(mpctx);
+ init_libav(mpctx->global);
+ mp_clients_init(mpctx);
- mp_print_version(mpctx->log, false);
-
- if (!mp_parse_cfgfiles(mpctx))
- exit_player(mpctx, EXIT_ERROR);
-
- int r = m_config_parse_mp_command_line(mpctx->mconfig, mpctx->playlist,
- mpctx->global, argc, argv);
- if (r < 0) {
- if (r <= M_OPT_EXIT) {
- exit_player(mpctx, EXIT_NONE);
- } else {
- exit_player(mpctx, EXIT_ERROR);
- }
- }
-
- mp_msg_update_msglevels(mpctx->global);
+ return mpctx;
+}
- if (handle_help_options(mpctx))
- exit_player(mpctx, EXIT_NONE);
+// Finish mpctx initialization. This must be done after setting up all options.
+// Some of the initializations depend on the options, and can't be changed or
+// undone later.
+// cplayer: true if called by the command line player, false for client API
+// Returns: <0 on error, 0 on success.
+int mp_initialize(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = mpctx->opts;
- MP_VERBOSE(mpctx, "Configuration: " CONFIGURATION "\n");
- MP_VERBOSE(mpctx, "Command line:");
- for (int i = 0; i < argc; i++)
- MP_VERBOSE(mpctx, " '%s'", argv[i]);
- MP_VERBOSE(mpctx, "\n");
+ assert(!mpctx->initialized);
- if (!mpctx->playlist->first && !opts->player_idle_mode) {
- mp_print_version(mpctx->log, true);
- MP_INFO(mpctx, "%s", mp_help_text);
- exit_player(mpctx, EXIT_NONE);
+ if (mpctx->opts->use_terminal && !terminal_initialized) {
+ terminal_initialized = true;
+ terminal_init();
}
-#if HAVE_PRIORITY
- set_priority();
-#endif
-
mpctx->input = mp_input_init(mpctx->global);
stream_set_interrupt_callback(mp_input_check_interrupt, mpctx->input);
-#if HAVE_COCOA
- cocoa_set_input_context(mpctx->input);
-#endif
#if HAVE_ENCODING
if (opts->encode_output.file && *opts->encode_output.file) {
@@ -400,7 +381,7 @@ static int mpv_main(int argc, char *argv[])
mpctx->global);
if(!mpctx->encode_lavc_ctx) {
MP_INFO(mpctx, "Encoding initialization failed.");
- exit_player(mpctx, EXIT_ERROR);
+ return -1;
}
m_config_set_option0(mpctx->mconfig, "vo", "lavc");
m_config_set_option0(mpctx->mconfig, "ao", "lavc");
@@ -431,6 +412,9 @@ static int mpv_main(int argc, char *argv[])
mpctx->osd = osd_create(mpctx->global);
+ // From this point on, all mpctx members are initialized.
+ mpctx->initialized = true;
+
if (opts->force_vo) {
opts->fixed_vo = 1;
mpctx->video_out = init_best_video_out(mpctx->global, mpctx->input,
@@ -438,7 +422,7 @@ static int mpv_main(int argc, char *argv[])
if (!mpctx->video_out) {
MP_FATAL(mpctx, "Error opening/initializing "
"the selected video_out (-vo) device.\n");
- exit_player(mpctx, EXIT_ERROR);
+ return -1;
}
mpctx->mouse_cursor_visible = true;
mpctx->initialized_flags |= INITIALIZED_VO;
@@ -460,6 +444,78 @@ static int mpv_main(int argc, char *argv[])
if (!mpctx->playlist->current)
mpctx->playlist->current = mpctx->playlist->first;
+ return 0;
+}
+
+static int mpv_main(int argc, char *argv[])
+{
+ osdep_preinit(&argc, &argv);
+
+ if (argc >= 1) {
+ argc--;
+ argv++;
+ }
+
+ struct MPContext *mpctx = mp_create();
+ struct MPOpts *opts = mpctx->opts;
+
+ char *verbose_env = getenv("MPV_VERBOSE");
+ if (verbose_env)
+ opts->verbose = atoi(verbose_env);
+
+ // Preparse the command line
+ m_config_preparse_command_line(mpctx->mconfig, mpctx->global, argc, argv);
+
+ if (mpctx->opts->use_terminal && !terminal_initialized) {
+ terminal_initialized = true;
+ terminal_init();
+ }
+
+ mp_msg_update_msglevels(mpctx->global);
+
+ mp_print_version(mpctx->log, false);
+
+ if (!mp_parse_cfgfiles(mpctx))
+ exit_player(mpctx, EXIT_ERROR);
+
+ int r = m_config_parse_mp_command_line(mpctx->mconfig, mpctx->playlist,
+ mpctx->global, argc, argv);
+ if (r < 0) {
+ if (r <= M_OPT_EXIT) {
+ exit_player(mpctx, EXIT_NONE);
+ } else {
+ exit_player(mpctx, EXIT_ERROR);
+ }
+ }
+
+ mp_msg_update_msglevels(mpctx->global);
+
+ if (handle_help_options(mpctx))
+ exit_player(mpctx, EXIT_NONE);
+
+ MP_VERBOSE(mpctx, "Configuration: " CONFIGURATION "\n");
+ MP_VERBOSE(mpctx, "Command line:");
+ for (int i = 0; i < argc; i++)
+ MP_VERBOSE(mpctx, " '%s'", argv[i]);
+ MP_VERBOSE(mpctx, "\n");
+
+ if (!mpctx->playlist->first && !opts->player_idle_mode) {
+ mp_print_version(mpctx->log, true);
+ MP_INFO(mpctx, "%s", mp_help_text);
+ exit_player(mpctx, EXIT_NONE);
+ }
+
+#if HAVE_PRIORITY
+ set_priority();
+#endif
+
+ if (mp_initialize(mpctx) < 0)
+ exit_player(mpctx, EXIT_ERROR);
+
+#if HAVE_COCOA
+ cocoa_set_input_context(mpctx->input);
+#endif
+
mp_play_files(mpctx);
exit_player(mpctx, mpctx->stop_play == PT_QUIT ? EXIT_QUIT : mpctx->quit_player_rc);