Use Variants To Build Audio and Video Tags
In the master play list, use a class called variant to build the video tags. The variant list will always have one entry. In the case that there are no audio streams, the variant list will have a null entry. Bug: #205 Change-Id: I6e4acd83a31cd267c173e4f4c910f93781fe6efd
This commit is contained in:
parent
771944a3f5
commit
0f17631017
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "packager/hls/base/master_playlist.h"
|
#include "packager/hls/base/master_playlist.h"
|
||||||
|
|
||||||
|
#include <algorithm> // std::max
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "packager/base/files/file_path.h"
|
#include "packager/base/files/file_path.h"
|
||||||
|
@ -19,6 +21,47 @@ namespace shaka {
|
||||||
namespace hls {
|
namespace hls {
|
||||||
|
|
||||||
namespace {
|
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<const MediaPlaylist*> playlists) {
|
||||||
|
uint64_t max = 0;
|
||||||
|
for (const auto& playlist : playlists) {
|
||||||
|
max = std::max(max, playlist->Bitrate());
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetAudioGroupCodecString(
|
||||||
|
const std::list<const MediaPlaylist*>& group) {
|
||||||
|
// TODO(vaage): Should be a concatenation of all the codecs in the group.
|
||||||
|
return group.front()->codec();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Variant> AudioGroupsToVariants(
|
||||||
|
const std::map<std::string, std::list<const MediaPlaylist*>>& groups) {
|
||||||
|
std::list<Variant> 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 {
|
class Tag {
|
||||||
public:
|
public:
|
||||||
|
@ -157,10 +200,11 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url,
|
||||||
// TODO(rkuroiwa): Handle audio only.
|
// TODO(rkuroiwa): Handle audio only.
|
||||||
std::string audio_output;
|
std::string audio_output;
|
||||||
std::string video_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;
|
// Write out all the audio tags.
|
||||||
const std::list<const MediaPlaylist*>& audio_playlists =
|
for (const auto& group : audio_playlist_groups_) {
|
||||||
group_id_audio_playlists.second;
|
const auto& group_id = group.first;
|
||||||
|
const auto& playlists = group.second;
|
||||||
|
|
||||||
// Tracks the language of the playlist in this group.
|
// Tracks the language of the playlist in this group.
|
||||||
// According to HLS spec: https://goo.gl/MiqjNd 4.3.4.1.1. Rendition Groups
|
// 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_|.
|
// |default_language_|.
|
||||||
std::set<std::string> languages;
|
std::set<std::string> languages;
|
||||||
|
|
||||||
uint64_t max_audio_bitrate = 0;
|
for (const auto& playlist : playlists) {
|
||||||
for (const MediaPlaylist* audio_playlist : audio_playlists) {
|
|
||||||
bool is_default = false;
|
bool is_default = false;
|
||||||
bool is_autoselect = false;
|
bool is_autoselect = false;
|
||||||
const std::string language = audio_playlist->GetLanguage();
|
|
||||||
|
const std::string language = playlist->GetLanguage();
|
||||||
if (languages.find(language) == languages.end()) {
|
if (languages.find(language) == languages.end()) {
|
||||||
is_default = !language.empty() && language == default_language_;
|
is_default = !language.empty() && language == default_language_;
|
||||||
is_autoselect = true;
|
is_autoselect = true;
|
||||||
languages.insert(language);
|
languages.insert(language);
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildAudioTag(base_url, group_id, *audio_playlist, is_default,
|
BuildAudioTag(base_url, group_id, *playlist, is_default, is_autoselect,
|
||||||
is_autoselect, &audio_output);
|
&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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_playlist_groups_.empty()) {
|
std::list<Variant> variants = AudioGroupsToVariants(audio_playlist_groups_);
|
||||||
for (const MediaPlaylist* video_playlist : video_playlists_) {
|
|
||||||
BuildVideoTag(*video_playlist, 0, "", nullptr, base_url, &video_output);
|
// 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());
|
GetPackagerProjectUrl().c_str(), version.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string content =
|
std::string content = "";
|
||||||
"#EXTM3U\n" + version_line + audio_output + video_output;
|
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.
|
// Skip if the playlist is already written.
|
||||||
if (content == written_playlist_)
|
if (content == written_playlist_)
|
||||||
|
|
Loading…
Reference in New Issue