Added DEFAULT and AUTOSELECT for Text
Took the same logic for DEFAULT and AUTOSELECT used by audio and applied it to text. Combined the build tag logic for audio and text as they were the same expect for a couple fields. Bug: #205 Change-Id: I75ecbf4b25cd559b826982d12a5b132e70b83b69
This commit is contained in:
parent
e2dae2d960
commit
e98a150d62
|
@ -137,35 +137,6 @@ std::list<Variant> BuildVariants(
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildAudioTag(const std::string& base_url,
|
|
||||||
const std::string& group_id,
|
|
||||||
const MediaPlaylist& audio_playlist,
|
|
||||||
bool is_default,
|
|
||||||
bool is_autoselect,
|
|
||||||
std::string* out) {
|
|
||||||
DCHECK(out);
|
|
||||||
|
|
||||||
Tag tag("#EXT-X-MEDIA", out);
|
|
||||||
tag.AddString("TYPE", "AUDIO");
|
|
||||||
tag.AddQuotedString("URI", base_url + audio_playlist.file_name());
|
|
||||||
tag.AddQuotedString("GROUP-ID", group_id);
|
|
||||||
const std::string& language = audio_playlist.GetLanguage();
|
|
||||||
if (!language.empty()) {
|
|
||||||
tag.AddQuotedString("LANGUAGE", language);
|
|
||||||
}
|
|
||||||
tag.AddQuotedString("NAME", audio_playlist.name());
|
|
||||||
if (is_default) {
|
|
||||||
tag.AddString("DEFAULT", "YES");
|
|
||||||
}
|
|
||||||
if (is_autoselect) {
|
|
||||||
tag.AddString("AUTOSELECT", "YES");
|
|
||||||
}
|
|
||||||
tag.AddQuotedString("CHANNELS",
|
|
||||||
std::to_string(audio_playlist.GetNumChannels()));
|
|
||||||
|
|
||||||
out->append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildVideoTag(const MediaPlaylist& playlist,
|
void BuildVideoTag(const MediaPlaylist& playlist,
|
||||||
uint64_t max_audio_bitrate,
|
uint64_t max_audio_bitrate,
|
||||||
const std::string& audio_codec,
|
const std::string& audio_codec,
|
||||||
|
@ -204,23 +175,102 @@ void BuildVideoTag(const MediaPlaylist& playlist,
|
||||||
playlist.file_name().c_str());
|
playlist.file_name().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildSubtitleTag(const MediaPlaylist& playlist,
|
// Need to pass in |group_id| as it may have changed to a new default when
|
||||||
const std::string& base_url,
|
// grouped with other playlists.
|
||||||
const std::string& group_id,
|
void BuildMediaTag(const MediaPlaylist& playlist,
|
||||||
std::string* out) {
|
const std::string& group_id,
|
||||||
|
bool is_default,
|
||||||
|
bool is_autoselect,
|
||||||
|
const std::string& base_url,
|
||||||
|
std::string* out) {
|
||||||
|
// Tag attribures should follow the order as defined in
|
||||||
|
// https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-3.5
|
||||||
|
|
||||||
Tag tag("#EXT-X-MEDIA", out);
|
Tag tag("#EXT-X-MEDIA", out);
|
||||||
|
|
||||||
tag.AddString("TYPE", "SUBTITLES");
|
// We should only be making media tags for audio and text.
|
||||||
|
switch (playlist.stream_type()) {
|
||||||
|
case MediaPlaylist::MediaPlaylistStreamType::kAudio:
|
||||||
|
tag.AddString("TYPE", "AUDIO");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MediaPlaylist::MediaPlaylistStreamType::kSubtitle:
|
||||||
|
tag.AddString("TYPE", "SUBTITLES");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
NOTREACHED() << "Cannot build media tag for type "
|
||||||
|
<< static_cast<int>(playlist.stream_type());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tag.AddQuotedString("URI", base_url + playlist.file_name());
|
tag.AddQuotedString("URI", base_url + playlist.file_name());
|
||||||
tag.AddQuotedString("GROUP-ID", group_id);
|
tag.AddQuotedString("GROUP-ID", group_id);
|
||||||
|
|
||||||
const std::string& language = playlist.GetLanguage();
|
const std::string& language = playlist.GetLanguage();
|
||||||
if (!language.empty()) {
|
if (!language.empty()) {
|
||||||
tag.AddQuotedString("LANGUAGE", language);
|
tag.AddQuotedString("LANGUAGE", language);
|
||||||
}
|
}
|
||||||
|
|
||||||
tag.AddQuotedString("NAME", playlist.name());
|
tag.AddQuotedString("NAME", playlist.name());
|
||||||
|
|
||||||
|
if (is_default) {
|
||||||
|
tag.AddString("DEFAULT", "YES");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_autoselect) {
|
||||||
|
tag.AddString("AUTOSELECT", "YES");
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaPlaylist::MediaPlaylistStreamType kAudio =
|
||||||
|
MediaPlaylist::MediaPlaylistStreamType::kAudio;
|
||||||
|
if (playlist.stream_type() == kAudio) {
|
||||||
|
std::string channel_string = std::to_string(playlist.GetNumChannels());
|
||||||
|
tag.AddQuotedString("CHANNELS", channel_string);
|
||||||
|
}
|
||||||
|
|
||||||
out->append("\n");
|
out->append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildMediaTags(
|
||||||
|
const std::map<std::string, std::list<const MediaPlaylist*>>& groups,
|
||||||
|
const std::string& default_language,
|
||||||
|
const std::string& base_url,
|
||||||
|
std::string* out) {
|
||||||
|
for (const auto& group : groups) {
|
||||||
|
const std::string& group_id = group.first;
|
||||||
|
const auto& playlists = group.second;
|
||||||
|
|
||||||
|
// Tracks the language of the playlist in this group.
|
||||||
|
// According to HLS spec: https://goo.gl/MiqjNd 4.3.4.1.1. Rendition Groups
|
||||||
|
// - A Group MUST NOT have more than one member with a DEFAULT attribute of
|
||||||
|
// YES.
|
||||||
|
// - Each EXT-X-MEDIA tag with an AUTOSELECT=YES attribute SHOULD have a
|
||||||
|
// combination of LANGUAGE[RFC5646], ASSOC-LANGUAGE, FORCED, and
|
||||||
|
// CHARACTERISTICS attributes that is distinct from those of other
|
||||||
|
// AUTOSELECT=YES members of its Group.
|
||||||
|
// We tag the first rendition encountered with a particular language with
|
||||||
|
// 'AUTOSELECT'; it is tagged with 'DEFAULT' too if the language matches
|
||||||
|
// |default_language_|.
|
||||||
|
std::set<std::string> languages;
|
||||||
|
|
||||||
|
for (const auto& playlist : playlists) {
|
||||||
|
bool is_default = false;
|
||||||
|
bool is_autoselect = false;
|
||||||
|
|
||||||
|
const std::string language = playlist->GetLanguage();
|
||||||
|
if (languages.find(language) == languages.end()) {
|
||||||
|
is_default = !language.empty() && language == default_language;
|
||||||
|
is_autoselect = true;
|
||||||
|
|
||||||
|
languages.insert(language);
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildMediaTag(*playlist, group_id, is_default, is_autoselect, base_url,
|
||||||
|
out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MasterPlaylist::MasterPlaylist(const std::string& file_name,
|
MasterPlaylist::MasterPlaylist(const std::string& file_name,
|
||||||
|
@ -264,47 +314,12 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url,
|
||||||
std::string subtitle_output;
|
std::string subtitle_output;
|
||||||
|
|
||||||
// Write out all the audio tags.
|
// Write out all the audio tags.
|
||||||
for (const auto& group : audio_playlist_groups_) {
|
BuildMediaTags(audio_playlist_groups_, default_language_, base_url,
|
||||||
const auto& group_id = group.first;
|
&audio_output);
|
||||||
const auto& playlists = group.second;
|
|
||||||
|
|
||||||
// Tracks the language of the playlist in this group.
|
|
||||||
// According to HLS spec: https://goo.gl/MiqjNd 4.3.4.1.1. Rendition Groups
|
|
||||||
// - A Group MUST NOT have more than one member with a DEFAULT attribute of
|
|
||||||
// YES.
|
|
||||||
// - Each EXT-X-MEDIA tag with an AUTOSELECT=YES attribute SHOULD have a
|
|
||||||
// combination of LANGUAGE[RFC5646], ASSOC-LANGUAGE, FORCED, and
|
|
||||||
// CHARACTERISTICS attributes that is distinct from those of other
|
|
||||||
// AUTOSELECT=YES members of its Group.
|
|
||||||
// We tag the first rendition encountered with a particular language with
|
|
||||||
// 'AUTOSELECT'; it is tagged with 'DEFAULT' too if the language matches
|
|
||||||
// |default_language_|.
|
|
||||||
std::set<std::string> languages;
|
|
||||||
|
|
||||||
for (const auto& playlist : playlists) {
|
|
||||||
bool is_default = false;
|
|
||||||
bool is_autoselect = false;
|
|
||||||
|
|
||||||
const std::string language = playlist->GetLanguage();
|
|
||||||
if (languages.find(language) == languages.end()) {
|
|
||||||
is_default = !language.empty() && language == default_language_;
|
|
||||||
is_autoselect = true;
|
|
||||||
languages.insert(language);
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildAudioTag(base_url, group_id, *playlist, is_default, is_autoselect,
|
|
||||||
&audio_output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out all the text tags.
|
// Write out all the text tags.
|
||||||
for (const auto& group : subtitle_playlist_groups_) {
|
BuildMediaTags(subtitle_playlist_groups_, default_language_, base_url,
|
||||||
const auto& group_id = group.first;
|
&subtitle_output);
|
||||||
const auto& playlists = group.second;
|
|
||||||
for (const auto& playlist : playlists) {
|
|
||||||
BuildSubtitleTag(*playlist, base_url, group_id, &subtitle_output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<Variant> variants =
|
std::list<Variant> variants =
|
||||||
BuildVariants(audio_playlist_groups_, subtitle_playlist_groups_);
|
BuildVariants(audio_playlist_groups_, subtitle_playlist_groups_);
|
||||||
|
|
|
@ -285,8 +285,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistSameAudioGroupSameLanguage) {
|
||||||
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
|
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
|
||||||
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
|
||||||
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\","
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\","
|
||||||
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
|
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\",CHANNELS=\"8\"\n"
|
||||||
"CHANNELS=\"8\"\n"
|
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec\","
|
||||||
"RESOLUTION=800x600,AUDIO=\"audio\"\n"
|
"RESOLUTION=800x600,AUDIO=\"audio\"\n"
|
||||||
"http://anydomain.com/video.m3u8\n";
|
"http://anydomain.com/video.m3u8\n";
|
||||||
|
@ -326,9 +325,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
||||||
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\"\n"
|
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
|
||||||
|
"AUTOSELECT=YES\n"
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
|
||||||
"GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\"\n"
|
"GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=YES\n"
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
||||||
"RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n"
|
"RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n"
|
||||||
"http://playlists.org/sd.m3u8\n"
|
"http://playlists.org/sd.m3u8\n"
|
||||||
|
@ -366,9 +366,11 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
||||||
"GROUP-ID=\"en-text-group\",LANGUAGE=\"en\",NAME=\"english\"\n"
|
"GROUP-ID=\"en-text-group\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
|
||||||
|
"AUTOSELECT=YES\n"
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
|
||||||
"GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\"\n"
|
"GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT="
|
||||||
|
"YES\n"
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
||||||
"RESOLUTION=800x600,SUBTITLES=\"en-text-group\"\n"
|
"RESOLUTION=800x600,SUBTITLES=\"en-text-group\"\n"
|
||||||
"http://playlists.org/sd.m3u8\n"
|
"http://playlists.org/sd.m3u8\n"
|
||||||
|
@ -409,7 +411,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
|
||||||
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
|
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
|
||||||
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/eng.m3u8\","
|
||||||
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\"\n"
|
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
|
||||||
|
"AUTOSELECT=YES\n"
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||||
"RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES=\"textgroup\"\n"
|
"RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES=\"textgroup\"\n"
|
||||||
"http://playlists.org/sd.m3u8\n";
|
"http://playlists.org/sd.m3u8\n";
|
||||||
|
@ -463,10 +466,12 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVidesAudiosTextsDifferentGroups) {
|
||||||
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
|
||||||
|
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-1.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-1.m3u8\","
|
||||||
"GROUP-ID=\"text-group-1\",LANGUAGE=\"en\",NAME=\"text 1\"\n"
|
"GROUP-ID=\"text-group-1\",LANGUAGE=\"en\",NAME=\"text "
|
||||||
|
"1\",DEFAULT=YES,AUTOSELECT=YES\n"
|
||||||
|
|
||||||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-2.m3u8\","
|
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/text-2.m3u8\","
|
||||||
"GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text 2\"\n"
|
"GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text "
|
||||||
|
"2\",DEFAULT=YES,AUTOSELECT=YES\n"
|
||||||
|
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||||
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
|
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
|
||||||
|
|
Loading…
Reference in New Issue