Remove redundant attributes from Representation
- @width, @height, @frameRate for Representation element will not be set if the attributes are set at AdaptationSet level. Issue #55 Change-Id: Ib4e669142874f9e8f0ca773df9f87a3fef01b729
This commit is contained in:
parent
a040fb711c
commit
2909a53568
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||
</ContentProtection>
|
||||
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>output_video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="1079-1146" timescale="30000">
|
||||
<Initialization range="0-1078"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>output_video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="815-882" timescale="30000">
|
||||
<Initialization range="0-814"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||
<Period start="PT0S">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="875620" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="875620" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||
</ContentProtection>
|
||||
<Representation id="0" bandwidth="875620" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="875620" 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"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||
<Period start="PT0S">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="876470" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="876470" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||
<Representation id="0" bandwidth="876470" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="876470" 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"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||
<Period start="PT0S">
|
||||
<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" width="640" height="360" frameRate="30000/1001">
|
||||
<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"/>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="1" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="1" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="1" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>output_video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="815-882" timescale="30000">
|
||||
<Initialization range="0-814"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7694332599639893S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="265022" codecs="hev1.1.6.L63.80" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="265022" codecs="hev1.1.6.L63.80" mimeType="video/mp4" sar="1:1">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7360665798187256S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>output_0.mp4</BaseURL>
|
||||
<SegmentBase indexRange="815-882" timescale="30000">
|
||||
<Initialization range="0-814"/>
|
||||
|
|
|
@ -39,7 +39,8 @@ namespace {
|
|||
|
||||
const int kAdaptationSetGroupNotSet = -1;
|
||||
|
||||
AdaptationSet::Role MediaInfoTextTypeToRole(MediaInfo::TextInfo::TextType type) {
|
||||
AdaptationSet::Role MediaInfoTextTypeToRole(
|
||||
MediaInfo::TextInfo::TextType type) {
|
||||
switch (type) {
|
||||
case MediaInfo::TextInfo::UNKNOWN:
|
||||
LOG(WARNING) << "Unknown text type, assuming subtitle.";
|
||||
|
@ -731,27 +732,16 @@ void AdaptationSet::AddRole(Role role) {
|
|||
|
||||
// Creates a copy of <AdaptationSet> xml element, iterate thru all the
|
||||
// <Representation> (child) elements and add them to the copy.
|
||||
// Set all the attributes first and then add the children elements so that flags
|
||||
// can be passed to Representation to avoid setting redundant attributes. For
|
||||
// example, if AdaptationSet@width is set, then Representation@width is
|
||||
// redundant and should not be set.
|
||||
xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
||||
AdaptationSetXmlNode adaptation_set;
|
||||
|
||||
if (!adaptation_set.AddContentProtectionElements(
|
||||
content_protection_elements_)) {
|
||||
return xml::scoped_xml_ptr<xmlNode>();
|
||||
}
|
||||
for (std::set<Role>::const_iterator role_it = roles_.begin();
|
||||
role_it != roles_.end(); ++role_it) {
|
||||
adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011",
|
||||
RoleToText(*role_it));
|
||||
}
|
||||
|
||||
std::list<Representation*>::iterator representation_it =
|
||||
representations_.begin();
|
||||
|
||||
for (; representation_it != representations_.end(); ++representation_it) {
|
||||
xml::scoped_xml_ptr<xmlNode> child((*representation_it)->GetXml());
|
||||
if (!child || !adaptation_set.AddChild(child.Pass()))
|
||||
return xml::scoped_xml_ptr<xmlNode>();
|
||||
}
|
||||
bool suppress_representation_width = false;
|
||||
bool suppress_representation_height = false;
|
||||
bool suppress_representation_frame_rate = false;
|
||||
|
||||
adaptation_set.SetId(id_);
|
||||
adaptation_set.SetStringAttribute("contentType", content_type_);
|
||||
|
@ -761,17 +751,20 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
|||
|
||||
// Note that std::{set,map} are ordered, so the last element is the max value.
|
||||
if (video_widths_.size() == 1) {
|
||||
suppress_representation_width = true;
|
||||
adaptation_set.SetIntegerAttribute("width", *video_widths_.begin());
|
||||
} else if (video_widths_.size() > 1) {
|
||||
adaptation_set.SetIntegerAttribute("maxWidth", *video_widths_.rbegin());
|
||||
}
|
||||
if (video_heights_.size() == 1) {
|
||||
suppress_representation_height = true;
|
||||
adaptation_set.SetIntegerAttribute("height", *video_heights_.begin());
|
||||
} else if (video_heights_.size() > 1) {
|
||||
adaptation_set.SetIntegerAttribute("maxHeight", *video_heights_.rbegin());
|
||||
}
|
||||
|
||||
if (video_frame_rates_.size() == 1) {
|
||||
suppress_representation_frame_rate = true;
|
||||
adaptation_set.SetStringAttribute("frameRate",
|
||||
video_frame_rates_.begin()->second);
|
||||
} else if (video_frame_rates_.size() > 1) {
|
||||
|
@ -779,7 +772,8 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
|||
video_frame_rates_.rbegin()->second);
|
||||
}
|
||||
|
||||
// Note: must be checked before checking segments_aligned_ (below).
|
||||
// Note: must be checked before checking segments_aligned_ (below). So that
|
||||
// segments_aligned_ is set before checking below.
|
||||
if (mpd_type_ == MpdBuilder::kStatic) {
|
||||
CheckVodSegmentAlignment();
|
||||
}
|
||||
|
@ -797,6 +791,25 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
|||
if (group_ >= 0)
|
||||
adaptation_set.SetIntegerAttribute("group", group_);
|
||||
|
||||
if (!adaptation_set.AddContentProtectionElements(
|
||||
content_protection_elements_)) {
|
||||
return xml::scoped_xml_ptr<xmlNode>();
|
||||
}
|
||||
for (AdaptationSet::Role role : roles_)
|
||||
adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011", RoleToText(role));
|
||||
|
||||
for (Representation* representation : representations_) {
|
||||
if (suppress_representation_width)
|
||||
representation->SuppressOnce(Representation::kSuppressWidth);
|
||||
if (suppress_representation_height)
|
||||
representation->SuppressOnce(Representation::kSuppressHeight);
|
||||
if (suppress_representation_frame_rate)
|
||||
representation->SuppressOnce(Representation::kSuppressFrameRate);
|
||||
xml::scoped_xml_ptr<xmlNode> child(representation->GetXml());
|
||||
if (!child || !adaptation_set.AddChild(child.Pass()))
|
||||
return xml::scoped_xml_ptr<xmlNode>();
|
||||
}
|
||||
|
||||
return adaptation_set.PassScopedPtr();
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1022,8 @@ Representation::Representation(
|
|||
bandwidth_estimator_(BandwidthEstimator::kUseAllBlocks),
|
||||
mpd_options_(mpd_options),
|
||||
start_number_(1),
|
||||
state_change_listener_(state_change_listener.Pass()) {}
|
||||
state_change_listener_(state_change_listener.Pass()),
|
||||
output_suppression_flags_(0) {}
|
||||
|
||||
Representation::~Representation() {}
|
||||
|
||||
|
@ -1131,7 +1145,11 @@ xml::scoped_xml_ptr<xmlNode> Representation::GetXml() {
|
|||
const bool has_audio_info = media_info_.has_audio_info();
|
||||
|
||||
if (has_video_info &&
|
||||
!representation.AddVideoInfo(media_info_.video_info())) {
|
||||
!representation.AddVideoInfo(
|
||||
media_info_.video_info(),
|
||||
!(output_suppression_flags_ & kSuppressWidth),
|
||||
!(output_suppression_flags_ & kSuppressHeight),
|
||||
!(output_suppression_flags_ & kSuppressFrameRate))) {
|
||||
LOG(ERROR) << "Failed to add video info to Representation XML.";
|
||||
return xml::scoped_xml_ptr<xmlNode>();
|
||||
}
|
||||
|
@ -1162,9 +1180,14 @@ xml::scoped_xml_ptr<xmlNode> Representation::GetXml() {
|
|||
// TODO(rkuroiwa): It is likely that all representations have the exact same
|
||||
// SegmentTemplate. Optimize and propagate the tag up to AdaptationSet level.
|
||||
|
||||
output_suppression_flags_ = 0;
|
||||
return representation.PassScopedPtr();
|
||||
}
|
||||
|
||||
void Representation::SuppressOnce(SuppressFlag flag) {
|
||||
output_suppression_flags_ |= flag;
|
||||
}
|
||||
|
||||
bool Representation::HasRequiredMediaInfoFields() {
|
||||
if (HasVODOnlyFields(media_info_) && HasLiveOnlyFields(media_info_)) {
|
||||
LOG(ERROR) << "MediaInfo cannot have both VOD and Live fields.";
|
||||
|
|
|
@ -414,6 +414,12 @@ class RepresentationStateChangeListener {
|
|||
/// well as optional ContentProtection elements for that stream.
|
||||
class Representation {
|
||||
public:
|
||||
enum SuppressFlag {
|
||||
kSuppressWidth = 1,
|
||||
kSuppressHeight = 2,
|
||||
kSuppressFrameRate = 4,
|
||||
};
|
||||
|
||||
virtual ~Representation();
|
||||
|
||||
/// Tries to initialize the instance. If this does not succeed, the instance
|
||||
|
@ -470,6 +476,16 @@ class Representation {
|
|||
/// @return Copy of <Representation>.
|
||||
xml::scoped_xml_ptr<xmlNode> GetXml();
|
||||
|
||||
/// By calling this methods, the next time GetXml() is
|
||||
/// called, the corresponding attributes will not be set.
|
||||
/// For example, if SuppressOnce(kSuppressWidth) is called, then GetXml() will
|
||||
/// return a <Representation> element without a @width attribute.
|
||||
/// Note that it only applies to the next call to GetXml(), calling GetXml()
|
||||
/// again without calling this methods will return a <Representation> element
|
||||
/// with the attribute.
|
||||
/// This may be called multiple times to set different (or the same) flags.
|
||||
void SuppressOnce(SuppressFlag flag);
|
||||
|
||||
/// @return ID number for <Representation>.
|
||||
uint32_t id() const { return id_; }
|
||||
|
||||
|
@ -540,6 +556,9 @@ class Representation {
|
|||
// right methods at right timings.
|
||||
scoped_ptr<RepresentationStateChangeListener> state_change_listener_;
|
||||
|
||||
// Bit vector for tracking witch attributes should not be output.
|
||||
int output_suppression_flags_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Representation);
|
||||
};
|
||||
|
||||
|
|
|
@ -110,6 +110,8 @@ class MpdBuilderTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
protected:
|
||||
// Creates a new AdaptationSet and adds a Representation element using
|
||||
// |media_info|.
|
||||
void AddRepresentation(const MediaInfo& media_info) {
|
||||
AdaptationSet* adaptation_set = mpd_.AddAdaptationSet("");
|
||||
ASSERT_TRUE(adaptation_set);
|
||||
|
@ -261,8 +263,7 @@ class SegmentTemplateTest : public DynamicMpdBuilderTest {
|
|||
" frameRate=\"10/5\" contentType=\"video\""
|
||||
" par=\"3:2\" segmentAlignment=\"true\">\n"
|
||||
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
||||
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
||||
"height=\"480\" frameRate=\"10/5\" sar=\"1:1\">\n"
|
||||
" codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\">\n"
|
||||
" <SegmentTemplate timescale=\"1000\" "
|
||||
"initialization=\"init.mp4\" media=\"$Time$.mp4\">\n"
|
||||
" <SegmentTimeline>\n%s"
|
||||
|
@ -347,11 +348,10 @@ class TimeShiftBufferDepthTest : public SegmentTemplateTest {
|
|||
" frameRate=\"10/2\" contentType=\"video\""
|
||||
" par=\"3:2\" segmentAlignment=\"true\">\n"
|
||||
" <Representation id=\"0\" bandwidth=\"%" PRIu64 "\" "
|
||||
"codecs=\"avc1.010101\" mimeType=\"video/mp4\" width=\"720\" "
|
||||
"height=\"480\" frameRate=\"10/2\" sar=\"1:1\">\n"
|
||||
" codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\">\n"
|
||||
" <SegmentTemplate timescale=\"1000\" "
|
||||
"initialization=\"init.mp4\" media=\"$Number$.mp4\" "
|
||||
"startNumber=\"%d\">\n"
|
||||
" initialization=\"init.mp4\" media=\"$Number$.mp4\" "
|
||||
" startNumber=\"%d\">\n"
|
||||
" <SegmentTimeline>\n"
|
||||
" %s\n"
|
||||
" </SegmentTimeline>\n"
|
||||
|
@ -1103,6 +1103,147 @@ TEST_F(CommonMpdBuilderTest,
|
|||
ExpectAttributeNotSet("frameRate", adaptation_set_xml.get()));
|
||||
}
|
||||
|
||||
// Verify that Suppress*() methods work.
|
||||
TEST_F(CommonMpdBuilderTest, SuppressRepresentationAttributes) {
|
||||
const char kTestMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 720\n"
|
||||
" height: 480\n"
|
||||
" time_scale: 10\n"
|
||||
" frame_duration: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
|
||||
auto representation =
|
||||
CreateRepresentation(ConvertToMediaInfo(kTestMediaInfo), MpdOptions(),
|
||||
kAnyRepresentationId, NoListener());
|
||||
|
||||
representation->SuppressOnce(Representation::kSuppressWidth);
|
||||
xml::scoped_xml_ptr<xmlNode> no_width(representation->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeNotSet("width", no_width.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("height", "480", no_width.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("frameRate", "10/10", no_width.get()));
|
||||
|
||||
representation->SuppressOnce(Representation::kSuppressHeight);
|
||||
xml::scoped_xml_ptr<xmlNode> no_height(representation->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeNotSet("height", no_height.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("width", "720", no_height.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("frameRate", "10/10", no_height.get()));
|
||||
|
||||
representation->SuppressOnce(Representation::kSuppressFrameRate);
|
||||
xml::scoped_xml_ptr<xmlNode> no_frame_rate(representation->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("frameRate", no_frame_rate.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("width", "720", no_frame_rate.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("height", "480", no_frame_rate.get()));
|
||||
}
|
||||
|
||||
// Attribute values that are common to all the children Representations should
|
||||
// propagate up to AdaptationSet. Otherwise, each Representation should have
|
||||
// its own values.
|
||||
TEST_F(CommonMpdBuilderTest, BubbleUpAttributesToAdaptationSet) {
|
||||
const char k1080p[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 1920\n"
|
||||
" height: 1080\n"
|
||||
" time_scale: 30\n"
|
||||
" frame_duration: 1\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
|
||||
// Different width from the one above.
|
||||
const char kDifferentWidth[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 1080\n"
|
||||
" height: 1080\n"
|
||||
" time_scale: 30\n"
|
||||
" frame_duration: 1\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
|
||||
// Different height from ones above
|
||||
const char kDifferentHeight[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 1440\n"
|
||||
" height: 900\n"
|
||||
" time_scale: 30\n"
|
||||
" frame_duration: 1\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
|
||||
const char kDifferentFrameRate[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 1920\n"
|
||||
" height: 1080\n"
|
||||
" time_scale: 15\n"
|
||||
" frame_duration: 1\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
|
||||
AdaptationSet* adaptation_set = mpd_.AddAdaptationSet("");
|
||||
ASSERT_TRUE(adaptation_set);
|
||||
ASSERT_TRUE(adaptation_set->AddRepresentation(ConvertToMediaInfo(k1080p)));
|
||||
|
||||
xml::scoped_xml_ptr<xmlNode> all_attributes_on_adaptation_set(
|
||||
adaptation_set->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeEqString(
|
||||
"width", "1920", all_attributes_on_adaptation_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeEqString(
|
||||
"height", "1080", all_attributes_on_adaptation_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeEqString(
|
||||
"frameRate", "30/1", all_attributes_on_adaptation_set.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(kDifferentWidth)));
|
||||
xml::scoped_xml_ptr<xmlNode> width_not_set(adaptation_set->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(ExpectAttributeNotSet("width", width_not_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("height", "1080", width_not_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("frameRate", "30/1", width_not_set.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(kDifferentHeight)));
|
||||
xml::scoped_xml_ptr<xmlNode> width_height_not_set(adaptation_set->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("width", width_height_not_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("height", width_height_not_set.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeEqString("frameRate", "30/1", width_height_not_set.get()));
|
||||
|
||||
ASSERT_TRUE(adaptation_set->AddRepresentation(
|
||||
ConvertToMediaInfo(kDifferentFrameRate)));
|
||||
xml::scoped_xml_ptr<xmlNode> no_common_attributes(adaptation_set->GetXml());
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("width", no_common_attributes.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("height", no_common_attributes.get()));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
ExpectAttributeNotSet("frameRate", no_common_attributes.get()));
|
||||
}
|
||||
|
||||
// Verify that subsegmentAlignment is set to true if all the Representations'
|
||||
// segments are aligned and the MPD type is static.
|
||||
// Also checking that not all Representations have to be added before calling
|
||||
|
@ -1454,8 +1595,7 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
" <cenc:pssh>any value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" mimeType=\"video/mp4\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
|
@ -1487,8 +1627,7 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) {
|
|||
//" <cenc:pssh>new pssh value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" mimeType=\"video/mp4\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
|
@ -1539,8 +1678,7 @@ TEST_F(CommonMpdBuilderTest, UpdateToRemovePsshElement) {
|
|||
" value=\"some value\">"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" mimeType=\"video/mp4\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
|
@ -1573,8 +1711,7 @@ TEST_F(CommonMpdBuilderTest, UpdateToRemovePsshElement) {
|
|||
//" <cenc:pssh>added pssh value</cenc:pssh>"
|
||||
" </ContentProtection>"
|
||||
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"avc1\""
|
||||
" mimeType=\"video/mp4\" width=\"1920\" height=\"1080\""
|
||||
" frameRate=\"3000/100\"/>"
|
||||
" mimeType=\"video/mp4\"/>"
|
||||
" </AdaptationSet>"
|
||||
" </Period>"
|
||||
"</MPD>";
|
||||
|
@ -1589,6 +1726,18 @@ TEST_F(StaticMpdBuilderTest, Video) {
|
|||
EXPECT_NO_FATAL_FAILURE(CheckMpd(kFileNameExpectedMpdOutputVideo1));
|
||||
}
|
||||
|
||||
TEST_F(StaticMpdBuilderTest, TwoVideosWithDifferentResolutions) {
|
||||
AdaptationSet* adaptation_set = mpd_.AddAdaptationSet("");
|
||||
|
||||
MediaInfo media_info1 = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
||||
ASSERT_TRUE(adaptation_set->AddRepresentation(media_info1));
|
||||
|
||||
MediaInfo media_info2 = GetTestMediaInfo(kFileNameVideoMediaInfo2);
|
||||
ASSERT_TRUE(adaptation_set->AddRepresentation(media_info2));
|
||||
|
||||
EXPECT_NO_FATAL_FAILURE(CheckMpd(kFileNameExpectedMpdOutputVideo1And2));
|
||||
}
|
||||
|
||||
// Add both video and audio and check the output.
|
||||
TEST_F(StaticMpdBuilderTest, VideoAndAudio) {
|
||||
MediaInfo video_media_info = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
||||
|
|
|
@ -215,7 +215,10 @@ RepresentationXmlNode::RepresentationXmlNode()
|
|||
: RepresentationBaseXmlNode("Representation") {}
|
||||
RepresentationXmlNode::~RepresentationXmlNode() {}
|
||||
|
||||
bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info) {
|
||||
bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info,
|
||||
bool set_width,
|
||||
bool set_height,
|
||||
bool set_frame_rate) {
|
||||
if (!video_info.has_width() || !video_info.has_height()) {
|
||||
LOG(ERROR) << "Missing width or height for adding a video info.";
|
||||
return false;
|
||||
|
@ -227,11 +230,15 @@ bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info) {
|
|||
base::IntToString(video_info.pixel_height()));
|
||||
}
|
||||
|
||||
if (set_width)
|
||||
SetIntegerAttribute("width", video_info.width());
|
||||
if (set_height)
|
||||
SetIntegerAttribute("height", video_info.height());
|
||||
if (set_frame_rate) {
|
||||
SetStringAttribute("frameRate",
|
||||
base::IntToString(video_info.time_scale()) + "/" +
|
||||
base::IntToString(video_info.frame_duration()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,9 +132,15 @@ class RepresentationXmlNode : public RepresentationBaseXmlNode {
|
|||
|
||||
/// Adds video metadata to the MPD.
|
||||
/// @param video_info constains the VideoInfo for a Representation.
|
||||
/// @param set_width is a flag for setting the width attribute.
|
||||
/// @param set_height is a flag for setting the height attribute.
|
||||
/// @param set_frame_rate is a flag for setting the frameRate attribute.
|
||||
/// @return true if successfully set attributes and children elements (if
|
||||
/// applicable), false otherwise.
|
||||
bool AddVideoInfo(const MediaInfo::VideoInfo& video_info);
|
||||
bool AddVideoInfo(const MediaInfo::VideoInfo& video_info,
|
||||
bool set_width,
|
||||
bool set_height,
|
||||
bool set_frame_rate);
|
||||
|
||||
/// Adds audio metadata to the MPD.
|
||||
/// @param audio_info constains the AudioInfos for a Representation.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||
<Representation id="1" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||
<Representation id="1" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||
<SegmentBase indexRange="121-221" timescale="1000">
|
||||
<Initialization range="0-120"/>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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" availabilityStartTime="2011-12-25T12:30:00" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011">
|
||||
<Period start="PT0S">
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/5" contentType="video" par="3:2" segmentAlignment="true">
|
||||
<Representation id="0" bandwidth="102400" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/5" sar="1:1">
|
||||
<Representation id="0" bandwidth="102400" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
<SegmentTemplate timescale="1000" initialization="init.mp4" media="$Time$.mp4">
|
||||
<SegmentTimeline>
|
||||
<S t="0" d="10"/>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||
<Representation id="3" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||
<Representation id="3" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||
<SegmentBase indexRange="121-221" timescale="1000">
|
||||
<Initialization range="0-120"/>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>test_output_file_name1.mp4</BaseURL>
|
||||
<SegmentBase indexRange="121-221" timescale="1000">
|
||||
<Initialization range="0-120"/>
|
||||
|
|
Loading…
Reference in New Issue