HLS with fragmented MP4
- Add EXT-X-MAP tag for init segment. - Do not set output field on stream descriptor if not specified on command line. If it's set (internally) then it gets copied to MediaInfo that gets passed to the manifest generators. b/36279481 Change-Id: I762c55b255699ec691817dc4806b0dee2f7504b8
This commit is contained in:
parent
cc04698460
commit
4891d9a6bf
|
@ -296,7 +296,7 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
remux_jobs->emplace_back(new RemuxJob(std::move(demuxer)));
|
remux_jobs->emplace_back(new RemuxJob(std::move(demuxer)));
|
||||||
previous_input = stream_iter->input;
|
previous_input = stream_iter->input;
|
||||||
// Skip setting up muxers if output is not needed.
|
// Skip setting up muxers if output is not needed.
|
||||||
if (stream_iter->output.empty())
|
if (stream_iter->output.empty() && stream_iter->segment_template.empty())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DCHECK(!remux_jobs->empty());
|
DCHECK(!remux_jobs->empty());
|
||||||
|
|
|
@ -187,12 +187,15 @@ bool InsertStreamDescriptor(const std::string& descriptor_string,
|
||||||
<< "' ignored. TS muxer does not support initialization "
|
<< "' ignored. TS muxer does not support initialization "
|
||||||
"segment generation.";
|
"segment generation.";
|
||||||
}
|
}
|
||||||
// For convenience, set descriptor.output to descriptor.segment_template. It
|
|
||||||
// is only used for flag checking in variuos places.
|
|
||||||
descriptor.output = descriptor.segment_template;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_dump_stream_info && descriptor.output.empty()) {
|
// For TS output, segment template is sufficient, and does not require an
|
||||||
|
// output entry.
|
||||||
|
const bool output_specified =
|
||||||
|
!descriptor.output.empty() ||
|
||||||
|
(descriptor.output_format == CONTAINER_MPEG2TS &&
|
||||||
|
!descriptor.segment_template.empty());
|
||||||
|
if (!FLAGS_dump_stream_info && !output_specified) {
|
||||||
LOG(ERROR) << "Stream output not specified.";
|
LOG(ERROR) << "Stream output not specified.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
#EXT-X-VERSION:5
|
#EXT-X-VERSION:6
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
#EXT-X-VERSION:5
|
#EXT-X-VERSION:6
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
#EXT-X-VERSION:5
|
#EXT-X-VERSION:6
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#EXTM3U
|
#EXTM3U
|
||||||
#EXT-X-VERSION:5
|
#EXT-X-VERSION:6
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
|
|
@ -32,6 +32,39 @@ uint32_t GetTimeScale(const MediaInfo& media_info) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CreatePlaylistHeader(
|
||||||
|
const std::string& init_segment_name,
|
||||||
|
uint32_t target_duration,
|
||||||
|
MediaPlaylist::MediaPlaylistType type) {
|
||||||
|
const std::string version = GetPackagerVersion();
|
||||||
|
std::string version_line;
|
||||||
|
if (!version.empty()) {
|
||||||
|
version_line =
|
||||||
|
base::StringPrintf("## Generated with %s version %s\n",
|
||||||
|
GetPackagerProjectUrl().c_str(), version.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6 is required for EXT-X-MAP without EXT-X-I-FRAMES-ONLY.
|
||||||
|
std::string header = base::StringPrintf(
|
||||||
|
"#EXTM3U\n"
|
||||||
|
"#EXT-X-VERSION:6\n"
|
||||||
|
"%s"
|
||||||
|
"#EXT-X-TARGETDURATION:%d\n",
|
||||||
|
version_line.c_str(), target_duration);
|
||||||
|
|
||||||
|
if (type == MediaPlaylist::MediaPlaylistType::kVod) {
|
||||||
|
header += "#EXT-X-PLAYLIST-TYPE:VOD\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put EXT-X-MAP at the end since the rest of the playlist is about the
|
||||||
|
// segment and key info.
|
||||||
|
if (!init_segment_name.empty()) {
|
||||||
|
header += "#EXT-X-MAP:URI=\"" + init_segment_name + "\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
class SegmentInfoEntry : public HlsEntry {
|
class SegmentInfoEntry : public HlsEntry {
|
||||||
public:
|
public:
|
||||||
SegmentInfoEntry(const std::string& file_name, double duration);
|
SegmentInfoEntry(const std::string& file_name, double duration);
|
||||||
|
@ -266,24 +299,8 @@ bool MediaPlaylist::WriteToFile(media::File* file) {
|
||||||
SetTargetDuration(ceil(GetLongestSegmentDuration()));
|
SetTargetDuration(ceil(GetLongestSegmentDuration()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string version = GetPackagerVersion();
|
std::string header = CreatePlaylistHeader(media_info_.init_segment_name(),
|
||||||
std::string version_line;
|
target_duration_, type_);
|
||||||
if (!version.empty()) {
|
|
||||||
version_line =
|
|
||||||
base::StringPrintf("## Generated with %s version %s\n",
|
|
||||||
GetPackagerProjectUrl().c_str(), version.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// KEYFORMAT and KEYFORMATVERSIONS on EXT-X-KEY requires 5 or above.
|
|
||||||
std::string header = base::StringPrintf(
|
|
||||||
"#EXTM3U\n"
|
|
||||||
"#EXT-X-VERSION:5\n"
|
|
||||||
"%s"
|
|
||||||
"#EXT-X-TARGETDURATION:%d\n",
|
|
||||||
version_line.c_str(), target_duration_);
|
|
||||||
if (type_ == MediaPlaylistType::kVod) {
|
|
||||||
header += "#EXT-X-PLAYLIST-TYPE:VOD\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string body;
|
std::string body;
|
||||||
if (!entries_.empty()) {
|
if (!entries_.empty()) {
|
||||||
|
|
|
@ -119,7 +119,7 @@ TEST_F(MediaPlaylistTest, WriteToFile) {
|
||||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:0\n"
|
"#EXT-X-TARGETDURATION:0\n"
|
||||||
|
@ -176,7 +176,7 @@ TEST_F(MediaPlaylistTest, SetTargetDuration) {
|
||||||
EXPECT_TRUE(media_playlist_.SetTargetDuration(20));
|
EXPECT_TRUE(media_playlist_.SetTargetDuration(20));
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:20\n"
|
"#EXT-X-TARGETDURATION:20\n"
|
||||||
|
@ -204,7 +204,7 @@ TEST_F(MediaPlaylistTest, WriteToFileWithSegments) {
|
||||||
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:30\n"
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
|
@ -235,7 +235,7 @@ TEST_F(MediaPlaylistTest, WriteToFileWithEncryptionInfo) {
|
||||||
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:30\n"
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
|
@ -269,7 +269,7 @@ TEST_F(MediaPlaylistTest, WriteToFileWithEncryptionInfoEmptyIv) {
|
||||||
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:30\n"
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
|
@ -302,7 +302,7 @@ TEST_F(MediaPlaylistTest, WriteToFileWithClearLead) {
|
||||||
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
media_playlist_.AddSegment("file2.ts", 2700000, 5000000);
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version test\n"
|
"## Generated with https://github.com/google/shaka-packager version test\n"
|
||||||
"#EXT-X-TARGETDURATION:30\n"
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||||
|
@ -336,7 +336,7 @@ TEST_F(MediaPlaylistTest, RemoveOldestSegment) {
|
||||||
|
|
||||||
const std::string kExpectedOutput =
|
const std::string kExpectedOutput =
|
||||||
"#EXTM3U\n"
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:5\n"
|
"#EXT-X-VERSION:6\n"
|
||||||
"## Generated with https://github.com/google/shaka-packager version "
|
"## Generated with https://github.com/google/shaka-packager version "
|
||||||
"test\n"
|
"test\n"
|
||||||
"#EXT-X-TARGETDURATION:30\n"
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
|
@ -370,5 +370,35 @@ TEST_F(MediaPlaylistTest, GetLanguage) {
|
||||||
EXPECT_EQ("apa", media_playlist_.GetLanguage()); // no short form exists
|
EXPECT_EQ("apa", media_playlist_.GetLanguage()); // no short form exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MediaPlaylistTest, InitSegment) {
|
||||||
|
valid_video_media_info_.set_reference_time_scale(90000);
|
||||||
|
valid_video_media_info_.set_init_segment_name("init_segment.mp4");
|
||||||
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
||||||
|
|
||||||
|
// 10 seconds.
|
||||||
|
media_playlist_.AddSegment("file1.mp4", 900000, 1000000);
|
||||||
|
// 30 seconds.
|
||||||
|
media_playlist_.AddSegment("file2.mp4", 2700000, 5000000);
|
||||||
|
|
||||||
|
const std::string kExpectedOutput =
|
||||||
|
"#EXTM3U\n"
|
||||||
|
"#EXT-X-VERSION:6\n"
|
||||||
|
"## Generated with https://github.com/google/shaka-packager version test\n"
|
||||||
|
"#EXT-X-TARGETDURATION:30\n"
|
||||||
|
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||||
|
"#EXT-X-MAP:URI=\"init_segment.mp4\"\n"
|
||||||
|
"#EXTINF:10.000,\n"
|
||||||
|
"file1.mp4\n"
|
||||||
|
"#EXTINF:30.000,\n"
|
||||||
|
"file2.mp4\n"
|
||||||
|
"#EXT-X-ENDLIST\n";
|
||||||
|
|
||||||
|
MockFile file;
|
||||||
|
EXPECT_CALL(file,
|
||||||
|
Write(MatchesString(kExpectedOutput), kExpectedOutput.size()))
|
||||||
|
.WillOnce(ReturnArg<1>());
|
||||||
|
EXPECT_TRUE(media_playlist_.WriteToFile(&file));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace hls
|
} // namespace hls
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
Loading…
Reference in New Issue