summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/input.rst3
-rw-r--r--player/command.c16
-rw-r--r--player/core.h4
-rw-r--r--player/loadfile.c93
4 files changed, 93 insertions, 23 deletions
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 205c732781..94e1ea0b1f 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -910,7 +910,8 @@ which will be fixed later. Using the ``async`` prefix makes them run the file
saving code in a detached manner.
Currently the following commands have different waiting characteristics with
-sync vs. async: sub-add, audio-add
+sync vs. async: sub-add, audio-add, sub-reload, audio-reload,
+rescan-external-files.
Input Sections
--------------
diff --git a/player/command.c b/player/command.c
index 9aa3a9e6d8..12c232640a 100644
--- a/player/command.c
+++ b/player/command.c
@@ -5520,7 +5520,7 @@ static void cmd_track_add(void *p)
return;
}
}
- int first = mp_add_external_file(mpctx, cmd->args[0].v.s, type, true);
+ int first = mp_add_external_file(mpctx, cmd->args[0].v.s, type);
if (first < 0) {
cmd->success = false;
return;
@@ -5584,7 +5584,7 @@ static void cmd_track_reload(void *p)
if (t && t->is_external && t->external_filename) {
char *filename = talloc_strdup(NULL, t->external_filename);
mp_remove_track(mpctx, t);
- nt_num = mp_add_external_file(mpctx, filename, type, false);
+ nt_num = mp_add_external_file(mpctx, filename, type);
talloc_free(filename);
}
@@ -6044,7 +6044,9 @@ const struct mp_cmd_def mp_cmds[] = {
{ "sub-remove", cmd_track_remove, { OARG_INT(-1) },
.priv = &(const int){STREAM_SUB}, },
{ "sub-reload", cmd_track_reload, { OARG_INT(-1) },
- .priv = &(const int){STREAM_SUB}, },
+ .priv = &(const int){STREAM_SUB},
+ .spawn_thread = true,
+ },
{ "tv-last-channel", cmd_tv_last_channel, },
@@ -6175,12 +6177,16 @@ const struct mp_cmd_def mp_cmds[] = {
{ "audio-remove", cmd_track_remove, { OARG_INT(-1) },
.priv = &(const int){STREAM_AUDIO}, },
{ "audio-reload", cmd_track_reload, { OARG_INT(-1) },
- .priv = &(const int){STREAM_AUDIO}, },
+ .priv = &(const int){STREAM_AUDIO},
+ .spawn_thread = true,
+ },
{ "rescan-external-files", cmd_rescan_external_files, {
OARG_CHOICE(1, ({"keep-selection", 0},
{"reselect", 1})),
- }},
+ },
+ .spawn_thread = true,
+ },
{ "apply-profile", cmd_apply_profile, {ARG_STRING } },
diff --git a/player/core.h b/player/core.h
index 5ca227a8fa..9a9eb81852 100644
--- a/player/core.h
+++ b/player/core.h
@@ -296,6 +296,8 @@ typedef struct MPContext {
struct track **tracks;
int num_tracks;
+ int64_t death_hack; // don't fucking ask, just don't
+
char *track_layout_hash;
// Selected tracks. NULL if no track selected.
@@ -488,7 +490,7 @@ struct playlist_entry *mp_check_playlist_resume(struct MPContext *mpctx,
void mp_abort_playback_async(struct MPContext *mpctx);
void uninit_player(struct MPContext *mpctx, unsigned int mask);
int mp_add_external_file(struct MPContext *mpctx, char *filename,
- enum stream_type filter, bool unlock);
+ enum stream_type filter);
#define FLAG_MARK_SELECTION 1
void mp_switch_track(struct MPContext *mpctx, enum stream_type type,
struct track *track, int flags);
diff --git a/player/loadfile.c b/player/loadfile.c
index 7acac24f72..766f86a77b 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -26,6 +26,8 @@
#include "config.h"
#include "mpv_talloc.h"
+#include "misc/thread_pool.h"
+#include "misc/thread_tools.h"
#include "osdep/io.h"
#include "osdep/terminal.h"
#include "osdep/threads.h"
@@ -578,8 +580,9 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
// Add the given file as additional track. The filter argument controls how or
// if tracks are auto-selected at any point.
+// To be run on a worker thread, locked (temporarily unlocks core).
int mp_add_external_file(struct MPContext *mpctx, char *filename,
- enum stream_type filter, bool unlock)
+ enum stream_type filter)
{
struct MPOpts *opts = mpctx->opts;
if (!filename || mp_cancel_test(mpctx->playback_abort))
@@ -600,16 +603,23 @@ int mp_add_external_file(struct MPContext *mpctx, char *filename,
break;
}
- if (unlock)
- mp_core_unlock(mpctx);
+ mp_core_unlock(mpctx);
struct demuxer *demuxer =
demux_open_url(filename, &params, mpctx->playback_abort, mpctx->global);
if (demuxer)
enable_demux_thread(mpctx, demuxer);
- if (unlock)
+ mp_core_lock(mpctx);
+
+ // The command could have overlapped with playback exiting. (We don't care
+ // if playback has started again meanwhile - weird, but not a problem.)
+ if (!mpctx->playing) {
+ mp_core_unlock(mpctx);
+ free_demuxer_and_stream(demuxer);
mp_core_lock(mpctx);
+ return -1;
+ }
if (!demuxer)
goto err_out;
@@ -627,11 +637,9 @@ int mp_add_external_file(struct MPContext *mpctx, char *filename,
}
if (!has_any) {
- if (unlock)
- mp_core_unlock(mpctx);
+ mp_core_unlock(mpctx);
free_demuxer_and_stream(demuxer);
- if (unlock)
- mp_core_lock(mpctx);
+ mp_core_lock(mpctx);
char *tname = mp_tprintf(20, "%s ", stream_type_name(filter));
if (filter == STREAM_TYPE_COUNT)
tname = "";
@@ -660,11 +668,18 @@ err_out:
return -1;
}
+// to be run on a worker thread, locked (temporarily unlocks core)
static void open_external_files(struct MPContext *mpctx, char **files,
enum stream_type filter)
{
+ // Need a copy, because the option value could be mutated during iteration.
+ void *tmp = talloc_new(NULL);
+ files = mp_dup_str_array(tmp, files);
+
for (int n = 0; files && files[n]; n++)
- mp_add_external_file(mpctx, files[n], filter, false);
+ mp_add_external_file(mpctx, files[n], filter);
+
+ talloc_free(tmp);
}
void autoload_external_files(struct MPContext *mpctx)
@@ -703,7 +718,7 @@ void autoload_external_files(struct MPContext *mpctx)
goto skip;
if (list[i].type == STREAM_AUDIO && !sc[STREAM_VIDEO])
goto skip;
- int first = mp_add_external_file(mpctx, filename, list[i].type, false);
+ int first = mp_add_external_file(mpctx, filename, list[i].type);
if (first < 0)
goto skip;
@@ -771,20 +786,25 @@ static void process_hooks(struct MPContext *mpctx, char *name)
mp_idle(mpctx);
}
+// to be run on a worker thread, locked (temporarily unlocks core)
static void load_chapters(struct MPContext *mpctx)
{
struct demuxer *src = mpctx->demuxer;
bool free_src = false;
char *chapter_file = mpctx->opts->chapter_file;
if (chapter_file && chapter_file[0]) {
+ chapter_file = talloc_strdup(NULL, chapter_file);
+ mp_core_unlock(mpctx);
struct demuxer *demux = demux_open_url(chapter_file, NULL,
mpctx->playback_abort, mpctx->global);
+ mp_core_lock(mpctx);
if (demux) {
src = demux;
free_src = true;
}
talloc_free(mpctx->chapters);
mpctx->chapters = NULL;
+ talloc_free(chapter_file);
}
if (src && !mpctx->chapters) {
talloc_free(mpctx->chapters);
@@ -795,8 +815,11 @@ static void load_chapters(struct MPContext *mpctx)
mpctx->chapters[n].pts -= src->start_time;
}
}
- if (free_src)
+ if (free_src) {
+ mp_core_unlock(mpctx);
free_demuxer_and_stream(src);
+ mp_core_lock(mpctx);
+ }
}
static void load_per_file_options(m_config_t *conf,
@@ -1143,6 +1166,44 @@ void update_lavfi_complex(struct MPContext *mpctx)
}
}
+
+// Worker thread for loading external files and such. This is needed to avoid
+// freezing the core when waiting for network while loading these.
+static void load_external_opts_thread(void *p)
+{
+ void **a = p;
+ struct MPContext *mpctx = a[0];
+ struct mp_waiter *waiter = a[1];
+
+ mp_core_lock(mpctx);
+
+ load_chapters(mpctx);
+ open_external_files(mpctx, mpctx->opts->audio_files, STREAM_AUDIO);
+ open_external_files(mpctx, mpctx->opts->sub_name, STREAM_SUB);
+ open_external_files(mpctx, mpctx->opts->external_files, STREAM_TYPE_COUNT);
+ autoload_external_files(mpctx);
+
+ mp_waiter_wakeup(waiter, 0);
+ mp_wakeup_core(mpctx);
+ mp_core_unlock(mpctx);
+}
+
+static void load_external_opts(struct MPContext *mpctx)
+{
+ struct mp_waiter wait = MP_WAITER_INITIALIZER;
+
+ void *a[] = {mpctx, &wait};
+ if (!mp_thread_pool_queue(mpctx->thread_pool, load_external_opts_thread, a)) {
+ mpctx->stop_play = PT_ERROR;
+ return;
+ }
+
+ while (!mp_waiter_poll(&wait))
+ mp_idle(mpctx);
+
+ mp_waiter_wait(&wait);
+}
+
// Start playing the current playlist entry.
// Handle initialization and deinitialization.
static void play_current_file(struct MPContext *mpctx)
@@ -1264,13 +1325,11 @@ reopen_file:
demux_set_ts_offset(mpctx->demuxer, -mpctx->demuxer->start_time);
enable_demux_thread(mpctx, mpctx->demuxer);
- load_chapters(mpctx);
add_demuxer_tracks(mpctx, mpctx->demuxer);
- open_external_files(mpctx, opts->audio_files, STREAM_AUDIO);
- open_external_files(mpctx, opts->sub_name, STREAM_SUB);
- open_external_files(mpctx, opts->external_files, STREAM_TYPE_COUNT);
- autoload_external_files(mpctx);
+ load_external_opts(mpctx);
+ if (mpctx->stop_play)
+ goto terminate_playback;
check_previous_track_selection(mpctx);
@@ -1465,6 +1524,8 @@ terminate_playback:
if (mpctx->playing)
playlist_entry_unref(mpctx->playing);
+ // Note: a lot of things assume that the core won't be unlocked between
+ // uninitializing various playback-only resources (such as tracks).
mpctx->playing = NULL;
talloc_free(mpctx->filename);
mpctx->filename = NULL;