From 88ae914b1ef2b76362c527985bd459b0d8226d45 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 10 Feb 2014 21:01:35 +0100 Subject: 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). --- player/main.c | 208 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 132 insertions(+), 76 deletions(-) (limited to 'player/main.c') 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); -- cgit v1.2.3