1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "NuPlayer2Drm" 19 20 #include "NuPlayer2Drm.h" 21 22 #include <media/NdkWrapper.h> 23 #include <utils/Log.h> 24 #include <sstream> 25 26 namespace android { 27 28 Vector<DrmUUID> NuPlayer2Drm::parsePSSH(const void *pssh, size_t psshsize) 29 { 30 Vector<DrmUUID> drmSchemes, empty; 31 const int DATALEN_SIZE = 4; 32 33 // the format of the buffer is 1 or more of: 34 // { 35 // 16 byte uuid 36 // 4 byte data length N 37 // N bytes of data 38 // } 39 // Determine the number of entries in the source data. 40 // Since we got the data from stagefright, we trust it is valid and properly formatted. 41 42 const uint8_t *data = (const uint8_t*)pssh; 43 size_t len = psshsize; 44 size_t numentries = 0; 45 while (len > 0) { 46 if (len < DrmUUID::UUID_SIZE) { 47 ALOGE("ParsePSSH: invalid PSSH data"); 48 return empty; 49 } 50 51 const uint8_t *uuidPtr = data; 52 53 // skip uuid 54 data += DrmUUID::UUID_SIZE; 55 len -= DrmUUID::UUID_SIZE; 56 57 // get data length 58 if (len < DATALEN_SIZE) { 59 ALOGE("ParsePSSH: invalid PSSH data"); 60 return empty; 61 } 62 63 uint32_t datalen = *((uint32_t*)data); 64 data += DATALEN_SIZE; 65 len -= DATALEN_SIZE; 66 67 if (len < datalen) { 68 ALOGE("ParsePSSH: invalid PSSH data"); 69 return empty; 70 } 71 72 // skip the data 73 data += datalen; 74 len -= datalen; 75 76 DrmUUID _uuid(uuidPtr); 77 drmSchemes.add(_uuid); 78 79 ALOGV("ParsePSSH[%zu]: %s: %s", numentries, 80 _uuid.toHexString().string(), 81 DrmUUID::arrayToHex(data, datalen).string() 82 ); 83 84 numentries++; 85 } 86 87 return drmSchemes; 88 } 89 90 Vector<DrmUUID> NuPlayer2Drm::getSupportedDrmSchemes(const void *pssh, size_t psshsize) 91 { 92 Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize); 93 94 Vector<DrmUUID> supportedDRMs; 95 for (size_t i = 0; i < psshDRMs.size(); i++) { 96 DrmUUID uuid = psshDRMs[i]; 97 if (AMediaDrmWrapper::isCryptoSchemeSupported(uuid.ptr(), NULL)) { 98 supportedDRMs.add(uuid); 99 } 100 } 101 102 ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu", 103 psshDRMs.size(), supportedDRMs.size()); 104 105 return supportedDRMs; 106 } 107 108 sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(const void *pssh, uint32_t psshsize) 109 { 110 std::ostringstream buf; 111 112 // 1) PSSH bytes 113 buf.write(reinterpret_cast<const char *>(&psshsize), sizeof(psshsize)); 114 buf.write(reinterpret_cast<const char *>(pssh), psshsize); 115 116 ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO PSSH: size: %u %s", psshsize, 117 DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string()); 118 119 // 2) supportedDRMs 120 Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize); 121 uint32_t n = supportedDRMs.size(); 122 buf.write(reinterpret_cast<char *>(&n), sizeof(n)); 123 for (size_t i = 0; i < n; i++) { 124 DrmUUID uuid = supportedDRMs[i]; 125 buf.write(reinterpret_cast<const char *>(&n), sizeof(n)); 126 buf.write(reinterpret_cast<const char *>(uuid.ptr()), DrmUUID::UUID_SIZE); 127 128 ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO supportedScheme[%zu] %s", i, 129 uuid.toHexString().string()); 130 } 131 132 sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(buf.str().c_str(), buf.tellp()); 133 return drmInfoBuffer; 134 } 135 136 sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo) 137 { 138 139 std::ostringstream pssh, drmInfo; 140 141 // 0) Generate PSSH bytes 142 for (size_t i = 0; i < psshInfo->numentries; i++) { 143 PsshEntry *entry = &psshInfo->entries[i]; 144 uint32_t datalen = entry->datalen; 145 pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid)); 146 pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen)); 147 pssh.write(reinterpret_cast<const char *>(entry->data), datalen); 148 } 149 150 uint32_t psshSize = pssh.tellp(); 151 const uint8_t* psshPtr = reinterpret_cast<const uint8_t*>(pssh.str().c_str()); 152 const char *psshHex = DrmUUID::arrayToHex(psshPtr, psshSize).string(); 153 ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize, psshHex); 154 155 // 1) Write PSSH bytes 156 drmInfo.write(reinterpret_cast<const char *>(&psshSize), sizeof(psshSize)); 157 drmInfo.write(reinterpret_cast<const char *>(pssh.str().c_str()), psshSize); 158 159 // 2) Write supportedDRMs 160 uint32_t numentries = psshInfo->numentries; 161 drmInfo.write(reinterpret_cast<const char *>(&numentries), sizeof(numentries)); 162 for (size_t i = 0; i < numentries; i++) { 163 PsshEntry *entry = &psshInfo->entries[i]; 164 drmInfo.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid)); 165 ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO supportedScheme[%zu] %s", i, 166 DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string()); 167 } 168 169 sp<ABuffer> drmInfoBuf = ABuffer::CreateAsCopy(drmInfo.str().c_str(), drmInfo.tellp()); 170 drmInfoBuf->setRange(0, drmInfo.tellp()); 171 return drmInfoBuf; 172 } 173 174 } // namespace android 175