diff --git a/packager/hls/base/master_playlist.cc b/packager/hls/base/master_playlist.cc index 78beb1c160..3635f15d99 100644 --- a/packager/hls/base/master_playlist.cc +++ b/packager/hls/base/master_playlist.cc @@ -6,6 +6,8 @@ #include "packager/hls/base/master_playlist.h" +#include // std::max + #include #include "packager/base/files/file_path.h" @@ -19,6 +21,47 @@ namespace shaka { namespace hls { namespace { +struct Variant { + std::string audio_codec; + const std::string* audio_group_id = nullptr; + uint64_t audio_bitrate = 0; +}; + +uint64_t MaxBitrate(const std::list playlists) { + uint64_t max = 0; + for (const auto& playlist : playlists) { + max = std::max(max, playlist->Bitrate()); + } + return max; +} + +std::string GetAudioGroupCodecString( + const std::list& group) { + // TODO(vaage): Should be a concatenation of all the codecs in the group. + return group.front()->codec(); +} + +std::list AudioGroupsToVariants( + const std::map>& groups) { + std::list variants; + + for (const auto& group : groups) { + Variant variant; + variant.audio_codec = GetAudioGroupCodecString(group.second); + variant.audio_group_id = &group.first; + variant.audio_bitrate = MaxBitrate(group.second); + + variants.push_back(variant); + } + + // Make sure we return at least one variant so create a null variant if there + // are no variants. + if (variants.empty()) { + variants.emplace_back(); + } + + return variants; +} class Tag { public: @@ -157,10 +200,11 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url, // TODO(rkuroiwa): Handle audio only. std::string audio_output; std::string video_output; - for (const auto& group_id_audio_playlists : audio_playlist_groups_) { - const std::string& group_id = group_id_audio_playlists.first; - const std::list& audio_playlists = - group_id_audio_playlists.second; + + // Write out all the audio tags. + for (const auto& group : audio_playlist_groups_) { + const auto& 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 @@ -175,40 +219,29 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url, // |default_language_|. std::set languages; - uint64_t max_audio_bitrate = 0; - for (const MediaPlaylist* audio_playlist : audio_playlists) { + for (const auto& playlist : playlists) { bool is_default = false; bool is_autoselect = false; - const std::string language = audio_playlist->GetLanguage(); + + 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, *audio_playlist, is_default, - is_autoselect, &audio_output); - - const uint64_t audio_bitrate = audio_playlist->Bitrate(); - if (audio_bitrate > max_audio_bitrate) - max_audio_bitrate = audio_bitrate; - } - for (const MediaPlaylist* video_playlist : video_playlists_) { - // Assume all codecs are the same for same group ID. - const std::string& audio_codec = audio_playlists.front()->codec(); - - uint32_t video_width; - uint32_t video_height; - CHECK(video_playlist->GetDisplayResolution(&video_width, &video_height)); - - BuildVideoTag(*video_playlist, max_audio_bitrate, audio_codec, &group_id, - base_url, &video_output); + BuildAudioTag(base_url, group_id, *playlist, is_default, is_autoselect, + &audio_output); } } - if (audio_playlist_groups_.empty()) { - for (const MediaPlaylist* video_playlist : video_playlists_) { - BuildVideoTag(*video_playlist, 0, "", nullptr, base_url, &video_output); + std::list variants = AudioGroupsToVariants(audio_playlist_groups_); + + // Write all the video tags out. + for (const auto& playlist : video_playlists_) { + for (const auto& variant : variants) { + BuildVideoTag(*playlist, variant.audio_bitrate, variant.audio_codec, + variant.audio_group_id, base_url, &video_output); } } @@ -220,8 +253,9 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url, GetPackagerProjectUrl().c_str(), version.c_str()); } - std::string content = - "#EXTM3U\n" + version_line + audio_output + video_output; + std::string content = ""; + base::StringAppendF(&content, "#EXTM3U\n%s%s%s", version_line.c_str(), + audio_output.c_str(), video_output.c_str()); // Skip if the playlist is already written. if (content == written_playlist_)