Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(916)

Unified Diff: media/cdm/cenc_utils.cc

Issue 1170923005: Revert of Combine 'pssh' parsing routines. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/cdm/cenc_utils.h ('k') | media/cdm/cenc_utils_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/cdm/cenc_utils.cc
diff --git a/media/cdm/cenc_utils.cc b/media/cdm/cenc_utils.cc
index 495a6f2fb2f6eba1d741a2dbf1c83bbd22ad5c00..86779b2174092ce5d0e3b5f5dca6a9c2f965c912 100644
--- a/media/cdm/cenc_utils.cc
+++ b/media/cdm/cenc_utils.cc
@@ -4,9 +4,7 @@
#include "media/cdm/cenc_utils.h"
-#include "base/stl_util.h"
-#include "media/formats/mp4/box_definitions.h"
-#include "media/formats/mp4/box_reader.h"
+#include "media/base/bit_reader.h"
namespace media {
@@ -14,6 +12,31 @@
// Encryption ('cenc') protection scheme may contain one or more protection
// system specific header ('pssh') boxes.
// ref: https://w3c.github.io/encrypted-media/cenc-format.html
+//
+// The format of a 'pssh' box is as follows:
+// unsigned int(32) size;
+// unsigned int(32) type = "pssh";
+// if (size==1) {
+// unsigned int(64) largesize;
+// } else if (size==0) {
+// -- box extends to end of file
+// }
+// unsigned int(8) version;
+// bit(24) flags;
+// unsigned int(8)[16] SystemID;
+// if (version > 0)
+// {
+// unsigned int(32) KID_count;
+// {
+// unsigned int(8)[16] KID;
+// } [KID_count]
+// }
+// unsigned int(32) DataSize;
+// unsigned int(8)[DataSize] Data;
+
+// Minimum size of a 'pssh' box includes all the required fields (size, type,
+// version, flags, SystemID, DataSize).
+const int kMinimumBoxSizeInBytes = 32;
// SystemID for the Common System.
// https://w3c.github.io/encrypted-media/cenc-format.html#common-system
@@ -22,102 +45,136 @@
0xac, 0xe3, 0x3c, 0x1e,
0x52, 0xe2, 0xfb, 0x4b };
-static bool ReadAllPsshBoxes(
- const std::vector<uint8_t>& input,
- std::vector<mp4::FullProtectionSystemSpecificHeader>* pssh_boxes) {
- DCHECK(!input.empty());
+#define RCHECK(x) \
+ do { \
+ if (!(x)) \
+ return false; \
+ } while (0)
- // Verify that |input| contains only 'pssh' boxes. ReadAllChildren() is
- // templated, so it checks that each box in |input| matches the box type of
- // the parameter (in this case mp4::ProtectionSystemSpecificHeader is a
- // 'pssh' box). mp4::ProtectionSystemSpecificHeader doesn't validate the
- // 'pssh' contents, so this simply verifies that |input| only contains
- // 'pssh' boxes and nothing else.
- scoped_ptr<mp4::BoxReader> input_reader(
- mp4::BoxReader::ReadConcatentatedBoxes(
- vector_as_array(&input), input.size()));
- std::vector<mp4::ProtectionSystemSpecificHeader> raw_pssh_boxes;
- if (!input_reader->ReadAllChildren(&raw_pssh_boxes))
- return false;
+// Helper function to read up to 32 bits from a bit stream.
+static uint32_t ReadBits(BitReader* reader, int num_bits) {
+ DCHECK_GE(reader->bits_available(), num_bits);
+ DCHECK((num_bits > 0) && (num_bits <= 32));
+ uint32_t value;
+ reader->ReadBits(num_bits, &value);
+ return value;
+}
- // Now that we have |input| parsed into |raw_pssh_boxes|, reparse each one
- // into a mp4::FullProtectionSystemSpecificHeader, which extracts all the
- // relevant fields from the box. Since there may be unparseable 'pssh' boxes
- // (due to unsupported version, for example), this is done one by one,
- // ignoring any boxes that can't be parsed.
- for (const auto& raw_pssh_box : raw_pssh_boxes) {
- scoped_ptr<mp4::BoxReader> raw_pssh_reader(
- mp4::BoxReader::ReadConcatentatedBoxes(
- vector_as_array(&raw_pssh_box.raw_box),
- raw_pssh_box.raw_box.size()));
- // ReadAllChildren() appends any successfully parsed box onto it's
- // parameter, so |pssh_boxes| will contain the collection of successfully
- // parsed 'pssh' boxes. If an error occurs, try the next box.
- if (!raw_pssh_reader->ReadAllChildren(pssh_boxes))
- continue;
+// 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 false;
+ }
+ return true;
+}
+
+// Checks that |reader| contains a valid 'ppsh' box header. |reader| is updated
+// to point to the content immediately following the box header. Returns true
+// 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) {
+ // Enough data for a miniumum size 'pssh' box?
+ uint32 available_bytes = reader->bits_available() / 8;
+ RCHECK(available_bytes >= kMinimumBoxSizeInBytes);
+
+ *size = ReadBits(reader, 32);
+
+ // Must be a 'pssh' box or else fail.
+ RCHECK(ReadBits(reader, 8) == 'p');
+ RCHECK(ReadBits(reader, 8) == 's');
+ RCHECK(ReadBits(reader, 8) == 's');
+ RCHECK(ReadBits(reader, 8) == 'h');
+
+ if (*size == 1) {
+ // If largesize > 2**32 it is too big.
+ RCHECK(ReadBits(reader, 32) == 0);
+ *size = ReadBits(reader, 32);
+ } else if (*size == 0) {
+ *size = available_bytes;
}
- // Must have successfully parsed at least one 'pssh' box.
- return pssh_boxes->size() > 0;
+ // Check that the buffer contains at least size bytes.
+ return available_bytes >= *size;
}
bool ValidatePsshInput(const std::vector<uint8_t>& input) {
- // No 'pssh' boxes is considered valid.
- if (input.empty())
- return true;
+ 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 size;
+ RCHECK(ValidBoxHeader(&reader, &size));
- std::vector<mp4::FullProtectionSystemSpecificHeader> children;
- return ReadAllPsshBoxes(input, &children);
+ // Update offset to point at the next 'pssh' box (may not be one).
+ offset += size;
+ }
+
+ // Only valid if this contains 0 or more 'pssh' boxes.
+ return offset == input.size();
}
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));
- if (!input.empty()) {
- std::vector<mp4::FullProtectionSystemSpecificHeader> children;
- if (!ReadAllPsshBoxes(input, &children))
- return false;
+ while (offset < input.size()) {
+ BitReader reader(&input[offset], input.size() - offset);
+ uint32 size;
+ RCHECK(ValidBoxHeader(&reader, &size));
- // Check all children for an appropriate 'pssh' box, concatenating any
- // key IDs found.
- for (const auto& child : children) {
- if (child.system_id == common_system_id && child.key_ids.size() > 0)
- result.insert(result.end(), child.key_ids.begin(), child.key_ids.end());
+ // 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.
+ uint8_t version = ReadBits(&reader, 8);
+ if (version == 0)
+ 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
+ RCHECK(static_cast<uint32_t>(reader.bits_available()) >=
+ arraysize(kCommonSystemId) * 8);
+ if (!IsCommonSystemID(&reader))
+ 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);
+ uint32_t count = ReadBits(&reader, 32);
+
+ if (count == 0)
+ continue;
+
+ // 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);
+ while (count > 0) {
+ std::vector<uint8_t> key;
+ key.reserve(16);
+ for (int i = 0; i < 16; ++i) {
+ key.push_back(ReadBits(&reader, 8));
+ }
+ result.push_back(key);
+ --count;
}
+
+ // Don't bother checking DataSize and Data.
}
- // No matching 'pssh' box found.
+ key_ids->swap(result);
+
// TODO(jrummell): This should return true only if there was at least one
// key ID present. However, numerous test files don't contain the 'pssh' box
// for Common Format, so no keys are found. http://crbug.com/460308
- key_ids->swap(result);
return true;
}
-bool GetPsshData(const std::vector<uint8_t>& input,
- const std::vector<uint8_t>& system_id,
- std::vector<uint8_t>* pssh_data) {
- if (input.empty())
- return false;
-
- std::vector<mp4::FullProtectionSystemSpecificHeader> children;
- if (!ReadAllPsshBoxes(input, &children))
- return false;
-
- // Check all children for an appropriate 'pssh' box, returning |data| from
- // the first one found.
- for (const auto& child : children) {
- if (child.system_id == system_id) {
- pssh_data->assign(child.data.begin(), child.data.end());
- return true;
- }
- }
-
- // No matching 'pssh' box found.
- return false;
-}
-
} // namespace media
« no previous file with comments | « media/cdm/cenc_utils.h ('k') | media/cdm/cenc_utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698