MpdBuilder should handle ContentProtectionXml

Added functions to add MediaInfo::ContentProtectionXml to
RepresentationBaseXmlNode. This allows adding ContentProtection elements
using MediaInfo protobuf.

Change-Id: I46aa97ba8cbf1548388ebbb61ac163786dfa0be8
This commit is contained in:
Rintaro Kuroiwa 2014-01-14 14:57:50 -08:00
parent 6957a4ac07
commit bd44c7d7b8
4 changed files with 170 additions and 1 deletions

View File

@ -323,7 +323,9 @@ bool Representation::AddNewSegment(uint64 start_time, uint64 duration) {
} }
// TODO(rkuroiwa): We don't need to create a node every single time. Make an // TODO(rkuroiwa): We don't need to create a node every single time. Make an
// internal copy of this element. // internal copy of this element. Then move most of the logic to
// RepresentationXmlNode so that all the work is done in it so that this class
// just becomes a thin layer.
// Uses info in |media_info_| and |content_protection_elements_| to create a // Uses info in |media_info_| and |content_protection_elements_| to create a
// "Representation" node. // "Representation" node.
xml::ScopedXmlPtr<xmlNode>::type Representation::GetXml() { xml::ScopedXmlPtr<xmlNode>::type Representation::GetXml() {
@ -337,6 +339,9 @@ xml::ScopedXmlPtr<xmlNode>::type Representation::GetXml() {
return xml::ScopedXmlPtr<xmlNode>::type(); return xml::ScopedXmlPtr<xmlNode>::type();
} }
if (!representation.AddContentProtectionElementsFromMediaInfo(media_info_))
return xml::ScopedXmlPtr<xmlNode>::type();
// Mandatory fields for Representation. // Mandatory fields for Representation.
representation.SetId(id_); representation.SetId(id_);
representation.SetIntegerAttribute("bandwidth", media_info_.bandwidth()); representation.SetIntegerAttribute("bandwidth", media_info_.bandwidth());

View File

@ -117,6 +117,8 @@ class AdaptationSet {
DISALLOW_COPY_AND_ASSIGN(AdaptationSet); DISALLOW_COPY_AND_ASSIGN(AdaptationSet);
}; };
// In |media_info|, ContentProtectionXml::{schemeIdUri,value} takes precedence
// over schemeIdUri and value specified in ContentProtectionXml::attributes.
class Representation { class Representation {
public: public:
Representation(const MediaInfo& media_info, uint32 representation_id); Representation(const MediaInfo& media_info, uint32 representation_id);

View File

@ -6,6 +6,11 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "mpd/base/media_info.pb.h" #include "mpd/base/media_info.pb.h"
using dash_packager::xml::XmlNode;
using dash_packager::MediaInfo;
typedef MediaInfo::ContentProtectionXml ContentProtectionXml;
typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
namespace { namespace {
@ -14,6 +19,132 @@ std::string RangeToString(const dash_packager::Range& range) {
base::Uint64ToString(range.end()); base::Uint64ToString(range.end());
} }
bool SetAttributes(const google::protobuf::RepeatedPtrField<
AttributeNameValuePair>& attributes,
XmlNode* xml_node) {
DCHECK(xml_node);
for (int i = 0; i < attributes.size(); ++i) {
const AttributeNameValuePair& attribute = attributes.Get(i);
const std::string& name = attribute.name();
const std::string& value = attribute.value();
if (name.empty()) {
LOG(ERROR) << "For element "
<< reinterpret_cast<const char*>(xml_node->GetRawPtr()->name)
<< ", no name specified for attribute with value: " << value;
return false;
}
xml_node->SetStringAttribute(name.c_str(), value);
}
return true;
}
// This function is recursive. Note that elements.size() == 0 is a terminating
// condition.
bool AddSubelements(const google::protobuf::RepeatedPtrField<
ContentProtectionXml::Element>& elements,
XmlNode* xml_node) {
DCHECK(xml_node);
for (int i = 0; i < elements.size(); ++i) {
const ContentProtectionXml::Element& subelement = elements.Get(i);
const std::string& subelement_name = subelement.name();
if (subelement_name.empty()) {
LOG(ERROR) << "Subelement name was not specified for node "
<< reinterpret_cast<const char*>(xml_node->GetRawPtr()->name);
return false;
}
XmlNode subelement_xml_node(subelement_name.c_str());
if (!SetAttributes(subelement.attributes(), &subelement_xml_node)) {
LOG(ERROR) << "Failed to set attributes for " << subelement_name;
return false;
}
if (!AddSubelements(subelement.subelements(), &subelement_xml_node)) {
LOG(ERROR) << "Failed to add subelements to " << subelement_name;
return false;
}
if (!xml_node->AddChild(subelement_xml_node.PassScopedPtr())) {
LOG(ERROR) << "Failed to add subelement " << subelement_name << " to "
<< reinterpret_cast<const char*>(xml_node->GetRawPtr()->name);
return false;
}
}
return true;
}
// Returns true if 'schemeIdUri' is set in |content_protection_xml| and sets
// |scheme_id_uri_output|. This function checks
// ContentProtectionXml::scheme_id_uri before searching thru attributes.
bool GetSchemeIdAttribute(const ContentProtectionXml& content_protection_xml,
std::string* scheme_id_uri_output) {
// Common case where 'schemeIdUri' is set directly.
if (content_protection_xml.has_scheme_id_uri()) {
scheme_id_uri_output->assign(content_protection_xml.scheme_id_uri());
return true;
}
// 'schemeIdUri' is one of the attributes.
for (int i = 0; i < content_protection_xml.attributes().size(); ++i) {
const AttributeNameValuePair& attribute =
content_protection_xml.attributes(i);
const std::string& name = attribute.name();
const std::string& value = attribute.value();
if (name == "schemeIdUri") {
if (value.empty())
LOG(WARNING) << "schemeIdUri is specified with an empty string.";
// 'schemeIdUri' is a mandatory field but MPD doesn't care what the actual
// value is, proceed.
scheme_id_uri_output->assign(value);
return true;
}
}
return false;
}
// Translates ContentProtectionXml to XmlNode.
// content_protection_xml.scheme_id_uri and content_protection_xml.value takes
// precedence over attributes in content_protection_xml.attributes.
bool TranslateToContentProtectionXmlNode(
const ContentProtectionXml& content_protection_xml,
XmlNode* xml_node_content_protection) {
std::string scheme_id_uri;
if (!GetSchemeIdAttribute(content_protection_xml, &scheme_id_uri)) {
LOG(ERROR) << "ContentProtection element requires schemeIdUri.";
return false;
}
if (!SetAttributes(content_protection_xml.attributes(),
xml_node_content_protection)) {
LOG(ERROR) << "Failed to set attributes for ContentProtection.";
return false;
}
if (!AddSubelements(content_protection_xml.subelements(),
xml_node_content_protection)) {
LOG(ERROR) << "Failed to add sublements to ContentProtection.";
return false;
}
// Add 'schemeIdUri' and 'value' attributes after SetAttributes() to avoid
// being overridden by content_protection_xml.attributes().
xml_node_content_protection->SetStringAttribute("schemeIdUri", scheme_id_uri);
if (content_protection_xml.has_value()) {
// Note that |value| is an optional field.
xml_node_content_protection->SetStringAttribute(
"value", content_protection_xml.value());
}
return true;
}
} // namespace } // namespace
namespace dash_packager { namespace dash_packager {
@ -104,6 +235,33 @@ bool RepresentationBaseXmlNode::AddContentProtectionElements(
return true; return true;
} }
bool RepresentationBaseXmlNode::AddContentProtectionElementsFromMediaInfo(
const MediaInfo& media_info) {
const bool has_content_protections =
media_info.content_protections().size() > 0;
if (!has_content_protections)
return true;
for (int i = 0; i < media_info.content_protections().size(); ++i) {
const ContentProtectionXml& content_protection_xml =
media_info.content_protections(i);
XmlNode content_protection_node("ContentProtection");
if (!TranslateToContentProtectionXmlNode(content_protection_xml,
&content_protection_node)) {
LOG(ERROR) << "Failed to make ContentProtection element from MediaInfo.";
return false;
}
if (!AddChild(content_protection_node.PassScopedPtr())) {
LOG(ERROR) << "Failed to add ContentProtection to Representation.";
return false;
}
}
return true;
}
bool RepresentationBaseXmlNode::AddContentProtectionElement( bool RepresentationBaseXmlNode::AddContentProtectionElement(
const ContentProtectionElement& content_protection_element) { const ContentProtectionElement& content_protection_element) {
XmlNode content_protection_node("ContentProtection"); XmlNode content_protection_node("ContentProtection");

View File

@ -68,6 +68,10 @@ class RepresentationBaseXmlNode : public XmlNode {
bool AddContentProtectionElements( bool AddContentProtectionElements(
const std::list<ContentProtectionElement>& content_protection_elements); const std::list<ContentProtectionElement>& content_protection_elements);
// Return true on success. If content_protections size is 0 in |media_info|,
// this will return true. Otherwise return false.
bool AddContentProtectionElementsFromMediaInfo(const MediaInfo& media_info);
protected: protected:
explicit RepresentationBaseXmlNode(const char* name); explicit RepresentationBaseXmlNode(const char* name);