如何生成 PlayReady 标头
打包程序需要在加密内容中包含 PlayReady 标头。
有关 PlayReady 标头和 PlayReady 对象的详细说明,请参阅 PlayReady 标头规范。
PlayReady 标头包含有关正在播放的内容的信息,包括密钥标识符 (KID) 标识用于加密数据的密钥、PlayReady 许可证服务器的默认许可证获取 URL 以及要包括的任何自定义数据。 用于加密内容的密钥和 KID 必须与 PlayReady 许可证服务器共享,该服务器将颁发该特定内容的许可证,通常通过密钥管理系统 (KMS) 。
注意
Microsoft 不提供带 PlayReady 的密钥管理系统。
以下 XML 代码提供了 PlayReady 标头的示例,该标头可能插入到分段 MP4 文件的标头中,通常适用于按需内容。 它包括 KID 列表 (客户端解密内容所需的内容加密密钥的 ID) 。 这是为按需文件或流发出这些 KID 信号的最常用方法。
<WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.3.0.0">
<DATA>
<PROTECTINFO>
<KIDS>
<KID ALGID="AESCTR" VALUE="PV1LM/VEVk+kEOB8qqcWDg=="></KID>
<KID ALGID="AESCTR" VALUE="tuhDoKUN7EyxDPtMRNmhyA=="></KID>
</KIDS>
</PROTECTINFO>
<LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL>
<DS_ID>AH+03juKbUGbHl1V/QIwRA==</DS_ID>
</DATA>
</WRMHEADER>
以下 XML 代码提供了 Live Linear 内容的 PlayReady 标头示例。 它不包括任何 KID,因为内容加密密钥 (及其关联的 KID) 偶尔会更改 (,例如,非常频繁,或在程序边界,或每小时,或每天) 。 用于内容流的 KID 将在段标头中发出信号,并且不需要在流顶级 PlayReady 标头中包含其中任何一个。 属性 DECRYPTORSETUP 设置为 ONDEMAND,这意味着将按需设置 PlayReady 标头和解密器,这意味着当客户端实际需要开始解密段时,此时,客户端将有权访问段标头中的另一个 PlayReady 标头,以确定涉及哪些 KID。
注意
DECRYPTORSETUP = ONDEMAND 并不意味着内容是按需提供的,它实际上是相反的。
<WRMHEADER version="4.2.0.0" xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader">
<DATA>
<DECRYPTORSETUP>ONDEMAND</DECRYPTORSETUP>
</DATA>
</WRMHEADER>
在打包程序中创建 PlayReady 标头生成器有多种方法。 以下部分一般介绍了如何生成 PlayReady 标头。
方法 1 - 基于 PlayReady 标头规范生成自己的代码
PlayReady 对象和标头规范是公开的,因此,在生成 PlayReady 对象和 PlayReady 标头的设备或服务中编写代码可以打包内容,并且非常简单。
PlayReady 标头生成器需要具有输入参数,例如:
- 按需内容或 Live Linear 内容。
- 用于保护整个资产的 KID 或 KID 列表。
- (AESCTR 或 AESCBC) 使用的加密类型。
- Defaut LA URL - PlayReady 许可证服务器的默认 URL,将在打包时发出许可证。
- 如果服务使用的是域,则默认域服务标识符。
现在可以创建 PlayReady 对象及其关联的 PlayReady 标头。 下面的代码示例演示如何创建包含用于按需内容的 PlayReady 标头的 PlayReady 对象。
// This function gets values from the key management system and your specified encryption mode
// (and optionally the domainID), creates a PlayReady Header, adds the header to a
// PlayReady Object, and stores them in a file in UTF-16 little endian format
void buildRMObject(string KeyID1, string KeyID2, string encryptMode, string domainID)
{
// The string parameters include the following:
// KeyID1, KeyID2 - The key identifiers - these values are returned from the key management system or
// the KeySeed mechanism
// encryptMode - the encryption mode used to encrypt content, can be AESCTR or AESCBC
// domainID - the optional domain service identifier (only used for domains)
string xmlString = "<WRMHEADER xmlns=\"http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader\" version=\"4.3.0.0\"><DATA><PROTECTINFO><KIDS><KID ALGID=\"";
xmlString.append(encryptMode);
xmlString.append("\" VALUE=\"");
xmlString.append(KeyID1);
xmlString.append("\"></KID><KID ALGID=\"");
xmlString.append(encryptMode);
xmlString.append("\" VALUE=\"");
xmlString.append(KeyID2);
xmlString.append("\"></KID></KIDS></PROTECTINFO><LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL><DS_ID>");
xmlString.append(domainID);
xmlString.append("</DS_ID></DATA></WRMHEADER>");
// Convert the PlayReady header to UFT-16 format
wstring_convert<codecvt_utf8_utf16<wchar_t>> convert;
wstring utf16XML = convert.from_bytes(xmlString);
// Calculate the length of the PlayReady Header
int32_t headerLength = (utf16XML.size() * sizeof(wchar_t));
// Calculate the length of the PlayReady Object
int32_t objectLength = headerLength + 10;
// Set the number of PlayReady object records (in this case, 1)
int16_t recordCount = 1;
// Set the record type (in this case, a PlayReady Header)
// If this was an embedded license store, this value would be 3
int16_t recordType = 1;
// Write the PlayReady Object and PlayReady Header to a file
wofstream wofs("C:\\Temp\\PRObject.txt", ios::binary);
wofs.imbue(locale(wofs.getloc(),
new codecvt_utf16<wchar_t, 0x10ffff, little_endian>));
wofs.write(reinterpret_cast<const wchar_t *>(&objectLength), 2);
wofs.write(reinterpret_cast<const wchar_t *>(&recordCount), 1);
wofs.write(reinterpret_cast<const wchar_t *>(&recordType), 1);
wofs.write(reinterpret_cast<const wchar_t *>(&headerLength), 1);
wofs << utf16XML;
}
方法 2 - 使用 PlayReady 服务器 API
如果你是 PlayReady Server SDK 许可者,则服务器 SDK 包含可用于构造 PlayReady Header 的 PlayReadyHeader 类。 它包括可以使用的方法和属性,你可以填写 PlayReady 标头所需的信息。
PlayReadyHeader 类详细介绍了使用 PlayReady Server SDK 许可证收到的 PlayReady 文档。 PlayReady Server SDK 还包括一个示例打包程序 (AESPackaging) ,演示如何创建 PlayReady 标头。
与方法 1 中一样,需要密钥管理系统生成的 KeyID () 、加密类型 (AESCTR 或 AESCBC) 、PlayReady 许可证服务器的 URL,以及域服务标识符(可选)。
方法 3 - 使用Windows应用程序
开始之前需要的东西。
- 必须具有密钥管理系统生成的 KeyID () 。
- 必须知道加密类型 (AESCTR 或 AESCBC) 。
- 使用 Windows 10 PlayReadyContentHeader 类在 PlayReady 对象中创建 PlayReady 标头。
与前面的方法一样,需要密钥管理系统生成的 KeyID () 、加密类型 (AESCTR 或 AESCBC) 、PlayReady 许可证服务器的 URL 以及域服务标识符(可选)。