diff --git a/player/loadfile.c b/player/loadfile.c index 75e248c073e99..6fd0f318d5874 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -473,11 +473,9 @@ void add_demuxer_tracks(struct MPContext *mpctx, struct demuxer *demuxer) */ // Return whether t1 is preferred over t2 static bool compare_track(struct track *t1, struct track *t2, char **langs, bool os_langs, - bool forced, struct MPOpts *opts, int preferred_program) + struct MPOpts *opts) { bool sub = t2->type == STREAM_SUB; - if (!opts->autoload_files && t1->is_external != t2->is_external) - return !t1->is_external; bool ext1 = t1->is_external && !t1->no_default; bool ext2 = t2->is_external && !t2->no_default; if (ext1 != ext2) { @@ -488,19 +486,14 @@ static bool compare_track(struct track *t1, struct track *t2, char **langs, bool } if (t1->auto_loaded != t2->auto_loaded) return !t1->auto_loaded; - if (preferred_program != -1 && t1->program_id != -1 && t2->program_id != -1) { - if ((t1->program_id == preferred_program) != - (t2->program_id == preferred_program)) - return t1->program_id == preferred_program; - } int l1 = mp_match_lang(langs, t1->lang), l2 = mp_match_lang(langs, t2->lang); if (!os_langs && l1 != l2) return l1 > l2; - if (forced) - return t1->forced_track; - if (t1->default_track != t2->default_track && !t2->forced_select) + if (t1->forced_select != t2->forced_select) + return t1->forced_select; + if (t1->default_track != t2->default_track) return t1->default_track; - if (sub && !t2->forced_select && t2->forced_track) + if (sub && t1->forced_track != t2->forced_track) return !t1->forced_track; if (os_langs && l1 != l2) return l1 > l2; @@ -605,6 +598,11 @@ struct track *select_default_track(struct MPContext *mpctx, int order, continue; if (track->no_auto_select) continue; + if (!opts->autoload_files && track->is_external) + continue; + if (preferred_program != -1 && !track->is_external && + track->program_id != -1 && track->program_id != preferred_program) + continue; if (duplicate_track(mpctx, order, type, track)) continue; if (sub) { @@ -617,21 +615,19 @@ struct track *select_default_track(struct MPContext *mpctx, int order, (opts->subs_fallback == 1 && track->default_track); bool subs_matching_audio = (!mp_match_lang(langs, audio_lang) || opts->subs_with_matching_audio == 2 || (opts->subs_with_matching_audio == 1 && track->forced_track)); - if (subs_matching_audio && ((!pick && (forced || lang_match || subs_fallback)) || - (pick && compare_track(track, pick, langs, os_langs, forced, mpctx->opts, preferred_program)))) - { - pick = track; - pick->forced_select = forced; - } - } else if (!pick || compare_track(track, pick, langs, os_langs, false, mpctx->opts, preferred_program)) { + if (!subs_matching_audio) + continue; + if (!forced && !lang_match && !subs_fallback) + continue; + track->forced_select = forced; + } + if (!pick || compare_track(track, pick, langs, os_langs, mpctx->opts)) { pick = track; } } if (pick && pick->attached_picture && !mpctx->opts->audio_display) pick = NULL; - if (pick && !opts->autoload_files && pick->is_external) - pick = NULL; cleanup: talloc_free(langs); return pick; diff --git a/test/libmpv_test_track_selection.c b/test/libmpv_test_track_selection.c index 8775669d00057..aebd8dbab438b 100644 --- a/test/libmpv_test_track_selection.c +++ b/test/libmpv_test_track_selection.c @@ -137,7 +137,8 @@ static void test_track_selection(char *file, char *path) set_property_string("subs-fallback", "yes"); reload_file(path); check_string("current-tracks/sub/selected", "yes"); - } else if (strcmp(file, "locale.mkv") == 0) { + } else if (strcmp(file, "locale.mkv") == 0 || + strcmp(file, "locale_forced.mkv") == 0) { // default english subs reload_file(path); check_string("current-tracks/sub/lang", "eng"); @@ -146,6 +147,60 @@ static void test_track_selection(char *file, char *path) set_property_string("subs-match-os-language", "no"); reload_file(path); check_string("current-tracks/sub/lang", "ger"); + } else if (strcmp(file, "locale_complex.mkv") == 0) { + set_property_string("subs-fallback", "yes"); + set_property_string("subs-match-os-language", "yes"); + + // default+forced eng subs to match audio + set_property_string("alang", "eng"); + reload_file(path); + check_string("current-tracks/audio/lang", "eng"); + check_string("current-tracks/sub/lang", "eng"); + // among all eng subs, track 4 should be selected + check_int("current-tracks/sub/id", 4); + + // forced jpn subs to match audio + set_property_string("alang", "jpn"); + reload_file(path); + check_string("current-tracks/audio/lang", "jpn"); + check_string("current-tracks/sub/lang", "jpn"); + + // default, non-forced ger subs + set_property_string("alang", "ger"); + reload_file(path); + check_string("current-tracks/audio/lang", "ger"); + check_string("current-tracks/sub/lang", "ger"); + + // default+forced pol subs to match audio + set_property_string("alang", "pol"); + reload_file(path); + check_string("current-tracks/audio/lang", "pol"); + check_string("current-tracks/sub/lang", "pol"); + + // default+forced pol subs (first default track) + set_property_string("subs-match-os-language", "no"); + set_property_string("subs-fallback-forced", "always"); + reload_file(path); + check_string("current-tracks/sub/lang", "pol"); + + // default+forced eng subs to match OS lang + set_property_string("subs-match-os-language", "yes"); + reload_file(path); + check_string("current-tracks/sub/lang", "eng"); + // among all eng subs, track 4 should be selected + check_int("current-tracks/sub/id", 4); + + // default, non-forced ger subs + set_property_string("subs-fallback-forced", "no"); + reload_file(path); + check_string("current-tracks/sub/lang", "ger"); + + // default+forced eng subs to match slang + set_property_string("slang", "eng"); + reload_file(path); + check_string("current-tracks/sub/lang", "eng"); + // among all eng subs, track 4 should be selected + check_int("current-tracks/sub/id", 4); } else if (strcmp(file, "multilang.mkv") == 0) { // --alang=jpn should select forced jpn subs set_property_string("alang", "jpn"); @@ -205,6 +260,15 @@ static void test_track_selection(char *file, char *path) reload_file(path); check_string("current-tracks/audio/lang", "ger"); check_string("current-tracks/sub/lang", "jpn"); + + // default+forced eng subs should be selected + set_property_string("alang", "jpn"); + set_property_string("slang", ""); + set_property_string("subs-with-matching-audio", "yes"); + set_property_string("subs-fallback-forced", "always"); + reload_file(path); + check_string("current-tracks/audio/lang", "jpn"); + check_string("current-tracks/sub/lang", "eng"); } else if (strcmp(file, "multilang2.mkv") == 0) { // default jpn subs set_property_string("subs-match-os-language", "no"); @@ -240,6 +304,29 @@ static void test_track_selection(char *file, char *path) set_property_string("sid", "3"); reload_file(path); check_string("track-list/5/selected", "yes"); + } else if (strcmp(file, "multiprogram.ts") == 0) { + set_property_string("subs-match-os-language", "no"); + set_property_string("vid", "2"); + + // no subs are selected by default + reload_file(path); + check_string("track-list/1/selected", "no"); + check_string("track-list/3/selected", "no"); + + // the eng track cannot be selected due to having the wrong program ID + // because subs-fallback=default, the jpn track cannot be chosen either + // so we get no subs + set_property_string("slang", "eng"); + reload_file(path); + check_string("track-list/1/selected", "no"); + check_string("track-list/3/selected", "no"); + + // the jpn track is selected to match video program ID + // even though the user requested eng subtitles + set_property_string("subs-fallback", "yes"); + reload_file(path); + check_string("current-tracks/sub/lang", "jpn"); + check_string("track-list/3/selected", "yes"); } } @@ -248,7 +335,9 @@ int main(int argc, char *argv[]) if (argc < 3) return 1; - if (!strcmp(argv[1], "locale.mkv") && !have_english_locale()) { + const char *locale_test_prefix = "locale"; + if (strncmp(argv[1], locale_test_prefix, strlen(locale_test_prefix)) == 0 && + !have_english_locale()) { printf("Non English language detected. Skipping locale test.\n"); return 77; } diff --git a/test/samples/img_sub.idx b/test/samples/img_sub.idx new file mode 100644 index 0000000000000..ab75f25b7b6f0 --- /dev/null +++ b/test/samples/img_sub.idx @@ -0,0 +1,16 @@ +# VobSub index file, v7 (do not modify this line!) +size: 1280x720 +org: 0, 0 +scale: 100%, 100% +alpha: 100% +smooth: OFF +fadein/out: 50, 50 +align: OFF at LEFT TOP +time offset: 0 +forced subs: OFF +palette: 000000, ffffff, 000000, 000000, 828282, 828282, 828282, ffffff, 828282, bababa, 828282, 828282, 828282, 828282, 828282, 828282 +custom colors: OFF, tridx: 0000, colors: 000000, 000000, 000000, 000000 +langidx: 0 +id: en, index: 0 +timestamp: 00:00:00:000, filepos: 000000000 +timestamp: 00:00:01:000, filepos: 000000800 diff --git a/test/samples/img_sub.sub b/test/samples/img_sub.sub new file mode 100644 index 0000000000000..ac3c6934c6898 Binary files /dev/null and b/test/samples/img_sub.sub differ diff --git a/test/samples/meson.build b/test/samples/meson.build index 2b5756e880dd4..bf88be8d39b79 100644 --- a/test/samples/meson.build +++ b/test/samples/meson.build @@ -2,7 +2,7 @@ video = custom_target('video.mkv', output: 'video.mkv', command: [ffmpeg, '-v', 'error', '-y', '-f', 'lavfi', '-i', - 'testsrc=duration=2:size=1280x720', '@OUTPUT@'], + 'testsrc=duration=2:size=1280x720', '-c:v', 'mpeg2video', '@OUTPUT@'], ) audio = custom_target('audio.flac', @@ -12,6 +12,7 @@ audio = custom_target('audio.flac', ) sub = join_paths(source_root, 'test', 'samples', 'sub.srt') +img_sub = join_paths(source_root, 'test', 'samples', 'img_sub.idx') common_args = ['-v', 'error', '-y', '-i', video, '-i', audio, '-f', 'srt', '-i', sub, '-c', 'copy', @@ -40,6 +41,21 @@ samples = { '-c', 'copy', '-map', '0:0', '-map', '1:0', '-map', '2:0', '-map', '3:0', '-metadata:s:s:0', 'language=ger', '-metadata:s:s:1', 'language=eng', '-disposition:s:0', 'default', '-disposition:s:1', 'default', '@OUTPUT@'], + 'locale_forced.mkv': + [ffmpeg, '-v', 'error', '-y', '-i', video, '-i', audio, '-f', 'srt', '-i', sub, '-i', sub, + '-c', 'copy', '-map', '0:0', '-map', '1:0', '-map', '2:0', '-map', '3:0', '-metadata:s:s:0', + 'language=ger', '-metadata:s:s:1', 'language=eng', '-disposition:s:0', 'default+forced', + '-disposition:s:1', 'default+forced', '@OUTPUT@'], + 'locale_complex.mkv': + [ffmpeg, '-v', 'error', '-y', '-i', video, '-i', audio, '-f', 'srt', '-i', sub, '-c', 'copy', + '-map', '0:0', '-map', '1:0', '-map', '1:0', '-map', '1:0', '-map', '1:0', + '-map', '2:0', '-map', '2:0', '-map', '2:0', '-map', '2:0', '-map', '2:0', '-map', '2:0', + '-metadata:s:a:0', 'language=eng', '-metadata:s:a:1', 'language=jpn', + '-metadata:s:a:2', 'language=ger', '-metadata:s:a:3', 'language=pol', + '-metadata:s:s:0', 'language=eng', '-metadata:s:s:1', 'language=jpn', '-metadata:s:s:2', 'language=pol', + '-metadata:s:s:3', 'language=eng', '-metadata:s:s:4', 'language=ger', '-metadata:s:s:5', 'language=eng', + '-disposition:s:1', 'forced', '-disposition:s:2', 'default+forced', '-disposition:s:3', 'default+forced', + '-disposition:s:4', 'default', '-disposition:s:5', 'default+forced', '@OUTPUT@'], 'multilang.mkv': [ffmpeg, '-v', 'error', '-y', '-i', video, '-i', audio, '-i', audio, '-i', audio, '-i', audio, '-f', 'srt', '-i', sub, '-i', sub, '-i', sub, '-i', sub, '-c', 'copy', '-map', '0:0', @@ -57,6 +73,11 @@ samples = { 'language=eng', '-metadata:s:s:2', 'language=eng', '-metadata:s:s:3', 'language=eng', '-disposition:s:0', 'default', '-disposition:s:1', 'forced', '-disposition:s:3', 'default', '@OUTPUT@'], + 'multiprogram.ts': + [ffmpeg, '-v', 'error', '-y', '-i', video, '-f', 'vobsub', '-i', img_sub, + '-c:v', 'copy', '-c:s', 'dvbsub', '-map', '0:0', '-map', '1:0', '-map', '0:0', '-map', '1:0', + '-metadata:s:s:0', 'language=eng', '-metadata:s:s:1', 'language=jpn', + '-program', 'program_num=1:st=0:st=1', '-program', 'program_num=2:st=2:st=3', '@OUTPUT@'], } foreach name, cmd: samples @@ -65,7 +86,7 @@ foreach name, cmd: samples depends: [video, audio], command: cmd, ) - env = name == 'locale.mkv' ? 'LANG=C' : [] + env = name.startswith('locale') ? 'LANG=C' : [] testname = 'libmpv-test-' + name exe = executable(testname, '../libmpv_test_track_selection.c', include_directories: incdir, dependencies: libmpv_dep)