Add new URL fields in MediaInfo
The file_name fields will be used to solely indicate file paths on the designated file system, and they are used to do normal file operations, including file creation, file updating and file removal if needed; added new xxx_url fields, for the URLs that should appear on DASH manifest or HLS playlists. xxx_url are the URIs of the media in the manifest. The fields are converted from file_name fields but adjusted to be relative to DASH manifest path or HLS playlist path, optionally with base_url prepended. Previously the file_name fields are converted in place to indicate URLs when passing to manifest / playlist builders. The original file names were lost, which made it difficult to remove files outside of live window. Now that the input file names are preserved. File system APIs can operate on the original file names while manifest / playlist generation functions can operate on URLs. Issue: #233 Change-Id: I36a64f16e3d1261ce91783a86588f24ad1371662
This commit is contained in:
parent
d63ed0ab3a
commit
adc9549e2d
|
@ -78,9 +78,9 @@ ExitStatus RunMpdGenerator() {
|
||||||
for (Iterator it = base_urls.begin(); it != base_urls.end(); ++it)
|
for (Iterator it = base_urls.begin(); it != base_urls.end(); ++it)
|
||||||
mpd_writer.AddBaseUrl(*it);
|
mpd_writer.AddBaseUrl(*it);
|
||||||
|
|
||||||
for (Iterator it = input_files.begin(); it != input_files.end(); ++it) {
|
for (const std::string& file : input_files) {
|
||||||
if (!mpd_writer.AddFile(it->c_str(), FLAGS_output)) {
|
if (!mpd_writer.AddFile(file)) {
|
||||||
LOG(WARNING) << "MpdWriter failed to read " << *it << ", skipping.";
|
LOG(WARNING) << "MpdWriter failed to read " << file << ", skipping.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,15 +53,15 @@ std::string GetLanguage(const MediaInfo& media_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendExtXMap(const MediaInfo& media_info, std::string* out) {
|
void AppendExtXMap(const MediaInfo& media_info, std::string* out) {
|
||||||
if (media_info.has_init_segment_name()) {
|
if (media_info.has_init_segment_url()) {
|
||||||
Tag tag("#EXT-X-MAP", out);
|
Tag tag("#EXT-X-MAP", out);
|
||||||
tag.AddQuotedString("URI", media_info.init_segment_name().data());
|
tag.AddQuotedString("URI", media_info.init_segment_url().data());
|
||||||
out->append("\n");
|
out->append("\n");
|
||||||
} else if (media_info.has_media_file_name() && media_info.has_init_range()) {
|
} else if (media_info.has_media_file_url() && media_info.has_init_range()) {
|
||||||
// It only makes sense for single segment media to have EXT-X-MAP if
|
// It only makes sense for single segment media to have EXT-X-MAP if
|
||||||
// there is init_range.
|
// there is init_range.
|
||||||
Tag tag("#EXT-X-MAP", out);
|
Tag tag("#EXT-X-MAP", out);
|
||||||
tag.AddQuotedString("URI", media_info.media_file_name().data());
|
tag.AddQuotedString("URI", media_info.media_file_url().data());
|
||||||
|
|
||||||
if (media_info.has_init_range()) {
|
if (media_info.has_init_range()) {
|
||||||
const uint64_t begin = media_info.init_range().begin();
|
const uint64_t begin = media_info.init_range().begin();
|
||||||
|
@ -368,7 +368,7 @@ bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
||||||
time_scale_ = time_scale;
|
time_scale_ = time_scale;
|
||||||
media_info_ = media_info;
|
media_info_ = media_info;
|
||||||
language_ = GetLanguage(media_info);
|
language_ = GetLanguage(media_info);
|
||||||
use_byte_range_ = !media_info_.has_segment_template();
|
use_byte_range_ = !media_info_.has_segment_template_url();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class MediaPlaylistMultiSegmentTest : public MediaPlaylistTest {
|
||||||
// This is just set to be consistent with the multisegment format and used
|
// This is just set to be consistent with the multisegment format and used
|
||||||
// as a switch in MediaPlaylist.
|
// as a switch in MediaPlaylist.
|
||||||
// The template string doesn't really matter.
|
// The template string doesn't really matter.
|
||||||
valid_video_media_info_.set_segment_template("file$Number$.ts");
|
valid_video_media_info_.set_segment_template_url("file$Number$.ts");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ TEST_F(MediaPlaylistSingleSegmentTest, InitRange) {
|
||||||
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||||
"#EXT-X-MAP:URI=\"file.mp4\",BYTERANGE=\"501@0\"\n"
|
"#EXT-X-MAP:URI=\"file.mp4\",BYTERANGE=\"501@0\"\n"
|
||||||
"#EXT-X-ENDLIST\n";
|
"#EXT-X-ENDLIST\n";
|
||||||
valid_video_media_info_.set_media_file_name("file.mp4");
|
valid_video_media_info_.set_media_file_url("file.mp4");
|
||||||
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
||||||
valid_video_media_info_.mutable_init_range()->set_end(500);
|
valid_video_media_info_.mutable_init_range()->set_end(500);
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ TEST_F(MediaPlaylistSingleSegmentTest, InitRangeWithOffset) {
|
||||||
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||||
"#EXT-X-MAP:URI=\"file.mp4\",BYTERANGE=\"485@16\"\n"
|
"#EXT-X-MAP:URI=\"file.mp4\",BYTERANGE=\"485@16\"\n"
|
||||||
"#EXT-X-ENDLIST\n";
|
"#EXT-X-ENDLIST\n";
|
||||||
valid_video_media_info_.set_media_file_name("file.mp4");
|
valid_video_media_info_.set_media_file_url("file.mp4");
|
||||||
valid_video_media_info_.mutable_init_range()->set_begin(16);
|
valid_video_media_info_.mutable_init_range()->set_begin(16);
|
||||||
valid_video_media_info_.mutable_init_range()->set_end(500);
|
valid_video_media_info_.mutable_init_range()->set_end(500);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ TEST_F(MediaPlaylistSingleSegmentTest, AddSegmentByteRange) {
|
||||||
"#EXT-X-BYTERANGE:2000000\n"
|
"#EXT-X-BYTERANGE:2000000\n"
|
||||||
"file.mp4\n"
|
"file.mp4\n"
|
||||||
"#EXT-X-ENDLIST\n";
|
"#EXT-X-ENDLIST\n";
|
||||||
valid_video_media_info_.set_media_file_name("file.mp4");
|
valid_video_media_info_.set_media_file_url("file.mp4");
|
||||||
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
||||||
valid_video_media_info_.mutable_init_range()->set_end(500);
|
valid_video_media_info_.mutable_init_range()->set_end(500);
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ TEST_F(MediaPlaylistMultiSegmentTest, GetNumChannels) {
|
||||||
|
|
||||||
TEST_F(MediaPlaylistMultiSegmentTest, InitSegment) {
|
TEST_F(MediaPlaylistMultiSegmentTest, InitSegment) {
|
||||||
valid_video_media_info_.set_reference_time_scale(90000);
|
valid_video_media_info_.set_reference_time_scale(90000);
|
||||||
valid_video_media_info_.set_init_segment_name("init_segment.mp4");
|
valid_video_media_info_.set_init_segment_url("init_segment.mp4");
|
||||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
||||||
|
|
||||||
media_playlist_.AddSegment("file1.mp4", 0, 10 * kTimeScale, kZeroByteOffset,
|
media_playlist_.AddSegment("file1.mp4", 0, 10 * kTimeScale, kZeroByteOffset,
|
||||||
|
@ -785,7 +785,7 @@ TEST_F(IFrameMediaPlaylistTest, MediaPlaylistType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IFrameMediaPlaylistTest, SingleSegment) {
|
TEST_F(IFrameMediaPlaylistTest, SingleSegment) {
|
||||||
valid_video_media_info_.set_media_file_name("file.mp4");
|
valid_video_media_info_.set_media_file_url("file.mp4");
|
||||||
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
valid_video_media_info_.mutable_init_range()->set_begin(0);
|
||||||
valid_video_media_info_.mutable_init_range()->set_end(500);
|
valid_video_media_info_.mutable_init_range()->set_end(500);
|
||||||
|
|
||||||
|
|
|
@ -283,15 +283,20 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
|
||||||
// Update init_segment_name to be relative to playlist path if needed.
|
// Update init_segment_name to be relative to playlist path if needed.
|
||||||
MediaInfo media_info_copy = media_info;
|
MediaInfo media_info_copy = media_info;
|
||||||
if (media_info_copy.has_init_segment_name()) {
|
if (media_info_copy.has_init_segment_name()) {
|
||||||
media_info_copy.set_init_segment_name(
|
media_info_copy.set_init_segment_url(
|
||||||
GenerateSegmentUrl(media_info_copy.init_segment_name(), prefix_,
|
GenerateSegmentUrl(media_info_copy.init_segment_name(), prefix_,
|
||||||
output_dir_, media_playlist->file_name()));
|
output_dir_, media_playlist->file_name()));
|
||||||
}
|
}
|
||||||
if (media_info_copy.has_media_file_name()) {
|
if (media_info_copy.has_media_file_name()) {
|
||||||
media_info_copy.set_media_file_name(
|
media_info_copy.set_media_file_url(
|
||||||
GenerateSegmentUrl(media_info_copy.media_file_name(), prefix_,
|
GenerateSegmentUrl(media_info_copy.media_file_name(), prefix_,
|
||||||
output_dir_, media_playlist->file_name()));
|
output_dir_, media_playlist->file_name()));
|
||||||
}
|
}
|
||||||
|
if (media_info_copy.has_segment_template()) {
|
||||||
|
media_info_copy.set_segment_template_url(
|
||||||
|
GenerateSegmentUrl(media_info_copy.segment_template(), prefix_,
|
||||||
|
output_dir_, media_playlist->file_name()));
|
||||||
|
}
|
||||||
if (!media_playlist->SetMediaInfo(media_info_copy)) {
|
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;
|
||||||
|
|
|
@ -170,7 +170,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) {
|
||||||
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", "");
|
||||||
|
|
||||||
EXPECT_CALL(*mock_media_playlist,
|
EXPECT_CALL(*mock_media_playlist,
|
||||||
SetMediaInfo(Property(&MediaInfo::init_segment_name, StrEq(""))))
|
SetMediaInfo(Property(&MediaInfo::init_segment_url, StrEq(""))))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
// Verify that the common prefix is stripped for AddSegment().
|
// Verify that the common prefix is stripped for AddSegment().
|
||||||
|
@ -211,7 +211,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) {
|
||||||
// Verify that the common prefix is stripped in init segment.
|
// Verify that the common prefix is stripped in init segment.
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
*mock_media_playlist,
|
*mock_media_playlist,
|
||||||
SetMediaInfo(Property(&MediaInfo::init_segment_name,
|
SetMediaInfo(Property(&MediaInfo::init_segment_url,
|
||||||
StrEq("http://testprefix.com/path/to/init.mp4"))))
|
StrEq("http://testprefix.com/path/to/init.mp4"))))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) {
|
||||||
|
|
||||||
// Verify that the init segment URL is relative to playlist path.
|
// Verify that the init segment URL is relative to playlist path.
|
||||||
EXPECT_CALL(*mock_media_playlist,
|
EXPECT_CALL(*mock_media_playlist,
|
||||||
SetMediaInfo(Property(&MediaInfo::init_segment_name,
|
SetMediaInfo(Property(&MediaInfo::init_segment_url,
|
||||||
StrEq("path/to/init.mp4"))))
|
StrEq("path/to/init.mp4"))))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
|
|
@ -1023,7 +1023,7 @@ TEST_F(OnDemandAdaptationSetTest,
|
||||||
" begin: 864\n"
|
" begin: 864\n"
|
||||||
" end: 931\n"
|
" end: 931\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"media_file_name: 'encrypted_audio.mp4'\n"
|
"media_file_url: 'encrypted_audio.mp4'\n"
|
||||||
"media_duration_seconds: 24.009434\n"
|
"media_duration_seconds: 24.009434\n"
|
||||||
"reference_time_scale: 44100\n"
|
"reference_time_scale: 44100\n"
|
||||||
"container_type: CONTAINER_MP4\n";
|
"container_type: CONTAINER_MP4\n";
|
||||||
|
@ -1071,7 +1071,7 @@ TEST_F(OnDemandAdaptationSetTest, Text) {
|
||||||
"}\n"
|
"}\n"
|
||||||
"media_duration_seconds: 35\n"
|
"media_duration_seconds: 35\n"
|
||||||
"bandwidth: 1000\n"
|
"bandwidth: 1000\n"
|
||||||
"media_file_name: 'subtitle.xml'\n"
|
"media_file_url: 'subtitle.xml'\n"
|
||||||
"container_type: CONTAINER_TEXT\n";
|
"container_type: CONTAINER_TEXT\n";
|
||||||
|
|
||||||
const char kExpectedOutput[] =
|
const char kExpectedOutput[] =
|
||||||
|
|
|
@ -153,4 +153,11 @@ message MediaInfo {
|
||||||
// MpdNotifier::NotifyNewSegment().
|
// MpdNotifier::NotifyNewSegment().
|
||||||
optional float segment_duration_seconds = 12;
|
optional float segment_duration_seconds = 12;
|
||||||
// END LIVE only.
|
// END LIVE only.
|
||||||
|
|
||||||
|
// URL fields for the corresponding file_name fields above.
|
||||||
|
// The file names are adjusted to be relative to DASH MPD or HLS media
|
||||||
|
// playlist, or with base url prepended.
|
||||||
|
optional string media_file_url = 17;
|
||||||
|
optional string init_segment_url = 18;
|
||||||
|
optional string segment_template_url = 19;
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,15 +414,15 @@ void MpdBuilder::MakePathsRelativeToMpd(const std::string& mpd_path,
|
||||||
.AsEndingWithSeparator());
|
.AsEndingWithSeparator());
|
||||||
if (!mpd_dir.empty()) {
|
if (!mpd_dir.empty()) {
|
||||||
if (media_info->has_media_file_name()) {
|
if (media_info->has_media_file_name()) {
|
||||||
media_info->set_media_file_name(
|
media_info->set_media_file_url(
|
||||||
MakePathRelative(media_info->media_file_name(), mpd_dir));
|
MakePathRelative(media_info->media_file_name(), mpd_dir));
|
||||||
}
|
}
|
||||||
if (media_info->has_init_segment_name()) {
|
if (media_info->has_init_segment_name()) {
|
||||||
media_info->set_init_segment_name(
|
media_info->set_init_segment_url(
|
||||||
MakePathRelative(media_info->init_segment_name(), mpd_dir));
|
MakePathRelative(media_info->init_segment_name(), mpd_dir));
|
||||||
}
|
}
|
||||||
if (media_info->has_segment_template()) {
|
if (media_info->has_segment_template()) {
|
||||||
media_info->set_segment_template(
|
media_info->set_segment_template_url(
|
||||||
MakePathRelative(media_info->segment_template(), mpd_dir));
|
MakePathRelative(media_info->segment_template(), mpd_dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,9 +355,9 @@ TEST(RelativePaths, PathsModified) {
|
||||||
media_info.set_init_segment_name(kInitSegment);
|
media_info.set_init_segment_name(kInitSegment);
|
||||||
media_info.set_segment_template(kSegmentTemplate);
|
media_info.set_segment_template(kSegmentTemplate);
|
||||||
MpdBuilder::MakePathsRelativeToMpd(kPathModifiedMpd, &media_info);
|
MpdBuilder::MakePathsRelativeToMpd(kPathModifiedMpd, &media_info);
|
||||||
EXPECT_EQ(kMediaFileBase, media_info.media_file_name());
|
EXPECT_EQ(kMediaFileBase, media_info.media_file_url());
|
||||||
EXPECT_EQ(kInitSegmentBase, media_info.init_segment_name());
|
EXPECT_EQ(kInitSegmentBase, media_info.init_segment_url());
|
||||||
EXPECT_EQ(kSegmentTemplateBase, media_info.segment_template());
|
EXPECT_EQ(kSegmentTemplateBase, media_info.segment_template_url());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RelativePaths, PathsNotModified) {
|
TEST(RelativePaths, PathsNotModified) {
|
||||||
|
@ -367,9 +367,9 @@ TEST(RelativePaths, PathsNotModified) {
|
||||||
media_info.set_init_segment_name(kInitSegment);
|
media_info.set_init_segment_name(kInitSegment);
|
||||||
media_info.set_segment_template(kSegmentTemplate);
|
media_info.set_segment_template(kSegmentTemplate);
|
||||||
MpdBuilder::MakePathsRelativeToMpd(kPathNotModifiedMpd, &media_info);
|
MpdBuilder::MakePathsRelativeToMpd(kPathNotModifiedMpd, &media_info);
|
||||||
EXPECT_EQ(kMediaFile, media_info.media_file_name());
|
EXPECT_EQ(kMediaFile, media_info.media_file_url());
|
||||||
EXPECT_EQ(kInitSegment, media_info.init_segment_name());
|
EXPECT_EQ(kInitSegment, media_info.init_segment_url());
|
||||||
EXPECT_EQ(kSegmentTemplate, media_info.segment_template());
|
EXPECT_EQ(kSegmentTemplate, media_info.segment_template_url());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -53,12 +53,12 @@ std::string TextCodecString(const MediaInfo& media_info) {
|
||||||
|
|
||||||
bool HasVODOnlyFields(const MediaInfo& media_info) {
|
bool HasVODOnlyFields(const MediaInfo& media_info) {
|
||||||
return media_info.has_init_range() || media_info.has_index_range() ||
|
return media_info.has_init_range() || media_info.has_index_range() ||
|
||||||
media_info.has_media_file_name();
|
media_info.has_media_file_url();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasLiveOnlyFields(const MediaInfo& media_info) {
|
bool HasLiveOnlyFields(const MediaInfo& media_info) {
|
||||||
return media_info.has_init_segment_name() ||
|
return media_info.has_init_segment_url() ||
|
||||||
media_info.has_segment_template() ||
|
media_info.has_segment_template_url() ||
|
||||||
media_info.has_segment_duration_seconds();
|
media_info.has_segment_duration_seconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,8 +409,8 @@ std::string GetDefaultMediaInfo() {
|
||||||
"}\n"
|
"}\n"
|
||||||
"reference_time_scale: %u\n"
|
"reference_time_scale: %u\n"
|
||||||
"container_type: 1\n"
|
"container_type: 1\n"
|
||||||
"init_segment_name: 'init.mp4'\n"
|
"init_segment_url: 'init.mp4'\n"
|
||||||
"segment_template: '$Time$.mp4'\n";
|
"segment_template_url: '$Time$.mp4'\n";
|
||||||
|
|
||||||
return base::StringPrintf(kMediaInfo, kDefaultTimeScale);
|
return base::StringPrintf(kMediaInfo, kDefaultTimeScale);
|
||||||
}
|
}
|
||||||
|
@ -503,7 +503,7 @@ TEST_F(SegmentTemplateTest, OneSegmentNormal) {
|
||||||
|
|
||||||
TEST_F(SegmentTemplateTest, RepresentationClone) {
|
TEST_F(SegmentTemplateTest, RepresentationClone) {
|
||||||
MediaInfo media_info = ConvertToMediaInfo(GetDefaultMediaInfo());
|
MediaInfo media_info = ConvertToMediaInfo(GetDefaultMediaInfo());
|
||||||
media_info.set_segment_template("$Number$.mp4");
|
media_info.set_segment_template_url("$Number$.mp4");
|
||||||
representation_ =
|
representation_ =
|
||||||
CreateRepresentation(media_info, kAnyRepresentationId, NoListener());
|
CreateRepresentation(media_info, kAnyRepresentationId, NoListener());
|
||||||
ASSERT_TRUE(representation_->Init());
|
ASSERT_TRUE(representation_->Init());
|
||||||
|
@ -703,8 +703,8 @@ class TimeShiftBufferDepthTest : public SegmentTemplateTest {
|
||||||
"}\n"
|
"}\n"
|
||||||
"reference_time_scale: %u\n"
|
"reference_time_scale: %u\n"
|
||||||
"container_type: 1\n"
|
"container_type: 1\n"
|
||||||
"init_segment_name: 'init.mp4'\n"
|
"init_segment_url: 'init.mp4'\n"
|
||||||
"segment_template: '$Number$.mp4'\n";
|
"segment_template_url: '$Number$.mp4'\n";
|
||||||
const std::string& number_template_media_info =
|
const std::string& number_template_media_info =
|
||||||
base::StringPrintf(kMediaInfo, kDefaultTimeScale);
|
base::StringPrintf(kMediaInfo, kDefaultTimeScale);
|
||||||
mpd_options_.mpd_type = MpdType::kDynamic;
|
mpd_options_.mpd_type = MpdType::kDynamic;
|
||||||
|
|
|
@ -276,9 +276,9 @@ bool RepresentationXmlNode::AddAudioInfo(const AudioInfo& audio_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepresentationXmlNode::AddVODOnlyInfo(const MediaInfo& media_info) {
|
bool RepresentationXmlNode::AddVODOnlyInfo(const MediaInfo& media_info) {
|
||||||
if (media_info.has_media_file_name()) {
|
if (media_info.has_media_file_url()) {
|
||||||
XmlNode base_url("BaseURL");
|
XmlNode base_url("BaseURL");
|
||||||
base_url.SetContent(media_info.media_file_name());
|
base_url.SetContent(media_info.media_file_url());
|
||||||
|
|
||||||
if (!AddChild(base_url.PassScopedPtr()))
|
if (!AddChild(base_url.PassScopedPtr()))
|
||||||
return false;
|
return false;
|
||||||
|
@ -336,24 +336,14 @@ bool RepresentationXmlNode::AddLiveOnlyInfo(
|
||||||
media_info.presentation_time_offset());
|
media_info.presentation_time_offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_info.has_init_segment_name()) {
|
if (media_info.has_init_segment_url()) {
|
||||||
// The spec does not allow '$Number$' and '$Time$' in initialization
|
|
||||||
// attribute.
|
|
||||||
// TODO(rkuroiwa, kqyang): Swap this check out with a better check. These
|
|
||||||
// templates allow formatting as well.
|
|
||||||
const std::string& init_segment_name = media_info.init_segment_name();
|
|
||||||
if (init_segment_name.find("$Number$") != std::string::npos ||
|
|
||||||
init_segment_name.find("$Time$") != std::string::npos) {
|
|
||||||
LOG(ERROR) << "$Number$ and $Time$ cannot be used for "
|
|
||||||
"SegmentTemplate@initialization";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
segment_template.SetStringAttribute("initialization",
|
segment_template.SetStringAttribute("initialization",
|
||||||
media_info.init_segment_name());
|
media_info.init_segment_url());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_info.has_segment_template()) {
|
if (media_info.has_segment_template_url()) {
|
||||||
segment_template.SetStringAttribute("media", media_info.segment_template());
|
segment_template.SetStringAttribute("media",
|
||||||
|
media_info.segment_template_url());
|
||||||
segment_template.SetIntegerAttribute("startNumber", start_number);
|
segment_template.SetIntegerAttribute("startNumber", start_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,28 +191,5 @@ TEST(XmlNodeTest, AddEC3AudioInfo) {
|
||||||
"</Representation>\n"));
|
"</Representation>\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some template names cannot be used for init segment name.
|
|
||||||
TEST(XmlNodeTest, InvalidLiveInitSegmentName) {
|
|
||||||
MediaInfo media_info;
|
|
||||||
const uint32_t kDefaultStartNumber = 1;
|
|
||||||
std::list<SegmentInfo> segment_infos;
|
|
||||||
RepresentationXmlNode representation;
|
|
||||||
|
|
||||||
// $Number$ cannot be used for segment name.
|
|
||||||
media_info.set_init_segment_name("$Number$.mp4");
|
|
||||||
ASSERT_FALSE(representation.AddLiveOnlyInfo(media_info, segment_infos,
|
|
||||||
kDefaultStartNumber));
|
|
||||||
|
|
||||||
// $Time$ as well.
|
|
||||||
media_info.set_init_segment_name("$Time$.mp4");
|
|
||||||
ASSERT_FALSE(representation.AddLiveOnlyInfo(media_info, segment_infos,
|
|
||||||
kDefaultStartNumber));
|
|
||||||
|
|
||||||
// This should be valid.
|
|
||||||
media_info.set_init_segment_name("some_non_template_name.mp4");
|
|
||||||
ASSERT_TRUE(representation.AddLiveOnlyInfo(media_info, segment_infos,
|
|
||||||
kDefaultStartNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xml
|
} // namespace xml
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -8,4 +8,5 @@ audio_info {
|
||||||
reference_time_scale: 50
|
reference_time_scale: 50
|
||||||
container_type: 1
|
container_type: 1
|
||||||
media_file_name: "test_output_file_name_audio1.mp4"
|
media_file_name: "test_output_file_name_audio1.mp4"
|
||||||
|
media_file_url: "test_output_file_name_audio1.mp4"
|
||||||
media_duration_seconds: 10.5
|
media_duration_seconds: 10.5
|
||||||
|
|
|
@ -19,4 +19,5 @@ index_range {
|
||||||
reference_time_scale: 1000
|
reference_time_scale: 1000
|
||||||
container_type: 1
|
container_type: 1
|
||||||
media_file_name: "test_output_file_name1.mp4"
|
media_file_name: "test_output_file_name1.mp4"
|
||||||
|
media_file_url: "test_output_file_name1.mp4"
|
||||||
media_duration_seconds: 10.5
|
media_duration_seconds: 10.5
|
||||||
|
|
|
@ -19,4 +19,5 @@ index_range {
|
||||||
reference_time_scale: 50
|
reference_time_scale: 50
|
||||||
container_type: 1
|
container_type: 1
|
||||||
media_file_name: "test_output_file_name2.mp4"
|
media_file_name: "test_output_file_name2.mp4"
|
||||||
|
media_file_url: "test_output_file_name2.mp4"
|
||||||
media_duration_seconds: 10.5
|
media_duration_seconds: 10.5
|
||||||
|
|
|
@ -44,8 +44,7 @@ class SimpleMpdNotifierFactory : public MpdNotifierFactory {
|
||||||
MpdWriter::MpdWriter() : notifier_factory_(new SimpleMpdNotifierFactory()) {}
|
MpdWriter::MpdWriter() : notifier_factory_(new SimpleMpdNotifierFactory()) {}
|
||||||
MpdWriter::~MpdWriter() {}
|
MpdWriter::~MpdWriter() {}
|
||||||
|
|
||||||
bool MpdWriter::AddFile(const std::string& media_info_path,
|
bool MpdWriter::AddFile(const std::string& media_info_path) {
|
||||||
const std::string& mpd_path) {
|
|
||||||
std::string file_content;
|
std::string file_content;
|
||||||
if (!File::ReadFileToString(media_info_path.c_str(), &file_content)) {
|
if (!File::ReadFileToString(media_info_path.c_str(), &file_content)) {
|
||||||
LOG(ERROR) << "Failed to read " << media_info_path << " to string.";
|
LOG(ERROR) << "Failed to read " << media_info_path << " to string.";
|
||||||
|
@ -59,7 +58,6 @@ bool MpdWriter::AddFile(const std::string& media_info_path,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdBuilder::MakePathsRelativeToMpd(mpd_path, &media_info);
|
|
||||||
media_infos_.push_back(media_info);
|
media_infos_.push_back(media_info);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -82,13 +80,11 @@ bool MpdWriter::WriteMpdToFile(const char* file_name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::list<MediaInfo>::const_iterator it = media_infos_.begin();
|
for (const MediaInfo& media_info : media_infos_) {
|
||||||
it != media_infos_.end();
|
|
||||||
++it) {
|
|
||||||
uint32_t unused_conatiner_id;
|
uint32_t unused_conatiner_id;
|
||||||
if (!notifier->NotifyNewContainer(*it, &unused_conatiner_id)) {
|
if (!notifier->NotifyNewContainer(media_info, &unused_conatiner_id)) {
|
||||||
LOG(ERROR) << "Failed to add MediaInfo for media file: "
|
LOG(ERROR) << "Failed to add MediaInfo for media file: "
|
||||||
<< it->media_file_name();
|
<< media_info.media_file_name();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,7 @@ class MpdWriter {
|
||||||
// MediaInfo, i.e. the content should be a result of using
|
// MediaInfo, i.e. the content should be a result of using
|
||||||
// google::protobuf::TestFormat::Print*() methods.
|
// google::protobuf::TestFormat::Print*() methods.
|
||||||
// If necessary, this method can be called after WriteMpd*() methods.
|
// If necessary, this method can be called after WriteMpd*() methods.
|
||||||
bool AddFile(const std::string& media_info_path,
|
bool AddFile(const std::string& media_info_path);
|
||||||
const std::string& mpd_path);
|
|
||||||
|
|
||||||
// |base_url| will be used for <BaseURL> element for the MPD. The BaseURL
|
// |base_url| will be used for <BaseURL> element for the MPD. The BaseURL
|
||||||
// element will be a direct child element of the <MPD> element.
|
// element will be a direct child element of the <MPD> element.
|
||||||
|
|
|
@ -88,8 +88,8 @@ TEST_F(MpdWriterTest, WriteMpdToFile) {
|
||||||
GetTestDataFilePath(kFileNameVideoMediaInfo2);
|
GetTestDataFilePath(kFileNameVideoMediaInfo2);
|
||||||
|
|
||||||
SetMpdNotifierFactoryForTest();
|
SetMpdNotifierFactoryForTest();
|
||||||
EXPECT_TRUE(mpd_writer_.AddFile(media_info_file1.AsUTF8Unsafe(), ""));
|
EXPECT_TRUE(mpd_writer_.AddFile(media_info_file1.AsUTF8Unsafe()));
|
||||||
EXPECT_TRUE(mpd_writer_.AddFile(media_info_file2.AsUTF8Unsafe(), ""));
|
EXPECT_TRUE(mpd_writer_.AddFile(media_info_file2.AsUTF8Unsafe()));
|
||||||
mpd_writer_.AddBaseUrl(kBaseUrl1);
|
mpd_writer_.AddBaseUrl(kBaseUrl1);
|
||||||
mpd_writer_.AddBaseUrl(kBaseUrl2);
|
mpd_writer_.AddBaseUrl(kBaseUrl2);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue