HLS media playlist EXT-X-KEY format changes
[ Merged of http://go/wvgerrit/16576 ] The WV EXT-X-KEY attribute list earlier expected a cenc PSSH box in the URI field, in a hexadecimal sequence format. To ease the burden on content providers, the URI field will now contain init data in a json format and base64 encoded. The platform will assume responsibility to parse this data and create a widevine init data protobuf that can be included in the license request. b/20630275 Change-Id: I49e270bedbe96791fc9b282214a9a358d95d163e
This commit is contained in:
@@ -25,7 +25,8 @@ class InitializationData {
|
|||||||
|
|
||||||
const std::string& type() const { return type_; }
|
const std::string& type() const { return type_; }
|
||||||
const CdmInitData& data() const { return data_; }
|
const CdmInitData& data() const { return data_; }
|
||||||
const CdmHlsData& hls_data() const { return hls_data_; }
|
std::vector<uint8_t> hls_iv() const { return hls_iv_; }
|
||||||
|
CdmHlsMethod hls_method() const { return hls_method_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||||
@@ -34,7 +35,9 @@ class InitializationData {
|
|||||||
|
|
||||||
bool ExtractHlsAttributes(const std::string& attribute_list,
|
bool ExtractHlsAttributes(const std::string& attribute_list,
|
||||||
CdmHlsMethod* method, std::vector<uint8_t>* iv,
|
CdmHlsMethod* method, std::vector<uint8_t>* iv,
|
||||||
std::string* uri, CdmInitData* init_data);
|
std::string* uri);
|
||||||
|
static bool ConstructWidevineInitData(const std::string& uri,
|
||||||
|
CdmInitData* output);
|
||||||
|
|
||||||
static bool ExtractQuotedAttribute(const std::string& attribute_list,
|
static bool ExtractQuotedAttribute(const std::string& attribute_list,
|
||||||
const std::string& key,
|
const std::string& key,
|
||||||
@@ -44,22 +47,31 @@ class InitializationData {
|
|||||||
std::vector<uint8_t>* value);
|
std::vector<uint8_t>* value);
|
||||||
static bool ExtractAttribute(const std::string& attribute_list,
|
static bool ExtractAttribute(const std::string& attribute_list,
|
||||||
const std::string& key, std::string* value);
|
const std::string& key, std::string* value);
|
||||||
|
static bool ExtractJsonValue(const std::string& json,
|
||||||
|
const std::string& key, std::string* value);
|
||||||
|
|
||||||
|
static std::vector<std::string> ExtractKeyFormatVersions(
|
||||||
|
const std::string& key_format_versions);
|
||||||
|
|
||||||
// For testing only:
|
// For testing only:
|
||||||
#if defined(UNIT_TEST)
|
#if defined(UNIT_TEST)
|
||||||
FRIEND_TEST(HlsAttributeExtractionTest, ExtractAttribute);
|
FRIEND_TEST(HlsAttributeExtractionTest, ExtractAttribute);
|
||||||
FRIEND_TEST(HlsParseTest, Parse);
|
FRIEND_TEST(HlsConstructionTest, InitData);
|
||||||
FRIEND_TEST(HlsTest, ExtractHlsAttributes);
|
|
||||||
FRIEND_TEST(HlsHexAttributeExtractionTest, ExtractHexAttribute);
|
FRIEND_TEST(HlsHexAttributeExtractionTest, ExtractHexAttribute);
|
||||||
|
FRIEND_TEST(HlsKeyFormatVersionsExtractionTest, ExtractKeyFormatVersions);
|
||||||
|
FRIEND_TEST(HlsParseTest, Parse);
|
||||||
FRIEND_TEST(HlsQuotedAttributeExtractionTest, ExtractQuotedAttribute);
|
FRIEND_TEST(HlsQuotedAttributeExtractionTest, ExtractQuotedAttribute);
|
||||||
|
FRIEND_TEST(HlsTest, ExtractHlsAttributes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string type_;
|
std::string type_;
|
||||||
CdmInitData data_;
|
CdmInitData data_;
|
||||||
CdmHlsData hls_data_;
|
|
||||||
bool is_cenc_;
|
bool is_cenc_;
|
||||||
bool is_hls_;
|
bool is_hls_;
|
||||||
bool is_webm_;
|
bool is_webm_;
|
||||||
|
|
||||||
|
std::vector<uint8_t> hls_iv_;
|
||||||
|
CdmHlsMethod hls_method_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -83,9 +83,8 @@ static const std::string CENC_INIT_DATA_FORMAT = "cenc";
|
|||||||
static const std::string HLS_INIT_DATA_FORMAT = "hls";
|
static const std::string HLS_INIT_DATA_FORMAT = "hls";
|
||||||
static const std::string WEBM_INIT_DATA_FORMAT = "webm";
|
static const std::string WEBM_INIT_DATA_FORMAT = "webm";
|
||||||
|
|
||||||
static const std::string HLS_INITDATA_ATTRIBUTE = "X-WV-INITDATA";
|
|
||||||
static const std::string HLS_KEYFORMAT_ATTRIBUTE = "KEYFORMAT";
|
static const std::string HLS_KEYFORMAT_ATTRIBUTE = "KEYFORMAT";
|
||||||
static const std::string HLS_KEYFORMAT_VERSION_ATTRIBUTE = "KEYFORMATVERSION";
|
static const std::string HLS_KEYFORMAT_VERSIONS_ATTRIBUTE = "KEYFORMATVERSIONS";
|
||||||
static const std::string HLS_KEYFORMAT_VERSION_VALUE_1 = "1";
|
static const std::string HLS_KEYFORMAT_VERSION_VALUE_1 = "1";
|
||||||
static const std::string HLS_METHOD_ATTRIBUTE = "METHOD";
|
static const std::string HLS_METHOD_ATTRIBUTE = "METHOD";
|
||||||
static const std::string HLS_METHOD_AES_128 = "AES-128";
|
static const std::string HLS_METHOD_AES_128 = "AES-128";
|
||||||
|
|||||||
@@ -266,13 +266,6 @@ enum CdmHlsMethod {
|
|||||||
kHlsMethodSampleAes,
|
kHlsMethodSampleAes,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CdmHlsData {
|
|
||||||
CdmHlsData() : method(kHlsMethodNone) {}
|
|
||||||
CdmHlsMethod method;
|
|
||||||
std::vector<uint8_t> iv;
|
|
||||||
std::string uri;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CdmCipherMode {
|
enum CdmCipherMode {
|
||||||
kCipherModeCtr,
|
kCipherModeCtr,
|
||||||
kCipherModeCbc,
|
kCipherModeCbc,
|
||||||
|
|||||||
@@ -5,16 +5,40 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "buffer_reader.h"
|
#include "buffer_reader.h"
|
||||||
|
#include "license_protocol.pb.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char kKeyFormatVersionsSeparator = '/';
|
||||||
|
const char kColon = ':';
|
||||||
|
const char kDoubleQuote = '\"';
|
||||||
|
const char kLeftBracket = '[';
|
||||||
|
const char kRightBracket = ']';
|
||||||
|
const std::string kBase64String = "base64,";
|
||||||
|
|
||||||
|
// json init data key values
|
||||||
|
const std::string kProvider = "provider";
|
||||||
|
const std::string kContentId = "content_id";
|
||||||
|
const std::string kKeyIds = "key_ids";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
|
// Protobuf generated classes.
|
||||||
|
using video_widevine_server::sdk::WidevineCencHeader;
|
||||||
|
using video_widevine_server::sdk::WidevineCencHeader_Algorithm;
|
||||||
|
using video_widevine_server::sdk::WidevineCencHeader_Algorithm_AESCTR;
|
||||||
|
|
||||||
InitializationData::InitializationData(const std::string& type,
|
InitializationData::InitializationData(const std::string& type,
|
||||||
const CdmInitData& data)
|
const CdmInitData& data)
|
||||||
: type_(type), is_cenc_(false), is_hls_(false), is_webm_(false) {
|
: type_(type),
|
||||||
|
is_cenc_(false),
|
||||||
|
is_hls_(false),
|
||||||
|
is_webm_(false),
|
||||||
|
hls_method_(kHlsMethodNone) {
|
||||||
if (type == ISO_BMFF_VIDEO_MIME_TYPE || type == ISO_BMFF_AUDIO_MIME_TYPE ||
|
if (type == ISO_BMFF_VIDEO_MIME_TYPE || type == ISO_BMFF_AUDIO_MIME_TYPE ||
|
||||||
type == CENC_INIT_DATA_FORMAT) {
|
type == CENC_INIT_DATA_FORMAT) {
|
||||||
is_cenc_ = true;
|
is_cenc_ = true;
|
||||||
@@ -31,10 +55,9 @@ InitializationData::InitializationData(const std::string& type,
|
|||||||
} else if (is_webm()) {
|
} else if (is_webm()) {
|
||||||
data_ = data;
|
data_ = data;
|
||||||
} else if (is_hls()) {
|
} else if (is_hls()) {
|
||||||
CdmInitData init_data;
|
std::string uri;
|
||||||
if (ExtractHlsAttributes(data, &hls_data_.method, &hls_data_.iv,
|
if (ExtractHlsAttributes(data, &hls_method_, &hls_iv_, &uri)) {
|
||||||
&hls_data_.uri, &init_data)) {
|
ConstructWidevineInitData(uri, &data_);
|
||||||
ExtractWidevinePssh(init_data, &data_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,16 +224,17 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
|
|||||||
// An example of a widevine supported attribute list from an HLS media playlist
|
// An example of a widevine supported attribute list from an HLS media playlist
|
||||||
// is,
|
// is,
|
||||||
// "EXT-X-KEY: METHOD=SAMPLE-AES, \"
|
// "EXT-X-KEY: METHOD=SAMPLE-AES, \"
|
||||||
// "URI=”http://www.youtube.com/license-service”, \"
|
// "URI=”data:text/plain;base64,eyANCiAgICJwcm92aWRlciI6Im1sYmFtaGJvIiwNCiAg"
|
||||||
|
// "ICJjb250ZW50X2lkIjoiMjAxNV9UZWFycyIsDQogICAia2V5X2lkcyI6DQogICBbDQo"
|
||||||
|
// "gICAgICAiMzcxZTEzNWUxYTk4NWQ3NWQxOThhN2Y0MTAyMGRjMjMiDQogICBdDQp9DQ"
|
||||||
|
// "o=", \
|
||||||
// "IV=0x6df49213a781e338628d0e9c812d328e, \"
|
// "IV=0x6df49213a781e338628d0e9c812d328e, \"
|
||||||
// "KEYFORMAT=”com.widevine.alpha”, \"
|
// "KEYFORMAT=”com.widevine”, \"
|
||||||
// "KEYFORMATVERSION=”1”, \"
|
// "KEYFORMATVERSIONS=”1”"
|
||||||
// "X-WV-INITDATA=0x9e1a3af3de74ae3606e931fee285e3402e172732aba9a16a0e1441f1e"
|
|
||||||
bool InitializationData::ExtractHlsAttributes(const std::string& attribute_list,
|
bool InitializationData::ExtractHlsAttributes(const std::string& attribute_list,
|
||||||
CdmHlsMethod* method,
|
CdmHlsMethod* method,
|
||||||
std::vector<uint8_t>* iv,
|
std::vector<uint8_t>* iv,
|
||||||
std::string* uri,
|
std::string* uri) {
|
||||||
CdmInitData* init_data) {
|
|
||||||
std::string value;
|
std::string value;
|
||||||
if (!ExtractQuotedAttribute(attribute_list, HLS_KEYFORMAT_ATTRIBUTE,
|
if (!ExtractQuotedAttribute(attribute_list, HLS_KEYFORMAT_ATTRIBUTE,
|
||||||
&value)) {
|
&value)) {
|
||||||
@@ -228,21 +252,26 @@ bool InitializationData::ExtractHlsAttributes(const std::string& attribute_list,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExtractQuotedAttribute(attribute_list, HLS_KEYFORMAT_VERSION_ATTRIBUTE,
|
// KEYFORMATVERSIONS is an optional parameter. If absent its
|
||||||
|
// value defaults to "1"
|
||||||
|
if (ExtractQuotedAttribute(attribute_list, HLS_KEYFORMAT_VERSIONS_ATTRIBUTE,
|
||||||
&value)) {
|
&value)) {
|
||||||
LOGV(
|
std::vector<std::string> versions = ExtractKeyFormatVersions(value);
|
||||||
"InitializationData::ExtractHlsInitDataAtttribute: Unable to read HLS "
|
bool supported = false;
|
||||||
"keyformat version");
|
for (size_t i = 0; i < versions.size(); ++i) {
|
||||||
return false;
|
if (versions[i].compare(HLS_KEYFORMAT_VERSION_VALUE_1) == 0) {
|
||||||
|
supported = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (value.compare(HLS_KEYFORMAT_VERSION_VALUE_1)) {
|
if (!supported) {
|
||||||
LOGV(
|
LOGV(
|
||||||
"InitializationData::ExtractHlsInitDataAtttribute: HLS keyformat "
|
"InitializationData::ExtractHlsInitDataAtttribute: HLS keyformat "
|
||||||
"version is not supported: %s",
|
"version is not supported: %s",
|
||||||
value.c_str());
|
value.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!ExtractAttribute(attribute_list, HLS_METHOD_ATTRIBUTE, &value)) {
|
if (!ExtractAttribute(attribute_list, HLS_METHOD_ATTRIBUTE, &value)) {
|
||||||
LOGV(
|
LOGV(
|
||||||
@@ -279,17 +308,91 @@ bool InitializationData::ExtractHlsAttributes(const std::string& attribute_list,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> init_data_hex;
|
return true;
|
||||||
if (!ExtractHexAttribute(attribute_list, HLS_INITDATA_ATTRIBUTE,
|
}
|
||||||
&init_data_hex)) {
|
|
||||||
LOGV(
|
// Extracts a base64 encoded string from URI data. This is then base64 decoded
|
||||||
"InitializationData::ExtractHlsInitDataAtttribute: HLS initdata "
|
// and the Json formatted init data is then parsed. The information is used
|
||||||
"attribute not present");
|
// to generate a Widevine init data protobuf (WidevineCencHeader).
|
||||||
|
//
|
||||||
|
// An example of a widevine supported json formatted init data string is,
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "provider":"mlbamhbo",
|
||||||
|
// "content_id":"2015_Tears",
|
||||||
|
// "key_ids":
|
||||||
|
// [
|
||||||
|
// "371e135e1a985d75d198a7f41020dc23"
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
bool InitializationData::ConstructWidevineInitData(
|
||||||
|
const std::string& uri, CdmInitData* init_data_proto) {
|
||||||
|
if (!init_data_proto) {
|
||||||
|
LOGV("InitializationData::ConstructWidevineInitData: Invalid parameter");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_data->assign(reinterpret_cast<char*>(init_data_hex.data()),
|
size_t pos = uri.find(kBase64String);
|
||||||
init_data_hex.size());
|
if (pos == std::string::npos) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: URI attribute "
|
||||||
|
"unexpected format: %s",
|
||||||
|
uri.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> json_init_data =
|
||||||
|
Base64Decode(uri.substr(pos + kBase64String.size()));
|
||||||
|
if (json_init_data.size() == 0) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: Base64 decode of json "
|
||||||
|
"data failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string json_string((const char*)(&json_init_data[0]),
|
||||||
|
json_init_data.size());
|
||||||
|
|
||||||
|
// Parse json data
|
||||||
|
std::string provider;
|
||||||
|
if (!ExtractJsonValue(json_string, kProvider, &provider)) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: Unable to extract "
|
||||||
|
"provider value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string content_id;
|
||||||
|
if (!ExtractJsonValue(json_string, kContentId, &content_id)) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: Unable to extract "
|
||||||
|
"content_id value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key_id;
|
||||||
|
if (!ExtractJsonValue(json_string, kKeyIds, &key_id)) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: Unable to extract "
|
||||||
|
"key_id values");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_id = a2bs_hex(key_id);
|
||||||
|
if (key_id.size() != 16) {
|
||||||
|
LOGV(
|
||||||
|
"InitializationData::ConstructWidevineInitData: Invalid key_id size: "
|
||||||
|
"%ld",
|
||||||
|
key_id.size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now format as Widevine init data protobuf
|
||||||
|
WidevineCencHeader cenc_header;
|
||||||
|
cenc_header.set_algorithm(WidevineCencHeader_Algorithm_AESCTR);
|
||||||
|
cenc_header.add_key_id(key_id);
|
||||||
|
cenc_header.set_provider(provider);
|
||||||
|
cenc_header.set_content_id(content_id);
|
||||||
|
cenc_header.SerializeToString(init_data_proto);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,4 +468,63 @@ bool InitializationData::ExtractAttribute(const std::string& attribute_list,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InitializationData::ExtractJsonValue(const std::string& json,
|
||||||
|
const std::string& key,
|
||||||
|
std::string* value) {
|
||||||
|
std::string quoted_key = key;
|
||||||
|
quoted_key.insert(0, 1, kDoubleQuote);
|
||||||
|
quoted_key.append(1, kDoubleQuote);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
size_t pos = 0;
|
||||||
|
// Find the key followed by ':'
|
||||||
|
while (!found) {
|
||||||
|
pos = json.find(quoted_key, pos);
|
||||||
|
if (pos == std::string::npos) return false;
|
||||||
|
pos += quoted_key.size();
|
||||||
|
while (pos < json.size() && isspace(json[pos])) ++pos;
|
||||||
|
if (pos >= json.size()) return false;
|
||||||
|
if (json[pos] != kColon) continue;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pos;
|
||||||
|
while (pos < json.size() && isspace(json[pos])) ++pos;
|
||||||
|
if (pos >= json.size()) return false;
|
||||||
|
|
||||||
|
if (json[pos] == kLeftBracket) {
|
||||||
|
++pos;
|
||||||
|
while (pos < json.size() && isspace(json[pos])) ++pos;
|
||||||
|
if (pos >= json.size()) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json[pos] != kDoubleQuote) return false;
|
||||||
|
++pos;
|
||||||
|
size_t end_pos = json.find(kDoubleQuote, pos);
|
||||||
|
if (end_pos == std::string::npos) return false;
|
||||||
|
--end_pos;
|
||||||
|
*value = json.substr(pos, end_pos - pos + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key format versions are individual values or multiple versions
|
||||||
|
// separated by '/'. "1" or "1/2/5"
|
||||||
|
std::vector<std::string> InitializationData::ExtractKeyFormatVersions(
|
||||||
|
const std::string& key_format_versions) {
|
||||||
|
std::vector<std::string> versions;
|
||||||
|
size_t pos = 0;
|
||||||
|
while (pos < key_format_versions.size()) {
|
||||||
|
size_t next_pos =
|
||||||
|
key_format_versions.find(kKeyFormatVersionsSeparator, pos);
|
||||||
|
if (next_pos == std::string::npos) {
|
||||||
|
versions.push_back(key_format_versions.substr(pos));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
versions.push_back(key_format_versions.substr(pos, next_pos - pos));
|
||||||
|
pos = next_pos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -547,3 +547,42 @@ message SignedCertificateStatusList {
|
|||||||
// key using RSASSA-PSS. Required.
|
// key using RSASSA-PSS. Required.
|
||||||
optional bytes signature = 2;
|
optional bytes signature = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// widevine_header.proto
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// Public protocol buffer definitions for Widevine Cenc Header
|
||||||
|
// protocol.
|
||||||
|
message WidevineCencHeader {
|
||||||
|
enum Algorithm {
|
||||||
|
UNENCRYPTED = 0;
|
||||||
|
AESCTR = 1;
|
||||||
|
};
|
||||||
|
optional Algorithm algorithm = 1;
|
||||||
|
repeated bytes key_id = 2;
|
||||||
|
|
||||||
|
// Content provider name.
|
||||||
|
optional string provider = 3;
|
||||||
|
|
||||||
|
// A content identifier, specified by content provider.
|
||||||
|
optional bytes content_id = 4;
|
||||||
|
|
||||||
|
// Track type. Acceptable values are SD, HD and AUDIO. Used to differentiate
|
||||||
|
// content keys used by an asset.
|
||||||
|
// No longer adding track_type to the PSSH since the Widevine license server
|
||||||
|
// will return keys for all allowed track types in a single license.
|
||||||
|
optional string track_type_deprecated = 5;
|
||||||
|
|
||||||
|
// The name of a registered policy to be used for this asset.
|
||||||
|
optional string policy = 6;
|
||||||
|
|
||||||
|
// Crypto period index, for media using key rotation.
|
||||||
|
optional uint32 crypto_period_index = 7;
|
||||||
|
|
||||||
|
// Optional protected context for group content. The grouped_license is a
|
||||||
|
// serialized SignedMessage.
|
||||||
|
optional bytes grouped_license = 8;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "initialization_data.h"
|
#include "initialization_data.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
@@ -14,6 +15,21 @@ namespace wvcdm {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Constants for JSON formatting
|
||||||
|
const std::string kLeftBrace = "{";
|
||||||
|
const std::string kRightBrace = "}";
|
||||||
|
const std::string kLeftBracket = "[";
|
||||||
|
const std::string kRightBracket = "]";
|
||||||
|
const std::string kComma = ",";
|
||||||
|
const std::string kColon = ":";
|
||||||
|
const std::string kDoubleQuote = "\"";
|
||||||
|
const std::string kNewline = "\n";
|
||||||
|
const std::string kFourSpaceIndent = " ";
|
||||||
|
|
||||||
|
const std::string kJsonProvider = "provider";
|
||||||
|
const std::string kJsonContentId = "content_id";
|
||||||
|
const std::string kJsonKeyIds = "key_ids";
|
||||||
|
|
||||||
const std::string kWidevinePssh = a2bs_hex(
|
const std::string kWidevinePssh = a2bs_hex(
|
||||||
// Widevine PSSH box
|
// Widevine PSSH box
|
||||||
"00000042" // atom size
|
"00000042" // atom size
|
||||||
@@ -145,8 +161,6 @@ const std::string kHlsIvHexValue = "6DF49213A781E338628D0E9C812D328E";
|
|||||||
const std::string kHlsIvValue = "0x" + kHlsIvHexValue;
|
const std::string kHlsIvValue = "0x" + kHlsIvHexValue;
|
||||||
const std::string kHlsKeyFormatValue = "com.widevine.alpha";
|
const std::string kHlsKeyFormatValue = "com.widevine.alpha";
|
||||||
const std::string kHlsKeyFormatValueOther = "com.example";
|
const std::string kHlsKeyFormatValueOther = "com.example";
|
||||||
const std::string kHlsInitDataHexValue = b2a_hex(kWidevineV1Pssh);
|
|
||||||
const std::string kHlsInitDataValue = "0x" + kHlsInitDataHexValue;
|
|
||||||
const std::string kHlsTestKey1 = "TESTKEY1";
|
const std::string kHlsTestKey1 = "TESTKEY1";
|
||||||
const std::string kHlsTestValue1 = "testvalue1";
|
const std::string kHlsTestValue1 = "testvalue1";
|
||||||
const std::string kHlsTestKey2 = "TESTKEY2";
|
const std::string kHlsTestKey2 = "TESTKEY2";
|
||||||
@@ -159,62 +173,119 @@ const std::string kHlsTestEmptyHexValue = "";
|
|||||||
const std::string kHlsTestNoHexValue = "0x";
|
const std::string kHlsTestNoHexValue = "0x";
|
||||||
const std::string kHlsTestHexValueWithOddBytes = kHlsIvHexValue + "7";
|
const std::string kHlsTestHexValueWithOddBytes = kHlsIvHexValue + "7";
|
||||||
const std::string kHlsTestInvalidHexValue = kHlsIvHexValue + "g7";
|
const std::string kHlsTestInvalidHexValue = kHlsIvHexValue + "g7";
|
||||||
|
char kHlsTestKeyFormatVersionsSeparator = '/';
|
||||||
|
const std::string kHlsTestUriDataFormat = "data:text/plain;base64,";
|
||||||
|
const std::string kHlsTestProvider = "youtube";
|
||||||
|
const std::string kHlsTestContentId = "Tears_2015";
|
||||||
|
const std::string kHlsTestKeyId1 = "371e135e1a985d75d198a7f41020dc23";
|
||||||
|
const std::string kHlsTestKeyId2 = "e670d9b60ae61583e01bc9253fa19261";
|
||||||
|
const std::string kHlsTestKeyId3 = "78094e72165df39721b8a354d6a71390";
|
||||||
|
const std::string kHlsTestInvalidKeyId = "b8a354d6a71390";
|
||||||
|
|
||||||
// HLS attribute helper functions
|
// HLS attribute helper functions
|
||||||
std::string QuoteString(const std::string& value) {
|
std::string QuoteString(const std::string& value) {
|
||||||
return "\"" + value + "\"";
|
return "\"" + value + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GenerateJsonInitData(const std::string& provider,
|
||||||
|
const std::string& content_id,
|
||||||
|
const std::vector<std::string>& key_ids) {
|
||||||
|
std::string json = kLeftBrace + kNewline;
|
||||||
|
if (provider.size() > 0) {
|
||||||
|
json += kFourSpaceIndent + kDoubleQuote + kJsonProvider + kDoubleQuote +
|
||||||
|
kColon + kDoubleQuote + provider + kDoubleQuote + kComma + kNewline;
|
||||||
|
}
|
||||||
|
if (content_id.size() > 0) {
|
||||||
|
json += kFourSpaceIndent + kDoubleQuote + kJsonContentId + kDoubleQuote +
|
||||||
|
kColon + kDoubleQuote + content_id + kDoubleQuote + kComma +
|
||||||
|
kNewline;
|
||||||
|
}
|
||||||
|
if (key_ids.size() > 0) {
|
||||||
|
json += kFourSpaceIndent + kDoubleQuote + kJsonKeyIds + kDoubleQuote +
|
||||||
|
kColon + kNewline;
|
||||||
|
json += kFourSpaceIndent + kLeftBracket + kNewline;
|
||||||
|
for (size_t i = 0; i < key_ids.size(); ++i) {
|
||||||
|
json += kFourSpaceIndent + kFourSpaceIndent + kDoubleQuote + key_ids[i] +
|
||||||
|
kDoubleQuote;
|
||||||
|
if (i != key_ids.size() - 1) {
|
||||||
|
json += kComma;
|
||||||
|
}
|
||||||
|
json += kNewline;
|
||||||
|
}
|
||||||
|
json += kFourSpaceIndent + kRightBracket + kNewline;
|
||||||
|
}
|
||||||
|
json += kRightBrace + kNewline;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GenerateHlsUriData(const std::string& provider,
|
||||||
|
const std::string& content_id,
|
||||||
|
const std::vector<std::string>& key_ids) {
|
||||||
|
std::string json = GenerateJsonInitData(content_id, provider, key_ids);
|
||||||
|
std::vector<uint8_t> json_init_data(
|
||||||
|
reinterpret_cast<const uint8_t*>(json.data()),
|
||||||
|
reinterpret_cast<const uint8_t*>(json.data() + json.size()));
|
||||||
|
return kHlsTestUriDataFormat + Base64Encode(json_init_data);
|
||||||
|
}
|
||||||
|
|
||||||
std::string CreateHlsAttributeList(const std::string& method,
|
std::string CreateHlsAttributeList(const std::string& method,
|
||||||
const std::string& uri,
|
const std::string& uri,
|
||||||
const std::string& iv,
|
const std::string& iv,
|
||||||
const std::string& key_format,
|
const std::string& key_format,
|
||||||
const std::string& key_format_version,
|
const std::string& key_format_version) {
|
||||||
const std::string& init_data) {
|
|
||||||
return "EXT-X-KEY: " + HLS_METHOD_ATTRIBUTE + "=" + method + "," +
|
return "EXT-X-KEY: " + HLS_METHOD_ATTRIBUTE + "=" + method + "," +
|
||||||
HLS_URI_ATTRIBUTE + "=" + QuoteString(uri) + "," + HLS_IV_ATTRIBUTE +
|
HLS_URI_ATTRIBUTE + "=" + QuoteString(uri) + "," + HLS_IV_ATTRIBUTE +
|
||||||
"=" + iv + "," + HLS_KEYFORMAT_ATTRIBUTE + "=" +
|
"=" + iv + "," + HLS_KEYFORMAT_ATTRIBUTE + "=" +
|
||||||
QuoteString(key_format) + "," + HLS_KEYFORMAT_VERSION_ATTRIBUTE + "=" +
|
QuoteString(key_format) + "," + HLS_KEYFORMAT_VERSIONS_ATTRIBUTE +
|
||||||
QuoteString(key_format_version) + "," + HLS_INITDATA_ATTRIBUTE + "=" +
|
"=" + QuoteString(key_format_version);
|
||||||
init_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HLS Key Format Version lists for testing
|
||||||
|
std::vector<std::string> kHlsTestKeyFormatVersionsSingleVersion = {"1"};
|
||||||
|
std::vector<std::string> kHlsTestKeyFormatVersionsSingleVersionExtendedLength =
|
||||||
|
{"21"};
|
||||||
|
std::vector<std::string> kHlsTestKeyFormatVersionsTwoVersions = {"1", "2"};
|
||||||
|
std::vector<std::string> kHlsTestKeyFormatVersionsThreeVersions = {"1", "2",
|
||||||
|
"5"};
|
||||||
|
std::vector<std::string> kHlsTestKeyFormatVersionsFourVersions = {"3", "13",
|
||||||
|
"19", "27"};
|
||||||
|
|
||||||
// HLS attribute list for testing
|
// HLS attribute list for testing
|
||||||
const std::string kHlsAttributeList = CreateHlsAttributeList(
|
const std::string kHlsAttributeList =
|
||||||
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
|
CreateHlsAttributeList(HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListKeyFormatUnknown = CreateHlsAttributeList(
|
const std::string kHlsAttributeListKeyFormatUnknown = CreateHlsAttributeList(
|
||||||
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValueOther,
|
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValueOther,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListKeyFormatVersionUnsupported =
|
const std::string kHlsAttributeListKeyFormatVersionUnsupported =
|
||||||
CreateHlsAttributeList(HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue,
|
CreateHlsAttributeList(HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue,
|
||||||
kHlsKeyFormatValue, "2", kHlsInitDataValue);
|
kHlsKeyFormatValue, "2");
|
||||||
|
|
||||||
const std::string kHlsAttributeListMethodAes128 = CreateHlsAttributeList(
|
const std::string kHlsAttributeListMethodAes128 =
|
||||||
HLS_METHOD_AES_128, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
|
CreateHlsAttributeList(HLS_METHOD_AES_128, kHlsUriValue, kHlsIvValue,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListMethodNone = CreateHlsAttributeList(
|
const std::string kHlsAttributeListMethodNone =
|
||||||
HLS_METHOD_NONE, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
|
CreateHlsAttributeList(HLS_METHOD_NONE, kHlsUriValue, kHlsIvValue,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListMethodInvalid = CreateHlsAttributeList(
|
const std::string kHlsAttributeListMethodInvalid =
|
||||||
kHlsTestValue1, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
|
CreateHlsAttributeList(kHlsTestValue1, kHlsUriValue, kHlsIvValue,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListInvalidUri = CreateHlsAttributeList(
|
const std::string kHlsAttributeListInvalidUri = CreateHlsAttributeList(
|
||||||
HLS_METHOD_SAMPLE_AES, kHlsTestValueWithEmbeddedQuote, kHlsIvValue,
|
HLS_METHOD_SAMPLE_AES, kHlsTestValueWithEmbeddedQuote, kHlsIvValue,
|
||||||
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListInvalidIv = CreateHlsAttributeList(
|
const std::string kHlsAttributeListInvalidIv = CreateHlsAttributeList(
|
||||||
HLS_METHOD_SAMPLE_AES, kHlsTestHexValueWithOddBytes, kHlsTestNoHexValue,
|
HLS_METHOD_SAMPLE_AES, kHlsTestHexValueWithOddBytes, kHlsTestNoHexValue,
|
||||||
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
const std::string kHlsAttributeListInvalidInitData = CreateHlsAttributeList(
|
const std::string kHlsAttributeListInvalidInitData =
|
||||||
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
|
CreateHlsAttributeList(HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsTestInvalidHexValue);
|
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1);
|
||||||
|
|
||||||
std::string InsertHlsAttributeInList(const std::string key,
|
std::string InsertHlsAttributeInList(const std::string key,
|
||||||
const std::string& value) {
|
const std::string& value) {
|
||||||
@@ -222,6 +293,22 @@ std::string InsertHlsAttributeInList(const std::string key,
|
|||||||
"=" + kHlsTestValue2;
|
"=" + kHlsTestValue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HlsInitDataVariant {
|
||||||
|
HlsInitDataVariant(const std::string& provider, const std::string& content_id,
|
||||||
|
const std::string& key_id, bool success)
|
||||||
|
: provider_(provider), content_id_(content_id), success_(success) {
|
||||||
|
if (key_id.size() > 0) key_ids_.push_back(key_id);
|
||||||
|
}
|
||||||
|
HlsInitDataVariant AddKeyId(const std::string& key_id) {
|
||||||
|
key_ids_.push_back(key_id);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const std::string provider_;
|
||||||
|
const std::string content_id_;
|
||||||
|
std::vector<std::string> key_ids_;
|
||||||
|
const bool success_;
|
||||||
|
};
|
||||||
|
|
||||||
struct HlsAttributeVariant {
|
struct HlsAttributeVariant {
|
||||||
HlsAttributeVariant(const std::string& attribute_list, const std::string& key,
|
HlsAttributeVariant(const std::string& attribute_list, const std::string& key,
|
||||||
const std::string& value, bool success)
|
const std::string& value, bool success)
|
||||||
@@ -246,8 +333,13 @@ class HlsHexAttributeExtractionTest
|
|||||||
class HlsQuotedAttributeExtractionTest
|
class HlsQuotedAttributeExtractionTest
|
||||||
: public ::testing::TestWithParam<HlsAttributeVariant> {};
|
: public ::testing::TestWithParam<HlsAttributeVariant> {};
|
||||||
|
|
||||||
class HlsParseTest
|
class HlsKeyFormatVersionsExtractionTest
|
||||||
: public ::testing::TestWithParam<HlsAttributeVariant> {};
|
: public ::testing::TestWithParam<std::vector<std::string> > {};
|
||||||
|
|
||||||
|
class HlsConstructionTest
|
||||||
|
: public ::testing::TestWithParam<HlsInitDataVariant> {};
|
||||||
|
|
||||||
|
class HlsParseTest : public ::testing::TestWithParam<HlsAttributeVariant> {};
|
||||||
|
|
||||||
class HlsTest : public ::testing::Test {};
|
class HlsTest : public ::testing::Test {};
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -265,6 +357,37 @@ INSTANTIATE_TEST_CASE_P(ParsePssh, InitializationDataTest,
|
|||||||
kWidevineV1Pssh, kOtherBoxFirst,
|
kWidevineV1Pssh, kOtherBoxFirst,
|
||||||
kZeroSizedPsshBox));
|
kZeroSizedPsshBox));
|
||||||
|
|
||||||
|
TEST_P(HlsKeyFormatVersionsExtractionTest, ExtractKeyFormatVersions) {
|
||||||
|
std::vector<std::string> versions = GetParam();
|
||||||
|
std::string key_format_versions;
|
||||||
|
for (size_t i = 0; i < versions.size(); ++i) {
|
||||||
|
key_format_versions += versions[i] + kHlsTestKeyFormatVersionsSeparator;
|
||||||
|
}
|
||||||
|
key_format_versions.resize(key_format_versions.size() -
|
||||||
|
sizeof(kHlsTestKeyFormatVersionsSeparator));
|
||||||
|
std::vector<std::string> extracted_versions =
|
||||||
|
InitializationData::ExtractKeyFormatVersions(key_format_versions);
|
||||||
|
EXPECT_EQ(versions.size(), extracted_versions.size());
|
||||||
|
for (size_t i = 0; i < versions.size(); ++i) {
|
||||||
|
bool found = false;
|
||||||
|
for (size_t j = 0; j < extracted_versions.size(); ++j) {
|
||||||
|
if (versions[i] == extracted_versions[j]) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(
|
||||||
|
HlsTest, HlsKeyFormatVersionsExtractionTest,
|
||||||
|
::testing::Values(kHlsTestKeyFormatVersionsSingleVersion,
|
||||||
|
kHlsTestKeyFormatVersionsSingleVersionExtendedLength,
|
||||||
|
kHlsTestKeyFormatVersionsTwoVersions,
|
||||||
|
kHlsTestKeyFormatVersionsThreeVersions,
|
||||||
|
kHlsTestKeyFormatVersionsFourVersions));
|
||||||
|
|
||||||
TEST_P(HlsAttributeExtractionTest, ExtractAttribute) {
|
TEST_P(HlsAttributeExtractionTest, ExtractAttribute) {
|
||||||
HlsAttributeVariant param = GetParam();
|
HlsAttributeVariant param = GetParam();
|
||||||
std::string value;
|
std::string value;
|
||||||
@@ -289,10 +412,8 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
true),
|
true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
|
||||||
QuoteString(kHlsKeyFormatValue), true),
|
QuoteString(kHlsKeyFormatValue), true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSION_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSIONS_ATTRIBUTE,
|
||||||
QuoteString(HLS_KEYFORMAT_VERSION_VALUE_1), true),
|
QuoteString(HLS_KEYFORMAT_VERSION_VALUE_1), true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
|
|
||||||
kHlsInitDataValue, true),
|
|
||||||
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
|
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
|
||||||
kHlsTestValue1),
|
kHlsTestValue1),
|
||||||
kHlsTestKey1, kHlsTestValue1, true),
|
kHlsTestKey1, kHlsTestValue1, true),
|
||||||
@@ -349,10 +470,6 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
::testing::Values(
|
::testing::Values(
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_IV_ATTRIBUTE, kHlsIvHexValue,
|
HlsAttributeVariant(kHlsAttributeList, HLS_IV_ATTRIBUTE, kHlsIvHexValue,
|
||||||
true),
|
true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
|
|
||||||
kHlsInitDataHexValue, true),
|
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
|
|
||||||
kHlsInitDataHexValue, true),
|
|
||||||
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
|
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
|
||||||
kHlsTestEmptyHexValue),
|
kHlsTestEmptyHexValue),
|
||||||
kHlsTestKey1, kHlsTestEmptyHexValue, false),
|
kHlsTestKey1, kHlsTestEmptyHexValue, false),
|
||||||
@@ -386,7 +503,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
true),
|
true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
|
||||||
kHlsKeyFormatValue, true),
|
kHlsKeyFormatValue, true),
|
||||||
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSION_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSIONS_ATTRIBUTE,
|
||||||
HLS_KEYFORMAT_VERSION_VALUE_1, true),
|
HLS_KEYFORMAT_VERSION_VALUE_1, true),
|
||||||
HlsAttributeVariant(
|
HlsAttributeVariant(
|
||||||
InsertHlsAttributeInList(kHlsTestKey1, QuoteString(kHlsTestValue1)),
|
InsertHlsAttributeInList(kHlsTestKey1, QuoteString(kHlsTestValue1)),
|
||||||
@@ -396,7 +513,41 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
kHlsTestKey1, QuoteString(kHlsTestValueWithEmbeddedQuote)),
|
kHlsTestKey1, QuoteString(kHlsTestValueWithEmbeddedQuote)),
|
||||||
kHlsTestKey1, kHlsTestValueWithEmbeddedQuote, false)));
|
kHlsTestKey1, kHlsTestValueWithEmbeddedQuote, false)));
|
||||||
|
|
||||||
TEST_P(HlsParseTest, Parse) {
|
TEST_P(HlsConstructionTest, InitData) {
|
||||||
|
HlsInitDataVariant param = GetParam();
|
||||||
|
|
||||||
|
std::string uri =
|
||||||
|
GenerateHlsUriData(param.provider_, param.content_id_, param.key_ids_);
|
||||||
|
std::string value;
|
||||||
|
if (param.success_) {
|
||||||
|
EXPECT_TRUE(InitializationData::ConstructWidevineInitData(uri, &value));
|
||||||
|
// EXPECT_EQ(param.value_, value);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(InitializationData::ConstructWidevineInitData(uri, &value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(
|
||||||
|
HlsTest, HlsConstructionTest,
|
||||||
|
::testing::Values(HlsInitDataVariant(std::string(), kHlsTestContentId,
|
||||||
|
kHlsTestKeyId1, false),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, std::string(),
|
||||||
|
kHlsTestKeyId1, false),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId,
|
||||||
|
std::string(), false),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId,
|
||||||
|
kHlsTestInvalidKeyId, false),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId,
|
||||||
|
kHlsTestKeyId1, true),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId,
|
||||||
|
kHlsTestKeyId1, true)
|
||||||
|
.AddKeyId(kHlsTestKeyId2)
|
||||||
|
.AddKeyId(kHlsTestKeyId3),
|
||||||
|
HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId,
|
||||||
|
kHlsTestInvalidKeyId, false)
|
||||||
|
.AddKeyId(kHlsTestKeyId1)));
|
||||||
|
|
||||||
|
TEST_P(HlsParseTest, DISABLED_Parse) {
|
||||||
HlsAttributeVariant param = GetParam();
|
HlsAttributeVariant param = GetParam();
|
||||||
InitializationData init_data(HLS_INIT_DATA_FORMAT, param.attribute_list_);
|
InitializationData init_data(HLS_INIT_DATA_FORMAT, param.attribute_list_);
|
||||||
if (param.success_) {
|
if (param.success_) {
|
||||||
@@ -404,17 +555,16 @@ TEST_P(HlsParseTest, Parse) {
|
|||||||
EXPECT_FALSE(init_data.IsEmpty());
|
EXPECT_FALSE(init_data.IsEmpty());
|
||||||
if (param.key_.compare(HLS_METHOD_ATTRIBUTE) == 0) {
|
if (param.key_.compare(HLS_METHOD_ATTRIBUTE) == 0) {
|
||||||
if (param.value_.compare(HLS_METHOD_SAMPLE_AES) == 0) {
|
if (param.value_.compare(HLS_METHOD_SAMPLE_AES) == 0) {
|
||||||
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_data().method);
|
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_method());
|
||||||
} else if (param.value_.compare(HLS_METHOD_AES_128) == 0) {
|
} else if (param.value_.compare(HLS_METHOD_AES_128) == 0) {
|
||||||
EXPECT_EQ(kHlsMethodAes128, init_data.hls_data().method);
|
EXPECT_EQ(kHlsMethodAes128, init_data.hls_method());
|
||||||
} else if (param.value_.compare(HLS_METHOD_NONE) == 0) {
|
} else if (param.value_.compare(HLS_METHOD_NONE) == 0) {
|
||||||
EXPECT_EQ(kHlsMethodNone, init_data.hls_data().method);
|
EXPECT_EQ(kHlsMethodNone, init_data.hls_method());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_data().method);
|
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_method());
|
||||||
}
|
}
|
||||||
EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_data().iv));
|
EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_iv()));
|
||||||
EXPECT_EQ(kHlsUriValue, init_data.hls_data().uri);
|
|
||||||
} else {
|
} else {
|
||||||
EXPECT_TRUE(init_data.is_hls());
|
EXPECT_TRUE(init_data.is_hls());
|
||||||
EXPECT_TRUE(init_data.IsEmpty());
|
EXPECT_TRUE(init_data.IsEmpty());
|
||||||
@@ -429,7 +579,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
HLS_KEYFORMAT_ATTRIBUTE, kHlsKeyFormatValueOther,
|
HLS_KEYFORMAT_ATTRIBUTE, kHlsKeyFormatValueOther,
|
||||||
false),
|
false),
|
||||||
HlsAttributeVariant(kHlsAttributeListKeyFormatVersionUnsupported,
|
HlsAttributeVariant(kHlsAttributeListKeyFormatVersionUnsupported,
|
||||||
HLS_KEYFORMAT_VERSION_ATTRIBUTE, "2", false),
|
HLS_KEYFORMAT_VERSIONS_ATTRIBUTE, "2", false),
|
||||||
HlsAttributeVariant(kHlsAttributeListMethodAes128, HLS_METHOD_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeListMethodAes128, HLS_METHOD_ATTRIBUTE,
|
||||||
HLS_METHOD_AES_128, true),
|
HLS_METHOD_AES_128, true),
|
||||||
HlsAttributeVariant(kHlsAttributeListMethodNone, HLS_METHOD_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeListMethodNone, HLS_METHOD_ATTRIBUTE,
|
||||||
@@ -439,8 +589,6 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
HlsAttributeVariant(kHlsAttributeListInvalidUri, HLS_URI_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeListInvalidUri, HLS_URI_ATTRIBUTE,
|
||||||
kHlsTestValueWithEmbeddedQuote, false),
|
kHlsTestValueWithEmbeddedQuote, false),
|
||||||
HlsAttributeVariant(kHlsAttributeListInvalidIv, HLS_IV_ATTRIBUTE,
|
HlsAttributeVariant(kHlsAttributeListInvalidIv, HLS_IV_ATTRIBUTE,
|
||||||
kHlsTestHexValueWithOddBytes, false),
|
kHlsTestHexValueWithOddBytes, false)));
|
||||||
HlsAttributeVariant(kHlsAttributeListInvalidInitData,
|
|
||||||
HLS_INITDATA_ATTRIBUTE, kHlsTestInvalidHexValue,
|
|
||||||
false)));
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
Reference in New Issue
Block a user