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 
parsePSSH(const void * pssh,size_t psshsize)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 
getSupportedDrmSchemes(const void * pssh,size_t psshsize)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 
retrieveDrmInfo(const void * pssh,uint32_t psshsize)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 
retrieveDrmInfo(PsshInfo * psshInfo)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