[HLS] Support AUTOSELECT and DEFAULT in EXT-X-MEDIA
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 with a particular language in an audio group with 'AUTOSELECT'; it is tagged with 'DEFAULT' too if the language matches --default_language. Fixes #315 Change-Id: Iacc0bc8c89ebffce8717fa65e82d6daf5a1f6adc
This commit is contained in:
parent
53892c7467
commit
32d26094ba
|
@ -406,6 +406,7 @@ base::Optional<PackagingParams> GetPackagingParams() {
|
||||||
hls_params.base_url = FLAGS_hls_base_url;
|
hls_params.base_url = FLAGS_hls_base_url;
|
||||||
hls_params.key_uri = FLAGS_hls_key_uri;
|
hls_params.key_uri = FLAGS_hls_key_uri;
|
||||||
hls_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
hls_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
||||||
|
hls_params.default_language = FLAGS_default_language;
|
||||||
|
|
||||||
TestParams& test_params = packaging_params.test_params;
|
TestParams& test_params = packaging_params.test_params;
|
||||||
test_params.dump_stream_info = FLAGS_dump_stream_info;
|
test_params.dump_stream_info = FLAGS_dump_stream_info;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="audio",NAME="stream_0",CHANNELS="2"
|
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="audio",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
|
||||||
#EXT-X-STREAM-INF:BANDWIDTH=1217518,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
#EXT-X-STREAM-INF:BANDWIDTH=1217518,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
||||||
video.m3u8
|
video.m3u8
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="audio",NAME="stream_0",CHANNELS="2"
|
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8",GROUP-ID="audio",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
|
||||||
#EXT-X-STREAM-INF:BANDWIDTH=1111147,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
#EXT-X-STREAM-INF:BANDWIDTH=1111147,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
||||||
video.m3u8
|
video.m3u8
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio/audio.m3u8",GROUP-ID="audio",NAME="stream_0",CHANNELS="2"
|
#EXT-X-MEDIA:TYPE=AUDIO,URI="audio/audio.m3u8",GROUP-ID="audio",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2"
|
||||||
#EXT-X-STREAM-INF:BANDWIDTH=1105129,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
#EXT-X-STREAM-INF:BANDWIDTH=1105129,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
|
||||||
video/video.m3u8
|
video/video.m3u8
|
||||||
|
|
|
@ -23,6 +23,9 @@ namespace {
|
||||||
void AppendMediaTag(const std::string& base_url,
|
void AppendMediaTag(const std::string& base_url,
|
||||||
const std::string& group_id,
|
const std::string& group_id,
|
||||||
const MediaPlaylist* audio_playlist,
|
const MediaPlaylist* audio_playlist,
|
||||||
|
const std::string& language,
|
||||||
|
bool is_default,
|
||||||
|
bool is_autoselect,
|
||||||
std::string* out) {
|
std::string* out) {
|
||||||
DCHECK(audio_playlist);
|
DCHECK(audio_playlist);
|
||||||
DCHECK(out);
|
DCHECK(out);
|
||||||
|
@ -31,10 +34,13 @@ void AppendMediaTag(const std::string& base_url,
|
||||||
base::StringAppendF(out, ",URI=\"%s\"",
|
base::StringAppendF(out, ",URI=\"%s\"",
|
||||||
(base_url + audio_playlist->file_name()).c_str());
|
(base_url + audio_playlist->file_name()).c_str());
|
||||||
base::StringAppendF(out, ",GROUP-ID=\"%s\"", group_id.c_str());
|
base::StringAppendF(out, ",GROUP-ID=\"%s\"", group_id.c_str());
|
||||||
std::string language = audio_playlist->GetLanguage();
|
|
||||||
if (!language.empty())
|
if (!language.empty())
|
||||||
base::StringAppendF(out, ",LANGUAGE=\"%s\"", language.c_str());
|
base::StringAppendF(out, ",LANGUAGE=\"%s\"", language.c_str());
|
||||||
base::StringAppendF(out, ",NAME=\"%s\"", audio_playlist->name().c_str());
|
base::StringAppendF(out, ",NAME=\"%s\"", audio_playlist->name().c_str());
|
||||||
|
if (is_default)
|
||||||
|
base::StringAppendF(out, ",DEFAULT=YES");
|
||||||
|
if (is_autoselect)
|
||||||
|
base::StringAppendF(out, ",AUTOSELECT=YES");
|
||||||
base::StringAppendF(out, ",CHANNELS=\"%d\"",
|
base::StringAppendF(out, ",CHANNELS=\"%d\"",
|
||||||
audio_playlist->GetNumChannels());
|
audio_playlist->GetNumChannels());
|
||||||
out->append("\n");
|
out->append("\n");
|
||||||
|
@ -62,8 +68,9 @@ void AppendStreamInfoTag(uint64_t bitrate,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MasterPlaylist::MasterPlaylist(const std::string& file_name)
|
MasterPlaylist::MasterPlaylist(const std::string& file_name,
|
||||||
: file_name_(file_name) {}
|
const std::string& default_language)
|
||||||
|
: file_name_(file_name), default_language_(default_language) {}
|
||||||
MasterPlaylist::~MasterPlaylist() {}
|
MasterPlaylist::~MasterPlaylist() {}
|
||||||
|
|
||||||
void MasterPlaylist::AddMediaPlaylist(MediaPlaylist* media_playlist) {
|
void MasterPlaylist::AddMediaPlaylist(MediaPlaylist* media_playlist) {
|
||||||
|
@ -99,9 +106,32 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url,
|
||||||
const std::list<const MediaPlaylist*>& audio_playlists =
|
const std::list<const MediaPlaylist*>& audio_playlists =
|
||||||
group_id_audio_playlists.second;
|
group_id_audio_playlists.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;
|
||||||
|
|
||||||
uint64_t max_audio_bitrate = 0;
|
uint64_t max_audio_bitrate = 0;
|
||||||
for (const MediaPlaylist* audio_playlist : audio_playlists) {
|
for (const MediaPlaylist* audio_playlist : audio_playlists) {
|
||||||
AppendMediaTag(base_url, group_id, audio_playlist, &audio_output);
|
bool is_default = false;
|
||||||
|
bool is_autoselect = false;
|
||||||
|
const std::string language = audio_playlist->GetLanguage();
|
||||||
|
if (languages.find(language) == languages.end()) {
|
||||||
|
is_default = !language.empty() && language == default_language_;
|
||||||
|
is_autoselect = true;
|
||||||
|
languages.insert(language);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendMediaTag(base_url, group_id, audio_playlist, language, is_default,
|
||||||
|
is_autoselect, &audio_output);
|
||||||
const uint64_t audio_bitrate = audio_playlist->Bitrate();
|
const uint64_t audio_bitrate = audio_playlist->Bitrate();
|
||||||
if (audio_bitrate > max_audio_bitrate)
|
if (audio_bitrate > max_audio_bitrate)
|
||||||
max_audio_bitrate = audio_bitrate;
|
max_audio_bitrate = audio_bitrate;
|
||||||
|
|
|
@ -23,7 +23,10 @@ class MediaPlaylist;
|
||||||
class MasterPlaylist {
|
class MasterPlaylist {
|
||||||
public:
|
public:
|
||||||
/// @param file_name is the file name of the master playlist.
|
/// @param file_name is the file name of the master playlist.
|
||||||
explicit MasterPlaylist(const std::string& file_name);
|
/// @param default_language determines the rendition that should be tagged
|
||||||
|
/// with 'DEFAULT'.
|
||||||
|
MasterPlaylist(const std::string& file_name,
|
||||||
|
const std::string& default_language);
|
||||||
virtual ~MasterPlaylist();
|
virtual ~MasterPlaylist();
|
||||||
|
|
||||||
/// @param media_playlist is a MediaPlaylist that should get added to this
|
/// @param media_playlist is a MediaPlaylist that should get added to this
|
||||||
|
@ -46,6 +49,7 @@ class MasterPlaylist {
|
||||||
private:
|
private:
|
||||||
std::string written_playlist_;
|
std::string written_playlist_;
|
||||||
const std::string file_name_;
|
const std::string file_name_;
|
||||||
|
const std::string default_language_;
|
||||||
std::list<MediaPlaylist*> all_playlists_;
|
std::list<MediaPlaylist*> all_playlists_;
|
||||||
std::list<const MediaPlaylist*> video_playlists_;
|
std::list<const MediaPlaylist*> video_playlists_;
|
||||||
// The key is the audio group name.
|
// The key is the audio group name.
|
||||||
|
|
|
@ -28,6 +28,7 @@ using base::FilePath;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char kDefaultMasterPlaylistName[] = "playlist.m3u8";
|
const char kDefaultMasterPlaylistName[] = "playlist.m3u8";
|
||||||
|
const char kDefaultLanguage[] = "en";
|
||||||
const uint32_t kWidth = 800;
|
const uint32_t kWidth = 800;
|
||||||
const uint32_t kHeight = 600;
|
const uint32_t kHeight = 600;
|
||||||
const HlsPlaylistType kVodPlaylist = HlsPlaylistType::kVod;
|
const HlsPlaylistType kVodPlaylist = HlsPlaylistType::kVod;
|
||||||
|
@ -36,7 +37,7 @@ const HlsPlaylistType kVodPlaylist = HlsPlaylistType::kVod;
|
||||||
class MasterPlaylistTest : public ::testing::Test {
|
class MasterPlaylistTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
MasterPlaylistTest()
|
MasterPlaylistTest()
|
||||||
: master_playlist_(kDefaultMasterPlaylistName),
|
: master_playlist_(kDefaultMasterPlaylistName, kDefaultLanguage),
|
||||||
test_output_dir_("memory://test_dir"),
|
test_output_dir_("memory://test_dir"),
|
||||||
master_playlist_path_(
|
master_playlist_path_(
|
||||||
FilePath::FromUTF8Unsafe(test_output_dir_)
|
FilePath::FromUTF8Unsafe(test_output_dir_)
|
||||||
|
@ -166,10 +167,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) {
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\","
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\","
|
||||||
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
|
"GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\","
|
||||||
"CHANNELS=\"2\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n"
|
||||||
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/spa.m3u8\","
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/spa.m3u8\","
|
||||||
"GROUP-ID=\"audiogroup\",LANGUAGE=\"es\",NAME=\"espanol\","
|
"GROUP-ID=\"audiogroup\",LANGUAGE=\"es\",NAME=\"espanol\","
|
||||||
"CHANNELS=\"5\"\n"
|
"AUTOSELECT=YES,CHANNELS=\"5\"\n"
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=360000,CODECS=\"sdvideocodec,audiocodec\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=360000,CODECS=\"sdvideocodec,audiocodec\","
|
||||||
"RESOLUTION=800x600,AUDIO=\"audiogroup\"\n"
|
"RESOLUTION=800x600,AUDIO=\"audiogroup\"\n"
|
||||||
"http://playlists.org/sd.m3u8\n"
|
"http://playlists.org/sd.m3u8\n"
|
||||||
|
@ -181,7 +182,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
|
TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
|
||||||
// First video, sd.m3u8.
|
// First video, video.m3u8.
|
||||||
std::string video_codec = "videocodec";
|
std::string video_codec = "videocodec";
|
||||||
MockMediaPlaylist video_playlist(kVodPlaylist, "video.m3u8", "somename",
|
MockMediaPlaylist video_playlist(kVodPlaylist, "video.m3u8", "somename",
|
||||||
"somegroupid");
|
"somegroupid");
|
||||||
|
@ -213,6 +214,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
|
||||||
.Times(0);
|
.Times(0);
|
||||||
master_playlist_.AddMediaPlaylist(&eng_lo_playlist);
|
master_playlist_.AddMediaPlaylist(&eng_lo_playlist);
|
||||||
|
|
||||||
|
// Second audio, eng_hi.m3u8.
|
||||||
std::string audio_codec_hi = "audiocodec_hi";
|
std::string audio_codec_hi = "audiocodec_hi";
|
||||||
MockMediaPlaylist eng_hi_playlist(kVodPlaylist, "eng_hi.m3u8", "english_hi",
|
MockMediaPlaylist eng_hi_playlist(kVodPlaylist, "eng_hi.m3u8", "english_hi",
|
||||||
"audio_hi");
|
"audio_hi");
|
||||||
|
@ -240,10 +242,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
|
||||||
"test\n"
|
"test\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_hi\",LANGUAGE=\"en\",NAME=\"english_hi\","
|
"GROUP-ID=\"audio_hi\",LANGUAGE=\"en\",NAME=\"english_hi\","
|
||||||
"CHANNELS=\"8\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"8\"\n"
|
||||||
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\","
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\","
|
||||||
"GROUP-ID=\"audio_lo\",LANGUAGE=\"en\",NAME=\"english_lo\","
|
"GROUP-ID=\"audio_lo\",LANGUAGE=\"en\",NAME=\"english_lo\","
|
||||||
"CHANNELS=\"1\"\n"
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
|
||||||
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec_hi\","
|
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec_hi\","
|
||||||
"RESOLUTION=800x600,AUDIO=\"audio_hi\"\n"
|
"RESOLUTION=800x600,AUDIO=\"audio_hi\"\n"
|
||||||
"http://anydomain.com/video.m3u8\n"
|
"http://anydomain.com/video.m3u8\n"
|
||||||
|
@ -254,5 +256,75 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
|
||||||
ASSERT_EQ(expected, actual);
|
ASSERT_EQ(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MasterPlaylistTest, WriteMasterPlaylistSameAudioGroupSameLanguage) {
|
||||||
|
// First video, video.m3u8.
|
||||||
|
std::string video_codec = "videocodec";
|
||||||
|
MockMediaPlaylist video_playlist(kVodPlaylist, "video.m3u8", "somename",
|
||||||
|
"somegroupid");
|
||||||
|
video_playlist.SetStreamTypeForTesting(
|
||||||
|
MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo);
|
||||||
|
video_playlist.SetCodecForTesting(video_codec);
|
||||||
|
EXPECT_CALL(video_playlist, Bitrate())
|
||||||
|
.Times(AtLeast(1))
|
||||||
|
.WillRepeatedly(Return(300000));
|
||||||
|
EXPECT_CALL(video_playlist, GetDisplayResolution(NotNull(), NotNull()))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<0>(kWidth), SetArgPointee<1>(kHeight),
|
||||||
|
Return(true)));
|
||||||
|
master_playlist_.AddMediaPlaylist(&video_playlist);
|
||||||
|
|
||||||
|
// First audio, eng_lo.m3u8.
|
||||||
|
const std::string audio_codec = "audiocodec";
|
||||||
|
MockMediaPlaylist eng_lo_playlist(kVodPlaylist, "eng_lo.m3u8", "english",
|
||||||
|
"audio");
|
||||||
|
EXPECT_CALL(eng_lo_playlist, GetLanguage()).WillRepeatedly(Return("en"));
|
||||||
|
EXPECT_CALL(eng_lo_playlist, GetNumChannels()).WillRepeatedly(Return(1));
|
||||||
|
eng_lo_playlist.SetStreamTypeForTesting(
|
||||||
|
MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio);
|
||||||
|
eng_lo_playlist.SetCodecForTesting(audio_codec);
|
||||||
|
EXPECT_CALL(eng_lo_playlist, Bitrate())
|
||||||
|
.Times(AtLeast(1))
|
||||||
|
.WillRepeatedly(Return(50000));
|
||||||
|
EXPECT_CALL(eng_lo_playlist, GetDisplayResolution(NotNull(), NotNull()))
|
||||||
|
.Times(0);
|
||||||
|
master_playlist_.AddMediaPlaylist(&eng_lo_playlist);
|
||||||
|
|
||||||
|
// Second audio, eng_hi.m3u8.
|
||||||
|
MockMediaPlaylist eng_hi_playlist(kVodPlaylist, "eng_hi.m3u8", "english",
|
||||||
|
"audio");
|
||||||
|
EXPECT_CALL(eng_hi_playlist, GetLanguage()).WillRepeatedly(Return("en"));
|
||||||
|
EXPECT_CALL(eng_hi_playlist, GetNumChannels()).WillRepeatedly(Return(8));
|
||||||
|
eng_hi_playlist.SetStreamTypeForTesting(
|
||||||
|
MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio);
|
||||||
|
eng_hi_playlist.SetCodecForTesting(audio_codec);
|
||||||
|
EXPECT_CALL(eng_hi_playlist, Bitrate())
|
||||||
|
.Times(AtLeast(1))
|
||||||
|
.WillRepeatedly(Return(100000));
|
||||||
|
EXPECT_CALL(eng_hi_playlist, GetDisplayResolution(NotNull(), NotNull()))
|
||||||
|
.Times(0);
|
||||||
|
master_playlist_.AddMediaPlaylist(&eng_hi_playlist);
|
||||||
|
|
||||||
|
const char kBaseUrl[] = "http://anydomain.com/";
|
||||||
|
EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_));
|
||||||
|
|
||||||
|
std::string actual;
|
||||||
|
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual));
|
||||||
|
|
||||||
|
const std::string expected =
|
||||||
|
"#EXTM3U\n"
|
||||||
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
|
"test\n"
|
||||||
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_lo.m3u8\","
|
||||||
|
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
|
||||||
|
"DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"1\"\n"
|
||||||
|
"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://anydomain.com/eng_hi.m3u8\","
|
||||||
|
"GROUP-ID=\"audio\",LANGUAGE=\"en\",NAME=\"english\","
|
||||||
|
"CHANNELS=\"8\"\n"
|
||||||
|
"#EXT-X-STREAM-INF:BANDWIDTH=400000,CODECS=\"videocodec,audiocodec\","
|
||||||
|
"RESOLUTION=800x600,AUDIO=\"audio\"\n"
|
||||||
|
"http://anydomain.com/video.m3u8\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace hls
|
} // namespace hls
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -247,19 +247,19 @@ std::unique_ptr<MediaPlaylist> MediaPlaylistFactory::Create(
|
||||||
type, time_shift_buffer_depth, file_name, name, group_id));
|
type, time_shift_buffer_depth, file_name, name, group_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleHlsNotifier::SimpleHlsNotifier(HlsPlaylistType playlist_type,
|
SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params)
|
||||||
double time_shift_buffer_depth,
|
: HlsNotifier(hls_params.playlist_type),
|
||||||
const std::string& prefix,
|
time_shift_buffer_depth_(hls_params.time_shift_buffer_depth),
|
||||||
const std::string& key_uri,
|
prefix_(hls_params.base_url),
|
||||||
const std::string& output_dir,
|
key_uri_(hls_params.key_uri),
|
||||||
const std::string& master_playlist_name)
|
media_playlist_factory_(new MediaPlaylistFactory()) {
|
||||||
: HlsNotifier(playlist_type),
|
const base::FilePath master_playlist_path(
|
||||||
time_shift_buffer_depth_(time_shift_buffer_depth),
|
base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output));
|
||||||
prefix_(prefix),
|
output_dir_ = master_playlist_path.DirName().AsUTF8Unsafe();
|
||||||
key_uri_(key_uri),
|
master_playlist_.reset(
|
||||||
output_dir_(output_dir),
|
new MasterPlaylist(master_playlist_path.BaseName().AsUTF8Unsafe(),
|
||||||
media_playlist_factory_(new MediaPlaylistFactory()),
|
hls_params.default_language));
|
||||||
master_playlist_(new MasterPlaylist(master_playlist_name)) {}
|
}
|
||||||
|
|
||||||
SimpleHlsNotifier::~SimpleHlsNotifier() {}
|
SimpleHlsNotifier::~SimpleHlsNotifier() {}
|
||||||
|
|
||||||
|
|
|
@ -38,25 +38,8 @@ class MediaPlaylistFactory {
|
||||||
/// This is thread safe.
|
/// This is thread safe.
|
||||||
class SimpleHlsNotifier : public HlsNotifier {
|
class SimpleHlsNotifier : public HlsNotifier {
|
||||||
public:
|
public:
|
||||||
/// @a prefix is used as hte prefix for all the URIs for Media Playlist. This
|
/// @param hls_params contains parameters for setting up the notifier.
|
||||||
/// includes the segment URIs in the Media Playlists.
|
explicit SimpleHlsNotifier(const HlsParams& hls_params);
|
||||||
/// @param playlist_type is the type of the playlists.
|
|
||||||
/// @param time_shift_buffer_depth determines the duration of the time
|
|
||||||
/// shifting buffer, only for live HLS.
|
|
||||||
/// @param prefix is the used as the prefix for MediaPlaylist URIs. May be
|
|
||||||
/// empty for relative URI from the playlist.
|
|
||||||
/// @param key_uri defines the key uri for "identity" and
|
|
||||||
/// "com.apple.streamingkeydelivery" key formats. Ignored if the
|
|
||||||
/// playlist is not encrypted or not using the above key formats.
|
|
||||||
/// @param output_dir is the output directory of the playlists. May be empty
|
|
||||||
/// to write to current directory.
|
|
||||||
/// @param master_playlist_name is the name of the master playlist.
|
|
||||||
SimpleHlsNotifier(HlsPlaylistType playlist_type,
|
|
||||||
double time_shift_buffer_depth,
|
|
||||||
const std::string& prefix,
|
|
||||||
const std::string& key_uri,
|
|
||||||
const std::string& output_dir,
|
|
||||||
const std::string& master_playlist_name);
|
|
||||||
~SimpleHlsNotifier() override;
|
~SimpleHlsNotifier() override;
|
||||||
|
|
||||||
/// @name HlsNotifier implemetation overrides.
|
/// @name HlsNotifier implemetation overrides.
|
||||||
|
@ -94,7 +77,7 @@ class SimpleHlsNotifier : public HlsNotifier {
|
||||||
const double time_shift_buffer_depth_ = 0;
|
const double time_shift_buffer_depth_ = 0;
|
||||||
const std::string prefix_;
|
const std::string prefix_;
|
||||||
const std::string key_uri_;
|
const std::string key_uri_;
|
||||||
const std::string output_dir_;
|
std::string output_dir_;
|
||||||
uint32_t target_duration_ = 0;
|
uint32_t target_duration_ = 0;
|
||||||
|
|
||||||
std::unique_ptr<MediaPlaylistFactory> media_playlist_factory_;
|
std::unique_ptr<MediaPlaylistFactory> media_playlist_factory_;
|
||||||
|
|
|
@ -31,6 +31,7 @@ using ::testing::_;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char kMasterPlaylistName[] = "master.m3u8";
|
const char kMasterPlaylistName[] = "master.m3u8";
|
||||||
|
const char kDefaultLanguage[] = "en";
|
||||||
const char kEmptyKeyUri[] = "";
|
const char kEmptyKeyUri[] = "";
|
||||||
const char kFairplayKeyUri[] = "skd://www.license.com/getkey?key_id=testing";
|
const char kFairplayKeyUri[] = "skd://www.license.com/getkey?key_id=testing";
|
||||||
const char kIdentityKeyUri[] = "https://www.license.com/getkey?key_id=testing";
|
const char kIdentityKeyUri[] = "https://www.license.com/getkey?key_id=testing";
|
||||||
|
@ -39,7 +40,8 @@ const HlsPlaylistType kLivePlaylist = HlsPlaylistType::kLive;
|
||||||
|
|
||||||
class MockMasterPlaylist : public MasterPlaylist {
|
class MockMasterPlaylist : public MasterPlaylist {
|
||||||
public:
|
public:
|
||||||
MockMasterPlaylist() : MasterPlaylist(kMasterPlaylistName) {}
|
MockMasterPlaylist()
|
||||||
|
: MasterPlaylist(kMasterPlaylistName, kDefaultLanguage) {}
|
||||||
|
|
||||||
MOCK_METHOD1(AddMediaPlaylist, void(MediaPlaylist* media_playlist));
|
MOCK_METHOD1(AddMediaPlaylist, void(MediaPlaylist* media_playlist));
|
||||||
MOCK_METHOD2(WriteMasterPlaylist,
|
MOCK_METHOD2(WriteMasterPlaylist,
|
||||||
|
@ -68,7 +70,7 @@ class MockMediaPlaylistFactory : public MediaPlaylistFactory {
|
||||||
const double kTestTimeShiftBufferDepth = 1800.0;
|
const double kTestTimeShiftBufferDepth = 1800.0;
|
||||||
const char kTestPrefix[] = "http://testprefix.com/";
|
const char kTestPrefix[] = "http://testprefix.com/";
|
||||||
const char kEmptyPrefix[] = "";
|
const char kEmptyPrefix[] = "";
|
||||||
const char kAnyOutputDir[] = "anything/";
|
const char kAnyOutputDir[] = "anything";
|
||||||
|
|
||||||
const uint64_t kAnyStartTime = 10;
|
const uint64_t kAnyStartTime = 10;
|
||||||
const uint64_t kAnyDuration = 1000;
|
const uint64_t kAnyDuration = 1000;
|
||||||
|
@ -92,7 +94,14 @@ class SimpleHlsNotifierTest : public ::testing::Test {
|
||||||
media::kCommonSystemId + arraysize(media::kCommonSystemId)),
|
media::kCommonSystemId + arraysize(media::kCommonSystemId)),
|
||||||
fairplay_system_id_(
|
fairplay_system_id_(
|
||||||
media::kFairplaySystemId,
|
media::kFairplaySystemId,
|
||||||
media::kFairplaySystemId + arraysize(media::kFairplaySystemId)) {}
|
media::kFairplaySystemId + arraysize(media::kFairplaySystemId)) {
|
||||||
|
hls_params_.playlist_type = kVodPlaylist;
|
||||||
|
hls_params_.time_shift_buffer_depth = kTestTimeShiftBufferDepth;
|
||||||
|
hls_params_.base_url = kTestPrefix;
|
||||||
|
hls_params_.key_uri = kEmptyKeyUri;
|
||||||
|
hls_params_.master_playlist_output =
|
||||||
|
std::string(kAnyOutputDir) + "/" + kMasterPlaylistName;
|
||||||
|
}
|
||||||
|
|
||||||
void InjectMediaPlaylistFactory(std::unique_ptr<MediaPlaylistFactory> factory,
|
void InjectMediaPlaylistFactory(std::unique_ptr<MediaPlaylistFactory> factory,
|
||||||
SimpleHlsNotifier* notifier) {
|
SimpleHlsNotifier* notifier) {
|
||||||
|
@ -138,12 +147,11 @@ class SimpleHlsNotifierTest : public ::testing::Test {
|
||||||
const std::vector<uint8_t> widevine_system_id_;
|
const std::vector<uint8_t> widevine_system_id_;
|
||||||
const std::vector<uint8_t> common_system_id_;
|
const std::vector<uint8_t> common_system_id_;
|
||||||
const std::vector<uint8_t> fairplay_system_id_;
|
const std::vector<uint8_t> fairplay_system_id_;
|
||||||
|
HlsParams hls_params_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(SimpleHlsNotifierTest, Init) {
|
TEST_F(SimpleHlsNotifierTest, Init) {
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
EXPECT_TRUE(notifier.Init());
|
EXPECT_TRUE(notifier.Init());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +182,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) {
|
||||||
StrEq("groupid")))
|
StrEq("groupid")))
|
||||||
.WillOnce(Return(mock_media_playlist));
|
.WillOnce(Return(mock_media_playlist));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
|
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
@ -215,9 +221,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) {
|
||||||
StrEq("groupid")))
|
StrEq("groupid")))
|
||||||
.WillOnce(Return(mock_media_playlist));
|
.WillOnce(Return(mock_media_playlist));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
|
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
@ -255,9 +259,8 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
|
||||||
StrEq("groupid")))
|
StrEq("groupid")))
|
||||||
.WillOnce(Return(mock_media_playlist));
|
.WillOnce(Return(mock_media_playlist));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
hls_params_.base_url = kEmptyPrefix;
|
||||||
kEmptyPrefix, kEmptyKeyUri, kAnyOutputDir,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kMasterPlaylistName);
|
|
||||||
|
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
@ -277,9 +280,9 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
|
||||||
// prefix is stripped from segment path.
|
// prefix is stripped from segment path.
|
||||||
TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) {
|
TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) {
|
||||||
const char kAbsoluteOutputDir[] = "/tmp/something/";
|
const char kAbsoluteOutputDir[] = "/tmp/something/";
|
||||||
SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
hls_params_.master_playlist_output =
|
||||||
kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir,
|
std::string(kAbsoluteOutputDir) + kMasterPlaylistName;
|
||||||
kMasterPlaylistName);
|
SimpleHlsNotifier test_notifier(hls_params_);
|
||||||
|
|
||||||
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
||||||
new MockMasterPlaylist());
|
new MockMasterPlaylist());
|
||||||
|
@ -319,9 +322,9 @@ TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) {
|
||||||
TEST_F(SimpleHlsNotifierTest,
|
TEST_F(SimpleHlsNotifierTest,
|
||||||
RebaseAbsoluteSegmentCompletelyDifferentDirectory) {
|
RebaseAbsoluteSegmentCompletelyDifferentDirectory) {
|
||||||
const char kAbsoluteOutputDir[] = "/tmp/something/";
|
const char kAbsoluteOutputDir[] = "/tmp/something/";
|
||||||
SimpleHlsNotifier test_notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
hls_params_.master_playlist_output =
|
||||||
kTestPrefix, kEmptyKeyUri, kAbsoluteOutputDir,
|
std::string(kAbsoluteOutputDir) + kMasterPlaylistName;
|
||||||
kMasterPlaylistName);
|
SimpleHlsNotifier test_notifier(hls_params_);
|
||||||
|
|
||||||
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
||||||
new MockMasterPlaylist());
|
new MockMasterPlaylist());
|
||||||
|
@ -356,9 +359,7 @@ TEST_F(SimpleHlsNotifierTest,
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimpleHlsNotifierTest, Flush) {
|
TEST_F(SimpleHlsNotifierTest, Flush) {
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
|
||||||
new MockMasterPlaylist());
|
new MockMasterPlaylist());
|
||||||
EXPECT_CALL(*mock_master_playlist,
|
EXPECT_CALL(*mock_master_playlist,
|
||||||
|
@ -386,9 +387,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) {
|
||||||
StrEq("groupid")))
|
StrEq("groupid")))
|
||||||
.WillOnce(Return(mock_media_playlist));
|
.WillOnce(Return(mock_media_playlist));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
|
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
@ -430,9 +429,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) {
|
||||||
EXPECT_CALL(*mock_media_playlist, GetLongestSegmentDuration())
|
EXPECT_CALL(*mock_media_playlist, GetLongestSegmentDuration())
|
||||||
.WillOnce(Return(kLongestSegmentDuration));
|
.WillOnce(Return(kLongestSegmentDuration));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
|
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
@ -463,9 +460,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimpleHlsNotifierTest, NotifyNewSegmentWithoutStreamsRegistered) {
|
TEST_F(SimpleHlsNotifierTest, NotifyNewSegmentWithoutStreamsRegistered) {
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
EXPECT_TRUE(notifier.Init());
|
EXPECT_TRUE(notifier.Init());
|
||||||
EXPECT_FALSE(notifier.NotifyNewSegment(1u, "anything", 0u, 0u, 0u, 0u));
|
EXPECT_FALSE(notifier.NotifyNewSegment(1u, "anything", 0u, 0u, 0u, 0u));
|
||||||
}
|
}
|
||||||
|
@ -474,9 +469,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -537,9 +530,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -596,9 +587,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentityKey) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -626,9 +615,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
uint32_t stream_id =
|
uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -704,9 +691,8 @@ TEST_F(SimpleHlsNotifierTest, EncryptionScheme) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
hls_params_.key_uri = kIdentityKeyUri;
|
||||||
kTestPrefix, kIdentityKeyUri, kAnyOutputDir,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -729,9 +715,9 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateFairplay) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kLivePlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kLivePlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kLivePlaylist, kTestTimeShiftBufferDepth,
|
hls_params_.playlist_type = kLivePlaylist;
|
||||||
kTestPrefix, kFairplayKeyUri, kAnyOutputDir,
|
hls_params_.key_uri = kFairplayKeyUri;
|
||||||
kMasterPlaylistName);
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
const std::vector<uint8_t> key_id(16, 0x12);
|
const std::vector<uint8_t> key_id(16, 0x12);
|
||||||
|
@ -752,9 +738,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineCencEncryptionScheme) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -801,9 +785,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kSampleAesProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -869,9 +851,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWithoutStreamsRegistered) {
|
||||||
std::vector<uint8_t> iv;
|
std::vector<uint8_t> iv;
|
||||||
std::vector<uint8_t> pssh_data;
|
std::vector<uint8_t> pssh_data;
|
||||||
std::vector<uint8_t> key_id;
|
std::vector<uint8_t> key_id;
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kEmptyKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
EXPECT_TRUE(notifier.Init());
|
EXPECT_TRUE(notifier.Init());
|
||||||
EXPECT_FALSE(
|
EXPECT_FALSE(
|
||||||
notifier.NotifyEncryptionUpdate(1238u, key_id, system_id, iv, pssh_data));
|
notifier.NotifyEncryptionUpdate(1238u, key_id, system_id, iv, pssh_data));
|
||||||
|
@ -881,9 +861,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyCueEvent) {
|
||||||
// Pointer released by SimpleHlsNotifier.
|
// Pointer released by SimpleHlsNotifier.
|
||||||
MockMediaPlaylist* mock_media_playlist =
|
MockMediaPlaylist* mock_media_playlist =
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
kTestPrefix, kIdentityKeyUri, kAnyOutputDir,
|
|
||||||
kMasterPlaylistName);
|
|
||||||
const uint32_t stream_id =
|
const uint32_t stream_id =
|
||||||
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
SetupStream(kCencProtectionScheme, mock_media_playlist, ¬ifier);
|
||||||
|
|
||||||
|
@ -945,8 +923,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) {
|
||||||
.AsUTF8Unsafe())))
|
.AsUTF8Unsafe())))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix,
|
hls_params_.playlist_type = GetParam();
|
||||||
kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName);
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
EXPECT_TRUE(notifier.Init());
|
EXPECT_TRUE(notifier.Init());
|
||||||
|
@ -990,8 +968,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
|
||||||
*mock_master_playlist,
|
*mock_master_playlist,
|
||||||
AddMediaPlaylist(static_cast<MediaPlaylist*>(mock_media_playlist2)));
|
AddMediaPlaylist(static_cast<MediaPlaylist*>(mock_media_playlist2)));
|
||||||
|
|
||||||
SimpleHlsNotifier notifier(GetParam(), kTestTimeShiftBufferDepth, kTestPrefix,
|
hls_params_.playlist_type = GetParam();
|
||||||
kEmptyKeyUri, kAnyOutputDir, kMasterPlaylistName);
|
SimpleHlsNotifier notifier(hls_params_);
|
||||||
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
|
MockMasterPlaylist* mock_master_playlist_ptr = mock_master_playlist.get();
|
||||||
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier);
|
||||||
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
InjectMediaPlaylistFactory(std::move(factory), ¬ifier);
|
||||||
|
|
|
@ -35,6 +35,10 @@ struct HlsParams {
|
||||||
/// key formats. Ignored if the playlist is not encrypted or not using the
|
/// key formats. Ignored if the playlist is not encrypted or not using the
|
||||||
/// above key formats.
|
/// above key formats.
|
||||||
std::string key_uri;
|
std::string key_uri;
|
||||||
|
/// 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.
|
||||||
|
std::string default_language;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -815,15 +815,7 @@ Status Packager::Initialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hls_params.master_playlist_output.empty()) {
|
if (!hls_params.master_playlist_output.empty()) {
|
||||||
base::FilePath master_playlist_path(
|
internal->hls_notifier.reset(new hls::SimpleHlsNotifier(hls_params));
|
||||||
base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output));
|
|
||||||
base::FilePath master_playlist_name = master_playlist_path.BaseName();
|
|
||||||
|
|
||||||
internal->hls_notifier.reset(new hls::SimpleHlsNotifier(
|
|
||||||
hls_params.playlist_type, hls_params.time_shift_buffer_depth,
|
|
||||||
hls_params.base_url, hls_params.key_uri,
|
|
||||||
master_playlist_path.DirName().AsEndingWithSeparator().AsUTF8Unsafe(),
|
|
||||||
master_playlist_name.AsUTF8Unsafe()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<StreamDescriptor> streams_for_jobs;
|
std::vector<StreamDescriptor> streams_for_jobs;
|
||||||
|
|
Loading…
Reference in New Issue