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 |