diff --git a/libwvdrmengine/cdm/core/include/initialization_data.h b/libwvdrmengine/cdm/core/include/initialization_data.h index f1ac8d74..c4edbd06 100644 --- a/libwvdrmengine/cdm/core/include/initialization_data.h +++ b/libwvdrmengine/cdm/core/include/initialization_data.h @@ -36,9 +36,9 @@ class InitializationData { bool ExtractHlsAttributes(const std::string& attribute_list, CdmHlsMethod* method, std::vector* iv, std::string* uri); - static bool ConstructWidevineInitData(const std::string& uri, - CdmInitData* output); - + static bool ConstructWidevineInitData(CdmHlsMethod method, + const std::string& uri, + CdmInitData* output); static bool ExtractQuotedAttribute(const std::string& attribute_list, const std::string& key, std::string* value); diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp index 13f4e404..ea692e01 100644 --- a/libwvdrmengine/cdm/core/src/initialization_data.cpp +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -20,6 +20,7 @@ const char kDoubleQuote = '\"'; const char kLeftBracket = '['; const char kRightBracket = ']'; const std::string kBase64String = "base64,"; +const uint32_t kFourCcCbc1 = 0x63626331; const uint32_t kFourCcCbcs = 0x63626373; // json init data key values @@ -63,7 +64,7 @@ InitializationData::InitializationData(const std::string& type, } else if (is_hls()) { std::string uri; if (ExtractHlsAttributes(data, &hls_method_, &hls_iv_, &uri)) { - ConstructWidevineInitData(uri, &data_); + ConstructWidevineInitData(hls_method_, uri, &data_); } } } @@ -332,11 +333,16 @@ bool InitializationData::ExtractHlsAttributes(const std::string& attribute_list, // ] // } bool InitializationData::ConstructWidevineInitData( - const std::string& uri, CdmInitData* init_data_proto) { + CdmHlsMethod method, const std::string& uri, CdmInitData* init_data_proto) { if (!init_data_proto) { LOGV("InitializationData::ConstructWidevineInitData: Invalid parameter"); return false; } + if (method != kHlsMethodAes128 && method != kHlsMethodSampleAes) { + LOGV("InitializationData::ConstructWidevineInitData: Invalid method" + " parameter"); + return false; + } size_t pos = uri.find(kBase64String); if (pos == std::string::npos) { @@ -419,8 +425,12 @@ bool InitializationData::ConstructWidevineInitData( break; case kContentIdState: if (tokens[i].type == JSMN_STRING) { - content_id.assign(json_string, tokens[i].start, - tokens[i].end - tokens[i].start); + std::string base64_content_id(json_string, tokens[i].start, + tokens[i].end - tokens[i].start); + std::vector content_id_data = + Base64Decode(base64_content_id); + content_id.assign(reinterpret_cast(&content_id_data[0]), + content_id_data.size()); } state = kParseState; break; @@ -465,7 +475,10 @@ bool InitializationData::ConstructWidevineInitData( } cenc_header.set_provider(provider); cenc_header.set_content_id(content_id); - cenc_header.set_protection_scheme(htonl(kFourCcCbcs)); + if (method == kHlsMethodAes128) + cenc_header.set_protection_scheme(htonl(kFourCcCbc1)); + else + cenc_header.set_protection_scheme(htonl(kFourCcCbcs)); cenc_header.SerializeToString(init_data_proto); return true; } diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 9509bf0b..20591e5f 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -246,7 +246,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( LicenseRequest_ContentIdentification* content_id = license_request.mutable_content_id(); - if (init_data.is_cenc()) { + if (init_data.is_cenc() || init_data.is_hls()) { LicenseRequest_ContentIdentification_CENC* cenc_content_id = content_id->mutable_cenc_id(); diff --git a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp index afce8bfb..e8de2ea2 100644 --- a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp @@ -1,5 +1,6 @@ // Copyright 2015 Google Inc. All Rights Reserved. +#include #include #include @@ -35,6 +36,9 @@ const std::string kJsonProvider = "provider"; const std::string kJsonContentId = "content_id"; const std::string kJsonKeyIds = "key_ids"; +const uint32_t kFourCcCbc1 = 0x63626331; +const uint32_t kFourCcCbcs = 0x63626373; + const std::string kWidevinePssh = a2bs_hex( // Widevine PSSH box "00000042" // atom size @@ -346,15 +350,18 @@ std::string InsertHlsAttributeInList(const std::string key, } 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) { + HlsInitDataVariant(CdmHlsMethod method, const std::string& provider, + const std::string& content_id, const std::string& key_id, + bool success) + : method_(method), 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 CdmHlsMethod method_; const std::string provider_; const std::string content_id_; std::vector key_ids_; @@ -588,8 +595,9 @@ TEST_P(HlsConstructionTest, InitData) { std::string uri = GenerateHlsUriData(param.provider_, param.content_id_, param.key_ids_); std::string value; + EXPECT_EQ(param.success_, InitializationData::ConstructWidevineInitData( + param.method_, uri, &value)); if (param.success_) { - EXPECT_TRUE(InitializationData::ConstructWidevineInitData(uri, &value)); WidevineCencHeader cenc_header; EXPECT_TRUE(cenc_header.ParseFromString(value)); EXPECT_EQ(video_widevine_server::sdk::WidevineCencHeader_Algorithm_AESCTR, @@ -606,28 +614,50 @@ TEST_P(HlsConstructionTest, InitData) { EXPECT_TRUE(key_id_found); } EXPECT_EQ(param.provider_, cenc_header.provider()); - EXPECT_EQ(param.content_id_, cenc_header.content_id()); - } else { - EXPECT_FALSE(InitializationData::ConstructWidevineInitData(uri, &value)); + std::vector param_content_id_vec(Base64Decode(param.content_id_)); + EXPECT_EQ( + std::string(param_content_id_vec.begin(), param_content_id_vec.end()), + cenc_header.content_id()); + uint32_t protection_scheme = 0; + switch (param.method_) { + case kHlsMethodAes128: protection_scheme = kFourCcCbc1; break; + case kHlsMethodSampleAes: protection_scheme = kFourCcCbcs; break; + default: break; + } + EXPECT_EQ(protection_scheme, ntohl(cenc_header.protection_scheme())); } } INSTANTIATE_TEST_CASE_P( HlsTest, HlsConstructionTest, ::testing::Values( - HlsInitDataVariant("", kHlsTestContentId, kHlsTestKeyId1, false), - HlsInitDataVariant(kHlsTestProvider, "", kHlsTestKeyId1, false), - HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId, "", false), - HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId, - kHlsTestInvalidKeyId, false), - HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId, kHlsTestKeyId1, - true), - HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId, kHlsTestKeyId1, - true) + HlsInitDataVariant(kHlsMethodAes128, "", kHlsTestContentId, + kHlsTestKeyId1, false), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + "", kHlsTestKeyId1, false), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + kHlsTestContentId, "", false), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + kHlsTestContentId, kHlsTestInvalidKeyId, false), + HlsInitDataVariant(kHlsMethodNone, kHlsTestProvider, kHlsTestContentId, + kHlsTestKeyId1, false), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + kHlsTestContentId, kHlsTestKeyId1, true), + HlsInitDataVariant(kHlsMethodSampleAes, kHlsTestProvider, + kHlsTestContentId, kHlsTestKeyId1, true), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + kHlsTestContentId, kHlsTestKeyId1, true) .AddKeyId(kHlsTestKeyId2) .AddKeyId(kHlsTestKeyId3), - HlsInitDataVariant(kHlsTestProvider, kHlsTestContentId, - kHlsTestInvalidKeyId, true) + HlsInitDataVariant(kHlsMethodSampleAes, kHlsTestProvider, + kHlsTestContentId, kHlsTestKeyId1, true) + .AddKeyId(kHlsTestKeyId2) + .AddKeyId(kHlsTestKeyId3), + HlsInitDataVariant(kHlsMethodAes128, kHlsTestProvider, + kHlsTestContentId, kHlsTestInvalidKeyId, true) + .AddKeyId(kHlsTestKeyId1), + HlsInitDataVariant(kHlsMethodSampleAes, kHlsTestProvider, + kHlsTestContentId, kHlsTestInvalidKeyId, true) .AddKeyId(kHlsTestKeyId1))); TEST_F(HlsInitDataConstructionTest, InvalidUriDataFormat) { @@ -639,7 +669,7 @@ TEST_F(HlsInitDataConstructionTest, InvalidUriDataFormat) { reinterpret_cast(json.data() + json.size())); std::string value; EXPECT_FALSE(InitializationData::ConstructWidevineInitData( - Base64Encode(json_init_data), &value)); + kHlsMethodAes128, Base64Encode(json_init_data), &value)); } TEST_F(HlsInitDataConstructionTest, InvalidUriBase64Encode) { @@ -648,7 +678,7 @@ TEST_F(HlsInitDataConstructionTest, InvalidUriBase64Encode) { VectorOfStrings(kHlsTestKeyId1).Generate()); std::string value; EXPECT_FALSE(InitializationData::ConstructWidevineInitData( - kHlsTestUriDataFormat + json, &value)); + kHlsMethodSampleAes, kHlsTestUriDataFormat + json, &value)); } TEST_P(HlsParseTest, Parse) { @@ -700,7 +730,7 @@ INSTANTIATE_TEST_CASE_P( HlsAttributeVariant(kHlsAttributeListMethodAes128, HLS_METHOD_ATTRIBUTE, HLS_METHOD_AES_128, true), HlsAttributeVariant(kHlsAttributeListMethodNone, HLS_METHOD_ATTRIBUTE, - HLS_METHOD_NONE, true), + HLS_METHOD_NONE, false), HlsAttributeVariant(kHlsAttributeListKeyFormatVersionMultiple, HLS_KEYFORMAT_VERSIONS_ATTRIBUTE, HLS_KEYFORMAT_VERSION_VALUE_1, true),