diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py
index 267e06fd57..51e86d9944 100755
--- a/packager/app/test/packager_test.py
+++ b/packager/app/test/packager_test.py
@@ -333,6 +333,14 @@ class PackagerAppTest(unittest.TestCase):
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
self._DiffLiveMpdGold(self.mpd_output, 'bear-640x360-av-live-golden.mpd')
+ def testPackageWithLiveStaticProfile(self):
+ self.packager.Package(
+ self._GetStreams(['audio', 'video'], live=True),
+ self._GetFlags(generate_static_mpd=True))
+ self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden')
+ self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
+ self._DiffGold(self.mpd_output, 'bear-640x360-av-live-static-golden.mpd')
+
def testPackageWithLiveProfileAndEncryption(self):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True),
@@ -493,6 +501,7 @@ class PackagerAppTest(unittest.TestCase):
dash_if_iop=True,
output_media_info=False,
output_hls=False,
+ generate_static_mpd=False,
use_fake_clock=True):
flags = []
if widevine_encryption:
@@ -528,6 +537,9 @@ class PackagerAppTest(unittest.TestCase):
else:
flags += ['--mpd_output', self.mpd_output]
+ if generate_static_mpd:
+ flags += ['--generate_static_mpd']
+
flags.append('--segment_duration=1')
# Use fake clock, so output can be compared.
if use_fake_clock:
diff --git a/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd
new file mode 100644
index 0000000000..d455b643e6
--- /dev/null
+++ b/packager/app/test/testdata/bear-640x360-av-live-static-golden.mpd
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packager/media/event/mpd_notify_muxer_listener.cc b/packager/media/event/mpd_notify_muxer_listener.cc
index 39bfbf1d6b..6838372918 100644
--- a/packager/media/event/mpd_notify_muxer_listener.cc
+++ b/packager/media/event/mpd_notify_muxer_listener.cc
@@ -119,6 +119,8 @@ void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
uint64_t file_size) {
if (mpd_notifier_->dash_profile() == DashProfile::kLive) {
DCHECK(subsegments_.empty());
+ // TODO(kqyang): Set mpd duration to |duration_seconds|, which is more
+ // accurate than the duration coded in the original media header.
if (mpd_notifier_->mpd_type() == MpdType::kStatic)
mpd_notifier_->Flush();
return;
diff --git a/packager/media/event/mpd_notify_muxer_listener_unittest.cc b/packager/media/event/mpd_notify_muxer_listener_unittest.cc
index 98b6b412b0..58bd5d3f0e 100644
--- a/packager/media/event/mpd_notify_muxer_listener_unittest.cc
+++ b/packager/media/event/mpd_notify_muxer_listener_unittest.cc
@@ -295,6 +295,7 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
" pixel_width: 1\n"
" pixel_height: 1\n"
"}\n"
+ "media_duration_seconds: 20.0\n"
"init_segment_name: \"liveinit.mp4\"\n"
"segment_template: \"live-$NUMBER$.mp4\"\n"
"reference_time_scale: 1000\n"
@@ -368,6 +369,7 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
" pixel_width: 1\n"
" pixel_height: 1\n"
"}\n"
+ "media_duration_seconds: 20.0\n"
"init_segment_name: \"liveinit.mp4\"\n"
"segment_template: \"live-$NUMBER$.mp4\"\n"
"reference_time_scale: 1000\n"
diff --git a/packager/media/event/muxer_listener_internal.cc b/packager/media/event/muxer_listener_internal.cc
index 6a937b3182..48c74740c0 100644
--- a/packager/media/event/muxer_listener_internal.cc
+++ b/packager/media/event/muxer_listener_internal.cc
@@ -144,6 +144,12 @@ void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
AddVideoInfo(static_cast(&stream_info),
media_info);
}
+ if (stream_info.duration() > 0) {
+ // |stream_info.duration()| contains the media duration from the original
+ // media header, which is usually good enough.
+ media_info->set_media_duration_seconds(
+ static_cast(stream_info.duration()) / stream_info.time_scale());
+ }
}
void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,
diff --git a/packager/mpd/base/media_info.proto b/packager/mpd/base/media_info.proto
index 7186c900a4..140d9da6e0 100644
--- a/packager/mpd/base/media_info.proto
+++ b/packager/mpd/base/media_info.proto
@@ -134,9 +134,11 @@ message MediaInfo {
optional Range init_range = 6;
optional Range index_range = 7;
optional string media_file_name = 8;
- optional float media_duration_seconds = 9;
// END VOD only.
+ // VOD and static LIVE.
+ optional float media_duration_seconds = 9;
+
// LIVE only.
optional string init_segment_name = 10;
optional string segment_template = 11;
diff --git a/packager/mpd/base/mpd_builder.cc b/packager/mpd/base/mpd_builder.cc
index 0bea87df40..1220317478 100644
--- a/packager/mpd/base/mpd_builder.cc
+++ b/packager/mpd/base/mpd_builder.cc
@@ -1199,6 +1199,15 @@ xml::scoped_xml_ptr Representation::GetXml() {
return xml::scoped_xml_ptr();
}
+ // Set media duration for static mpd.
+ if (mpd_options_.mpd_type == MpdType::kStatic &&
+ media_info_.has_media_duration_seconds()) {
+ // Adding 'duration' attribute, so that this information can be used when
+ // generating one MPD file. This should be removed from the final MPD.
+ representation.SetFloatingPointAttribute(
+ "duration", media_info_.media_duration_seconds());
+ }
+
if (HasVODOnlyFields(media_info_) &&
!representation.AddVODOnlyInfo(media_info_)) {
LOG(ERROR) << "Failed to add VOD segment info.";
diff --git a/packager/mpd/base/mpd_utils.cc b/packager/mpd/base/mpd_utils.cc
index 3d571e089f..a3cd39d81a 100644
--- a/packager/mpd/base/mpd_utils.cc
+++ b/packager/mpd/base/mpd_utils.cc
@@ -33,8 +33,7 @@ std::string TextCodecString(const MediaInfo& media_info) {
bool HasVODOnlyFields(const MediaInfo& media_info) {
return media_info.has_init_range() || media_info.has_index_range() ||
- media_info.has_media_file_name() ||
- media_info.has_media_duration_seconds();
+ media_info.has_media_file_name();
}
bool HasLiveOnlyFields(const MediaInfo& media_info) {
diff --git a/packager/mpd/base/xml/xml_node.cc b/packager/mpd/base/xml/xml_node.cc
index 49343a4594..3dd571b6d8 100644
--- a/packager/mpd/base/xml/xml_node.cc
+++ b/packager/mpd/base/xml/xml_node.cc
@@ -294,12 +294,6 @@ bool RepresentationXmlNode::AddVODOnlyInfo(const MediaInfo& media_info) {
return false;
}
- if (media_info.has_media_duration_seconds()) {
- // Adding 'duration' attribute, so that this information can be used when
- // generating one MPD file. This should be removed from the final MPD.
- SetFloatingPointAttribute("duration", media_info.media_duration_seconds());
- }
-
return true;
}