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; }