mirror of
https://github.com/mpv-player/mpv
synced 2025-03-25 04:38:01 +00:00
player: make all external file loading actions async
Still missing: not freezing when removing a track (i.e. closing demuxer) with the sub-remove/audio-remove/rescan-external-files commands.
This commit is contained in:
parent
115a9b19f1
commit
1b611e38ef
@ -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
|
||||
--------------
|
||||
|
@ -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 } },
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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, ¶ms, 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;
|
||||
|
Loading…
Reference in New Issue
Block a user