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
26namespace android {
27
28Vector<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
90Vector<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
108sp<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
136sp<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