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()));
93 XmlNode::~XmlNode() {}
98 if (!xmlAddChild(node_.get(), child.get()))
103 ignore_result(child.release());
108 for (
size_t element_index = 0; element_index < elements.size();
110 const Element& child_element = elements[element_index];
111 XmlNode child_node(child_element.name.c_str());
112 for (std::map<std::string, std::string>::const_iterator attribute_it =
113 child_element.attributes.begin();
114 attribute_it != child_element.attributes.end(); ++attribute_it) {
116 attribute_it->second);
119 if (!child_node.AddElements(child_element.subelements))
122 child_node.SetContent(child_element.content);
124 if (!xmlAddChild(node_.get(), child_node.GetRawPtr())) {
125 LOG(ERROR) <<
"Failed to set child " << child_element.name
126 <<
" to parent element " 127 <<
reinterpret_cast<const char*
>(node_->name);
132 ignore_result(child_node.Release());
138 const std::string& attribute) {
140 DCHECK(attribute_name);
141 xmlSetProp(node_.get(), BAD_CAST attribute_name, BAD_CAST attribute.c_str());
146 DCHECK(attribute_name);
147 xmlSetProp(node_.get(),
148 BAD_CAST attribute_name,
149 BAD_CAST (base::Uint64ToString(number).c_str()));
155 DCHECK(attribute_name);
156 xmlSetProp(node_.get(), BAD_CAST attribute_name,
157 BAD_CAST(base::DoubleToString(number).c_str()));
166 xmlNodeSetContent(node_.get(), BAD_CAST content.c_str());
170 DVLOG(2) <<
"Passing node_.";
172 return std::move(node_);
176 DVLOG(2) <<
"Releasing node_.";
178 return node_.release();
185 RepresentationBaseXmlNode::RepresentationBaseXmlNode(
const char* name)
187 RepresentationBaseXmlNode::~RepresentationBaseXmlNode() {}
189 bool RepresentationBaseXmlNode::AddContentProtectionElements(
190 const std::list<ContentProtectionElement>& content_protection_elements) {
191 std::list<ContentProtectionElement>::const_iterator content_protection_it =
192 content_protection_elements.begin();
193 for (; content_protection_it != content_protection_elements.end();
194 ++content_protection_it) {
195 if (!AddContentProtectionElement(*content_protection_it))
203 const std::string& scheme_id_uri,
204 const std::string& value) {
205 XmlNode supplemental_property(
"SupplementalProperty");
212 const std::string& scheme_id_uri,
213 const std::string& value) {
214 XmlNode essential_property(
"EssentialProperty");
220 bool RepresentationBaseXmlNode::AddContentProtectionElement(
222 XmlNode content_protection_node(
"ContentProtection");
225 if (!content_protection_element.value.empty()) {
227 "value", content_protection_element.value);
230 "schemeIdUri", content_protection_element.scheme_id_uri);
232 typedef std::map<std::string, std::string> AttributesMapType;
233 const AttributesMapType& additional_attributes =
234 content_protection_element.additional_attributes;
236 AttributesMapType::const_iterator attributes_it =
237 additional_attributes.begin();
238 for (; attributes_it != additional_attributes.end(); ++attributes_it) {
240 attributes_it->second);
244 content_protection_element.subelements)) {
250 AdaptationSetXmlNode::AdaptationSetXmlNode()
252 AdaptationSetXmlNode::~AdaptationSetXmlNode() {}
255 const std::string& value) {
262 RepresentationXmlNode::RepresentationXmlNode()
264 RepresentationXmlNode::~RepresentationXmlNode() {}
269 bool set_frame_rate) {
270 if (!video_info.has_width() || !video_info.has_height()) {
271 LOG(ERROR) <<
"Missing width or height for adding a video info.";
275 if (video_info.has_pixel_width() && video_info.has_pixel_height()) {
278 base::IntToString(video_info.pixel_height()));
285 if (set_frame_rate) {
287 base::IntToString(video_info.time_scale()) +
"/" +
288 base::IntToString(video_info.frame_duration()));
291 if (video_info.has_playback_rate()) {
293 base::IntToString(video_info.playback_rate()));
304 if (!AddAudioChannelInfo(audio_info))
307 AddAudioSamplingRateInfo(audio_info);
312 if (media_info.has_media_file_url()) {
314 base_url.
SetContent(media_info.media_file_url());
320 const bool need_segment_base = media_info.has_index_range() ||
321 media_info.has_init_range() ||
322 media_info.has_reference_time_scale();
324 if (need_segment_base) {
325 XmlNode segment_base(
"SegmentBase");
326 if (media_info.has_index_range()) {
328 RangeToString(media_info.index_range()));
331 if (media_info.has_reference_time_scale()) {
333 media_info.reference_time_scale());
336 if (media_info.has_presentation_time_offset()) {
338 media_info.presentation_time_offset());
341 if (media_info.has_init_range()) {
342 XmlNode initialization(
"Initialization");
344 RangeToString(media_info.init_range()));
358 const MediaInfo& media_info,
359 const std::list<SegmentInfo>& segment_infos,
360 uint32_t start_number) {
361 XmlNode segment_template(
"SegmentTemplate");
362 if (media_info.has_reference_time_scale()) {
364 media_info.reference_time_scale());
367 if (media_info.has_presentation_time_offset()) {
369 media_info.presentation_time_offset());
372 if (media_info.has_init_segment_url()) {
374 media_info.init_segment_url());
377 if (media_info.has_segment_template_url()) {
379 media_info.segment_template_url());
383 if (!segment_infos.empty()) {
386 if (IsTimelineConstantDuration(segment_infos, start_number)) {
388 segment_infos.front().duration);
390 XmlNode segment_timeline(
"SegmentTimeline");
391 if (!PopulateSegmentTimeline(segment_infos, &segment_timeline) ||
400 bool RepresentationXmlNode::AddAudioChannelInfo(
const AudioInfo& audio_info) {
401 std::string audio_channel_config_scheme;
402 std::string audio_channel_config_value;
404 if (audio_info.codec() == kEC3Codec) {
407 const uint16_t ec3_channel_map =
408 base::HostToNet16(audio_info.codec_specific_data().ec3_channel_map());
409 audio_channel_config_value =
410 base::HexEncode(&ec3_channel_map,
sizeof(ec3_channel_map));
411 audio_channel_config_scheme =
412 "tag:dolby.com,2014:dash:audio_channel_configuration:2011";
414 audio_channel_config_value = base::UintToString(audio_info.num_channels());
415 audio_channel_config_scheme =
416 "urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
419 XmlNode audio_channel_config(
"AudioChannelConfiguration");
421 audio_channel_config_scheme);
429 void RepresentationXmlNode::AddAudioSamplingRateInfo(
430 const AudioInfo& audio_info) {
431 if (audio_info.has_sampling_frequency())
bool AddVideoInfo(const MediaInfo::VideoInfo &video_info, bool set_width, bool set_height, bool set_frame_rate)
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)