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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user