From 2909a53568272f5d87d5e6e21eafce30bd2f05c7 Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Mon, 4 Jan 2016 16:33:53 -0800 Subject: [PATCH] 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 --- .../testdata/bear-640x360-av-cenc-golden.mpd | 2 +- .../bear-640x360-av-cenc-iop-golden.mpd | 2 +- .../test/testdata/bear-640x360-av-golden.mpd | 2 +- .../bear-640x360-av-live-cenc-golden.mpd | 2 +- .../bear-640x360-av-live-cenc-iop-golden.mpd | 2 +- ...r-640x360-av-live-cenc-rotation-golden.mpd | 2 +- ...0x360-av-live-cenc-rotation-iop-golden.mpd | 2 +- .../testdata/bear-640x360-av-live-golden.mpd | 2 +- .../test/testdata/bear-640x360-avt-golden.mpd | 2 +- .../bear-640x360-hevc-v-cenc-golden.mpd | 2 +- .../test/testdata/bear-640x360-v-golden.mpd | 2 +- packager/mpd/base/mpd_builder.cc | 67 ++++--- packager/mpd/base/mpd_builder.h | 19 ++ packager/mpd/base/mpd_builder_unittest.cc | 179 ++++++++++++++++-- packager/mpd/base/xml/xml_node.cc | 19 +- packager/mpd/base/xml/xml_node.h | 8 +- ..._video_media_info1_expected_mpd_output.txt | 2 +- packager/mpd/test/data/dynamic_normal_mpd.txt | 2 +- ...guage_audio_media_info_expected_output.txt | 2 +- .../video_media_info1_expected_mpd_output.txt | 2 +- 20 files changed, 263 insertions(+), 59 deletions(-) diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd index 4a93b551c3..ebc2354c38 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-golden.mpd @@ -3,7 +3,7 @@ - + AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2 diff --git a/packager/app/test/testdata/bear-640x360-av-cenc-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-cenc-iop-golden.mpd index 10667545aa..53b2a086a9 100644 --- a/packager/app/test/testdata/bear-640x360-av-cenc-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-cenc-iop-golden.mpd @@ -7,7 +7,7 @@ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2 - + output_video.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-golden.mpd b/packager/app/test/testdata/bear-640x360-av-golden.mpd index a5a8c9b634..971115fdfd 100644 --- a/packager/app/test/testdata/bear-640x360-av-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-golden.mpd @@ -3,7 +3,7 @@ - + output_video.mp4 diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd index 836af9866d..dcb921e2d6 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-golden.mpd @@ -3,7 +3,7 @@ - + AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2 diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-iop-golden.mpd index 4dc639a9fd..deb01bae4b 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-iop-golden.mpd @@ -7,7 +7,7 @@ AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2 - + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd index c438cd3b37..04bd50f74f 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-golden.mpd @@ -3,7 +3,7 @@ - + diff --git a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-iop-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-iop-golden.mpd index 1d38bb188c..e7dcb2ae89 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-iop-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-cenc-rotation-iop-golden.mpd @@ -5,7 +5,7 @@ - + diff --git a/packager/app/test/testdata/bear-640x360-av-live-golden.mpd b/packager/app/test/testdata/bear-640x360-av-live-golden.mpd index 94cf9ccc2b..8917ceab39 100644 --- a/packager/app/test/testdata/bear-640x360-av-live-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-av-live-golden.mpd @@ -3,7 +3,7 @@ - + diff --git a/packager/app/test/testdata/bear-640x360-avt-golden.mpd b/packager/app/test/testdata/bear-640x360-avt-golden.mpd index c0e04a7a91..6a2d908edb 100644 --- a/packager/app/test/testdata/bear-640x360-avt-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-avt-golden.mpd @@ -8,7 +8,7 @@ - + output_video.mp4 diff --git a/packager/app/test/testdata/bear-640x360-hevc-v-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-hevc-v-cenc-golden.mpd index 7dff2a0281..31e5ae397b 100644 --- a/packager/app/test/testdata/bear-640x360-hevc-v-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-hevc-v-cenc-golden.mpd @@ -3,7 +3,7 @@ - + AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2 diff --git a/packager/app/test/testdata/bear-640x360-v-golden.mpd b/packager/app/test/testdata/bear-640x360-v-golden.mpd index c374b9fd55..644644fec2 100644 --- a/packager/app/test/testdata/bear-640x360-v-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-v-golden.mpd @@ -3,7 +3,7 @@ - + output_0.mp4 diff --git a/packager/mpd/base/mpd_builder.cc b/packager/mpd/base/mpd_builder.cc index 6a25ed9707..8dbd6386cf 100644 --- a/packager/mpd/base/mpd_builder.cc +++ b/packager/mpd/base/mpd_builder.cc @@ -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 xml element, iterate thru all the // (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 AdaptationSet::GetXml() { AdaptationSetXmlNode adaptation_set; - if (!adaptation_set.AddContentProtectionElements( - content_protection_elements_)) { - return xml::scoped_xml_ptr(); - } - for (std::set::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::iterator representation_it = - representations_.begin(); - - for (; representation_it != representations_.end(); ++representation_it) { - xml::scoped_xml_ptr child((*representation_it)->GetXml()); - if (!child || !adaptation_set.AddChild(child.Pass())) - return xml::scoped_xml_ptr(); - } + 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 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 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 AdaptationSet::GetXml() { if (group_ >= 0) adaptation_set.SetIntegerAttribute("group", group_); + if (!adaptation_set.AddContentProtectionElements( + content_protection_elements_)) { + return xml::scoped_xml_ptr(); + } + 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 child(representation->GetXml()); + if (!child || !adaptation_set.AddChild(child.Pass())) + return xml::scoped_xml_ptr(); + } + 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 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(); } @@ -1162,9 +1180,14 @@ xml::scoped_xml_ptr 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."; diff --git a/packager/mpd/base/mpd_builder.h b/packager/mpd/base/mpd_builder.h index d296bbfc1b..e58317994d 100644 --- a/packager/mpd/base/mpd_builder.h +++ b/packager/mpd/base/mpd_builder.h @@ -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 . xml::scoped_xml_ptr 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 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 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 . uint32_t id() const { return id_; } @@ -540,6 +556,9 @@ class Representation { // right methods at right timings. scoped_ptr state_change_listener_; + // Bit vector for tracking witch attributes should not be output. + int output_suppression_flags_; + DISALLOW_COPY_AND_ASSIGN(Representation); }; diff --git a/packager/mpd/base/mpd_builder_unittest.cc b/packager/mpd/base/mpd_builder_unittest.cc index f4ca90a6bf..4932ea3c8a 100644 --- a/packager/mpd/base/mpd_builder_unittest.cc +++ b/packager/mpd/base/mpd_builder_unittest.cc @@ -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" " \n" + " codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\">\n" " \n" " \n%s" @@ -347,13 +348,12 @@ class TimeShiftBufferDepthTest : public SegmentTemplateTest { " frameRate=\"10/2\" contentType=\"video\"" " par=\"3:2\" segmentAlignment=\"true\">\n" " \n" + " codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\">\n" " \n" + " initialization=\"init.mp4\" media=\"$Number$.mp4\" " + " startNumber=\"%d\">\n" " \n" - " %s\n" + " %s\n" " \n" " \n" " \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 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 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 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 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 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 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 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) { " any value" " " " " + " mimeType=\"video/mp4\"/>" " " " " ""; @@ -1487,8 +1627,7 @@ TEST_F(CommonMpdBuilderTest, AdaptationSetAddContentProtectionAndUpdate) { //" new pssh value" " " " " + " mimeType=\"video/mp4\"/>" " " " " ""; @@ -1539,8 +1678,7 @@ TEST_F(CommonMpdBuilderTest, UpdateToRemovePsshElement) { " value=\"some value\">" " " " " + " mimeType=\"video/mp4\"/>" " " " " ""; @@ -1573,8 +1711,7 @@ TEST_F(CommonMpdBuilderTest, UpdateToRemovePsshElement) { //" added pssh value" " " " " + " mimeType=\"video/mp4\"/>" " " " " ""; @@ -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); diff --git a/packager/mpd/base/xml/xml_node.cc b/packager/mpd/base/xml/xml_node.cc index 6480259b47..7e2b1e66b7 100644 --- a/packager/mpd/base/xml/xml_node.cc +++ b/packager/mpd/base/xml/xml_node.cc @@ -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())); } - SetIntegerAttribute("width", video_info.width()); - SetIntegerAttribute("height", video_info.height()); - SetStringAttribute("frameRate", - base::IntToString(video_info.time_scale()) + "/" + - base::IntToString(video_info.frame_duration())); + 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; } diff --git a/packager/mpd/base/xml/xml_node.h b/packager/mpd/base/xml/xml_node.h index 39c7266169..e0d481ef97 100644 --- a/packager/mpd/base/xml/xml_node.h +++ b/packager/mpd/base/xml/xml_node.h @@ -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. diff --git a/packager/mpd/test/data/audio_media_info1_video_media_info1_expected_mpd_output.txt b/packager/mpd/test/data/audio_media_info1_video_media_info1_expected_mpd_output.txt index a058d16dec..587ccaa537 100644 --- a/packager/mpd/test/data/audio_media_info1_video_media_info1_expected_mpd_output.txt +++ b/packager/mpd/test/data/audio_media_info1_video_media_info1_expected_mpd_output.txt @@ -2,7 +2,7 @@ - + test_output_file_name1.mp4 diff --git a/packager/mpd/test/data/dynamic_normal_mpd.txt b/packager/mpd/test/data/dynamic_normal_mpd.txt index c15790b1b3..075c9e53ac 100644 --- a/packager/mpd/test/data/dynamic_normal_mpd.txt +++ b/packager/mpd/test/data/dynamic_normal_mpd.txt @@ -2,7 +2,7 @@ - + diff --git a/packager/mpd/test/data/language_audio_media_info_expected_output.txt b/packager/mpd/test/data/language_audio_media_info_expected_output.txt index 1e6aa020cd..68dd6b8afc 100644 --- a/packager/mpd/test/data/language_audio_media_info_expected_output.txt +++ b/packager/mpd/test/data/language_audio_media_info_expected_output.txt @@ -2,7 +2,7 @@ - + test_output_file_name1.mp4 diff --git a/packager/mpd/test/data/video_media_info1_expected_mpd_output.txt b/packager/mpd/test/data/video_media_info1_expected_mpd_output.txt index c0411ce5ec..d5c4429555 100644 --- a/packager/mpd/test/data/video_media_info1_expected_mpd_output.txt +++ b/packager/mpd/test/data/video_media_info1_expected_mpd_output.txt @@ -2,7 +2,7 @@ - + test_output_file_name1.mp4