diff --git a/packager/hls/base/media_playlist.h b/packager/hls/base/media_playlist.h index 23458bd1d3..9d5e22c7cd 100644 --- a/packager/hls/base/media_playlist.h +++ b/packager/hls/base/media_playlist.h @@ -61,7 +61,8 @@ class MediaPlaylist { }; /// @param hls_params contains HLS parameters. - /// @param file_name is the file name of this media playlist. + /// @param file_name is the file name of this media playlist, relative to + /// master playlist output path. /// @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. diff --git a/packager/hls/base/simple_hls_notifier.cc b/packager/hls/base/simple_hls_notifier.cc index 6b8c11caa9..bf9926f2a1 100644 --- a/packager/hls/base/simple_hls_notifier.cc +++ b/packager/hls/base/simple_hls_notifier.cc @@ -281,7 +281,7 @@ SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params) media_playlist_factory_(new MediaPlaylistFactory()) { const base::FilePath master_playlist_path( base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output)); - output_dir_ = master_playlist_path.DirName().AsUTF8Unsafe(); + master_playlist_dir_ = master_playlist_path.DirName().AsUTF8Unsafe(); const std::string& default_audio_langauge = hls_params.default_language; const std::string& default_text_language = hls_params.default_text_language.empty() @@ -305,11 +305,14 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info, uint32_t* stream_id) { DCHECK(stream_id); + const std::string relative_playlist_path = MakePathRelative( + playlist_name, FilePath::FromUTF8Unsafe(master_playlist_dir_)); + std::unique_ptr media_playlist = - media_playlist_factory_->Create(hls_params(), playlist_name, name, - group_id); + media_playlist_factory_->Create(hls_params(), relative_playlist_path, + name, group_id); MediaInfo adjusted_media_info = MakeMediaInfoPathsRelativeToPlaylist( - media_info, hls_params().base_url, output_dir_, + media_info, hls_params().base_url, master_playlist_dir_, media_playlist->file_name()); if (!media_playlist->SetMediaInfo(adjusted_media_info)) { LOG(ERROR) << "Failed to set media info for playlist " << playlist_name; @@ -353,8 +356,8 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id, } auto& media_playlist = stream_iterator->second->media_playlist; const std::string& segment_url = - GenerateSegmentUrl(segment_name, hls_params().base_url, output_dir_, - media_playlist->file_name()); + GenerateSegmentUrl(segment_name, hls_params().base_url, + master_playlist_dir_, media_playlist->file_name()); media_playlist->AddSegment(segment_url, start_time, duration, start_byte_offset, size); @@ -374,15 +377,15 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id, if (target_duration_updated) { for (MediaPlaylist* playlist : media_playlists_) { playlist->SetTargetDuration(target_duration_); - if (!WriteMediaPlaylist(output_dir_, playlist)) + if (!WriteMediaPlaylist(master_playlist_dir_, playlist)) return false; } } else { - if (!WriteMediaPlaylist(output_dir_, media_playlist.get())) + if (!WriteMediaPlaylist(master_playlist_dir_, media_playlist.get())) return false; } - if (!master_playlist_->WriteMasterPlaylist(hls_params().base_url, - output_dir_, media_playlists_)) { + if (!master_playlist_->WriteMasterPlaylist( + hls_params().base_url, master_playlist_dir_, media_playlists_)) { LOG(ERROR) << "Failed to write master playlist."; return false; } @@ -482,11 +485,11 @@ bool SimpleHlsNotifier::Flush() { base::AutoLock auto_lock(lock_); for (MediaPlaylist* playlist : media_playlists_) { playlist->SetTargetDuration(target_duration_); - if (!WriteMediaPlaylist(output_dir_, playlist)) + if (!WriteMediaPlaylist(master_playlist_dir_, playlist)) return false; } - if (!master_playlist_->WriteMasterPlaylist(hls_params().base_url, output_dir_, - media_playlists_)) { + if (!master_playlist_->WriteMasterPlaylist( + hls_params().base_url, master_playlist_dir_, media_playlists_)) { LOG(ERROR) << "Failed to write master playlist."; return false; } diff --git a/packager/hls/base/simple_hls_notifier.h b/packager/hls/base/simple_hls_notifier.h index d835169191..e0632293b2 100644 --- a/packager/hls/base/simple_hls_notifier.h +++ b/packager/hls/base/simple_hls_notifier.h @@ -77,7 +77,7 @@ class SimpleHlsNotifier : public HlsNotifier { MediaPlaylist::EncryptionMethod encryption_method; }; - std::string output_dir_; + std::string master_playlist_dir_; uint32_t target_duration_ = 0; std::unique_ptr media_playlist_factory_; diff --git a/packager/hls/base/simple_hls_notifier_unittest.cc b/packager/hls/base/simple_hls_notifier_unittest.cc index 1b120d93d0..f816be95b4 100644 --- a/packager/hls/base/simple_hls_notifier_unittest.cc +++ b/packager/hls/base/simple_hls_notifier_unittest.cc @@ -379,6 +379,8 @@ struct RebaseUrlTestData { std::string master_playlist_dir; // Media playlist path. This may be relative or absolute. std::string playlist_path; + // Expected relative playlist path. It is path_relative_to(master_directory). + std::string expected_relative_playlist_path; // Media segment path. This may be relative or absolute. std::string segment_path; // Expected segment URL in the media playlist: @@ -421,7 +423,7 @@ TEST_P(SimpleHlsNotifierRebaseUrlTest, Test) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = - new MockMediaPlaylist(test_data_.playlist_path, "", ""); + new MockMediaPlaylist(test_data_.expected_relative_playlist_path, "", ""); EXPECT_CALL( *mock_media_playlist, @@ -433,8 +435,9 @@ TEST_P(SimpleHlsNotifierRebaseUrlTest, Test) { EXPECT_CALL(*mock_media_playlist, AddSegment(test_data_.expected_segment_url, _, _, _, _)); } - EXPECT_CALL(*factory, CreateMock(_, StrEq(test_data_.playlist_path), - StrEq("name"), StrEq("groupid"))) + EXPECT_CALL(*factory, + CreateMock(_, StrEq(test_data_.expected_relative_playlist_path), + StrEq("name"), StrEq("groupid"))) .WillOnce(Return(mock_media_playlist)); InjectMasterPlaylist(std::move(mock_master_playlist), &test_notifier); @@ -459,35 +462,54 @@ INSTANTIATE_TEST_CASE_P( SimpleHlsNotifierRebaseUrlTest, ::testing::Values( // Verify relative segment path. - RebaseUrlTestData{ - "http://testprefix.com/", "master_directory/", - "video_playlist.m3u8", "master_directory/path/to/media1.ts", - "http://testprefix.com/path/to/media1.ts", - "" /* init segment path */, "" /* expected init segment url */}, + RebaseUrlTestData{"http://testprefix.com/", "master_directory/", + "video_playlist.m3u8", "video_playlist.m3u8", + "master_directory/path/to/media1.ts", + "http://testprefix.com/path/to/media1.ts", + "" /* init segment path */, + "" /* expected init segment url */}, // Verify relative init segment path. RebaseUrlTestData{"http://testprefix.com/", "master_directory/", - "video_playlist.m3u8", "" /* segment path */, - "" /* expected segment url */, + "video_playlist.m3u8", "video_playlist.m3u8", + "" /* segment path */, "" /* expected segment url */, "master_directory/path/to/init.mp4", "http://testprefix.com/path/to/init.mp4"}, // Verify segment url relative to playlist. RebaseUrlTestData{ - "" /* no base_url */, "master_directory/", - "video/video_playlist.m3u8", + "" /* no base url */, "master_directory/", + "video/video_playlist.m3u8", "video/video_playlist.m3u8", "master_directory/video/path/to/media1.m4s", "path/to/media1.m4s", "master_directory/video/path/to/init.mp4", "path/to/init.mp4"}, // Verify absolute directory. RebaseUrlTestData{ "http://testprefix.com/", "/tmp/something/", "video_playlist.m3u8", - "/tmp/something/media1.ts", "http://testprefix.com/media1.ts", - "" /* init segment path */, "" /* expected init segment url */}, + "video_playlist.m3u8", "/tmp/something/media1.ts", + "http://testprefix.com/media1.ts", "" /* init segment path */, + "" /* expected init segment url */}, // Verify absolute directory, but media in a different directory. // Note that we don't really expect this in practice. - RebaseUrlTestData{"http://testprefix.com/", "/tmp/something/", - "video_playlist.m3u8", "/var/somewhereelse/media1.ts", - "http://testprefix.com//var/somewhereelse/media1.ts", - "" /* init segment path */, - "" /* expected init segment url */})); + RebaseUrlTestData{ + "http://testprefix.com/", "/tmp/something/", "video_playlist.m3u8", + "video_playlist.m3u8", "/var/somewhereelse/media1.ts", + "http://testprefix.com//var/somewhereelse/media1.ts", + "" /* init segment path */, "" /* expected init segment url */ + }, + // Verify absolute directory, absolute media playlist path. + RebaseUrlTestData{ + "http://testprefix.com/", "/tmp/something/", + "/tmp/something/video/video_playlist.m3u8", + "video/video_playlist.m3u8", "/tmp/something/video/media1.ts", + "http://testprefix.com/video/media1.ts", "" /* init segment path */, + "" /* expected init segment url */ + }, + // Same as above, but without base_url. + RebaseUrlTestData{ + "" /* no base url */, "/tmp/something/", + "/tmp/something/video/video_playlist.m3u8", + "video/video_playlist.m3u8", "/tmp/something/video/media1.ts", + "media1.ts", "" /* init segment path */, + "" /* expected init segment url */ + })); class LiveOrEventSimpleHlsNotifierTest : public SimpleHlsNotifierTest,