diff --git a/common/msg.c b/common/msg.c index 2454dcea8d341..650b183fd42dd 100644 --- a/common/msg.c +++ b/common/msg.c @@ -1029,6 +1029,14 @@ void mp_msg_set_early_logging(struct mpv_global *global, bool enable) { struct mp_log_root *root = global->log->root; + if (enable) { + // Nothing is initialized when we get here, so default to logging to the + // terminal. There normally aren't any messages unless verbose is enabled. + char *verbose_env = getenv("MPV_VERBOSE"); + root->verbose = verbose_env ? strtol(verbose_env, NULL, 10) : 0; + root->use_terminal = true; + } + mp_msg_set_early_logging_raw(global, enable, &root->early_buffer, EARLY_TERM_BUF, MP_LOG_BUFFER_MSGL_TERM); diff --git a/player/main.c b/player/main.c index 0ef3d7f6d6581..e6a9cb820a684 100644 --- a/player/main.c +++ b/player/main.c @@ -290,17 +290,18 @@ struct MPContext *mp_create(void) mpctx->global = talloc_zero(mpctx, struct mpv_global); + // Nothing must call mp_msg*() and related before this + mp_msg_init(mpctx->global); + mp_msg_set_early_logging(mpctx->global, true); + mpctx->log = mp_log_new(mpctx, mpctx->global->log, "!cplayer"); + mpctx->statusline = mp_log_new(mpctx, mpctx->log, "!statusline"); + demux_packet_pool_init(mpctx->global); stats_global_init(mpctx->global); #if HAVE_LIBCURL mp_curl_global_init(mpctx->global); #endif - // Nothing must call mp_msg*() and related before this - mp_msg_init(mpctx->global); - mpctx->log = mp_log_new(mpctx, mpctx->global->log, "!cplayer"); - mpctx->statusline = mp_log_new(mpctx, mpctx->log, "!statusline"); - mpctx->stats = stats_ctx_create(mpctx, mpctx->global, "main"); // Create the config context and register the options @@ -326,10 +327,6 @@ struct MPContext *mp_create(void) cocoa_set_input_context(mpctx->input); #endif - char *verbose_env = getenv("MPV_VERBOSE"); - if (verbose_env) - mpctx->opts->verbose = strtol(verbose_env, NULL, 10); - mp_cancel_trigger(mpctx->playback_abort); return mpctx; @@ -353,7 +350,6 @@ int mp_initialize(struct MPContext *mpctx, char **options) } mp_init_paths(mpctx->global, opts); - mp_msg_set_early_logging(mpctx->global, true); mp_update_logging(mpctx, true); if (options) { diff --git a/stream/stream_curl.c b/stream/stream_curl.c index ceb843bc4da01..11e1f30a8094d 100644 --- a/stream/stream_curl.c +++ b/stream/stream_curl.c @@ -142,7 +142,9 @@ static const struct curl_scheme *curl_scheme_lookup(bstr url) return NULL; } +// Global state struct curl_ctx { + struct mp_log *log; mp_thread thread; struct mp_dispatch_queue *dispatch; CURLM *multi; @@ -299,11 +301,18 @@ static MP_THREAD_VOID curl_thread(void *arg) mp_thread_set_name("curl"); struct curl_ctx *ctx = arg; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT); + if (res != CURLE_OK) { + MP_ERR(ctx, "libcurl failed to initialize: %d\n", (int)res); + MP_THREAD_RETURN(); + } + ctx->multi = curl_multi_init(); + mp_require(ctx->multi); curl_multi_setopt(ctx->multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); mp_dispatch_set_wakeup_fn(ctx->dispatch, curl_wakeup, ctx); + MP_TRACE(ctx, "thread is ready\n"); while (!ctx->exit) { mp_dispatch_queue_process(ctx->dispatch, 0); @@ -314,8 +323,10 @@ static MP_THREAD_VOID curl_thread(void *arg) int running = 0; CURLMcode mres = curl_multi_perform(ctx->multi, &running); - if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) + if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) { + MP_ERR(ctx, "perform error: %s\n", curl_multi_strerror(mres)); break; + } CURLMsg *msg; int left = 0; @@ -325,16 +336,20 @@ static MP_THREAD_VOID curl_thread(void *arg) struct priv *p = NULL; curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &p); mp_assert(p); - curl_multi_remove_handle(ctx->multi, msg->easy_handle); + mres = curl_multi_remove_handle(ctx->multi, msg->easy_handle); + mp_assert(mres == CURLM_OK); p->active = false; on_done(p, msg->data.result); } - curl_multi_poll(ctx->multi, NULL, 0, 1000, NULL); + mres = curl_multi_poll(ctx->multi, NULL, 0, 1000, NULL); + if (mres != CURLM_OK) { + MP_WARN(ctx, "poll error: %s\n", curl_multi_strerror(mres)); + } } curl_multi_cleanup(ctx->multi); - curl_global_cleanup(); + ctx->multi = NULL; MP_THREAD_RETURN(); } @@ -342,14 +357,17 @@ static void mp_curl_destroy(void *ptr) { struct curl_ctx *ctx = ptr; struct cmd c = { .kind = CMD_EXIT, .ctx = ctx }; - mp_dispatch_run(ctx->dispatch, run_cmd, &c); + // use async cmd in case the thread is already dead + mp_dispatch_enqueue_autofree(ctx->dispatch, run_cmd, talloc_dup(NULL, &c)); mp_thread_join(ctx->thread); + curl_global_cleanup(); } void mp_curl_global_init(struct mpv_global *global) { struct curl_ctx *ctx = talloc_zero(global, struct curl_ctx); talloc_set_destructor(ctx, mp_curl_destroy); + ctx->log = mp_log_new(ctx, global->log, "curl"); ctx->dispatch = mp_dispatch_create(ctx); global->curl = ctx; mp_require(!mp_thread_create(&ctx->thread, curl_thread, ctx)); @@ -917,7 +935,8 @@ static int curl_control(struct stream *s, int cmd, void *arg) static void priv_destructor(void *ptr) { struct priv *p = ptr; - mp_cancel_set_cb(p->s->cancel, NULL, NULL); + if (p->s->cancel) + mp_cancel_set_cb(p->s->cancel, NULL, NULL); if (p->curl) { cmd_sync(p, CMD_REMOVE, 0, false); curl_easy_cleanup(p->curl); @@ -933,7 +952,8 @@ static void curl_close(struct stream *s) struct priv *p = s->priv; if (!p) return; - mp_cancel_set_cb(s->cancel, NULL, NULL); + if (s->cancel) + mp_cancel_set_cb(s->cancel, NULL, NULL); if (p->curl) { cmd_sync(p, CMD_REMOVE, 0, false); curl_easy_cleanup(p->curl); @@ -949,6 +969,10 @@ static int curl_open(stream_t *s, const struct stream_open_args *args) MP_ERR(s, "curl backend not initialized\n"); return STREAM_ERROR; } + if (!s->global->curl->multi) { + // curl thread is gone for some reason, fall back cleanly + return STREAM_NO_MATCH; + } struct curl_opts *opts = mp_get_config_group(s, s->global, &curl_conf); if (!opts->enabled) @@ -994,7 +1018,8 @@ static int curl_open(stream_t *s, const struct stream_open_args *args) } setup_curl(p); - mp_cancel_set_cb(s->cancel, on_cancel, p); + if (s->cancel) + mp_cancel_set_cb(s->cancel, on_cancel, p); cmd_sync(p, CMD_ADD, 0, false);