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,PlayerMessage * playerMsg)136 status_t NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo, PlayerMessage *playerMsg)
137 {
138     std::ostringstream pssh, drmInfo;
139 
140     // 0) Generate PSSH bytes
141     for (size_t i = 0; i < psshInfo->numentries; i++) {
142         PsshEntry *entry = &psshInfo->entries[i];
143         uint32_t datalen = entry->datalen;
144         pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
145         pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen));
146         pssh.write(reinterpret_cast<const char *>(entry->data), datalen);
147     }
148 
149     uint32_t psshSize = pssh.tellp();
150     std::string psshBase = pssh.str();
151     const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
152     ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize,
153             DrmUUID::arrayToHex(psshPtr, psshSize).string());
154 
155     // 1) Write PSSH bytes
156     playerMsg->add_values()->set_bytes_value(
157             reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
158 
159     // 2) Write supportedDRMs
160     uint32_t numentries = psshInfo->numentries;
161     playerMsg->add_values()->set_int32_value(numentries);
162     for (size_t i = 0; i < numentries; i++) {
163         PsshEntry *entry = &psshInfo->entries[i];
164         playerMsg->add_values()->set_bytes_value(
165                 reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
166         ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
167                 DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
168     }
169     return OK;
170 }
171 
172 }   // namespace android
173