0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

player: add external audio file auto-loading

Apparently some people want this. Not enabled by default.

Fixes #967.
This commit is contained in:
wm4 2015-02-02 21:23:12 +01:00
parent cf8fa2bdd4
commit c07e046bfa
6 changed files with 134 additions and 84 deletions

View File

@ -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),

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);