[HLS] Fix init segment URL isn't respecting folder locations

Problem occurs when the media playlists are in a sub-directory under
master playlist. If base_url is not set, segment URL should be
relative to the media playlist.

This only affects fMP4 as TS does not have init segment.

Fixes #253

Change-Id: Icddd9ed500d0a705e8b3260bfd4e916ecbba3f28
This commit is contained in:
KongQun Yang 2017-10-06 17:01:56 -07:00
parent 94a64bef03
commit ae17159b73
2 changed files with 58 additions and 5 deletions

View File

@ -275,7 +275,15 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
std::unique_ptr<MediaPlaylist> media_playlist = std::unique_ptr<MediaPlaylist> media_playlist =
media_playlist_factory_->Create(playlist_type(), time_shift_buffer_depth_, media_playlist_factory_->Create(playlist_type(), time_shift_buffer_depth_,
playlist_name, name, group_id); playlist_name, name, group_id);
if (!media_playlist->SetMediaInfo(media_info)) {
// Update init_segment_name to be relative to playlist path if needed.
MediaInfo media_info_copy = media_info;
if (media_info_copy.has_init_segment_name()) {
media_info_copy.set_init_segment_name(
GenerateSegmentUrl(media_info_copy.init_segment_name(), prefix_,
output_dir_, media_playlist->file_name()));
}
if (!media_playlist->SetMediaInfo(media_info_copy)) {
LOG(ERROR) << "Failed to set media info for playlist " << playlist_name; LOG(ERROR) << "Failed to set media info for playlist " << playlist_name;
return false; return false;
} }

View File

@ -24,6 +24,7 @@ namespace hls {
using ::testing::Eq; using ::testing::Eq;
using ::testing::InSequence; using ::testing::InSequence;
using ::testing::Mock; using ::testing::Mock;
using ::testing::Property;
using ::testing::Return; using ::testing::Return;
using ::testing::StrEq; using ::testing::StrEq;
using ::testing::_; using ::testing::_;
@ -156,7 +157,9 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) {
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist));
EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_media_playlist,
SetMediaInfo(Property(&MediaInfo::init_segment_name, StrEq(""))))
.WillOnce(Return(true));
// Verify that the common prefix is stripped for AddSegment(). // Verify that the common prefix is stripped for AddSegment().
EXPECT_CALL( EXPECT_CALL(
@ -184,6 +187,43 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) {
kAnySize)); kAnySize));
} }
TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) {
std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
new MockMasterPlaylist());
std::unique_ptr<MockMediaPlaylistFactory> factory(
new MockMediaPlaylistFactory());
// Pointer released by SimpleHlsNotifier.
MockMediaPlaylist* mock_media_playlist =
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist));
// Verify that the common prefix is stripped in init segment.
EXPECT_CALL(
*mock_media_playlist,
SetMediaInfo(Property(&MediaInfo::init_segment_name,
StrEq("http://testprefix.com/path/to/init.mp4"))))
.WillOnce(Return(true));
EXPECT_CALL(*factory, CreateMock(kVodPlaylist, Eq(kTestTimeShiftBufferDepth),
StrEq("video_playlist.m3u8"), StrEq("name"),
StrEq("groupid")))
.WillOnce(Return(mock_media_playlist));
SimpleHlsNotifier notifier(kVodPlaylist, kTestTimeShiftBufferDepth,
kTestPrefix, kAnyOutputDir, kMasterPlaylistName);
InjectMasterPlaylist(std::move(mock_master_playlist), &notifier);
InjectMediaPlaylistFactory(std::move(factory), &notifier);
EXPECT_TRUE(notifier.Init());
MediaInfo media_info;
media_info.set_init_segment_name("anything/path/to/init.mp4");
uint32_t stream_id;
EXPECT_TRUE(notifier.NotifyNewStream(media_info, "video_playlist.m3u8",
"name", "groupid", &stream_id));
}
TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) { TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
std::unique_ptr<MockMasterPlaylist> mock_master_playlist( std::unique_ptr<MockMasterPlaylist> mock_master_playlist(
new MockMasterPlaylist()); new MockMasterPlaylist());
@ -195,11 +235,15 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
new MockMediaPlaylist(kVodPlaylist, "video/playlist.m3u8", "", ""); new MockMediaPlaylist(kVodPlaylist, "video/playlist.m3u8", "", "");
EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist));
EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); // Verify that the init segment URL is relative to playlist path.
EXPECT_CALL(*mock_media_playlist,
SetMediaInfo(Property(&MediaInfo::init_segment_name,
StrEq("path/to/init.mp4"))))
.WillOnce(Return(true));
// Verify that the segment URL is relative to playlist path. // Verify that the segment URL is relative to playlist path.
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
AddSegment(StrEq("path/to/media1.ts"), _, _, _, _)); AddSegment(StrEq("path/to/media1.m4s"), _, _, _, _));
EXPECT_CALL(*factory, CreateMock(kVodPlaylist, Eq(kTestTimeShiftBufferDepth), EXPECT_CALL(*factory, CreateMock(kVodPlaylist, Eq(kTestTimeShiftBufferDepth),
StrEq("video/playlist.m3u8"), StrEq("name"), StrEq("video/playlist.m3u8"), StrEq("name"),
StrEq("groupid"))) StrEq("groupid")))
@ -213,11 +257,12 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
EXPECT_TRUE(notifier.Init()); EXPECT_TRUE(notifier.Init());
MediaInfo media_info; MediaInfo media_info;
media_info.set_init_segment_name("anything/video/path/to/init.mp4");
uint32_t stream_id; uint32_t stream_id;
EXPECT_TRUE(notifier.NotifyNewStream(media_info, "video/playlist.m3u8", EXPECT_TRUE(notifier.NotifyNewStream(media_info, "video/playlist.m3u8",
"name", "groupid", &stream_id)); "name", "groupid", &stream_id));
EXPECT_TRUE( EXPECT_TRUE(
notifier.NotifyNewSegment(stream_id, "anything/video/path/to/media1.ts", notifier.NotifyNewSegment(stream_id, "anything/video/path/to/media1.m4s",
kAnyStartTime, kAnyDuration, 0, kAnySize)); kAnyStartTime, kAnyDuration, 0, kAnySize));
} }