| Index: media/cdm/cenc_utils.cc
|
| diff --git a/media/cdm/cenc_utils.cc b/media/cdm/cenc_utils.cc
|
| index 86779b2174092ce5d0e3b5f5dca6a9c2f965c912..b184bd259631e50c83365cd4b752f7603512e9b0 100644
|
| --- a/media/cdm/cenc_utils.cc
|
| +++ b/media/cdm/cenc_utils.cc
|
| @@ -33,10 +33,18 @@ namespace media {
|
| // }
|
| // unsigned int(32) DataSize;
|
| // unsigned int(8)[DataSize] Data;
|
| +// Only versions 0 and 1 of the 'pssh' boxes are supported. Any other versions
|
| +// are ignored.
|
|
|
| // Minimum size of a 'pssh' box includes all the required fields (size, type,
|
| // version, flags, SystemID, DataSize).
|
| -const int kMinimumBoxSizeInBytes = 32;
|
| +const uint32_t kMinimumBoxSizeInBytes = 32;
|
| +
|
| +// Size of a SystemID field in bytes.
|
| +const uint32_t kSystemIDSizeInBytes = 16;
|
| +
|
| +// Size of a KID field in bytes.
|
| +const uint32_t kKIDSizeInBytes = 16;
|
|
|
| // SystemID for the Common System.
|
| // https://w3c.github.io/encrypted-media/cenc-format.html#common-system
|
| @@ -60,11 +68,17 @@ static uint32_t ReadBits(BitReader* reader, int num_bits) {
|
| return value;
|
| }
|
|
|
| -// Checks whether the next 16 bytes matches the Common SystemID.
|
| -// Assumes |reader| has enough data.
|
| -static bool IsCommonSystemID(BitReader* reader) {
|
| - for (uint32_t i = 0; i < arraysize(kCommonSystemId); ++i) {
|
| - if (ReadBits(reader, 8) != kCommonSystemId[i])
|
| +// Return the number of bytes available in |reader|.
|
| +static uint32_t BytesAvailable(BitReader* reader) {
|
| + return reader->bits_available() / 8;
|
| +}
|
| +
|
| +// Checks whether the next bytes in |reader| match the specified |system_id|.
|
| +static bool MatchSystemID(BitReader* reader,
|
| + const std::vector<uint8_t>& system_id) {
|
| + RCHECK(BytesAvailable(reader) >= system_id.size());
|
| + for (const auto& data : system_id) {
|
| + if (ReadBits(reader, 8) != data)
|
| return false;
|
| }
|
| return true;
|
| @@ -75,9 +89,9 @@ static bool IsCommonSystemID(BitReader* reader) {
|
| // if the header looks valid and |reader| contains enough data for the size of
|
| // header. |size| is updated as the computed size of the box header. Otherwise
|
| // false is returned.
|
| -static bool ValidBoxHeader(BitReader* reader, uint32* size) {
|
| +static bool ValidBoxHeader(BitReader* reader, uint32_t* size) {
|
| // Enough data for a miniumum size 'pssh' box?
|
| - uint32 available_bytes = reader->bits_available() / 8;
|
| + uint32_t available_bytes = BytesAvailable(reader);
|
| RCHECK(available_bytes >= kMinimumBoxSizeInBytes);
|
|
|
| *size = ReadBits(reader, 32);
|
| @@ -105,7 +119,7 @@ bool ValidatePsshInput(const std::vector<uint8_t>& input) {
|
| while (offset < input.size()) {
|
| // Create a BitReader over the remaining part of the buffer.
|
| BitReader reader(&input[offset], input.size() - offset);
|
| - uint32 size;
|
| + uint32_t size;
|
| RCHECK(ValidBoxHeader(&reader, &size));
|
|
|
| // Update offset to point at the next 'pssh' box (may not be one).
|
| @@ -120,18 +134,21 @@ bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
|
| KeyIdList* key_ids) {
|
| size_t offset = 0;
|
| KeyIdList result;
|
| + std::vector<uint8_t> common_system_id(
|
| + kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
|
|
| while (offset < input.size()) {
|
| BitReader reader(&input[offset], input.size() - offset);
|
| - uint32 size;
|
| + uint32_t size;
|
| RCHECK(ValidBoxHeader(&reader, &size));
|
|
|
| // Update offset to point at the next 'pssh' box (may not be one).
|
| offset += size;
|
|
|
| - // Check the version, as KIDs only available if version > 0.
|
| + // Check the version. Only version 0 and 1 'pssh' boxes are supported.
|
| + // However, KIDs only available if version > 0, so skip if version != 1.
|
| uint8_t version = ReadBits(&reader, 8);
|
| - if (version == 0)
|
| + if (version != 1)
|
| continue;
|
|
|
| // flags must be 0. If not, assume incorrect 'pssh' box and move to the
|
| @@ -140,14 +157,11 @@ bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
|
| continue;
|
|
|
| // Validate SystemID
|
| - RCHECK(static_cast<uint32_t>(reader.bits_available()) >=
|
| - arraysize(kCommonSystemId) * 8);
|
| - if (!IsCommonSystemID(&reader))
|
| + if (!MatchSystemID(&reader, common_system_id))
|
| continue; // Not Common System, so try the next pssh box.
|
|
|
| // Since version > 0, next field is the KID_count.
|
| - RCHECK(static_cast<uint32_t>(reader.bits_available()) >=
|
| - sizeof(uint32_t) * 8);
|
| + RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t));
|
| uint32_t count = ReadBits(&reader, 32);
|
|
|
| if (count == 0)
|
| @@ -155,11 +169,11 @@ bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
|
|
|
| // Make sure there is enough data for all the KIDs specified, and then
|
| // extract them.
|
| - RCHECK(static_cast<uint32_t>(reader.bits_available()) > count * 16 * 8);
|
| + RCHECK(BytesAvailable(&reader) > count * kKIDSizeInBytes);
|
| while (count > 0) {
|
| std::vector<uint8_t> key;
|
| - key.reserve(16);
|
| - for (int i = 0; i < 16; ++i) {
|
| + key.reserve(kKIDSizeInBytes);
|
| + for (uint32_t i = 0; i < kKIDSizeInBytes; ++i) {
|
| key.push_back(ReadBits(&reader, 8));
|
| }
|
| result.push_back(key);
|
| @@ -177,4 +191,58 @@ bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
|
| return true;
|
| }
|
|
|
| +bool GetPsshData(const std::vector<uint8_t>& input,
|
| + const std::vector<uint8_t>& system_id,
|
| + std::vector<uint8_t>* pssh_data) {
|
| + DCHECK_EQ(system_id.size(), kSystemIDSizeInBytes);
|
| + size_t offset = 0;
|
| +
|
| + while (offset < input.size()) {
|
| + // Create a BitReader over the remaining part of the buffer.
|
| + BitReader reader(&input[offset], input.size() - offset);
|
| + uint32_t size;
|
| + RCHECK(ValidBoxHeader(&reader, &size));
|
| +
|
| + // Update offset to point at the next 'pssh' box (may not be one).
|
| + offset += size;
|
| +
|
| + // Check the version. Only version 0 and 1 'pssh' boxes are supported.
|
| + // Other versions are skipped.
|
| + uint8_t version = ReadBits(&reader, 8);
|
| + if (version > 1)
|
| + continue;
|
| +
|
| + // flags must be 0. If not, assume incorrect 'pssh' box and move to the
|
| + // next one.
|
| + if (ReadBits(&reader, 24) != 0)
|
| + continue;
|
| +
|
| + // Validate SystemID. If not, try the next 'pssh' box.
|
| + if (!MatchSystemID(&reader, system_id))
|
| + continue;
|
| +
|
| + // If version > 0, next field is the KID_count. Skip any KIDs in the
|
| + // 'pssh' box.
|
| + if (version > 0) {
|
| + RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t));
|
| + uint32_t count = ReadBits(&reader, 32);
|
| + RCHECK(reader.SkipBits(count * kKIDSizeInBytes * 8));
|
| + }
|
| +
|
| + // Now get the datasize.
|
| + RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t));
|
| + uint32_t datasize = ReadBits(&reader, 32);
|
| +
|
| + // Now get the data and return it.
|
| + RCHECK(BytesAvailable(&reader) >= datasize);
|
| + for (uint32_t i = 0; i < datasize; ++i) {
|
| + pssh_data->push_back(ReadBits(&reader, 8));
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + // No matching 'pssh' box found, so fail.
|
| + return false;
|
| +}
|
| +
|
| } // namespace media
|
|
|