From 67e0f9f31b3a87532ed4a7ac9672358a9668fc0a Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Wed, 20 Apr 2016 15:23:19 -0700 Subject: [PATCH] Pass playlist type to MediaPlaylist - The current implementation only handles VOD. - Add #EXT-X-PLATLIST-TYPE. - For VOD Add #EXT-X-ENDLIST at the end. - Append comma at the end of EXTINF. Change-Id: I16f01da66f8bbf0229395cb380fa125ffd9328a8 --- packager/hls/base/master_playlist.cc | 10 +-- packager/hls/base/master_playlist_unittest.cc | 68 +++++++++++-------- packager/hls/base/media_playlist.cc | 32 ++++++--- packager/hls/base/media_playlist.h | 22 ++++-- packager/hls/base/media_playlist_unittest.cc | 43 ++++++++---- packager/hls/base/mock_media_playlist.cc | 5 +- packager/hls/base/mock_media_playlist.h | 3 +- packager/hls/base/simple_hls_notifier.cc | 22 ++++-- packager/hls/base/simple_hls_notifier.h | 13 ++-- .../hls/base/simple_hls_notifier_unittest.cc | 45 +++++++----- 10 files changed, 175 insertions(+), 88 deletions(-) diff --git a/packager/hls/base/master_playlist.cc b/packager/hls/base/master_playlist.cc index a6e5322c09..ac2cecc577 100644 --- a/packager/hls/base/master_playlist.cc +++ b/packager/hls/base/master_playlist.cc @@ -87,14 +87,16 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url, std::map> audio_group_map; std::list video_playlists; for (const MediaPlaylist* media_playlist : media_playlists_) { - MediaPlaylist::MediaPlaylistType type = media_playlist->type(); - if (type == MediaPlaylist::MediaPlaylistType::kPlayListAudio) { + MediaPlaylist::MediaPlaylistStreamType stream_type = + media_playlist->stream_type(); + if (stream_type == MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio) { auto& audio_playlists = audio_group_map[media_playlist->group_id()]; audio_playlists.push_back(media_playlist); - } else if (type == MediaPlaylist::MediaPlaylistType::kPlayListVideo) { + } else if (stream_type == + MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo) { video_playlists.push_back(media_playlist); } else { - NOTIMPLEMENTED() << static_cast(type) << " not handled."; + NOTIMPLEMENTED() << static_cast(stream_type) << " not handled."; } } diff --git a/packager/hls/base/master_playlist_unittest.cc b/packager/hls/base/master_playlist_unittest.cc index 70c9a6bb35..56c994d481 100644 --- a/packager/hls/base/master_playlist_unittest.cc +++ b/packager/hls/base/master_playlist_unittest.cc @@ -24,6 +24,8 @@ using ::testing::_; namespace { const char kDefaultMasterPlaylistName[] = "playlist.m3u8"; +const MediaPlaylist::MediaPlaylistType kVodPlaylist = + MediaPlaylist::MediaPlaylistType::kVod; } // namespace class MasterPlaylistTest : public ::testing::Test { @@ -56,15 +58,17 @@ class MasterPlaylistTest : public ::testing::Test { }; TEST_F(MasterPlaylistTest, AddMediaPlaylist) { - MockMediaPlaylist mock_playlist("playlist1.m3u8", "somename", "somegroupid"); + MockMediaPlaylist mock_playlist(kVodPlaylist, "playlist1.m3u8", "somename", + "somegroupid"); master_playlist_.AddMediaPlaylist(&mock_playlist); } TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) { std::string codec = "avc1"; - MockMediaPlaylist mock_playlist("media1.m3u8", "somename", "somegroupid"); - mock_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListVideo); + MockMediaPlaylist mock_playlist(kVodPlaylist, "media1.m3u8", "somename", + "somegroupid"); + mock_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo); mock_playlist.SetCodecForTesting(codec); EXPECT_CALL(mock_playlist, Bitrate()).WillOnce(Return(435889)); master_playlist_.AddMediaPlaylist(&mock_playlist); @@ -91,9 +95,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) { TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { // First video, sd.m3u8. std::string sd_video_codec = "sdvideocodec"; - MockMediaPlaylist sd_video_playlist("sd.m3u8", "somename", "somegroupid"); - sd_video_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListVideo); + MockMediaPlaylist sd_video_playlist(kVodPlaylist, "sd.m3u8", "somename", + "somegroupid"); + sd_video_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo); sd_video_playlist.SetCodecForTesting(sd_video_codec); EXPECT_CALL(sd_video_playlist, Bitrate()) .Times(AtLeast(1)) @@ -102,9 +107,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { // Second video, hd.m3u8. std::string hd_video_codec = "hdvideocodec"; - MockMediaPlaylist hd_video_playlist("hd.m3u8", "somename", "somegroupid"); - hd_video_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListVideo); + MockMediaPlaylist hd_video_playlist(kVodPlaylist, "hd.m3u8", "somename", + "somegroupid"); + hd_video_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo); hd_video_playlist.SetCodecForTesting(hd_video_codec); EXPECT_CALL(hd_video_playlist, Bitrate()) .Times(AtLeast(1)) @@ -115,9 +121,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { // Note that audiocodecs should match for different audio tracks with same // group ID. std::string audio_codec = "audiocodec"; - MockMediaPlaylist english_playlist("eng.m3u8", "english", "audiogroup"); - english_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListAudio); + MockMediaPlaylist english_playlist(kVodPlaylist, "eng.m3u8", "english", + "audiogroup"); + english_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio); english_playlist.SetCodecForTesting(audio_codec); EXPECT_CALL(english_playlist, Bitrate()) .Times(AtLeast(1)) @@ -125,9 +132,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { master_playlist_.AddMediaPlaylist(&english_playlist); // Second audio, spanish.m3u8. - MockMediaPlaylist spanish_playlist("spa.m3u8", "espanol", "audiogroup"); - spanish_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListAudio); + MockMediaPlaylist spanish_playlist(kVodPlaylist, "spa.m3u8", "espanol", + "audiogroup"); + spanish_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio); spanish_playlist.SetCodecForTesting(audio_codec); EXPECT_CALL(spanish_playlist, Bitrate()) .Times(AtLeast(1)) @@ -166,9 +174,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) { // First video, sd.m3u8. std::string video_codec = "videocodec"; - MockMediaPlaylist video_playlist("video.m3u8", "somename", "somegroupid"); - video_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListVideo); + 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)) @@ -177,9 +186,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) { // First audio, eng_lo.m3u8. std::string audio_codec_lo = "audiocodec_lo"; - MockMediaPlaylist eng_lo_playlist("eng_lo.m3u8", "english_lo", "audio_lo"); - eng_lo_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListAudio); + MockMediaPlaylist eng_lo_playlist(kVodPlaylist, "eng_lo.m3u8", "english_lo", + "audio_lo"); + eng_lo_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio); eng_lo_playlist.SetCodecForTesting(audio_codec_lo); EXPECT_CALL(eng_lo_playlist, Bitrate()) .Times(AtLeast(1)) @@ -187,9 +197,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) { master_playlist_.AddMediaPlaylist(&eng_lo_playlist); std::string audio_codec_hi = "audiocodec_hi"; - MockMediaPlaylist eng_hi_playlist("eng_hi.m3u8", "english_hi", "audio_hi"); - eng_hi_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListAudio); + MockMediaPlaylist eng_hi_playlist(kVodPlaylist, "eng_hi.m3u8", "english_hi", + "audio_hi"); + eng_hi_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListAudio); eng_hi_playlist.SetCodecForTesting(audio_codec_hi); EXPECT_CALL(eng_hi_playlist, Bitrate()) .Times(AtLeast(1)) @@ -236,9 +247,10 @@ MATCHER_P(FileNameMatches, expected_file_name, "") { // MediaPlaylist::WriteToFile() is called. TEST_F(MasterPlaylistTest, WriteAllPlaylists) { std::string codec = "avc1"; - MockMediaPlaylist mock_playlist("media1.m3u8", "somename", "somegroupid"); - mock_playlist.SetTypeForTesting( - MediaPlaylist::MediaPlaylistType::kPlayListVideo); + MockMediaPlaylist mock_playlist(kVodPlaylist, "media1.m3u8", "somename", + "somegroupid"); + mock_playlist.SetStreamTypeForTesting( + MediaPlaylist::MediaPlaylistStreamType::kPlayListVideo); mock_playlist.SetCodecForTesting(codec); ON_CALL(mock_playlist, Bitrate()).WillByDefault(Return(435889)); diff --git a/packager/hls/base/media_playlist.cc b/packager/hls/base/media_playlist.cc index 13d150e04d..bb73f6687a 100644 --- a/packager/hls/base/media_playlist.cc +++ b/packager/hls/base/media_playlist.cc @@ -51,7 +51,7 @@ SegmentInfoEntry::SegmentInfoEntry(const std::string& file_name, SegmentInfoEntry::~SegmentInfoEntry() {} std::string SegmentInfoEntry::ToString() { - return base::StringPrintf("#EXTINF:%.3f\n%s\n", duration_, + return base::StringPrintf("#EXTINF:%.3f,\n%s\n", duration_, file_name_.c_str()); } @@ -120,15 +120,23 @@ std::string EncryptionInfoEntry::ToString() { HlsEntry::HlsEntry(HlsEntry::EntryType type) : type_(type) {} HlsEntry::~HlsEntry() {} -MediaPlaylist::MediaPlaylist(const std::string& file_name, +MediaPlaylist::MediaPlaylist(MediaPlaylistType type, + const std::string& file_name, const std::string& name, const std::string& group_id) - : file_name_(file_name), name_(name), group_id_(group_id), - entries_deleter_(&entries_) {} + : file_name_(file_name), + name_(name), + group_id_(group_id), + type_(type), + entries_deleter_(&entries_) { + LOG_IF(WARNING, type != MediaPlaylistType::kVod) + << "Non VOD Media Playlist is not supported."; +} MediaPlaylist::~MediaPlaylist() {} -void MediaPlaylist::SetTypeForTesting(MediaPlaylistType type) { - type_ = type; +void MediaPlaylist::SetStreamTypeForTesting( + MediaPlaylistStreamType stream_type) { + stream_type_ = stream_type; } void MediaPlaylist::SetCodecForTesting(const std::string& codec) { @@ -143,10 +151,10 @@ bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) { } if (media_info.has_video_info()) { - type_ = MediaPlaylistType::kPlayListVideo; + stream_type_ = MediaPlaylistStreamType::kPlayListVideo; codec_ = media_info.video_info().codec(); } else if (media_info.has_audio_info()) { - type_ = MediaPlaylistType::kPlayListAudio; + stream_type_ = MediaPlaylistStreamType::kPlayListAudio; codec_ = media_info.audio_info().codec(); } else { NOTIMPLEMENTED(); @@ -270,12 +278,20 @@ bool MediaPlaylist::WriteToFile(media::File* file) { "#EXT-X-VERSION:4\n" "#EXT-X-TARGETDURATION:%d\n", target_duration_); + if (type_ == MediaPlaylistType::kVod) { + header += "#EXT-X-PLAYLIST-TYPE:VOD\n"; + } std::string body; for (const auto& entry : entries_) { body.append(entry->ToString()); } std::string content = header + body; + + if (type_ == MediaPlaylistType::kVod) { + content += "#EXT-X-ENDLIST\n"; + } + int64_t bytes_written = file->Write(content.data(), content.size()); if (bytes_written < 0) { LOG(ERROR) << "Error while writing playlist to file."; diff --git a/packager/hls/base/media_playlist.h b/packager/hls/base/media_playlist.h index 979807cb65..a54185d712 100644 --- a/packager/hls/base/media_playlist.h +++ b/packager/hls/base/media_playlist.h @@ -45,6 +45,11 @@ class HlsEntry { class MediaPlaylist { public: enum class MediaPlaylistType { + kVod, + kEvent, + kLive, + }; + enum class MediaPlaylistStreamType { kPlaylistUnknown, kPlayListAudio, kPlayListVideo, @@ -56,26 +61,27 @@ class MediaPlaylist { kSampleAes, // Encrypted using Sample AES method. }; + /// @param type is the type of this media playlist. /// @param file_name is the file name of this media playlist. /// @param name is the name of this playlist. In other words this is the /// value of the NAME attribute for EXT-X-MEDIA. This is not /// necessarily the same as @a file_name. /// @param group_id is the group ID for this playlist. This is the value of /// GROUP-ID attribute for EXT-X-MEDIA. - MediaPlaylist( - const std::string& file_name, - const std::string& name, - const std::string& group_id); + MediaPlaylist(MediaPlaylistType type, + const std::string& file_name, + const std::string& name, + const std::string& group_id); virtual ~MediaPlaylist(); const std::string& file_name() const { return file_name_; } const std::string& name() const { return name_; } const std::string& group_id() const { return group_id_; } - MediaPlaylistType type() const { return type_; } + MediaPlaylistStreamType stream_type() const { return stream_type_; } const std::string& codec() const { return codec_; } /// For testing only. - void SetTypeForTesting(MediaPlaylistType type); + void SetStreamTypeForTesting(MediaPlaylistStreamType stream_type); /// For testing only. void SetCodecForTesting(const std::string& codec); @@ -151,7 +157,9 @@ class MediaPlaylist { const std::string name_; const std::string group_id_; MediaInfo media_info_; - MediaPlaylistType type_ = MediaPlaylistType::kPlaylistUnknown; + const MediaPlaylistType type_; + MediaPlaylistStreamType stream_type_ = + MediaPlaylistStreamType::kPlaylistUnknown; std::string codec_; double longest_segment_duration_ = 0.0; diff --git a/packager/hls/base/media_playlist_unittest.cc b/packager/hls/base/media_playlist_unittest.cc index d67790d45f..8f86f7ea01 100644 --- a/packager/hls/base/media_playlist_unittest.cc +++ b/packager/hls/base/media_playlist_unittest.cc @@ -50,7 +50,10 @@ class MediaPlaylistTest : public ::testing::Test { : default_file_name_(kDefaultPlaylistFileName), default_name_("default_name"), default_group_id_("default_group_id"), - media_playlist_(default_file_name_, default_name_, default_group_id_) {} + media_playlist_(MediaPlaylist::MediaPlaylistType::kVod, + default_file_name_, + default_name_, + default_group_id_) {} void SetUp() override { MediaInfo::VideoInfo* video_info = @@ -114,7 +117,9 @@ TEST_F(MediaPlaylistTest, WriteToFile) { const std::string kExpectedOutput = "#EXTM3U\n" "#EXT-X-VERSION:4\n" - "#EXT-X-TARGETDURATION:0\n"; + "#EXT-X-TARGETDURATION:0\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, @@ -167,7 +172,9 @@ TEST_F(MediaPlaylistTest, SetTargetDuration) { const std::string kExpectedOutput = "#EXTM3U\n" "#EXT-X-VERSION:4\n" - "#EXT-X-TARGETDURATION:20\n"; + "#EXT-X-TARGETDURATION:20\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, @@ -192,10 +199,12 @@ TEST_F(MediaPlaylistTest, WriteToFileWithSegments) { "#EXTM3U\n" "#EXT-X-VERSION:4\n" "#EXT-X-TARGETDURATION:30\n" - "#EXTINF:10.000\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXTINF:10.000,\n" "file1.ts\n" - "#EXTINF:30.000\n" - "file2.ts\n"; + "#EXTINF:30.000,\n" + "file2.ts\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, @@ -219,13 +228,15 @@ TEST_F(MediaPlaylistTest, WriteToFileWithEncryptionInfo) { "#EXTM3U\n" "#EXT-X-VERSION:4\n" "#EXT-X-TARGETDURATION:30\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" "#EXT-X-KEY:METHOD=SAMPLE-AES," "URI=\"http://example.com\",IV=0x12345678,KEYFORMATVERSIONS=\"1/2/4\"," "KEYFORMAT=\"com.widevine\"\n" - "#EXTINF:10.000\n" + "#EXTINF:10.000,\n" "file1.ts\n" - "#EXTINF:30.000\n" - "file2.ts\n"; + "#EXTINF:30.000,\n" + "file2.ts\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, @@ -249,12 +260,14 @@ TEST_F(MediaPlaylistTest, WriteToFileWithEncryptionInfoEmptyIv) { "#EXTM3U\n" "#EXT-X-VERSION:4\n" "#EXT-X-TARGETDURATION:30\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" "#EXT-X-KEY:METHOD=SAMPLE-AES," "URI=\"http://example.com\",KEYFORMAT=\"com.widevine\"\n" - "#EXTINF:10.000\n" + "#EXTINF:10.000,\n" "file1.ts\n" - "#EXTINF:30.000\n" - "file2.ts\n"; + "#EXTINF:30.000,\n" + "file2.ts\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, @@ -277,8 +290,10 @@ TEST_F(MediaPlaylistTest, RemoveOldestSegment) { "#EXTM3U\n" "#EXT-X-VERSION:4\n" "#EXT-X-TARGETDURATION:30\n" - "#EXTINF:30.000\n" - "file2.ts\n"; + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXTINF:30.000,\n" + "file2.ts\n" + "#EXT-X-ENDLIST\n"; MockFile file; EXPECT_CALL(file, diff --git a/packager/hls/base/mock_media_playlist.cc b/packager/hls/base/mock_media_playlist.cc index d0a7faec9d..f9e2b7ef59 100644 --- a/packager/hls/base/mock_media_playlist.cc +++ b/packager/hls/base/mock_media_playlist.cc @@ -9,10 +9,11 @@ namespace edash_packager { namespace hls { -MockMediaPlaylist::MockMediaPlaylist(const std::string& file_name, +MockMediaPlaylist::MockMediaPlaylist(MediaPlaylistType type, + const std::string& file_name, const std::string& name, const std::string& group_id) - : MediaPlaylist(file_name, name, group_id) {} + : MediaPlaylist(type, file_name, name, group_id) {} MockMediaPlaylist::~MockMediaPlaylist() {} } // namespace hls diff --git a/packager/hls/base/mock_media_playlist.h b/packager/hls/base/mock_media_playlist.h index 93b6b27018..61abe2b75c 100644 --- a/packager/hls/base/mock_media_playlist.h +++ b/packager/hls/base/mock_media_playlist.h @@ -18,7 +18,8 @@ class MockMediaPlaylist : public MediaPlaylist { public: // The actual parameters to MediaPlaylist() (parent) constructor doesn't // matter because the return value can be mocked. - MockMediaPlaylist(const std::string& file_name, + MockMediaPlaylist(MediaPlaylistType type, + const std::string& file_name, const std::string& name, const std::string& group_id); ~MockMediaPlaylist() override; diff --git a/packager/hls/base/simple_hls_notifier.cc b/packager/hls/base/simple_hls_notifier.cc index b2d11ca06c..326273de46 100644 --- a/packager/hls/base/simple_hls_notifier.cc +++ b/packager/hls/base/simple_hls_notifier.cc @@ -29,17 +29,19 @@ bool IsWidevineSystemId(const std::vector& system_id) { MediaPlaylistFactory::~MediaPlaylistFactory() {} scoped_ptr MediaPlaylistFactory::Create( + MediaPlaylist::MediaPlaylistType type, const std::string& file_name, const std::string& name, const std::string& group_id) { return scoped_ptr( - new MediaPlaylist(file_name, name, group_id)); + new MediaPlaylist(type, file_name, name, group_id)); } -SimpleHlsNotifier::SimpleHlsNotifier(const std::string& prefix, +SimpleHlsNotifier::SimpleHlsNotifier(HlsProfile profile, + const std::string& prefix, const std::string& output_dir, const std::string& master_playlist_name) - : HlsNotifier(HlsNotifier::HlsProfile::kOnDemandProfile), + : HlsNotifier(profile), prefix_(prefix), output_dir_(output_dir), media_playlist_factory_(new MediaPlaylistFactory()), @@ -60,8 +62,20 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info, DCHECK(stream_id); *stream_id = sequence_number_.GetNext(); + MediaPlaylist::MediaPlaylistType type; + switch (profile()) { + case HlsProfile::kLiveProfile: + type = MediaPlaylist::MediaPlaylistType::kLive; + break; + case HlsProfile::kOnDemandProfile: + type = MediaPlaylist::MediaPlaylistType::kVod; + break; + default: + NOTREACHED(); + return false; + } scoped_ptr media_playlist = - media_playlist_factory_->Create(playlist_name, name, group_id); + media_playlist_factory_->Create(type, playlist_name, name, group_id); if (!media_playlist->SetMediaInfo(media_info)) { LOG(ERROR) << "Failed to set media info for playlist " << playlist_name; return false; diff --git a/packager/hls/base/simple_hls_notifier.h b/packager/hls/base/simple_hls_notifier.h index ed8a1a0d07..4e1be4723a 100644 --- a/packager/hls/base/simple_hls_notifier.h +++ b/packager/hls/base/simple_hls_notifier.h @@ -14,6 +14,7 @@ #include "packager/base/synchronization/lock.h" #include "packager/hls/base/hls_notifier.h" #include "packager/hls/base/master_playlist.h" +#include "packager/hls/base/media_playlist.h" namespace edash_packager { namespace hls { @@ -23,9 +24,11 @@ namespace hls { class MediaPlaylistFactory { public: virtual ~MediaPlaylistFactory(); - virtual scoped_ptr Create(const std::string& file_name, - const std::string& name, - const std::string& group_id); + virtual scoped_ptr Create( + MediaPlaylist::MediaPlaylistType type, + const std::string& file_name, + const std::string& name, + const std::string& group_id); }; /// This is thread safe. @@ -33,12 +36,14 @@ class SimpleHlsNotifier : public HlsNotifier { public: /// @a prefix is used as hte prefix for all the URIs for Media Playlist. This /// includes the segment URIs in the Media Playlists. + /// @param profile is the profile of the playlists. /// @param prefix is the used as the prefix for MediaPlaylist URIs. May be /// empty for relative URI from the playlist. /// @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(const std::string& prefix, + SimpleHlsNotifier(HlsProfile profile, + const std::string& prefix, const std::string& output_dir, const std::string& master_playlist_name); ~SimpleHlsNotifier() override; diff --git a/packager/hls/base/simple_hls_notifier_unittest.cc b/packager/hls/base/simple_hls_notifier_unittest.cc index b6e600bb8d..ad60ac08bc 100644 --- a/packager/hls/base/simple_hls_notifier_unittest.cc +++ b/packager/hls/base/simple_hls_notifier_unittest.cc @@ -21,6 +21,8 @@ using ::testing::_; namespace { const char kMasterPlaylistName[] = "master.m3u8"; +const MediaPlaylist::MediaPlaylistType kVodPlaylist = + MediaPlaylist::MediaPlaylistType::kVod; class MockMasterPlaylist : public MasterPlaylist { public: @@ -35,15 +37,18 @@ class MockMasterPlaylist : public MasterPlaylist { class MockMediaPlaylistFactory : public MediaPlaylistFactory { public: - MOCK_METHOD3(CreateMock, - MediaPlaylist*(const std::string& file_name, + MOCK_METHOD4(CreateMock, + MediaPlaylist*(MediaPlaylist::MediaPlaylistType type, + const std::string& file_name, const std::string& name, const std::string& group_id)); - scoped_ptr Create(const std::string& file_name, + scoped_ptr Create(MediaPlaylist::MediaPlaylistType type, + const std::string& file_name, const std::string& name, const std::string& group_id) override { - return scoped_ptr(CreateMock(file_name, name, group_id)); + return scoped_ptr( + CreateMock(type, file_name, name, group_id)); } }; @@ -55,7 +60,10 @@ const char kAnyOutputDir[] = "anything/"; class SimpleHlsNotifierTest : public ::testing::Test { protected: SimpleHlsNotifierTest() - : notifier_(kTestPrefix, kAnyOutputDir, kMasterPlaylistName) {} + : notifier_(HlsNotifier::HlsProfile::kOnDemandProfile, + kTestPrefix, + kAnyOutputDir, + kMasterPlaylistName) {} void InjectMediaPlaylistFactory(scoped_ptr factory) { notifier_.media_playlist_factory_ = factory.Pass(); @@ -81,12 +89,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) { scoped_ptr factory(new MockMediaPlaylistFactory()); // Pointer released by SimpleHlsNotifier. - MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist("", "", ""); + MockMediaPlaylist* mock_media_playlist = + new MockMediaPlaylist(kVodPlaylist, "", "", ""); EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL(*factory, CreateMock(StrEq("video_playlist.m3u8"), StrEq("name"), - StrEq("groupid"))) + EXPECT_CALL(*factory, CreateMock(kVodPlaylist, StrEq("video_playlist.m3u8"), + StrEq("name"), StrEq("groupid"))) .WillOnce(Return(mock_media_playlist)); InjectMasterPlaylist(mock_master_playlist.Pass()); @@ -104,13 +113,14 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) { scoped_ptr factory(new MockMediaPlaylistFactory()); // Pointer released by SimpleHlsNotifier. - MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist("", "", ""); + MockMediaPlaylist* mock_media_playlist = + new MockMediaPlaylist(kVodPlaylist, "", "", ""); EXPECT_CALL( *mock_master_playlist, AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL(*factory, CreateMock(_, _, _)) + EXPECT_CALL(*factory, CreateMock(_, _, _, _)) .WillOnce(Return(mock_media_playlist)); const uint64_t kStartTime = 1328; @@ -142,13 +152,14 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdate) { scoped_ptr factory(new MockMediaPlaylistFactory()); // Pointer released by SimpleHlsNotifier. - MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist("", "", ""); + MockMediaPlaylist* mock_media_playlist = + new MockMediaPlaylist(kVodPlaylist, "", "", ""); EXPECT_CALL( *mock_master_playlist, AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL(*factory, CreateMock(_, _, _)) + EXPECT_CALL(*factory, CreateMock(_, _, _, _)) .WillOnce(Return(mock_media_playlist)); InjectMasterPlaylist(mock_master_playlist.Pass()); @@ -206,13 +217,14 @@ TEST_F(SimpleHlsNotifierTest, MultipleKeyIdsInPssh) { scoped_ptr factory(new MockMediaPlaylistFactory()); // Pointer released by SimpleHlsNotifier. - MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist("", "", ""); + MockMediaPlaylist* mock_media_playlist = + new MockMediaPlaylist(kVodPlaylist, "", "", ""); EXPECT_CALL( *mock_master_playlist, AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL(*factory, CreateMock(_, _, _)) + EXPECT_CALL(*factory, CreateMock(_, _, _, _)) .WillOnce(Return(mock_media_playlist)); InjectMasterPlaylist(mock_master_playlist.Pass()); @@ -276,13 +288,14 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateEmptyIv) { scoped_ptr factory(new MockMediaPlaylistFactory()); // Pointer released by SimpleHlsNotifier. - MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist("", "", ""); + MockMediaPlaylist* mock_media_playlist = + new MockMediaPlaylist(kVodPlaylist, "", "", ""); EXPECT_CALL( *mock_master_playlist, AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL(*factory, CreateMock(_, _, _)) + EXPECT_CALL(*factory, CreateMock(_, _, _, _)) .WillOnce(Return(mock_media_playlist)); InjectMasterPlaylist(mock_master_playlist.Pass());