7 #include "packager/mpd/base/xml/xml_node.h"
12 #include "packager/base/logging.h"
13 #include "packager/base/macros.h"
14 #include "packager/base/stl_util.h"
15 #include "packager/base/strings/string_number_conversions.h"
16 #include "packager/mpd/base/media_info.pb.h"
17 #include "packager/mpd/base/segment_info.h"
21 using edash_packager::MediaInfo;
22 typedef edash_packager::MediaInfo::AudioInfo AudioInfo;
23 typedef edash_packager::MediaInfo::VideoInfo VideoInfo;
24 typedef MediaInfo::ContentProtectionXml ContentProtectionXml;
25 typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
27 namespace edash_packager {
31 std::string RangeToString(
const Range& range) {
32 return base::Uint64ToString(range.begin()) +
"-" +
33 base::Uint64ToString(range.end());
36 bool PopulateSegmentTimeline(
const std::list<SegmentInfo>& segment_infos,
38 for (std::list<SegmentInfo>::const_iterator it = segment_infos.begin();
39 it != segment_infos.end();
42 s_element.SetIntegerAttribute(
"t", it->start_time);
43 s_element.SetIntegerAttribute(
"d", it->duration);
45 s_element.SetIntegerAttribute(
"r", it->repeat);
47 CHECK(segment_timeline->
AddChild(s_element.PassScopedPtr()));
62 XmlNode::~XmlNode() {}
67 if (!xmlAddChild(node_.get(), child.get()))
72 ignore_result(child.release());
77 for (
size_t element_index = 0; element_index < elements.size();
79 const Element& child_element = elements[element_index];
80 XmlNode child_node(child_element.name.c_str());
81 for (std::map<std::string, std::string>::const_iterator attribute_it =
82 child_element.attributes.begin();
83 attribute_it != child_element.attributes.end(); ++attribute_it) {
85 attribute_it->second);
88 if (!child_node.AddElements(child_element.subelements))
91 child_node.SetContent(child_element.content);
93 if (!xmlAddChild(node_.get(), child_node.GetRawPtr())) {
94 LOG(ERROR) <<
"Failed to set child " << child_element.name
95 <<
" to parent element "
96 <<
reinterpret_cast<const char*
>(node_->name);
101 ignore_result(child_node.Release());
107 const std::string& attribute) {
109 DCHECK(attribute_name);
110 xmlSetProp(node_.get(), BAD_CAST attribute_name, BAD_CAST attribute.c_str());
115 DCHECK(attribute_name);
116 xmlSetProp(node_.get(),
117 BAD_CAST attribute_name,
118 BAD_CAST (base::Uint64ToString(number).c_str()));
124 DCHECK(attribute_name);
125 xmlSetProp(node_.get(),
126 BAD_CAST attribute_name,
127 BAD_CAST (base::DoubleToString(number).c_str()));
136 xmlNodeSetContent(node_.get(), BAD_CAST content.c_str());
140 DVLOG(2) <<
"Passing node_.";
146 DVLOG(2) <<
"Releasing node_.";
148 return node_.release();
155 RepresentationBaseXmlNode::RepresentationBaseXmlNode(
const char* name)
157 RepresentationBaseXmlNode::~RepresentationBaseXmlNode() {}
159 bool RepresentationBaseXmlNode::AddContentProtectionElements(
160 const std::list<ContentProtectionElement>& content_protection_elements) {
161 std::list<ContentProtectionElement>::const_iterator content_protection_it =
162 content_protection_elements.begin();
163 for (; content_protection_it != content_protection_elements.end();
164 ++content_protection_it) {
165 if (!AddContentProtectionElement(*content_protection_it))
172 bool RepresentationBaseXmlNode::AddContentProtectionElement(
173 const ContentProtectionElement& content_protection_element) {
174 XmlNode content_protection_node(
"ContentProtection");
177 if (!content_protection_element.value.empty()) {
178 content_protection_node.SetStringAttribute(
179 "value", content_protection_element.value);
181 content_protection_node.SetStringAttribute(
182 "schemeIdUri", content_protection_element.scheme_id_uri);
184 typedef std::map<std::string, std::string> AttributesMapType;
185 const AttributesMapType& additional_attributes =
186 content_protection_element.additional_attributes;
188 AttributesMapType::const_iterator attributes_it =
189 additional_attributes.begin();
190 for (; attributes_it != additional_attributes.end(); ++attributes_it) {
191 content_protection_node.SetStringAttribute(attributes_it->first.c_str(),
192 attributes_it->second);
195 if (!content_protection_node.AddElements(
196 content_protection_element.subelements)) {
199 return AddChild(content_protection_node.PassScopedPtr());
202 AdaptationSetXmlNode::AdaptationSetXmlNode()
203 : RepresentationBaseXmlNode(
"AdaptationSet") {}
204 AdaptationSetXmlNode::~AdaptationSetXmlNode() {}
207 const std::string& value) {
214 RepresentationXmlNode::RepresentationXmlNode()
216 RepresentationXmlNode::~RepresentationXmlNode() {}
219 if (!video_info.has_width() || !video_info.has_height()) {
220 LOG(ERROR) <<
"Missing width or height for adding a video info.";
224 if (video_info.has_pixel_width() && video_info.has_pixel_height()) {
227 base::IntToString(video_info.pixel_height()));
233 base::IntToString(video_info.time_scale()) +
"/" +
234 base::IntToString(video_info.frame_duration()));
239 if (!AddAudioChannelInfo(audio_info))
242 AddAudioSamplingRateInfo(audio_info);
247 if (media_info.has_media_file_name()) {
249 base_url.
SetContent(media_info.media_file_name());
255 const bool need_segment_base = media_info.has_index_range() ||
256 media_info.has_init_range() ||
257 media_info.has_reference_time_scale();
259 if (need_segment_base) {
260 XmlNode segment_base(
"SegmentBase");
261 if (media_info.has_index_range()) {
263 RangeToString(media_info.index_range()));
266 if (media_info.has_reference_time_scale()) {
268 media_info.reference_time_scale());
271 if (media_info.has_init_range()) {
272 XmlNode initialization(
"Initialization");
274 RangeToString(media_info.init_range()));
284 if (media_info.has_media_duration_seconds()) {
294 const MediaInfo& media_info,
295 const std::list<SegmentInfo>& segment_infos,
296 uint32_t start_number) {
297 XmlNode segment_template(
"SegmentTemplate");
298 if (media_info.has_reference_time_scale()) {
300 media_info.reference_time_scale());
303 if (media_info.has_init_segment_name()) {
308 const std::string& init_segment_name = media_info.init_segment_name();
309 if (init_segment_name.find(
"$Number$") != std::string::npos ||
310 init_segment_name.find(
"$Time$") != std::string::npos) {
311 LOG(ERROR) <<
"$Number$ and $Time$ cannot be used for "
312 "SegmentTemplate@initialization";
316 media_info.init_segment_name());
319 if (media_info.has_segment_template()) {
324 if (media_info.segment_template().find(
"$Number") != std::string::npos) {
325 DCHECK_GE(start_number, 1u);
331 XmlNode segment_timeline(
"SegmentTimeline");
333 return PopulateSegmentTimeline(segment_infos, &segment_timeline) &&
338 bool RepresentationXmlNode::AddAudioChannelInfo(
const AudioInfo& audio_info) {
339 const uint32_t num_channels = audio_info.num_channels();
340 XmlNode audio_channel_config(
"AudioChannelConfiguration");
341 const char kAudioChannelConfigScheme[] =
342 "urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
343 audio_channel_config.SetStringAttribute(
"schemeIdUri",
344 kAudioChannelConfigScheme);
345 audio_channel_config.SetIntegerAttribute(
"value", num_channels);
347 return AddChild(audio_channel_config.PassScopedPtr());
352 void RepresentationXmlNode::AddAudioSamplingRateInfo(
353 const AudioInfo& audio_info) {
354 if (audio_info.has_sampling_frequency())
bool AddVODOnlyInfo(const MediaInfo &media_info)
bool AddLiveOnlyInfo(const MediaInfo &media_info, const std::list< SegmentInfo > &segment_infos, uint32_t start_number)
void SetStringAttribute(const char *attribute_name, const std::string &attribute)
void SetFloatingPointAttribute(const char *attribute_name, double number)
bool AddAudioInfo(const MediaInfo::AudioInfo &audio_info)
XmlNode(const char *name)
void SetIntegerAttribute(const char *attribute_name, uint64_t number)
bool AddElements(const std::vector< Element > &elements)
Adds Elements to this node using the Element struct.
bool AddChild(ScopedXmlPtr< xmlNode >::type child)
bool AddVideoInfo(const MediaInfo::VideoInfo &video_info)
void SetContent(const std::string &content)
void AddRoleElement(const std::string &scheme_id_uri, const std::string &value)
ScopedXmlPtr< xmlNode >::type PassScopedPtr()
scoped_ptr for libxml2 resources.