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:
Rintaro Kuroiwa 2016-01-04 16:33:53 -08:00
parent a040fb711c
commit 2909a53568
20 changed files with 263 additions and 59 deletions

View File

@ -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>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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>

View File

@ -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"/>

View File

@ -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">

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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>

View File

@ -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"/>

View File

@ -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.";

View File

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

View File

@ -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);

View File

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

View File

@ -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.

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>