Modify initialization data to support HLS

[ Merge of http://go/wvgerrit/16290 ]

HLS uses an EXT-X-KEY tag and attribute list in the media playlist to
identify the key and method used to encrypt media segments. This allows
for the attributes to be parsed and extracted.

b/20630275

Change-Id: I2c4a419022f933b7b34b64dc48930f167abe65c6
This commit is contained in:
Rahul Frias
2016-01-07 13:06:42 -08:00
parent 53463f292d
commit 355471c408
5 changed files with 571 additions and 34 deletions

View File

@@ -139,8 +139,117 @@ const std::string kZeroSizedPsshBox = a2bs_hex(
// data:
"08011a0d7769646576696e655f74657374220f73747265616d696e675f636c697031");
// HLS test attribute key and values
const std::string kHlsUriValue = "http://www.youtube.com/license-service";
const std::string kHlsIvHexValue = "6DF49213A781E338628D0E9C812D328E";
const std::string kHlsIvValue = "0x" + kHlsIvHexValue;
const std::string kHlsKeyFormatValue = "com.widevine.alpha";
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 kHlsTestValue1 = "testvalue1";
const std::string kHlsTestKey2 = "TESTKEY2";
const std::string kHlsTestValue2 = "testvalue2";
const std::string kHlsTestInvalidLowercaseKey = "testkey3";
const std::string kHlsTestKeyWithDash = "TEST-KEY4";
const std::string kHlsTestInvalidNonAlphanumKey = "TEST;KEY4";
const std::string kHlsTestValueWithEmbeddedQuote = "test\"value1";
const std::string kHlsTestEmptyHexValue = "";
const std::string kHlsTestNoHexValue = "0x";
const std::string kHlsTestHexValueWithOddBytes = kHlsIvHexValue + "7";
const std::string kHlsTestInvalidHexValue = kHlsIvHexValue + "g7";
// HLS attribute helper functions
std::string QuoteString(const std::string& value) {
return "\"" + value + "\"";
}
std::string CreateHlsAttributeList(const std::string& method,
const std::string& uri,
const std::string& iv,
const std::string& key_format,
const std::string& key_format_version,
const std::string& init_data) {
return "EXT-X-KEY: " + HLS_METHOD_ATTRIBUTE + "=" + method + "," +
HLS_URI_ATTRIBUTE + "=" + QuoteString(uri) + "," + HLS_IV_ATTRIBUTE +
"=" + iv + "," + HLS_KEYFORMAT_ATTRIBUTE + "=" +
QuoteString(key_format) + "," + HLS_KEYFORMAT_VERSION_ATTRIBUTE + "=" +
QuoteString(key_format_version) + "," + HLS_INITDATA_ATTRIBUTE + "=" +
init_data;
}
// HLS attribute list for testing
const std::string kHlsAttributeList = CreateHlsAttributeList(
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListKeyFormatUnknown = CreateHlsAttributeList(
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValueOther,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListKeyFormatVersionUnsupported =
CreateHlsAttributeList(HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue,
kHlsKeyFormatValue, "2", kHlsInitDataValue);
const std::string kHlsAttributeListMethodAes128 = CreateHlsAttributeList(
HLS_METHOD_AES_128, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListMethodNone = CreateHlsAttributeList(
HLS_METHOD_NONE, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListMethodInvalid = CreateHlsAttributeList(
kHlsTestValue1, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListInvalidUri = CreateHlsAttributeList(
HLS_METHOD_SAMPLE_AES, kHlsTestValueWithEmbeddedQuote, kHlsIvValue,
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListInvalidIv = CreateHlsAttributeList(
HLS_METHOD_SAMPLE_AES, kHlsTestHexValueWithOddBytes, kHlsTestNoHexValue,
kHlsKeyFormatValue, HLS_KEYFORMAT_VERSION_VALUE_1, kHlsInitDataValue);
const std::string kHlsAttributeListInvalidInitData = CreateHlsAttributeList(
HLS_METHOD_SAMPLE_AES, kHlsUriValue, kHlsIvValue, kHlsKeyFormatValue,
HLS_KEYFORMAT_VERSION_VALUE_1, kHlsTestInvalidHexValue);
std::string InsertHlsAttributeInList(const std::string key,
const std::string& value) {
return kHlsAttributeList + "," + key + "=" + value + "," + kHlsTestKey2 +
"=" + kHlsTestValue2;
}
struct HlsAttributeVariant {
HlsAttributeVariant(const std::string& attribute_list, const std::string& key,
const std::string& value, bool success)
: attribute_list_(attribute_list),
key_(key),
value_(value),
success_(success) {}
const std::string attribute_list_;
const std::string key_;
const std::string value_;
const bool success_;
};
class InitializationDataTest : public ::testing::TestWithParam<std::string> {};
class HlsAttributeExtractionTest
: public ::testing::TestWithParam<HlsAttributeVariant> {};
class HlsHexAttributeExtractionTest
: public ::testing::TestWithParam<HlsAttributeVariant> {};
class HlsQuotedAttributeExtractionTest
: public ::testing::TestWithParam<HlsAttributeVariant> {};
class HlsParseTest
: public ::testing::TestWithParam<HlsAttributeVariant> {};
class HlsTest : public ::testing::Test {};
} // namespace
TEST_P(InitializationDataTest, Parse) {
@@ -148,17 +257,190 @@ TEST_P(InitializationDataTest, Parse) {
EXPECT_FALSE(init_data.IsEmpty());
}
INSTANTIATE_TEST_CASE_P(
ParsePssh, InitializationDataTest,
::testing::Values(
kWidevinePssh,
kWidevinePsshFirst,
kWidevinePsshAfterV0Pssh,
kWidevinePsshAfterNonZeroFlags,
kWidevinePsshAfterV1Pssh,
kWidevineV1Pssh,
kOtherBoxFirst,
kZeroSizedPsshBox
));
INSTANTIATE_TEST_CASE_P(ParsePssh, InitializationDataTest,
::testing::Values(kWidevinePssh, kWidevinePsshFirst,
kWidevinePsshAfterV0Pssh,
kWidevinePsshAfterNonZeroFlags,
kWidevinePsshAfterV1Pssh,
kWidevineV1Pssh, kOtherBoxFirst,
kZeroSizedPsshBox));
TEST_P(HlsAttributeExtractionTest, ExtractAttribute) {
HlsAttributeVariant param = GetParam();
std::string value;
if (param.success_) {
EXPECT_TRUE(InitializationData::ExtractAttribute(param.attribute_list_,
param.key_, &value));
EXPECT_EQ(param.value_, value);
} else {
EXPECT_FALSE(InitializationData::ExtractAttribute(param.attribute_list_,
param.key_, &value));
}
}
INSTANTIATE_TEST_CASE_P(
HlsTest, HlsAttributeExtractionTest,
::testing::Values(
HlsAttributeVariant(kHlsAttributeList, HLS_METHOD_ATTRIBUTE,
HLS_METHOD_SAMPLE_AES, true),
HlsAttributeVariant(kHlsAttributeList, HLS_URI_ATTRIBUTE,
QuoteString(kHlsUriValue), true),
HlsAttributeVariant(kHlsAttributeList, HLS_IV_ATTRIBUTE, kHlsIvValue,
true),
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
QuoteString(kHlsKeyFormatValue), true),
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSION_ATTRIBUTE,
QuoteString(HLS_KEYFORMAT_VERSION_VALUE_1), true),
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
kHlsInitDataValue, true),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestValue1),
kHlsTestKey1, kHlsTestValue1, true),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestValue1),
kHlsTestKey2, kHlsTestValue2, true),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1 + "\t",
kHlsTestValue1),
kHlsTestKey1, kHlsTestValue1, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
" " + kHlsTestValue1),
kHlsTestKey1, kHlsTestValue1, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestValue1 + " "),
kHlsTestKey1, kHlsTestValue1, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1 + "3",
kHlsTestValue1),
kHlsTestKey1, kHlsTestValue1, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1, ""),
kHlsTestKey1, "", true),
HlsAttributeVariant(InsertHlsAttributeInList(
kHlsTestInvalidLowercaseKey, kHlsTestValue1),
kHlsTestInvalidLowercaseKey, kHlsTestValue1, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKeyWithDash,
kHlsTestValue1),
kHlsTestKeyWithDash, kHlsTestValue1, true),
HlsAttributeVariant(InsertHlsAttributeInList(
kHlsTestInvalidNonAlphanumKey, kHlsTestValue1),
kHlsTestInvalidNonAlphanumKey, kHlsTestValue1,
false),
HlsAttributeVariant(
InsertHlsAttributeInList(kHlsTestKey1, QuoteString(kHlsTestValue1)),
kHlsTestKey1, QuoteString(kHlsTestValue1), true),
HlsAttributeVariant(
InsertHlsAttributeInList(
kHlsTestKey1, QuoteString(kHlsTestValueWithEmbeddedQuote)),
kHlsTestKey1, QuoteString(kHlsTestValueWithEmbeddedQuote), true)));
TEST_P(HlsHexAttributeExtractionTest, ExtractHexAttribute) {
HlsAttributeVariant param = GetParam();
std::vector<uint8_t> value;
if (param.success_) {
EXPECT_TRUE(InitializationData::ExtractHexAttribute(param.attribute_list_,
param.key_, &value));
EXPECT_EQ(param.value_, b2a_hex(value));
} else {
EXPECT_FALSE(InitializationData::ExtractHexAttribute(param.attribute_list_,
param.key_, &value));
}
}
INSTANTIATE_TEST_CASE_P(
HlsTest, HlsHexAttributeExtractionTest,
::testing::Values(
HlsAttributeVariant(kHlsAttributeList, HLS_IV_ATTRIBUTE, kHlsIvHexValue,
true),
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
kHlsInitDataHexValue, true),
HlsAttributeVariant(kHlsAttributeList, HLS_INITDATA_ATTRIBUTE,
kHlsInitDataHexValue, true),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestEmptyHexValue),
kHlsTestKey1, kHlsTestEmptyHexValue, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestNoHexValue),
kHlsTestKey1, kHlsTestNoHexValue, false),
HlsAttributeVariant(InsertHlsAttributeInList(
kHlsTestKey1, kHlsTestHexValueWithOddBytes),
kHlsTestKey1, kHlsTestHexValueWithOddBytes, false),
HlsAttributeVariant(InsertHlsAttributeInList(kHlsTestKey1,
kHlsTestInvalidHexValue),
kHlsTestKey1, kHlsTestInvalidHexValue, false)));
TEST_P(HlsQuotedAttributeExtractionTest, ExtractQuotedAttribute) {
HlsAttributeVariant param = GetParam();
std::string value;
if (param.success_) {
EXPECT_TRUE(InitializationData::ExtractQuotedAttribute(
param.attribute_list_, param.key_, &value));
EXPECT_EQ(param.value_, value);
} else {
EXPECT_FALSE(InitializationData::ExtractQuotedAttribute(
param.attribute_list_, param.key_, &value));
}
}
INSTANTIATE_TEST_CASE_P(
HlsTest, HlsQuotedAttributeExtractionTest,
::testing::Values(
HlsAttributeVariant(kHlsAttributeList, HLS_URI_ATTRIBUTE, kHlsUriValue,
true),
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_ATTRIBUTE,
kHlsKeyFormatValue, true),
HlsAttributeVariant(kHlsAttributeList, HLS_KEYFORMAT_VERSION_ATTRIBUTE,
HLS_KEYFORMAT_VERSION_VALUE_1, true),
HlsAttributeVariant(
InsertHlsAttributeInList(kHlsTestKey1, QuoteString(kHlsTestValue1)),
kHlsTestKey1, kHlsTestValue1, true),
HlsAttributeVariant(
InsertHlsAttributeInList(
kHlsTestKey1, QuoteString(kHlsTestValueWithEmbeddedQuote)),
kHlsTestKey1, kHlsTestValueWithEmbeddedQuote, false)));
TEST_P(HlsParseTest, Parse) {
HlsAttributeVariant param = GetParam();
InitializationData init_data(HLS_INIT_DATA_FORMAT, param.attribute_list_);
if (param.success_) {
EXPECT_TRUE(init_data.is_hls());
EXPECT_FALSE(init_data.IsEmpty());
if (param.key_.compare(HLS_METHOD_ATTRIBUTE) == 0) {
if (param.value_.compare(HLS_METHOD_SAMPLE_AES) == 0) {
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_data().method);
} else if (param.value_.compare(HLS_METHOD_AES_128) == 0) {
EXPECT_EQ(kHlsMethodAes128, init_data.hls_data().method);
} else if (param.value_.compare(HLS_METHOD_NONE) == 0) {
EXPECT_EQ(kHlsMethodNone, init_data.hls_data().method);
}
} else {
EXPECT_EQ(kHlsMethodSampleAes, init_data.hls_data().method);
}
EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_data().iv));
EXPECT_EQ(kHlsUriValue, init_data.hls_data().uri);
} else {
EXPECT_TRUE(init_data.is_hls());
EXPECT_TRUE(init_data.IsEmpty());
}
}
INSTANTIATE_TEST_CASE_P(
HlsTest, HlsParseTest,
::testing::Values(
HlsAttributeVariant(kHlsAttributeList, "", "", true),
HlsAttributeVariant(kHlsAttributeListKeyFormatUnknown,
HLS_KEYFORMAT_ATTRIBUTE, kHlsKeyFormatValueOther,
false),
HlsAttributeVariant(kHlsAttributeListKeyFormatVersionUnsupported,
HLS_KEYFORMAT_VERSION_ATTRIBUTE, "2", false),
HlsAttributeVariant(kHlsAttributeListMethodAes128, HLS_METHOD_ATTRIBUTE,
HLS_METHOD_AES_128, true),
HlsAttributeVariant(kHlsAttributeListMethodNone, HLS_METHOD_ATTRIBUTE,
HLS_METHOD_NONE, true),
HlsAttributeVariant(kHlsAttributeListMethodInvalid,
HLS_METHOD_ATTRIBUTE, kHlsTestValue1, false),
HlsAttributeVariant(kHlsAttributeListInvalidUri, HLS_URI_ATTRIBUTE,
kHlsTestValueWithEmbeddedQuote, false),
HlsAttributeVariant(kHlsAttributeListInvalidIv, HLS_IV_ATTRIBUTE,
kHlsTestHexValueWithOddBytes, false),
HlsAttributeVariant(kHlsAttributeListInvalidInitData,
HLS_INITDATA_ATTRIBUTE, kHlsTestInvalidHexValue,
false)));
} // namespace wvcdm