Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 17 additions & 21 deletions player/loadfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
93 changes: 91 additions & 2 deletions test/libmpv_test_track_selection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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");
}
}

Expand All @@ -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;
}
Expand Down
16 changes: 16 additions & 0 deletions test/samples/img_sub.idx
Original file line number Diff line number Diff line change
@@ -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
Binary file added test/samples/img_sub.sub
Binary file not shown.
25 changes: 23 additions & 2 deletions test/samples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -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',
Expand All @@ -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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not with audio? It can influence the selection too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly because I didn't care enough about multiprogram files to put effort into making comprehensive tests, but also, currently only the video determines preferred program ID:

    int preferred_program = (type != STREAM_VIDEO && mpctx->current_track[0][STREAM_VIDEO]) ?
                            mpctx->current_track[0][STREAM_VIDEO]->program_id : -1;

'-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
Expand All @@ -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)
Expand Down