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
This commit is contained in:
parent
25305b6aa3
commit
67e0f9f31b
|
@ -87,14 +87,16 @@ bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url,
|
|||
std::map<std::string, std::list<const MediaPlaylist*>> audio_group_map;
|
||||
std::list<const MediaPlaylist*> 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<int>(type) << " not handled.";
|
||||
NOTIMPLEMENTED() << static_cast<int>(stream_type) << " not handled.";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -45,6 +45,11 @@ class HlsEntry {
|
|||
class MediaPlaylist {
|
||||
public:
|
||||
enum class MediaPlaylistType {
|
||||
kVod,
|
||||
kEvent,
|
||||
kLive,
|
||||
};
|
||||
enum class MediaPlaylistStreamType {
|
||||
kPlaylistUnknown,
|
||||
kPlayListAudio,
|
||||
kPlayListVideo,
|
||||
|
@ -56,13 +61,14 @@ 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(
|
||||
MediaPlaylist(MediaPlaylistType type,
|
||||
const std::string& file_name,
|
||||
const std::string& name,
|
||||
const std::string& group_id);
|
||||
|
@ -71,11 +77,11 @@ class 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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -29,17 +29,19 @@ bool IsWidevineSystemId(const std::vector<uint8_t>& system_id) {
|
|||
MediaPlaylistFactory::~MediaPlaylistFactory() {}
|
||||
|
||||
scoped_ptr<MediaPlaylist> MediaPlaylistFactory::Create(
|
||||
MediaPlaylist::MediaPlaylistType type,
|
||||
const std::string& file_name,
|
||||
const std::string& name,
|
||||
const std::string& group_id) {
|
||||
return scoped_ptr<MediaPlaylist>(
|
||||
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<MediaPlaylist> 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;
|
||||
|
|
|
@ -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,7 +24,9 @@ namespace hls {
|
|||
class MediaPlaylistFactory {
|
||||
public:
|
||||
virtual ~MediaPlaylistFactory();
|
||||
virtual scoped_ptr<MediaPlaylist> Create(const std::string& file_name,
|
||||
virtual scoped_ptr<MediaPlaylist> Create(
|
||||
MediaPlaylist::MediaPlaylistType type,
|
||||
const std::string& file_name,
|
||||
const std::string& name,
|
||||
const std::string& group_id);
|
||||
};
|
||||
|
@ -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;
|
||||
|
|
|
@ -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<MediaPlaylist> Create(const std::string& file_name,
|
||||
scoped_ptr<MediaPlaylist> Create(MediaPlaylist::MediaPlaylistType type,
|
||||
const std::string& file_name,
|
||||
const std::string& name,
|
||||
const std::string& group_id) override {
|
||||
return scoped_ptr<MediaPlaylist>(CreateMock(file_name, name, group_id));
|
||||
return scoped_ptr<MediaPlaylist>(
|
||||
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<MediaPlaylistFactory> factory) {
|
||||
notifier_.media_playlist_factory_ = factory.Pass();
|
||||
|
@ -81,12 +89,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) {
|
|||
scoped_ptr<MockMediaPlaylistFactory> 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<MockMediaPlaylistFactory> 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<MediaPlaylist*>(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<MockMediaPlaylistFactory> 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<MediaPlaylist*>(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<MockMediaPlaylistFactory> 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<MediaPlaylist*>(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<MockMediaPlaylistFactory> 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<MediaPlaylist*>(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());
|
||||
|
|
Loading…
Reference in New Issue