summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-02-02 21:23:12 +0100
committerwm4 <wm4@nowhere>2015-02-02 21:23:12 +0100
commitc07e046bfa5a736ddf6c185b48cd1c6929840186 (patch)
tree33ba8244e1118c892cd5e3483198a411992fda65
parentcf8fa2bdd4789248bb4407294e60fe21393633d8 (diff)
downloadmpv-c07e046bfa5a736ddf6c185b48cd1c6929840186.tar.bz2
mpv-c07e046bfa5a736ddf6c185b48cd1c6929840186.tar.xz
player: add external audio file auto-loading
Apparently some people want this. Not enabled by default. Fixes #967.
-rw-r--r--DOCS/man/options.rst10
-rw-r--r--options/options.c3
-rw-r--r--options/options.h1
-rw-r--r--player/loadfile.c102
-rw-r--r--sub/find_subfiles.c99
-rw-r--r--sub/find_subfiles.h3
6 files changed, 134 insertions, 84 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index a60302c27d..852752e5ff 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -1039,6 +1039,16 @@ Audio
maximum amplification, i.e. amplify by 200%. The default volume (no
change in volume) will be ``50`` in this case.
+``--audio-file-auto=<no|exact|fuzzy|all>``, ``--no-audio-file-auto``
+ Load additional audio files matching the video filename. The parameter
+ specifies how external audio files are matched. This is disabled by
+ default.
+
+ :no: Don't automatically load external audio files (default).
+ :exact: Load the media filename with audio file extension.
+ :fuzzy: Load all audio files containing media filename.
+ :all: Load all audio files in the current directory.
+
``--audio-client-name=<name>``
The application name the player reports to the audio API. Can be useful
if you want to force a different audio profile (e.g. with PulseAudio),
diff --git a/options/options.c b/options/options.c
index e5e5975224..4c2cde9a2d 100644
--- a/options/options.c
+++ b/options/options.c
@@ -328,6 +328,8 @@ const m_option_t mp_opts[] = {
OPT_FLAG("sub-fix-timing", sub_fix_timing, 0),
OPT_CHOICE("sub-auto", sub_auto, 0,
({"no", -1}, {"exact", 0}, {"fuzzy", 1}, {"all", 2})),
+ OPT_CHOICE("audio-file-auto", audiofile_auto, 0,
+ ({"no", -1}, {"exact", 0}, {"fuzzy", 1}, {"all", 2})),
OPT_INTRANGE("sub-pos", sub_pos, 0, 0, 100),
OPT_FLOATRANGE("sub-gauss", sub_gauss, 0, 0.0, 3.0),
OPT_FLAG("sub-gray", sub_gray, 0),
@@ -764,6 +766,7 @@ const struct MPOpts mp_default_opts = {
.movie_aspect = -1.,
.field_dominance = -1,
.sub_auto = 0,
+ .audiofile_auto = -1,
.osd_bar_visible = 1,
#if HAVE_LIBASS
.ass_enabled = 1,
diff --git a/options/options.h b/options/options.h
index 8313ce1448..5d9504902e 100644
--- a/options/options.h
+++ b/options/options.h
@@ -231,6 +231,7 @@ typedef struct MPOpts {
char **sub_name;
char **sub_paths;
int sub_auto;
+ int audiofile_auto;
int use_text_osd;
int osd_bar_visible;
float osd_bar_align_x;
diff --git a/player/loadfile.c b/player/loadfile.c
index 549aacc8de..bf4121ba00 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -646,57 +646,32 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
return true;
}
-static void open_subtitles_from_options(struct MPContext *mpctx)
-{
- if (mpctx->opts->sub_name) {
- for (int i = 0; mpctx->opts->sub_name[i] != NULL; ++i)
- mp_add_subtitles(mpctx, mpctx->opts->sub_name[i]);
- }
- if (mpctx->opts->sub_auto >= 0) { // auto load sub file ...
- void *tmp = talloc_new(NULL);
- char *base_filename = mpctx->filename;
- char *stream_filename = NULL;
- if (mpctx->demuxer) {
- if (demux_stream_control(mpctx->demuxer, STREAM_CTRL_GET_BASE_FILENAME,
- &stream_filename) > 0)
- base_filename = talloc_steal(tmp, stream_filename);
- }
- struct subfn *list = find_text_subtitles(mpctx->global, base_filename);
- talloc_steal(tmp, list);
- for (int i = 0; list && list[i].fname; i++) {
- char *filename = list[i].fname;
- char *lang = list[i].lang;
- for (int n = 0; n < mpctx->num_sources; n++) {
- if (strcmp(mpctx->sources[n]->stream->url, filename) == 0)
- goto skip;
- }
- struct track *track = mp_add_subtitles(mpctx, filename);
- if (track) {
- track->auto_loaded = true;
- if (!track->lang)
- track->lang = talloc_strdup(track, lang);
- }
- skip:;
- }
- talloc_free(tmp);
- }
-}
-
static struct track *open_external_file(struct MPContext *mpctx, char *filename,
- char *demuxer_name,
enum stream_type filter)
{
struct MPOpts *opts = mpctx->opts;
if (!filename)
return NULL;
+
char *disp_filename = filename;
if (strncmp(disp_filename, "memory://", 9) == 0)
disp_filename = "memory://"; // avoid noise
+
struct stream *stream = stream_open(filename, mpctx->global);
if (!stream)
goto err_out;
- if (filter != STREAM_SUB)
+
+ char *demuxer_name = NULL;
+ switch (filter) {
+ case STREAM_SUB:
+ demuxer_name = opts->sub_demuxer_name;
+ break;
+ case STREAM_AUDIO:
+ demuxer_name = opts->audio_demuxer_name;
stream_enable_cache(&stream, &opts->stream_cache);
+ break;
+ }
+
struct demuxer_params params = {
.expect_subtitle = filter == STREAM_SUB,
};
@@ -706,6 +681,7 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
free_stream(stream);
goto err_out;
}
+
struct track *first = NULL;
for (int n = 0; n < demuxer->num_streams; n++) {
struct sh_stream *sh = demuxer->streams[n];
@@ -724,6 +700,7 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
disp_filename);
goto err_out;
}
+
MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, demuxer);
return first;
@@ -736,17 +713,53 @@ err_out:
static void open_audiofiles_from_options(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
- for (int n = 0; opts->audio_files && opts->audio_files[n]; n++) {
- open_external_file(mpctx, opts->audio_files[n], opts->audio_demuxer_name,
- STREAM_AUDIO);
- }
+ for (int n = 0; opts->audio_files && opts->audio_files[n]; n++)
+ open_external_file(mpctx, opts->audio_files[n], STREAM_AUDIO);
}
struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename)
{
+ return open_external_file(mpctx, filename, STREAM_SUB);
+}
+
+static void open_subtitles_from_options(struct MPContext *mpctx)
+{
struct MPOpts *opts = mpctx->opts;
- return open_external_file(mpctx, filename, opts->sub_demuxer_name,
- STREAM_SUB);
+ for (int i = 0; opts->sub_name && opts->sub_name[i] != NULL; i++)
+ mp_add_subtitles(mpctx, opts->sub_name[i]);
+}
+
+static void autoload_external_files(struct MPContext *mpctx)
+{
+ if (mpctx->opts->sub_auto < 0 && mpctx->opts->audiofile_auto < 0)
+ return;
+
+ void *tmp = talloc_new(NULL);
+ char *base_filename = mpctx->filename;
+ char *stream_filename = NULL;
+ if (mpctx->demuxer) {
+ if (demux_stream_control(mpctx->demuxer, STREAM_CTRL_GET_BASE_FILENAME,
+ &stream_filename) > 0)
+ base_filename = talloc_steal(tmp, stream_filename);
+ }
+ struct subfn *list = find_external_files(mpctx->global, base_filename);
+ talloc_steal(tmp, list);
+ for (int i = 0; list && list[i].fname; i++) {
+ char *filename = list[i].fname;
+ char *lang = list[i].lang;
+ for (int n = 0; n < mpctx->num_sources; n++) {
+ if (strcmp(mpctx->sources[n]->stream->url, filename) == 0)
+ goto skip;
+ }
+ struct track *track = open_external_file(mpctx, filename, list[i].type);
+ if (track) {
+ track->auto_loaded = true;
+ if (!track->lang)
+ track->lang = talloc_strdup(track, lang);
+ }
+ skip:;
+ }
+ talloc_free(tmp);
}
// Do stuff to a newly loaded playlist. This includes any processing that may
@@ -1086,6 +1099,7 @@ goto_reopen_demuxer: ;
open_subtitles_from_options(mpctx);
open_audiofiles_from_options(mpctx);
+ autoload_external_files(mpctx);
check_previous_track_selection(mpctx);
diff --git a/sub/find_subfiles.c b/sub/find_subfiles.c
index f703c8d910..e6116d1b91 100644
--- a/sub/find_subfiles.c
+++ b/sub/find_subfiles.c
@@ -18,15 +18,27 @@ static const char *const sub_exts[] = {"utf", "utf8", "utf-8", "idx", "sub", "sr
"smi", "rt", "txt", "ssa", "aqt", "jss",
"js", "ass", "mks", NULL};
-static bool is_sub_ext(bstr ext)
+static const char *const audio_exts[] = {"mp3", "aac", "mka", "dts", "flac",
+ "ogg", "m4a", NULL};
+
+static bool test_ext_list(bstr ext, const char *const *list)
{
- for (int n = 0; sub_exts[n]; n++) {
- if (bstrcasecmp(bstr0(sub_exts[n]), ext) == 0)
+ for (int n = 0; list[n]; n++) {
+ if (bstrcasecmp(bstr0(list[n]), ext) == 0)
return true;
}
return false;
}
+static int test_ext(bstr ext)
+{
+ if (test_ext_list(ext, sub_exts))
+ return STREAM_SUB;
+ if (test_ext_list(ext, audio_exts))
+ return STREAM_AUDIO;
+ return -1;
+}
+
static struct bstr strip_ext(struct bstr str)
{
int dotpos = bstrrchr(str, '.');
@@ -45,7 +57,7 @@ static struct bstr get_ext(struct bstr s)
bool mp_might_be_subtitle_file(const char *filename)
{
- return is_sub_ext(get_ext(bstr0(filename)));
+ return test_ext(get_ext(bstr0(filename))) == STREAM_SUB;
}
static int compare_sub_filename(const void *a, const void *b)
@@ -87,15 +99,6 @@ static struct bstr guess_lang_from_filename(struct bstr name)
return (struct bstr){name.start + i + 1, n};
}
-/**
- * @brief Append all the subtitles in the given path matching fname
- * @param opts MPlayer options
- * @param slist pointer to the subtitles list tallocated
- * @param nsub pointer to the number of subtitles
- * @param path Look for subtitles in this directory
- * @param fname Subtitle filename (pattern)
- * @param limit_fuzziness Ignore flag when sub_fuziness == 2
- */
static void append_dir_subtitles(struct mpv_global *global,
struct subfn **slist, int *nsub,
struct bstr path, const char *fname,
@@ -103,7 +106,7 @@ static void append_dir_subtitles(struct mpv_global *global,
{
void *tmpmem = talloc_new(NULL);
struct MPOpts *opts = global->opts;
- struct mp_log *log = mp_log_new(tmpmem, global->log, "find_subfiles");
+ struct mp_log *log = mp_log_new(tmpmem, global->log, "find_files");
if (mp_is_url(bstr0(fname)))
goto out;
@@ -121,7 +124,7 @@ static void append_dir_subtitles(struct mpv_global *global,
DIR *d = opendir(path0);
if (!d)
goto out;
- mp_verbose(log, "Load subtitles in %.*s\n", BSTR_P(path));
+ mp_verbose(log, "Loading external files in %.*s\n", BSTR_P(path));
struct dirent *de;
while ((de = readdir(d))) {
struct bstr dename = bstr0(de->d_name);
@@ -133,21 +136,35 @@ static void append_dir_subtitles(struct mpv_global *global,
struct bstr tmp_fname_ext = get_ext(dename);
struct bstr tmp_fname_trim = bstr_strip(tmp_fname_noext);
- // does it end with a subtitle extension?
- if (!is_sub_ext(tmp_fname_ext))
+ // check what it is (most likely)
+ int type = test_ext(tmp_fname_ext);
+ char **langs = NULL;
+ int fuzz = -1;
+ switch (type) {
+ case STREAM_SUB:
+ langs = opts->sub_lang;
+ fuzz = opts->sub_auto;
+ break;
+ case STREAM_AUDIO:
+ langs = opts->audio_lang;
+ fuzz = opts->audiofile_auto;
+ break;
+ }
+
+ if (fuzz < 0)
goto next_sub;
// we have a (likely) subtitle file
int prio = 0;
char *found_lang = NULL;
- if (opts->sub_lang) {
+ if (langs) {
if (bstr_startswith(tmp_fname_trim, f_fname_trim)) {
struct bstr lang = guess_lang_from_filename(tmp_fname_trim);
if (lang.len) {
- for (int n = 0; opts->sub_lang[n]; n++) {
- if (bstr_startswith0(lang, opts->sub_lang[n])) {
+ for (int n = 0; langs[n]; n++) {
+ if (bstr_startswith0(lang, langs[n])) {
prio = 4; // matches the movie name + lang extension
- found_lang = opts->sub_lang[n];
+ found_lang = langs[n];
break;
}
}
@@ -156,18 +173,19 @@ static void append_dir_subtitles(struct mpv_global *global,
}
if (!prio && bstrcmp(tmp_fname_trim, f_fname_trim) == 0)
prio = 3; // matches the movie name
- if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0
- && opts->sub_auto >= 1)
+ if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0 && fuzz >= 1)
prio = 2; // contains the movie name
if (!prio) {
// doesn't contain the movie name
// don't try in the mplayer subtitle directory
- if (!limit_fuzziness && opts->sub_auto >= 2) {
+ if (!limit_fuzziness && fuzz >= 2) {
prio = 1;
}
}
- mp_dbg(log, "Potential sub file: \"%s\" Priority: %d\n", de->d_name, prio);
+ mp_dbg(log, "Potential external file: \"%s\" Priority: %d\n",
+ de->d_name, prio);
+
if (prio) {
prio += prio;
char *subpath = mp_path_join(*slist, path, dename);
@@ -179,6 +197,7 @@ static void append_dir_subtitles(struct mpv_global *global,
if (strncmp(subpath, "./", 2) == 0)
subpath += 2;
+ sub->type = type;
sub->priority = prio;
sub->fname = subpath;
sub->lang = found_lang;
@@ -222,9 +241,9 @@ static void filter_subidx(struct subfn **slist, int *nsub)
}
}
-// Return a list of subtitles found, sorted by priority.
+// Return a list of subtitles and audio files found, sorted by priority.
// Last element is terminated with a fname==NULL entry.
-struct subfn *find_text_subtitles(struct mpv_global *global, const char *fname)
+struct subfn *find_external_files(struct mpv_global *global, const char *fname)
{
struct MPOpts *opts = global->opts;
struct subfn *slist = talloc_array_ptrtype(NULL, slist, 1);
@@ -233,20 +252,22 @@ struct subfn *find_text_subtitles(struct mpv_global *global, const char *fname)
// Load subtitles from current media directory
append_dir_subtitles(global, &slist, &n, mp_dirname(fname), fname, 0);
- // Load subtitles in dirs specified by sub-paths option
- if (opts->sub_paths) {
- for (int i = 0; opts->sub_paths[i]; i++) {
- char *path = mp_path_join(slist, mp_dirname(fname),
- bstr0(opts->sub_paths[i]));
- append_dir_subtitles(global, &slist, &n, bstr0(path), fname, 0);
+ if (opts->sub_auto >= 0) {
+ // Load subtitles in dirs specified by sub-paths option
+ if (opts->sub_paths) {
+ for (int i = 0; opts->sub_paths[i]; i++) {
+ char *path = mp_path_join(slist, mp_dirname(fname),
+ bstr0(opts->sub_paths[i]));
+ append_dir_subtitles(global, &slist, &n, bstr0(path), fname, 0);
+ }
}
- }
- // Load subtitles in ~/.mpv/sub limiting sub fuzziness
- char *mp_subdir = mp_find_config_file(NULL, global, "sub/");
- if (mp_subdir)
- append_dir_subtitles(global, &slist, &n, bstr0(mp_subdir), fname, 1);
- talloc_free(mp_subdir);
+ // Load subtitles in ~/.mpv/sub limiting sub fuzziness
+ char *mp_subdir = mp_find_config_file(NULL, global, "sub/");
+ if (mp_subdir)
+ append_dir_subtitles(global, &slist, &n, bstr0(mp_subdir), fname, 1);
+ talloc_free(mp_subdir);
+ }
// Sort by name for filter_subidx()
qsort(slist, n, sizeof(*slist), compare_sub_filename);
diff --git a/sub/find_subfiles.h b/sub/find_subfiles.h
index 85b491f1f9..a531b3e36a 100644
--- a/sub/find_subfiles.h
+++ b/sub/find_subfiles.h
@@ -22,13 +22,14 @@
#include <stdbool.h>
struct subfn {
+ int type; // STREAM_SUB/STREAM_AUDIO
int priority;
char *fname;
char *lang;
};
struct mpv_global;
-struct subfn *find_text_subtitles(struct mpv_global *global, const char *fname);
+struct subfn *find_external_files(struct mpv_global *global, const char *fname);
bool mp_might_be_subtitle_file(const char *filename);