summaryrefslogtreecommitdiffstats
path: root/player/main.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-02-10 21:01:35 +0100
committerwm4 <wm4@nowhere>2014-02-10 21:01:35 +0100
commit88ae914b1ef2b76362c527985bd459b0d8226d45 (patch)
treefbab27d01347c98fd36348821fafc47037193810 /player/main.c
parentc6166ff448432dc74c300933e5c93838d06c420a (diff)
downloadmpv-88ae914b1ef2b76362c527985bd459b0d8226d45.tar.bz2
mpv-88ae914b1ef2b76362c527985bd459b0d8226d45.tar.xz
Add a client API
Add a client API, which is intended to be a stable API to get some rough control over the player. Basically, it reflects what can be done with input.conf commands or the old slavemode. It will replace the old slavemode (and enable the implementation of a new slave protocol).
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);