diff --git a/docs/source/options/dash_options.rst b/docs/source/options/dash_options.rst
index b7e94d3bd7..3402dea526 100644
--- a/docs/source/options/dash_options.rst
+++ b/docs/source/options/dash_options.rst
@@ -64,6 +64,14 @@ DASH options
in the manifest. This allows the player to
choose the correct default language for the content.
+ This applies to both audio and text tracks. The default language for text
+ tracks can be overriden by 'default_text_language'.
+
+--default_text_language
+
+ Same as above, but this applies to text tracks only, and overrides the
+ default language for text tracks.
+
--allow_approximate_segment_timeline
For live profile only.
diff --git a/docs/source/options/hls_options.rst b/docs/source/options/hls_options.rst
index 6a82b8d355..476f354627 100644
--- a/docs/source/options/hls_options.rst
+++ b/docs/source/options/hls_options.rst
@@ -43,3 +43,11 @@ HLS options
The first audio/text rendition in a group tagged with this language will
have 'DEFAULT' attribute set to 'YES'. This allows the player to choose the
correct default language for the content.
+
+ This applies to both audio and text tracks. The default language for text
+ tracks can be overriden by 'default_text_language'.
+
+--default_text_language
+
+ Same as above, but this applies to text tracks only, and overrides the
+ default language for text tracks.
diff --git a/packager/app/manifest_flags.cc b/packager/app/manifest_flags.cc
index 4f7d8e582f..337ac93d99 100644
--- a/packager/app/manifest_flags.cc
+++ b/packager/app/manifest_flags.cc
@@ -25,4 +25,11 @@ DEFINE_string(default_language,
"have in the manifest; For HLS, the "
"first audio/text rendition in a group tagged with this language "
"will have 'DEFAULT' attribute set to 'YES'. This allows the "
- "player to choose the correct default language for the content.");
+ "player to choose the correct default language for the content."
+ "This applies to both audio and text tracks. The default "
+ "language for text tracks can be overriden by "
+ "'--default_text_language'.");
+DEFINE_string(default_text_language,
+ "",
+ "Same as above, but this applies to text tracks only, and "
+ "overrides the default language for text tracks.");
diff --git a/packager/app/manifest_flags.h b/packager/app/manifest_flags.h
index 7acecf3da9..36a5c5df2e 100644
--- a/packager/app/manifest_flags.h
+++ b/packager/app/manifest_flags.h
@@ -14,5 +14,6 @@
DECLARE_double(time_shift_buffer_depth);
DECLARE_uint64(preserved_segments_outside_live_window);
DECLARE_string(default_language);
+DECLARE_string(default_text_language);
#endif // PACKAGER_APP_MANIFEST_FLAGS_H_
diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc
index 45f44aa758..ff853bf746 100644
--- a/packager/app/packager_main.cc
+++ b/packager/app/packager_main.cc
@@ -443,6 +443,7 @@ base::Optional GetPackagingParams() {
}
mpd_params.default_language = FLAGS_default_language;
+ mpd_params.default_text_language = FLAGS_default_text_language;
mpd_params.generate_static_live_mpd = FLAGS_generate_static_mpd;
mpd_params.generate_dash_if_iop_compliant_mpd =
FLAGS_generate_dash_if_iop_compliant_mpd;
@@ -460,6 +461,7 @@ base::Optional GetPackagingParams() {
hls_params.preserved_segments_outside_live_window =
FLAGS_preserved_segments_outside_live_window;
hls_params.default_language = FLAGS_default_language;
+ hls_params.default_text_language = FLAGS_default_text_language;
TestParams& test_params = packaging_params.test_params;
test_params.dump_stream_info = FLAGS_dump_stream_info;
diff --git a/packager/hls/base/master_playlist.cc b/packager/hls/base/master_playlist.cc
index 1819d0ea18..a5f479cad1 100644
--- a/packager/hls/base/master_playlist.cc
+++ b/packager/hls/base/master_playlist.cc
@@ -343,7 +343,8 @@ void BuildMediaTags(
}
}
-void AppendPlaylists(const std::string& default_language,
+void AppendPlaylists(const std::string& default_audio_language,
+ const std::string& default_text_language,
const std::string& base_url,
const std::list& playlists,
std::string* content) {
@@ -374,12 +375,13 @@ void AppendPlaylists(const std::string& default_language,
if (!audio_playlist_groups.empty()) {
content->append("\n");
- BuildMediaTags(audio_playlist_groups, default_language, base_url, content);
+ BuildMediaTags(audio_playlist_groups, default_audio_language, base_url,
+ content);
}
if (!subtitle_playlist_groups.empty()) {
content->append("\n");
- BuildMediaTags(subtitle_playlist_groups, default_language, base_url,
+ BuildMediaTags(subtitle_playlist_groups, default_text_language, base_url,
content);
}
@@ -406,8 +408,12 @@ void AppendPlaylists(const std::string& default_language,
} // namespace
MasterPlaylist::MasterPlaylist(const std::string& file_name,
- const std::string& default_language)
- : file_name_(file_name), default_language_(default_language) {}
+ const std::string& default_audio_language,
+ const std::string& default_text_language)
+ : file_name_(file_name),
+ default_audio_language_(default_audio_language),
+ default_text_language_(default_text_language) {}
+
MasterPlaylist::~MasterPlaylist() {}
bool MasterPlaylist::WriteMasterPlaylist(
@@ -416,7 +422,8 @@ bool MasterPlaylist::WriteMasterPlaylist(
const std::list& playlists) {
std::string content = "#EXTM3U\n";
AppendVersionString(&content);
- AppendPlaylists(default_language_, base_url, playlists, &content);
+ AppendPlaylists(default_audio_language_, default_text_language_, base_url,
+ playlists, &content);
// Skip if the playlist is already written.
if (content == written_playlist_)
diff --git a/packager/hls/base/master_playlist.h b/packager/hls/base/master_playlist.h
index 18590f73a1..a758806f03 100644
--- a/packager/hls/base/master_playlist.h
+++ b/packager/hls/base/master_playlist.h
@@ -20,10 +20,13 @@ class MediaPlaylist;
class MasterPlaylist {
public:
/// @param file_name is the file name of the master playlist.
- /// @param default_language determines the rendition that should be tagged
- /// with 'DEFAULT'.
+ /// @param default_audio_language determines the audio rendition that should
+ /// be tagged with 'DEFAULT'.
+ /// @param default_text_language determines the text rendition that should be
+ /// tagged with 'DEFAULT'.
MasterPlaylist(const std::string& file_name,
- const std::string& default_language);
+ const std::string& default_audio_language,
+ const std::string& default_text_language);
virtual ~MasterPlaylist();
/// Writes Master Playlist to output_dir + .
@@ -45,7 +48,8 @@ class MasterPlaylist {
std::string written_playlist_;
const std::string file_name_;
- const std::string default_language_;
+ const std::string default_audio_language_;
+ const std::string default_text_language_;
};
} // namespace hls
diff --git a/packager/hls/base/master_playlist_unittest.cc b/packager/hls/base/master_playlist_unittest.cc
index 0e1bb7daff..2d3e043e12 100644
--- a/packager/hls/base/master_playlist_unittest.cc
+++ b/packager/hls/base/master_playlist_unittest.cc
@@ -28,7 +28,8 @@ using ::testing::StrEq;
namespace {
const char kDefaultMasterPlaylistName[] = "playlist.m3u8";
-const char kDefaultLanguage[] = "en";
+const char kDefaultAudioLanguage[] = "en";
+const char kDefaultTextLanguage[] = "fr";
const uint32_t kWidth = 800;
const uint32_t kHeight = 600;
@@ -123,7 +124,9 @@ std::unique_ptr CreateTextPlaylist(
class MasterPlaylistTest : public ::testing::Test {
protected:
MasterPlaylistTest()
- : master_playlist_(kDefaultMasterPlaylistName, kDefaultLanguage),
+ : master_playlist_(kDefaultMasterPlaylistName,
+ kDefaultAudioLanguage,
+ kDefaultTextLanguage),
test_output_dir_("memory://test_dir"),
master_playlist_path_(
FilePath::FromUTF8Unsafe(test_output_dir_)
@@ -382,10 +385,11 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
"test\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
- "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
+ "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\","
"AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
- "GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=YES\n"
+ "GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",DEFAULT=YES,"
+ "AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,AVERAGE-BANDWIDTH=200000,"
"CODECS=\"sdvideocodec,textcodec\",RESOLUTION=800x600,"
@@ -423,8 +427,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextWithCharacteritics) {
"test\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
- "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
- "AUTOSELECT=YES,CHARACTERISTICS=\""
+ "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",AUTOSELECT=YES,"
+ "CHARACTERISTICS=\""
"public.accessibility.transcribes-spoken-dialog,public.easy-to-read\"\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,AVERAGE-BANDWIDTH=200000,"
@@ -463,10 +467,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
"GROUP-ID=\"en-text-group\",LANGUAGE=\"en\",NAME=\"english\","
- "DEFAULT=YES,AUTOSELECT=YES\n"
+ "AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
"GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\","
- "AUTOSELECT=YES\n"
+ "DEFAULT=YES,AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=300000,AVERAGE-BANDWIDTH=200000,"
"CODECS=\"sdvideocodec,textcodec\",RESOLUTION=800x600,"
@@ -511,7 +515,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
- "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
+ "GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\","
"AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,AVERAGE-BANDWIDTH=230000,"
@@ -537,14 +541,14 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
"audiocodec", "en", kAudioChannels, kAudioMaxBitrate,
kAudioAvgBitrate),
CreateAudioPlaylist("audio-2.m3u8", "audio 2", "audio-group-2",
- "audiocodec", "en", kAudioChannels, kAudioMaxBitrate,
+ "audiocodec", "fr", kAudioChannels, kAudioMaxBitrate,
kAudioAvgBitrate),
// SUBTITLES
CreateTextPlaylist("text-1.m3u8", "text 1", "text-group-1", "textcodec",
"en"),
CreateTextPlaylist("text-2.m3u8", "text 2", "text-group-2", "textcodec",
- "en"),
+ "fr"),
// VIDEO
CreateVideoPlaylist("video-1.m3u8", "sdvideocodec", kVideoMaxBitrate,
@@ -581,14 +585,14 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
"GROUP-ID=\"audio-group-1\",LANGUAGE=\"en\",NAME=\"audio 1\","
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/audio-2.m3u8\","
- "GROUP-ID=\"audio-group-2\",LANGUAGE=\"en\",NAME=\"audio 2\","
- "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
+ "GROUP-ID=\"audio-group-2\",LANGUAGE=\"fr\",NAME=\"audio 2\","
+ "AUTOSELECT=YES,CHANNELS=\"2\"\n"
"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-1.m3u8\","
"GROUP-ID=\"text-group-1\",LANGUAGE=\"en\",NAME=\"text 1\","
- "DEFAULT=YES,AUTOSELECT=YES\n"
+ "AUTOSELECT=YES\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-2.m3u8\","
- "GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text 2\","
+ "GROUP-ID=\"text-group-2\",LANGUAGE=\"fr\",NAME=\"text 2\","
"DEFAULT=YES,AUTOSELECT=YES\n"
"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=350000,AVERAGE-BANDWIDTH=130000,"
diff --git a/packager/hls/base/simple_hls_notifier.cc b/packager/hls/base/simple_hls_notifier.cc
index 11dde8e31e..6b8c11caa9 100644
--- a/packager/hls/base/simple_hls_notifier.cc
+++ b/packager/hls/base/simple_hls_notifier.cc
@@ -282,9 +282,14 @@ SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params)
const base::FilePath master_playlist_path(
base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output));
output_dir_ = master_playlist_path.DirName().AsUTF8Unsafe();
+ const std::string& default_audio_langauge = hls_params.default_language;
+ const std::string& default_text_language =
+ hls_params.default_text_language.empty()
+ ? hls_params.default_language
+ : hls_params.default_text_language;
master_playlist_.reset(
new MasterPlaylist(master_playlist_path.BaseName().AsUTF8Unsafe(),
- hls_params.default_language));
+ default_audio_langauge, default_text_language));
}
SimpleHlsNotifier::~SimpleHlsNotifier() {}
diff --git a/packager/hls/base/simple_hls_notifier_unittest.cc b/packager/hls/base/simple_hls_notifier_unittest.cc
index 17f6943c88..6443deb9f1 100644
--- a/packager/hls/base/simple_hls_notifier_unittest.cc
+++ b/packager/hls/base/simple_hls_notifier_unittest.cc
@@ -35,7 +35,8 @@ using ::testing::WithParamInterface;
namespace {
const char kMasterPlaylistName[] = "master.m3u8";
-const char kDefaultLanguage[] = "en";
+const char kDefaultAudioLanguage[] = "en";
+const char kDefaultTextLanguage[] = "fr";
const char kEmptyKeyUri[] = "";
const char kFairPlayKeyUri[] = "skd://www.license.com/getkey?key_id=testing";
const char kIdentityKeyUri[] = "https://www.license.com/getkey?key_id=testing";
@@ -45,7 +46,9 @@ const HlsPlaylistType kLivePlaylist = HlsPlaylistType::kLive;
class MockMasterPlaylist : public MasterPlaylist {
public:
MockMasterPlaylist()
- : MasterPlaylist(kMasterPlaylistName, kDefaultLanguage) {}
+ : MasterPlaylist(kMasterPlaylistName,
+ kDefaultAudioLanguage,
+ kDefaultTextLanguage) {}
MOCK_METHOD3(WriteMasterPlaylist,
bool(const std::string& prefix,
diff --git a/packager/hls/public/hls_params.h b/packager/hls/public/hls_params.h
index 22c7d882c1..f35618db4b 100644
--- a/packager/hls/public/hls_params.h
+++ b/packager/hls/public/hls_params.h
@@ -45,7 +45,12 @@ struct HlsParams {
/// The renditions tagged with this language will have 'DEFAULT' set to 'YES'
/// in 'EXT-X-MEDIA' tag. This allows the player to choose the correct default
/// language for the content.
+ /// This applies to both audio and text tracks. The default language for text
+ /// tracks can be overriden by 'default_text_language'.
std::string default_language;
+ /// Same as above, but this overrides the default language for text tracks,
+ /// i.e. subtitles or close-captions.
+ std::string default_text_language;
/// This is the target segment duration requested by the user. The actual
/// segment duration may be different to the target segment duration.
/// This parameter is included here to for bandwidth estimator to exclude the
diff --git a/packager/mpd/base/period.cc b/packager/mpd/base/period.cc
index fa41da2d67..06c85ed9d0 100644
--- a/packager/mpd/base/period.cc
+++ b/packager/mpd/base/period.cc
@@ -32,6 +32,16 @@ std::set GetUUIDs(
return uuids;
}
+const std::string& GetDefaultAudioLanguage(const MpdOptions& mpd_options) {
+ return mpd_options.mpd_params.default_language;
+}
+
+const std::string& GetDefaultTextLanguage(const MpdOptions& mpd_options) {
+ return mpd_options.mpd_params.default_text_language.empty()
+ ? mpd_options.mpd_params.default_language
+ : mpd_options.mpd_params.default_text_language;
+}
+
} // namespace
Period::Period(uint32_t period_id,
@@ -149,8 +159,14 @@ bool Period::SetNewAdaptationSetAttributes(
const MediaInfo& media_info,
const std::list& adaptation_sets,
AdaptationSet* new_adaptation_set) {
- if (!language.empty() && language == mpd_options_.mpd_params.default_language)
- new_adaptation_set->AddRole(AdaptationSet::kRoleMain);
+ if (!language.empty()) {
+ const bool is_main_role =
+ language == (media_info.has_audio_info()
+ ? GetDefaultAudioLanguage(mpd_options_)
+ : GetDefaultTextLanguage(mpd_options_));
+ if (is_main_role)
+ new_adaptation_set->AddRole(AdaptationSet::kRoleMain);
+ }
if (media_info.has_video_info()) {
// Because 'language' is ignored for videos, |adaptation_sets| must have
diff --git a/packager/mpd/base/period_unittest.cc b/packager/mpd/base/period_unittest.cc
index 0c5afa5f75..59622a5662 100644
--- a/packager/mpd/base/period_unittest.cc
+++ b/packager/mpd/base/period_unittest.cc
@@ -93,15 +93,13 @@ class TestablePeriod : public Period {
} // namespace
-class PeriodTest : public ::testing::TestWithParam {
+class PeriodTest : public ::testing::Test {
public:
PeriodTest()
: testable_period_(mpd_options_),
default_adaptation_set_(new StrictMock()),
default_adaptation_set_ptr_(default_adaptation_set_.get()) {}
- void SetUp() override { content_protection_in_adaptation_set_ = GetParam(); }
-
protected:
MpdOptions mpd_options_;
TestablePeriod testable_period_;
@@ -112,7 +110,7 @@ class PeriodTest : public ::testing::TestWithParam {
StrictMock* default_adaptation_set_ptr_;
};
-TEST_P(PeriodTest, GetXml) {
+TEST_F(PeriodTest, GetXml) {
const char kVideoMediaInfo[] =
"video_info {\n"
" codec: 'avc1'\n"
@@ -143,7 +141,7 @@ TEST_P(PeriodTest, GetXml) {
XmlNodeEqual(kExpectedXml));
}
-TEST_P(PeriodTest, DynamicMpdGetXml) {
+TEST_F(PeriodTest, DynamicMpdGetXml) {
const char kVideoMediaInfo[] =
"video_info {\n"
" codec: 'avc1'\n"
@@ -175,7 +173,7 @@ TEST_P(PeriodTest, DynamicMpdGetXml) {
XmlNodeEqual(kExpectedXml));
}
-TEST_P(PeriodTest, SetDurationAndGetXml) {
+TEST_F(PeriodTest, SetDurationAndGetXml) {
const char kVideoMediaInfo[] =
"video_info {\n"
" codec: 'avc1'\n"
@@ -217,7 +215,7 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
}
// Verify ForceSetSegmentAlignment is called.
-TEST_P(PeriodTest, Text) {
+TEST_F(PeriodTest, Text) {
const char kTextMediaInfo[] =
"text_info {\n"
" codec: 'ttml'\n"
@@ -235,7 +233,7 @@ TEST_P(PeriodTest, Text) {
content_protection_in_adaptation_set_));
}
-TEST_P(PeriodTest, TrickPlayWithMatchingAdaptationSet) {
+TEST_F(PeriodTest, TrickPlayWithMatchingAdaptationSet) {
const char kVideoMediaInfo[] =
"video_info {\n"
" codec: 'avc1'\n"
@@ -282,7 +280,7 @@ TEST_P(PeriodTest, TrickPlayWithMatchingAdaptationSet) {
}
// Verify no AdaptationSet is returned on trickplay media info.
-TEST_P(PeriodTest, TrickPlayWithNoMatchingAdaptationSet) {
+TEST_F(PeriodTest, TrickPlayWithNoMatchingAdaptationSet) {
const char kVideoMediaInfo[] =
"video_info {\n"
" codec: 'avc1'\n"
@@ -324,11 +322,338 @@ TEST_P(PeriodTest, TrickPlayWithNoMatchingAdaptationSet) {
content_protection_in_adaptation_set_));
}
+// Don't put different audio languages or codecs in the same AdaptationSet.
+TEST_F(PeriodTest, SplitAdaptationSetsByLanguageAndCodec) {
+ const char kAacEnglishAudioContent[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'eng'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ const char kAacGermanAudioContent[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'ger'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ const char kVorbisGermanAudioContent1[] =
+ "audio_info {\n"
+ " codec: 'vorbis'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'ger'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_WEBM\n"
+ "media_duration_seconds: 10.5\n";
+ const char kVorbisGermanAudioContent2[] =
+ "audio_info {\n"
+ " codec: 'vorbis'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'ger'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_WEBM\n"
+ "media_duration_seconds: 10.5\n";
+
+ std::unique_ptr> aac_eng_adaptation_set(
+ new StrictMock());
+ auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get();
+ std::unique_ptr> aac_ger_adaptation_set(
+ new StrictMock());
+ auto* aac_ger_adaptation_set_ptr = aac_ger_adaptation_set.get();
+ std::unique_ptr> vorbis_german_adaptation_set(
+ new StrictMock());
+ auto* vorbis_german_adaptation_set_ptr = vorbis_german_adaptation_set.get();
+
+ // We expect three AdaptationSets.
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set))))
+ .WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set))))
+ .WillOnce(Return(ByMove(std::move(vorbis_german_adaptation_set))));
+
+ ASSERT_EQ(aac_eng_adaptation_set_ptr,
+ testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kAacEnglishAudioContent),
+ content_protection_in_adaptation_set_));
+ ASSERT_EQ(aac_ger_adaptation_set_ptr,
+ testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kAacGermanAudioContent),
+ content_protection_in_adaptation_set_));
+ ASSERT_EQ(vorbis_german_adaptation_set_ptr,
+ testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kVorbisGermanAudioContent1),
+ content_protection_in_adaptation_set_));
+ // The same AdaptationSet is returned.
+ ASSERT_EQ(vorbis_german_adaptation_set_ptr,
+ testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kVorbisGermanAudioContent2),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, GetAdaptationSets) {
+ const char kContent1[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'eng'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ const char kContent2[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'ger'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+
+ std::unique_ptr> adaptation_set_1(
+ new StrictMock());
+ auto* adaptation_set_1_ptr = adaptation_set_1.get();
+ std::unique_ptr> adaptation_set_2(
+ new StrictMock());
+ auto* adaptation_set_2_ptr = adaptation_set_2.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
+ .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
+
+ ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kContent1),
+ content_protection_in_adaptation_set_));
+ EXPECT_THAT(testable_period_.GetAdaptationSets(),
+ ElementsAre(adaptation_set_1_ptr));
+
+ ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kContent2),
+ content_protection_in_adaptation_set_));
+ EXPECT_THAT(testable_period_.GetAdaptationSets(),
+ ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
+}
+
+TEST_F(PeriodTest, OrderedByAdaptationSetId) {
+ const char kContent1[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'eng'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ const char kContent2[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'ger'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+
+ std::unique_ptr> adaptation_set_1(
+ new StrictMock());
+ auto* adaptation_set_1_ptr = adaptation_set_1.get();
+ std::unique_ptr> adaptation_set_2(
+ new StrictMock());
+ auto* adaptation_set_2_ptr = adaptation_set_2.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
+ .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
+
+ ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kContent1),
+ content_protection_in_adaptation_set_));
+ ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kContent2),
+ content_protection_in_adaptation_set_));
+
+ adaptation_set_1_ptr->set_id(2);
+ adaptation_set_2_ptr->set_id(1);
+ const char kExpectedXml[] =
+ R"()"
+ // ContentType and Representation elements are populated after
+ // Representation::Init() is called.
+ R"( )"
+ R"( )"
+ R"()";
+ EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
+ XmlNodeEqual(kExpectedXml));
+}
+
+TEST_F(PeriodTest, AudioAdaptationSetDefaultLanguage) {
+ mpd_options_.mpd_params.default_language = "en";
+ const char kEnglishAudioContent[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'en'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain));
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishAudioContent),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, AudioAdaptationSetNonDefaultLanguage) {
+ mpd_options_.mpd_params.default_language = "fr";
+ const char kEnglishAudioContent[] =
+ "audio_info {\n"
+ " codec: 'mp4a.40.2'\n"
+ " sampling_frequency: 44100\n"
+ " time_scale: 1200\n"
+ " num_channels: 2\n"
+ " language: 'en'\n"
+ "}\n"
+ "reference_time_scale: 50\n"
+ "container_type: CONTAINER_MP4\n"
+ "media_duration_seconds: 10.5\n";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain)).Times(0);
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishAudioContent),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, TextAdaptationSetDefaultLanguage) {
+ mpd_options_.mpd_params.default_language = "en";
+ const char kEnglishTextContent[] =
+ "text_info {\n"
+ " codec: 'webvtt'\n"
+ " language: 'en'\n"
+ " type: SUBTITLE\n"
+ "}";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain));
+ EXPECT_CALL(*adaptation_set_ptr, ForceSetSegmentAlignment(true));
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishTextContent),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, TextAdaptationSetNonDefaultLanguage) {
+ mpd_options_.mpd_params.default_language = "fr";
+ const char kEnglishTextContent[] =
+ "text_info {\n"
+ " codec: 'webvtt'\n"
+ " language: 'en'\n"
+ " type: SUBTITLE\n"
+ "}";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain)).Times(0);
+ EXPECT_CALL(*adaptation_set_ptr, ForceSetSegmentAlignment(true));
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishTextContent),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, TextAdaptationSetNonDefaultLanguageButDefaultTextLanguage) {
+ mpd_options_.mpd_params.default_language = "fr";
+ mpd_options_.mpd_params.default_text_language = "en";
+ const char kEnglishTextContent[] =
+ "text_info {\n"
+ " codec: 'webvtt'\n"
+ " language: 'en'\n"
+ " type: SUBTITLE\n"
+ "}";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain));
+ EXPECT_CALL(*adaptation_set_ptr, ForceSetSegmentAlignment(true));
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishTextContent),
+ content_protection_in_adaptation_set_));
+}
+
+TEST_F(PeriodTest, TextAdaptationSetDefaultLanguageButNonDefaultTextLanguage) {
+ mpd_options_.mpd_params.default_language = "en";
+ mpd_options_.mpd_params.default_text_language = "fr";
+ const char kEnglishTextContent[] =
+ "text_info {\n"
+ " codec: 'webvtt'\n"
+ " language: 'en'\n"
+ " type: SUBTITLE\n"
+ "}";
+ std::unique_ptr> adaptation_set(
+ new StrictMock());
+ auto* adaptation_set_ptr = adaptation_set.get();
+
+ EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
+ .WillOnce(Return(ByMove(std::move(adaptation_set))));
+ EXPECT_CALL(*adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain)).Times(0);
+ EXPECT_CALL(*adaptation_set_ptr, ForceSetSegmentAlignment(true));
+ ASSERT_EQ(adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
+ ConvertToMediaInfo(kEnglishTextContent),
+ content_protection_in_adaptation_set_));
+}
+
+class PeriodTestWithContentProtection
+ : public PeriodTest,
+ public ::testing::WithParamInterface {
+ void SetUp() override { content_protection_in_adaptation_set_ = GetParam(); }
+};
+
// With content_protection_adaptation_set_ == true, verify with different
// MediaInfo::ProtectedContent, two AdaptationSets should be created.
// AdaptationSets with different DRM won't be switchable.
// Otherwise, only one AdaptationSet is created.
-TEST_P(PeriodTest, DifferentProtectedContent) {
+TEST_P(PeriodTestWithContentProtection, DifferentProtectedContent) {
// Note they both have different (bogus) pssh, like real use case.
// default Key ID = _default_key_id_
const char kSdProtectedContent[] =
@@ -435,7 +760,7 @@ TEST_P(PeriodTest, DifferentProtectedContent) {
// Verify with the same MediaInfo::ProtectedContent, only one AdaptationSets
// should be created regardless of the value of
// content_protection_in_adaptation_set_.
-TEST_P(PeriodTest, SameProtectedContent) {
+TEST_P(PeriodTestWithContentProtection, SameProtectedContent) {
// These have the same default key ID and PSSH.
const char kSdProtectedContent[] =
"video_info {\n"
@@ -527,7 +852,7 @@ TEST_P(PeriodTest, SameProtectedContent) {
// 3. Add a 4k protected content. This should also make a new AdaptationSet.
// It should be switchable with SD/HD AdaptationSet.
// Otherwise only one AdaptationSet is created.
-TEST_P(PeriodTest, SetAdaptationSetSwitching) {
+TEST_P(PeriodTestWithContentProtection, SetAdaptationSetSwitching) {
// These have the same default key ID and PSSH.
const char kSdProtectedContent[] =
"video_info {\n"
@@ -668,7 +993,8 @@ TEST_P(PeriodTest, SetAdaptationSetSwitching) {
// Even if the UUIDs match, video and audio AdaptationSets should not be
// switchable.
-TEST_P(PeriodTest, DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) {
+TEST_P(PeriodTestWithContentProtection,
+ DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) {
// These have the same default key ID and PSSH.
const char kVideoContent[] =
"video_info {\n"
@@ -745,192 +1071,8 @@ TEST_P(PeriodTest, DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) {
content_protection_in_adaptation_set_));
}
-// Don't put different audio languages or codecs in the same AdaptationSet.
-TEST_P(PeriodTest, SplitAdaptationSetsByLanguageAndCodec) {
- const char kAacEnglishAudioContent[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'eng'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
- const char kAacGermanAudioContent[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'ger'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
- const char kVorbisGermanAudioContent1[] =
- "audio_info {\n"
- " codec: 'vorbis'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'ger'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_WEBM\n"
- "media_duration_seconds: 10.5\n";
- const char kVorbisGermanAudioContent2[] =
- "audio_info {\n"
- " codec: 'vorbis'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'ger'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_WEBM\n"
- "media_duration_seconds: 10.5\n";
-
- std::unique_ptr> aac_eng_adaptation_set(
- new StrictMock());
- auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get();
- std::unique_ptr> aac_ger_adaptation_set(
- new StrictMock());
- auto* aac_ger_adaptation_set_ptr = aac_ger_adaptation_set.get();
- std::unique_ptr> vorbis_german_adaptation_set(
- new StrictMock());
- auto* vorbis_german_adaptation_set_ptr = vorbis_german_adaptation_set.get();
-
- // We expect three AdaptationSets.
- EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
- .WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set))))
- .WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set))))
- .WillOnce(Return(ByMove(std::move(vorbis_german_adaptation_set))));
-
- ASSERT_EQ(aac_eng_adaptation_set_ptr,
- testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kAacEnglishAudioContent),
- content_protection_in_adaptation_set_));
- ASSERT_EQ(aac_ger_adaptation_set_ptr,
- testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kAacGermanAudioContent),
- content_protection_in_adaptation_set_));
- ASSERT_EQ(vorbis_german_adaptation_set_ptr,
- testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kVorbisGermanAudioContent1),
- content_protection_in_adaptation_set_));
- // The same AdaptationSet is returned.
- ASSERT_EQ(vorbis_german_adaptation_set_ptr,
- testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kVorbisGermanAudioContent2),
- content_protection_in_adaptation_set_));
-}
-
-TEST_P(PeriodTest, GetAdaptationSets) {
- const char kContent1[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'eng'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
- const char kContent2[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'ger'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
-
- std::unique_ptr> adaptation_set_1(
- new StrictMock());
- auto* adaptation_set_1_ptr = adaptation_set_1.get();
- std::unique_ptr> adaptation_set_2(
- new StrictMock());
- auto* adaptation_set_2_ptr = adaptation_set_2.get();
-
- EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
- .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
- .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
-
- ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kContent1),
- content_protection_in_adaptation_set_));
- EXPECT_THAT(testable_period_.GetAdaptationSets(),
- ElementsAre(adaptation_set_1_ptr));
-
- ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kContent2),
- content_protection_in_adaptation_set_));
- EXPECT_THAT(testable_period_.GetAdaptationSets(),
- ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
-}
-
-TEST_P(PeriodTest, OrderedByAdaptationSetId) {
- const char kContent1[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'eng'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
- const char kContent2[] =
- "audio_info {\n"
- " codec: 'mp4a.40.2'\n"
- " sampling_frequency: 44100\n"
- " time_scale: 1200\n"
- " num_channels: 2\n"
- " language: 'ger'\n"
- "}\n"
- "reference_time_scale: 50\n"
- "container_type: CONTAINER_MP4\n"
- "media_duration_seconds: 10.5\n";
-
- std::unique_ptr> adaptation_set_1(
- new StrictMock());
- auto* adaptation_set_1_ptr = adaptation_set_1.get();
- std::unique_ptr> adaptation_set_2(
- new StrictMock());
- auto* adaptation_set_2_ptr = adaptation_set_2.get();
-
- EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
- .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
- .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
-
- ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kContent1),
- content_protection_in_adaptation_set_));
- ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
- ConvertToMediaInfo(kContent2),
- content_protection_in_adaptation_set_));
-
- adaptation_set_1_ptr->set_id(2);
- adaptation_set_2_ptr->set_id(1);
- const char kExpectedXml[] =
- R"()"
- // ContentType and Representation elements are populated after
- // Representation::Init() is called.
- R"( )"
- R"( )"
- R"()";
- EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
- XmlNodeEqual(kExpectedXml));
-}
INSTANTIATE_TEST_CASE_P(ContentProtectionInAdaptationSet,
- PeriodTest,
+ PeriodTestWithContentProtection,
::testing::Bool());
} // namespace shaka
diff --git a/packager/mpd/public/mpd_params.h b/packager/mpd/public/mpd_params.h
index 1b2bfab61e..2b249cc412 100644
--- a/packager/mpd/public/mpd_params.h
+++ b/packager/mpd/public/mpd_params.h
@@ -53,7 +53,12 @@ struct MpdParams {
/// The tracks tagged with this language will have
/// in the manifest. This allows the player to choose the correct default
/// language for the content.
+ /// This applies to both audio and text tracks. The default language for text
+ /// tracks can be overriden by 'default_text_language'.
std::string default_language;
+ /// Same as above, but this overrides the default language for text tracks,
+ /// i.e. subtitles or close-captions.
+ std::string default_text_language;
/// Generate static MPD for live profile. Note that this flag has no effect
/// for on-demand profile, in which case static MPD is always used.
bool generate_static_live_mpd = false;
diff --git a/packager/packager.cc b/packager/packager.cc
index 335919997c..953d1c8d25 100644
--- a/packager/packager.cc
+++ b/packager/packager.cc
@@ -895,8 +895,12 @@ Status Packager::Initialize(
// in the shortest form.
mpd_params.default_language =
LanguageToShortestForm(mpd_params.default_language);
+ mpd_params.default_text_language =
+ LanguageToShortestForm(mpd_params.default_text_language);
hls_params.default_language =
LanguageToShortestForm(hls_params.default_language);
+ hls_params.default_text_language =
+ LanguageToShortestForm(hls_params.default_text_language);
if (!mpd_params.mpd_output.empty()) {
const bool on_demand_dash_profile =