(This is a merge of https://widevine-internal-review.googlesource.com/9711 from the Widevine CDM repo.) This change updates the CDM's handling of init data types, previously known as MIME types, to comply with the latest version of the EME spec. Following this change, in addition to accepting the deprecated MIME types "video/mp4", "audio/mp4", "video/webm", and "audio/webm", the CDM will accept the new standard: Init data types "cenc" and "webm". Furthermore, this removes the non-PSSH-parsing path from the CDM. All platforms have unified on the CDM being responsible for parsing the concatenated PSSH box list, as outlined in the latest EME spec. As Android has shipped code that expects pre-unwrapped PSSH boxes and must maintain backwards-compatibility, code has been inserted on that platform to detect pre-unwrapped data and re-wrap it with a PSSH header before sending it to the CDM. There are some small changes to unit tests because of this change: 1) The CDM Engine unit test now no longer needs to unwrap the PSSH on any platforms when testing ISO-BMFF. It now pre-caches the unwrapped key ID for use when testing WebM. 2) Several substantially-similar unit tests in the Android code have been rolled into one test. Bug: 13564917 Bug: 13570595 Bug: 9465346 Bug: 13570288 Change-Id: I7f27b16b8503f24a26746b5dce71fb61b6fd1bb2
126 lines
3.4 KiB
C++
126 lines
3.4 KiB
C++
// Copyright 2014 Google Inc. All Rights Reserved.
|
|
|
|
#include "initialization_data.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "buffer_reader.h"
|
|
#include "log.h"
|
|
#include "properties.h"
|
|
#include "wv_cdm_constants.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
InitializationData::InitializationData(const std::string& type,
|
|
const CdmInitData& data)
|
|
: type_(type), is_cenc_(false), is_webm_(false) {
|
|
if (type == ISO_BMFF_VIDEO_MIME_TYPE ||
|
|
type == ISO_BMFF_AUDIO_MIME_TYPE ||
|
|
type == CENC_INIT_DATA_FORMAT) {
|
|
is_cenc_ = true;
|
|
} else if (type == WEBM_VIDEO_MIME_TYPE ||
|
|
type == WEBM_AUDIO_MIME_TYPE ||
|
|
type == WEBM_INIT_DATA_FORMAT) {
|
|
is_webm_ = true;
|
|
}
|
|
|
|
if (is_supported()) {
|
|
if (is_cenc()) {
|
|
ExtractWidevinePssh(data, &data_);
|
|
} else {
|
|
data_ = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
|
// Widevine PSSH.
|
|
bool InitializationData::ExtractWidevinePssh(
|
|
const CdmInitData& init_data, CdmInitData* output) {
|
|
BufferReader reader(
|
|
reinterpret_cast<const uint8_t*>(init_data.data()), init_data.length());
|
|
|
|
// TODO(kqyang): Extracted from an actual init_data;
|
|
// Need to find out where it comes from.
|
|
static const uint8_t kWidevineSystemId[] = {
|
|
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
|
|
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
|
};
|
|
|
|
// one PSSH blob consists of:
|
|
// 4 byte size of the PSSH atom, inclusive
|
|
// "pssh"
|
|
// 4 byte flags, value 0
|
|
// 16 byte system id
|
|
// 4 byte size of PSSH data, exclusive
|
|
while (1) {
|
|
// size of PSSH atom, used for skipping
|
|
uint32_t size;
|
|
if (!reader.Read4(&size)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH atom size");
|
|
return false;
|
|
}
|
|
|
|
// "pssh"
|
|
std::vector<uint8_t> pssh;
|
|
if (!reader.ReadVec(&pssh, 4)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH literal");
|
|
return false;
|
|
}
|
|
if (memcmp(&pssh[0], "pssh", 4)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present");
|
|
return false;
|
|
}
|
|
|
|
// flags
|
|
uint32_t flags;
|
|
if (!reader.Read4(&flags)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH flags");
|
|
return false;
|
|
}
|
|
if (flags != 0) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: PSSH flags not zero");
|
|
return false;
|
|
}
|
|
|
|
// system id
|
|
std::vector<uint8_t> system_id;
|
|
if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read system ID");
|
|
return false;
|
|
}
|
|
|
|
if (memcmp(&system_id[0], kWidevineSystemId,
|
|
sizeof(kWidevineSystemId))) {
|
|
// skip the remaining contents of the atom,
|
|
// after size field, atom name, flags and system id
|
|
if (!reader.SkipBytes(
|
|
size - 4 - 4 - 4 - sizeof(kWidevineSystemId))) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to rest of PSSH atom");
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// size of PSSH box
|
|
uint32_t pssh_length;
|
|
if (!reader.Read4(&pssh_length)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH box size");
|
|
return false;
|
|
}
|
|
|
|
output->clear();
|
|
if (!reader.ReadString(output, pssh_length)) {
|
|
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// we did not find a matching record
|
|
return false;
|
|
}
|
|
|
|
} // namespace wvcdm
|