Fix mpd duration not set in static live manifest

Closes #201

Change-Id: Ie9ab58ec58e1b135931a6576fb46145454b0f049
This commit is contained in:
Kongqun Yang 2017-02-08 16:42:44 -08:00 committed by KongQun Yang
parent 871c7b38d6
commit 94cadf9e28
9 changed files with 62 additions and 9 deletions

View File

@ -333,6 +333,14 @@ class PackagerAppTest(unittest.TestCase):
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden') self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
self._DiffLiveMpdGold(self.mpd_output, 'bear-640x360-av-live-golden.mpd') 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): def testPackageWithLiveProfileAndEncryption(self):
self.packager.Package( self.packager.Package(
self._GetStreams(['audio', 'video'], live=True), self._GetStreams(['audio', 'video'], live=True),
@ -493,6 +501,7 @@ class PackagerAppTest(unittest.TestCase):
dash_if_iop=True, dash_if_iop=True,
output_media_info=False, output_media_info=False,
output_hls=False, output_hls=False,
generate_static_mpd=False,
use_fake_clock=True): use_fake_clock=True):
flags = [] flags = []
if widevine_encryption: if widevine_encryption:
@ -528,6 +537,9 @@ class PackagerAppTest(unittest.TestCase):
else: else:
flags += ['--mpd_output', self.mpd_output] flags += ['--mpd_output', self.mpd_output]
if generate_static_mpd:
flags += ['--generate_static_mpd']
flags.append('--segment_duration=1') flags.append('--segment_duration=1')
# Use fake clock, so output can be compared. # Use fake clock, so output can be compared.
if use_fake_clock: if use_fake_clock:

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
<Period id="0">
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
<Representation id="0" bandwidth="872999" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
<SegmentTimeline>
<S t="2002" d="30030" r="1"/>
<S t="62062" d="22022"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
<Representation id="1" bandwidth="121855" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<SegmentTemplate timescale="44100" initialization="output_audio-init.mp4" media="output_audio-$Number$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="45056" r="1"/>
<S t="90112" d="31744"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>

View File

@ -119,6 +119,8 @@ void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
uint64_t file_size) { uint64_t file_size) {
if (mpd_notifier_->dash_profile() == DashProfile::kLive) { if (mpd_notifier_->dash_profile() == DashProfile::kLive) {
DCHECK(subsegments_.empty()); 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) if (mpd_notifier_->mpd_type() == MpdType::kStatic)
mpd_notifier_->Flush(); mpd_notifier_->Flush();
return; return;

View File

@ -295,6 +295,7 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
" pixel_width: 1\n" " pixel_width: 1\n"
" pixel_height: 1\n" " pixel_height: 1\n"
"}\n" "}\n"
"media_duration_seconds: 20.0\n"
"init_segment_name: \"liveinit.mp4\"\n" "init_segment_name: \"liveinit.mp4\"\n"
"segment_template: \"live-$NUMBER$.mp4\"\n" "segment_template: \"live-$NUMBER$.mp4\"\n"
"reference_time_scale: 1000\n" "reference_time_scale: 1000\n"
@ -368,6 +369,7 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
" pixel_width: 1\n" " pixel_width: 1\n"
" pixel_height: 1\n" " pixel_height: 1\n"
"}\n" "}\n"
"media_duration_seconds: 20.0\n"
"init_segment_name: \"liveinit.mp4\"\n" "init_segment_name: \"liveinit.mp4\"\n"
"segment_template: \"live-$NUMBER$.mp4\"\n" "segment_template: \"live-$NUMBER$.mp4\"\n"
"reference_time_scale: 1000\n" "reference_time_scale: 1000\n"

View File

@ -144,6 +144,12 @@ void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info), AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info),
media_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<double>(stream_info.duration()) / stream_info.time_scale());
}
} }
void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options, void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,

View File

@ -134,9 +134,11 @@ message MediaInfo {
optional Range init_range = 6; optional Range init_range = 6;
optional Range index_range = 7; optional Range index_range = 7;
optional string media_file_name = 8; optional string media_file_name = 8;
optional float media_duration_seconds = 9;
// END VOD only. // END VOD only.
// VOD and static LIVE.
optional float media_duration_seconds = 9;
// LIVE only. // LIVE only.
optional string init_segment_name = 10; optional string init_segment_name = 10;
optional string segment_template = 11; optional string segment_template = 11;

View File

@ -1199,6 +1199,15 @@ xml::scoped_xml_ptr<xmlNode> Representation::GetXml() {
return xml::scoped_xml_ptr<xmlNode>(); return xml::scoped_xml_ptr<xmlNode>();
} }
// 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_) && if (HasVODOnlyFields(media_info_) &&
!representation.AddVODOnlyInfo(media_info_)) { !representation.AddVODOnlyInfo(media_info_)) {
LOG(ERROR) << "Failed to add VOD segment info."; LOG(ERROR) << "Failed to add VOD segment info.";

View File

@ -33,8 +33,7 @@ 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_name();
media_info.has_media_duration_seconds();
} }
bool HasLiveOnlyFields(const MediaInfo& media_info) { bool HasLiveOnlyFields(const MediaInfo& media_info) {

View File

@ -294,12 +294,6 @@ bool RepresentationXmlNode::AddVODOnlyInfo(const MediaInfo& media_info) {
return false; 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; return true;
} }