7 #include "packager/mpd/base/xml/xml_node.h" 9 #include <gflags/gflags.h> 14 #include "packager/base/logging.h" 15 #include "packager/base/macros.h" 16 #include "packager/base/strings/string_number_conversions.h" 17 #include "packager/base/sys_byteorder.h" 18 #include "packager/mpd/base/media_info.pb.h" 19 #include "packager/mpd/base/mpd_utils.h" 20 #include "packager/mpd/base/segment_info.h" 22 DEFINE_bool(segment_template_constant_duration,
24 "Generates SegmentTemplate@duration if all segments except the " 25 "last one has the same duration if this flag is set to true.");
30 typedef MediaInfo::AudioInfo AudioInfo;
31 typedef MediaInfo::VideoInfo VideoInfo;
34 const char kEC3Codec[] =
"ec-3";
36 std::string RangeToString(
const Range& range) {
37 return base::Uint64ToString(range.begin()) +
"-" +
38 base::Uint64ToString(range.end());
43 bool IsTimelineConstantDuration(
const std::list<SegmentInfo>& segment_infos,
44 uint32_t start_number) {
45 if (!FLAGS_segment_template_constant_duration)
48 DCHECK(!segment_infos.empty());
49 if (segment_infos.size() > 2)
52 const SegmentInfo& first_segment = segment_infos.front();
53 if (first_segment.start_time != first_segment.duration * (start_number - 1))
56 if (segment_infos.size() == 1)
59 const SegmentInfo& last_segment = segment_infos.back();
60 if (last_segment.repeat != 0)
63 const int64_t expected_last_segment_start_time =
64 first_segment.start_time +
65 first_segment.duration * (first_segment.repeat + 1);
66 return expected_last_segment_start_time == last_segment.start_time;
69 bool PopulateSegmentTimeline(
const std::list<SegmentInfo>& segment_infos,
70 XmlNode* segment_timeline) {
71 for (
const SegmentInfo& segment_info : segment_infos) {
72 XmlNode s_element(
"S");
73 s_element.SetIntegerAttribute(
"t", segment_info.start_time);
74 s_element.SetIntegerAttribute(
"d", segment_info.duration);
75 if (segment_info.repeat > 0)
76 s_element.SetIntegerAttribute(
"r", segment_info.repeat);
78 CHECK(segment_timeline->AddChild(s_element.PassScopedPtr()));
84 void CollectNamespaceFromName(
const std::string& name,
85 std::set<std::string>* namespaces) {
86 const size_t pos = name.find(
':');
87 if (pos != std::string::npos)
88 namespaces->insert(name.substr(0, pos));
91 void TraverseAttrsAndCollectNamespaces(
const xmlAttr* attr,
92 std::set<std::string>* namespaces) {
93 for (
const xmlAttr* cur_attr = attr; cur_attr; cur_attr = cur_attr->next) {
94 CollectNamespaceFromName(reinterpret_cast<const char*>(cur_attr->name),
99 void TraverseNodesAndCollectNamespaces(
const xmlNode* node,
100 std::set<std::string>* namespaces) {
101 for (
const xmlNode* cur_node = node; cur_node; cur_node = cur_node->next) {
102 CollectNamespaceFromName(reinterpret_cast<const char*>(cur_node->name),
105 TraverseNodesAndCollectNamespaces(cur_node->children, namespaces);
106 TraverseAttrsAndCollectNamespaces(cur_node->properties, namespaces);
119 XmlNode::~XmlNode() {}
124 if (!xmlAddChild(node_.get(), child.get()))
129 ignore_result(child.release());
134 for (
size_t element_index = 0; element_index < elements.size();
136 const Element& child_element = elements[element_index];
137 XmlNode child_node(child_element.name.c_str());
138 for (std::map<std::string, std::string>::const_iterator attribute_it =
139 child_element.attributes.begin();
140 attribute_it != child_element.attributes.end(); ++attribute_it) {
142 attribute_it->second);
147 child_node.SetContent(child_element.content);
150 if (!child_node.AddElements(child_element.subelements))
153 if (!xmlAddChild(node_.get(), child_node.GetRawPtr())) {
154 LOG(ERROR) <<
"Failed to set child " << child_element.name
155 <<
" to parent element " 156 <<
reinterpret_cast<const char*
>(node_->name);
161 ignore_result(child_node.Release());
167 const std::string& attribute) {
169 DCHECK(attribute_name);
170 xmlSetProp(node_.get(), BAD_CAST attribute_name, BAD_CAST attribute.c_str());
175 DCHECK(attribute_name);
176 xmlSetProp(node_.get(),
177 BAD_CAST attribute_name,
178 BAD_CAST (base::Uint64ToString(number).c_str()));
184 DCHECK(attribute_name);
185 xmlSetProp(node_.get(), BAD_CAST attribute_name,
186 BAD_CAST(base::DoubleToString(number).c_str()));
195 xmlNodeSetContent(node_.get(), BAD_CAST content.c_str());
199 std::set<std::string> namespaces;
200 TraverseNodesAndCollectNamespaces(node_.get(), &namespaces);
205 DVLOG(2) <<
"Passing node_.";
207 return std::move(node_);
211 DVLOG(2) <<
"Releasing node_.";
213 return node_.release();
220 RepresentationBaseXmlNode::RepresentationBaseXmlNode(
const char* name)
222 RepresentationBaseXmlNode::~RepresentationBaseXmlNode() {}
224 bool RepresentationBaseXmlNode::AddContentProtectionElements(
225 const std::list<ContentProtectionElement>& content_protection_elements) {
226 std::list<ContentProtectionElement>::const_iterator content_protection_it =
227 content_protection_elements.begin();
228 for (; content_protection_it != content_protection_elements.end();
229 ++content_protection_it) {
230 if (!AddContentProtectionElement(*content_protection_it))
238 const std::string& scheme_id_uri,
239 const std::string& value) {
240 XmlNode supplemental_property(
"SupplementalProperty");
247 const std::string& scheme_id_uri,
248 const std::string& value) {
249 XmlNode essential_property(
"EssentialProperty");
255 bool RepresentationBaseXmlNode::AddContentProtectionElement(
257 XmlNode content_protection_node(
"ContentProtection");
260 if (!content_protection_element.value.empty()) {
262 "value", content_protection_element.value);
265 "schemeIdUri", content_protection_element.scheme_id_uri);
267 typedef std::map<std::string, std::string> AttributesMapType;
268 const AttributesMapType& additional_attributes =
269 content_protection_element.additional_attributes;
271 AttributesMapType::const_iterator attributes_it =
272 additional_attributes.begin();
273 for (; attributes_it != additional_attributes.end(); ++attributes_it) {
275 attributes_it->second);
279 content_protection_element.subelements)) {
285 AdaptationSetXmlNode::AdaptationSetXmlNode()
287 AdaptationSetXmlNode::~AdaptationSetXmlNode() {}
290 const std::string& value) {
297 RepresentationXmlNode::RepresentationXmlNode()
299 RepresentationXmlNode::~RepresentationXmlNode() {}
304 bool set_frame_rate) {
305 if (!video_info.has_width() || !video_info.has_height()) {
306 LOG(ERROR) <<
"Missing width or height for adding a video info.";
310 if (video_info.has_pixel_width() && video_info.has_pixel_height()) {
313 base::IntToString(video_info.pixel_height()));
320 if (set_frame_rate) {
322 base::IntToString(video_info.time_scale()) +
"/" +
323 base::IntToString(video_info.frame_duration()));
326 if (video_info.has_playback_rate()) {
328 base::IntToString(video_info.playback_rate()));
339 if (!AddAudioChannelInfo(audio_info))
342 AddAudioSamplingRateInfo(audio_info);
347 if (media_info.has_media_file_url()) {
349 base_url.
SetContent(media_info.media_file_url());
355 const bool need_segment_base = media_info.has_index_range() ||
356 media_info.has_init_range() ||
357 media_info.has_reference_time_scale();
359 if (need_segment_base) {
360 XmlNode segment_base(
"SegmentBase");
361 if (media_info.has_index_range()) {
363 RangeToString(media_info.index_range()));
366 if (media_info.has_reference_time_scale()) {
368 media_info.reference_time_scale());
371 if (media_info.has_presentation_time_offset()) {
373 media_info.presentation_time_offset());
376 if (media_info.has_init_range()) {
377 XmlNode initialization(
"Initialization");
379 RangeToString(media_info.init_range()));
393 const MediaInfo& media_info,
394 const std::list<SegmentInfo>& segment_infos,
395 uint32_t start_number) {
396 XmlNode segment_template(
"SegmentTemplate");
397 if (media_info.has_reference_time_scale()) {
399 media_info.reference_time_scale());
402 if (media_info.has_presentation_time_offset()) {
404 media_info.presentation_time_offset());
407 if (media_info.has_init_segment_url()) {
409 media_info.init_segment_url());
412 if (media_info.has_segment_template_url()) {
414 media_info.segment_template_url());
418 if (!segment_infos.empty()) {
421 if (IsTimelineConstantDuration(segment_infos, start_number)) {
423 segment_infos.front().duration);
425 XmlNode segment_timeline(
"SegmentTimeline");
426 if (!PopulateSegmentTimeline(segment_infos, &segment_timeline) ||
435 bool RepresentationXmlNode::AddAudioChannelInfo(
const AudioInfo& audio_info) {
436 std::string audio_channel_config_scheme;
437 std::string audio_channel_config_value;
439 if (audio_info.codec() == kEC3Codec) {
442 const uint16_t ec3_channel_map =
443 base::HostToNet16(audio_info.codec_specific_data().ec3_channel_map());
444 audio_channel_config_value =
445 base::HexEncode(&ec3_channel_map,
sizeof(ec3_channel_map));
446 audio_channel_config_scheme =
447 "tag:dolby.com,2014:dash:audio_channel_configuration:2011";
449 audio_channel_config_value = base::UintToString(audio_info.num_channels());
450 audio_channel_config_scheme =
451 "urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
454 XmlNode audio_channel_config(
"AudioChannelConfiguration");
456 audio_channel_config_scheme);
464 void RepresentationXmlNode::AddAudioSamplingRateInfo(
465 const AudioInfo& audio_info) {
466 if (audio_info.has_sampling_frequency())
bool AddVideoInfo(const MediaInfo::VideoInfo &video_info, bool set_width, bool set_height, bool set_frame_rate)
std::set< std::string > ExtractReferencedNamespaces()
void SetFloatingPointAttribute(const char *attribute_name, double number)
scoped_xml_ptr< xmlNode > PassScopedPtr()
XmlNode(const char *name)
All the methods that are virtual are virtual for mocking.
bool AddVODOnlyInfo(const MediaInfo &media_info)
void AddEssentialProperty(const std::string &scheme_id_uri, const std::string &value)
void SetStringAttribute(const char *attribute_name, const std::string &attribute)
bool AddChild(scoped_xml_ptr< xmlNode > child)
bool AddLiveOnlyInfo(const MediaInfo &media_info, const std::list< SegmentInfo > &segment_infos, uint32_t start_number)
bool AddElements(const std::vector< Element > &elements)
Adds Elements to this node using the Element struct.
void AddSupplementalProperty(const std::string &scheme_id_uri, const std::string &value)
void SetIntegerAttribute(const char *attribute_name, uint64_t number)
void AddRoleElement(const std::string &scheme_id_uri, const std::string &value)
void SetContent(const std::string &content)
bool AddAudioInfo(const MediaInfo::AudioInfo &audio_info)