RDK Documentation (Open Sourced RDK Components)
AampWidevineDrmHelper.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2020 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21  * @file AampWidevineDrmHelper.cpp
22  * @brief Handles the Widevine DRM helper functions
23  */
24 
25 #include <memory>
26 #include <iostream>
27 
28 #include "AampWidevineDrmHelper.h"
29 #include "AampDRMutils.h"
30 #include "AampConfig.h"
31 #include "AampConstants.h"
32 
33 static AampWidevineDrmHelperFactory widevine_helper_factory;
34 
35 const std::string AampWidevineDrmHelper::WIDEVINE_OCDM_ID = "com.widevine.alpha";
36 
37 bool AampWidevineDrmHelper::parsePssh(const uint8_t* initData, uint32_t initDataLen)
38 {
39  this->mInitData.assign(initData, initData+initDataLen);
40 
41  // Extract key
42  const char* keyIdBegin;
43  uint8_t keyIdSize = 0u;
44  uint8_t psshDataVer = initData[WIDEVINE_PSSH_DATA_VERSION_POSITION];
45  bool ret = false;
46 
47  /*
48  WV PSSH Header Format : for version 0 and version 1
49  readme : https://www.w3.org/TR/2014/WD-encrypted-media-20140828/cenc-format.html
50  online parser : https://tools.axinom.com/generators/PsshBox
51  [ 4 bytes (total (header and data) size) + 4 bytes (type-PSSH) +
52  1 byte (version) + 3 bytes (flags) +
53  16 bytes (system id) + 4 bytes (wv pssh data size) ]
54 
55  WV PSSH Data format:
56 
57  Version 0:
58  [ optinal field: [2 byte ( Author Id Indicator + Author Id ) ] +
59  2 bytes (keyId size indicator + keyid size) + ( keyId) +
60  2 bytes (content id size indiacater + content id size) + (content id)]
61 
62  Version 1:
63  [4 byte (Number of Key Id) + 16 Byte (Key Id 1) + 16 Byte (Key Id 2) +... +
64  4 byte (Data size) + (Data) ]
65  */
66 
67  //AAMPLOG_INFO("wv pssh data version - %u ", psshDataVer);
68  if (psshDataVer == 0)
69  {
70  uint32_t header = 0;
71  int i = 0;
72  uint8_t contentIdSize = 0u;
73  uint8_t keyIdCount = 0;
74  const uint8_t* psshData;
75 
76  if (initData[WIDEVINE_PSSH_KEYID_SIZE_OFFSET] == WIDEVINE_KEY_ID_SIZE_INDICATOR)
77  {
78  header = WIDEVINE_PSSH_KEYID_SIZE_OFFSET;
79  }
80  else if(initData[WIDEVINE_PSSH_KEYID_SIZE_OFFSET_WITH_AUTHOR] == WIDEVINE_KEY_ID_SIZE_INDICATOR)
81  {
82  header = WIDEVINE_PSSH_KEYID_SIZE_OFFSET_WITH_AUTHOR;
83  }
84  else
85  {
86  AAMPLOG_WARN("WV Version: %u, Keyid indicator byte not found using default logic", psshDataVer);
87  header = WIDEVINE_PSSH_KEYID_SIZE_OFFSET; //pssh data in default format
88  }
89  psshData = initData;
90  i = header;
91  while (i < initDataLen)
92  {
93  if (KEYID_MARKER == psshData[i])
94  {
95  keyIdSize = psshData[i +1];
96  i += DATA_LENGTH_FIELD_SIZE; // Skip key Id size indicator (1byte) + key Id size (1byte)
97 
98  keyIdBegin = reinterpret_cast<const char*>(psshData + i);
99  if (keyIdSize >0)
100  {
101  std::vector<uint8_t> keyId;
102  keyId.assign(keyIdBegin, keyIdBegin + keyIdSize);
103  mKeyIDs[keyIdCount]=keyId;
104  keyIdCount += 1;
105  ret = true;
106  }
107  else
108  {
109  AAMPLOG_INFO("WV version: %u, KeyIdlen: %u", psshDataVer, keyIdSize);
110  }
111 
112  i += keyIdSize;
113  }
114  else if (CONTENTID_MARKER == psshData[i])
115  {
116  /*Some streams might don't have Keyid but they may have content id.
117  So parsing the content id from the pssh and assigning it into keyid.*/
118 
119  const char* ContentIdBegin;
120  uint8_t ContentIDSize = psshData[i +1];
121  i += DATA_LENGTH_FIELD_SIZE; // Skip Content Id size indicator (1byte) + content Id size (1byte)
122  ContentIdBegin = reinterpret_cast<const char*>(psshData + i);
123  if (ContentIDSize > 0)
124  {
125  std::vector<uint8_t> ContentId;
126  ContentId.assign(ContentIdBegin, ContentIdBegin + ContentIDSize);
127  mKeyIDs[keyIdCount]=ContentId;
128  keyIdCount++;
129  ret = true;
130  }
131 
132  i += ContentIDSize;
133  }
134  else
135  {
136  keyIdSize = psshData[i +1];
137  AAMPLOG_INFO("WV Invalid type : %d size:%d", psshData[i], keyIdSize);
138  i += DATA_LENGTH_FIELD_SIZE; // Skip key Id size indicator (1byte) + key Id size (1byte)
139  i += keyIdSize;
140  }
141  }
142  }
143  else if (psshDataVer == 1)
144  {
145  //PSSH version 1
146  //8 byte BMFF box header + 4 byte Full box header + 16 (system id) +
147  //4(KID Count) + 16 byte KID 1 + .. + 4 byte Data Size
148  //TODO : Handle multiple key Id logic, right now we are choosing only first one if have multiple key Id
149  uint32_t header = WIDEVINE_DASH_KEY_ID_OFFSET;
150  keyIdSize = WIDEVINE_PSSH_VER1_KEY_ID_SIZE;
151  keyIdBegin = reinterpret_cast<const char*>(initData + header);
152 
153  if (keyIdSize != 0u)
154  {
155  std::vector<uint8_t> keyId;
156  keyId.assign(keyIdBegin, keyIdBegin + keyIdSize);
157  mKeyIDs[0]=keyId;
158  ret = true;
159  }
160  else
161  {
162  AAMPLOG_INFO("WV version: %u, KeyIdlen: %u", psshDataVer, keyIdSize);
163  }
164  }
165  else
166  {
167  AAMPLOG_ERR("Unsupported PSSH version: %u", psshDataVer);
168  }
169  return ret;
170 }
171 
172 
173 void AampWidevineDrmHelper::setDrmMetaData(const std::string& metaData)
174 {
175  mContentMetadata = metaData;
176 }
177 
178 void AampWidevineDrmHelper::setDefaultKeyID(const std::string& cencData)
179 {
180  std::vector<uint8_t> defaultKeyID(cencData.begin(), cencData.end());
181  if(!mKeyIDs.empty())
182  {
183  for(auto& it : mKeyIDs)
184  {
185  if(defaultKeyID == it.second)
186  {
187  mDefaultKeySlot = it.first;
188  AAMPLOG_WARN("setDefaultKeyID : %s slot : %d", cencData.c_str(), mDefaultKeySlot);
189  }
190  }
191  }
192 }
193 
194 
195 const std::string& AampWidevineDrmHelper::ocdmSystemId() const
196 {
197  return WIDEVINE_OCDM_ID;
198 }
199 
200 void AampWidevineDrmHelper::createInitData(std::vector<uint8_t>& initData) const
201 {
202  initData = this->mInitData;
203 }
204 
205 void AampWidevineDrmHelper::getKey(std::vector<uint8_t>& keyID) const
206 {
207  AAMPLOG_WARN("AampWidevineDrmHelper::getKey defaultkey: %d mKeyIDs.size:%d", mDefaultKeySlot, mKeyIDs.size());
208  if ((mDefaultKeySlot >= 0) && (mDefaultKeySlot < mKeyIDs.size()))
209  {
210  keyID = this->mKeyIDs.at(mDefaultKeySlot);
211  }
212  else if (mKeyIDs.size() > 0)
213  {
214  keyID = this->mKeyIDs.at(0);
215  }
216  else
217  {
218  AAMPLOG_ERR("No key");
219  }
220 }
221 
222 void AampWidevineDrmHelper::getKeys(std::map<int, std::vector<uint8_t>>& keyIDs) const
223 {
224  keyIDs = this->mKeyIDs;
225 }
226 
228 {
229  licenseRequest.method = AampLicenseRequest::POST;
230 
231  if (licenseRequest.url.empty())
232  {
233  licenseRequest.url = challengeInfo.url;
234  }
235 
236  licenseRequest.headers = {{"Content-Type:", {"application/octet-stream"}}};
237 
238  licenseRequest.payload= challengeInfo.data->getData();
239 }
240 
241 bool AampWidevineDrmHelperFactory::isDRM(const struct DrmInfo& drmInfo) const
242 {
243  return (((WIDEVINE_UUID == drmInfo.systemUUID) || (AampWidevineDrmHelper::WIDEVINE_OCDM_ID == drmInfo.keyFormat))
244  && ((drmInfo.mediaFormat == eMEDIAFORMAT_DASH) || (drmInfo.mediaFormat == eMEDIAFORMAT_HLS_MP4))
245  );
246 }
247 
248 std::shared_ptr<AampDrmHelper> AampWidevineDrmHelperFactory::createHelper(const struct DrmInfo& drmInfo, AampLogManager *logObj) const
249 {
250  if (isDRM(drmInfo))
251  {
252  return std::make_shared<AampWidevineDrmHelper>(drmInfo,logObj);
253  }
254  return NULL;
255 }
256 
257 void AampWidevineDrmHelperFactory::appendSystemId(std::vector<std::string>& systemIds) const
258 {
259  systemIds.push_back(WIDEVINE_UUID);
260 }
261 
AampWidevineDrmHelper.h
Handles the operation for Wide vine DRM operation.
AampChallengeInfo::data
std::shared_ptr< DrmData > data
Definition: AampDrmHelper.h:46
eMEDIAFORMAT_DASH
@ eMEDIAFORMAT_DASH
Definition: AampDrmMediaFormat.h:35
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
AampWidevineDrmHelper::setDefaultKeyID
void setDefaultKeyID(const std::string &cencData)
Sets the defualt keyID.
Definition: AampWidevineDrmHelper.cpp:178
AampWidevineDrmHelperFactory::createHelper
std::shared_ptr< AampDrmHelper > createHelper(const struct DrmInfo &drmInfo, AampLogManager *logObj=NULL) const
Build a helper class to support the identified DRM.
Definition: AampWidevineDrmHelper.cpp:248
AampLicenseRequest
Holds the data to get the License.
Definition: AampDrmHelper.h:57
DrmInfo::systemUUID
std::string systemUUID
Definition: AampDrmInfo.h:89
AampWidevineDrmHelperFactory
Helps to handle widevine DRM.
Definition: AampWidevineDrmHelper.h:104
DrmInfo
DRM information required to decrypt.
Definition: AampDrmInfo.h:47
AampChallengeInfo::url
std::string url
Definition: AampDrmHelper.h:48
AampWidevineDrmHelper::getKey
void getKey(std::vector< uint8_t > &keyID) const
Get the key ID.
Definition: AampWidevineDrmHelper.cpp:205
DrmInfo::keyFormat
std::string keyFormat
Definition: AampDrmInfo.h:88
AampWidevineDrmHelper::ocdmSystemId
virtual const std::string & ocdmSystemId() const
Returns the OCDM system ID of the helper.
Definition: AampWidevineDrmHelper.cpp:195
AampWidevineDrmHelper::createInitData
void createInitData(std::vector< uint8_t > &initData) const
Definition: AampWidevineDrmHelper.cpp:200
AampWidevineDrmHelperFactory::appendSystemId
void appendSystemId(std::vector< std::string > &systemIds) const
Adds the system IDs supported by the DRM to a vector Used by the GStreamer plugins to advertise the D...
Definition: AampWidevineDrmHelper.cpp:257
AampWidevineDrmHelper::getKeys
void getKeys(std::map< int, std::vector< uint8_t >> &keyIDs) const
Get the key IDs.
Definition: AampWidevineDrmHelper.cpp:222
AampDRMutils.h
Context-free common utility functions.
AampConfig.h
Configurations for AAMP.
AampWidevineDrmHelper::parsePssh
bool parsePssh(const uint8_t *initData, uint32_t initDataLen)
Parse the optional PSSH data.
Definition: AampWidevineDrmHelper.cpp:37
AampLicenseRequest::POST
@ POST
Definition: AampDrmHelper.h:65
AampConstants.h
Constants in AAMP.
AampWidevineDrmHelper::generateLicenseRequest
void generateLicenseRequest(const AampChallengeInfo &challengeInfo, AampLicenseRequest &licenseRequest) const
Generate the request details for the DRM license.
Definition: AampWidevineDrmHelper.cpp:227
eMEDIAFORMAT_HLS_MP4
@ eMEDIAFORMAT_HLS_MP4
Definition: AampDrmMediaFormat.h:37
AampChallengeInfo
Aamp challenge info to get the License.
Definition: AampDrmHelper.h:44
DrmInfo::mediaFormat
MediaFormat mediaFormat
Definition: AampDrmInfo.h:80
AampWidevineDrmHelperFactory::isDRM
bool isDRM(const struct DrmInfo &drmInfo) const
Determines if a helper class provides the identified DRM.
Definition: AampWidevineDrmHelper.cpp:241
AampWidevineDrmHelper::setDrmMetaData
void setDrmMetaData(const std::string &metaData)
Sets the content specific DRM metadata.
Definition: AampWidevineDrmHelper.cpp:173