diff options
author | kjellander <kjellander@google.com> | 2015-06-10 00:22:31 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-10 07:23:00 +0000 |
commit | 74f559c2c8d23115ad7e3c4f9335230edd155546 (patch) | |
tree | e3cb36a6f885e93cbe7bd0ea79aced35f6c649a1 /media | |
parent | 61457e1b32f76deca86870a6e714b1100ae21cbb (diff) | |
download | chromium_src-74f559c2c8d23115ad7e3c4f9335230edd155546.zip chromium_src-74f559c2c8d23115ad7e3c4f9335230edd155546.tar.gz chromium_src-74f559c2c8d23115ad7e3c4f9335230edd155546.tar.bz2 |
Revert of Combine 'pssh' parsing routines. (patchset #8 id:140001 of https://codereview.chromium.org/1149023002/)
Reason for revert:
Breaks compile on 'Google Chrome Win' bot:
https://build.chromium.org/p/chromium.chrome/builders/Google%20Chrome%20Win/builds/1066
Original issue's description:
> Combine CENC 'pssh' box parsing routines.
>
> Also update the routines to ignore 'pssh' boxes with version 2 or
> later.
>
> BUG=460359, 460360
> TEST=new unittests pass
>
> Committed: https://crrev.com/b666d7874efac44b359a95329f0cb890e97671df
> Cr-Commit-Position: refs/heads/master@{#333556}
>
> Committed: https://crrev.com/7a84443597e92a03f90806712f8629df40bf408e
> Cr-Commit-Position: refs/heads/master@{#333611}
TBR=sandersd@chromium.org,ddorwin@chromium.org,xhwang@chromium.org,jrummell@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=460359, 460360
Review URL: https://codereview.chromium.org/1165313003
Cr-Commit-Position: refs/heads/master@{#333694}
Diffstat (limited to 'media')
-rw-r--r-- | media/cdm/cenc_utils.cc | 215 | ||||
-rw-r--r-- | media/cdm/cenc_utils.h | 11 | ||||
-rw-r--r-- | media/cdm/cenc_utils_unittest.cc | 215 | ||||
-rw-r--r-- | media/formats/mp4/box_definitions.cc | 57 | ||||
-rw-r--r-- | media/formats/mp4/box_definitions.h | 12 | ||||
-rw-r--r-- | media/formats/mp4/box_reader.cc | 56 | ||||
-rw-r--r-- | media/formats/mp4/box_reader.h | 19 |
7 files changed, 195 insertions, 390 deletions
diff --git a/media/cdm/cenc_utils.cc b/media/cdm/cenc_utils.cc index 495a6f2..86779b2 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 @@ namespace media { // 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 @@ const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec, 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()); - - // 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; - - // 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; +#define RCHECK(x) \ + do { \ + if (!(x)) \ + return false; \ + } while (0) + +// 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; +} + +// 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)); + + // Update offset to point at the next 'pssh' box (may not be one). + offset += size; + } - std::vector<mp4::FullProtectionSystemSpecificHeader> children; - return ReadAllPsshBoxes(input, &children); + // 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)); + + // 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. - // 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()); + // 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 diff --git a/media/cdm/cenc_utils.h b/media/cdm/cenc_utils.h index 7dd82a1..ec85fb3 100644 --- a/media/cdm/cenc_utils.h +++ b/media/cdm/cenc_utils.h @@ -28,17 +28,6 @@ MEDIA_EXPORT bool ValidatePsshInput(const std::vector<uint8_t>& input); MEDIA_EXPORT bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input, KeyIdList* key_ids); -// Gets the data field from the first 'pssh' box containing |system_id| UUID. -// Returns true if such a box is found and successfully parsed. Returns false -// otherwise. -// Notes: -// 1. If multiple PSSH boxes are found, the "Data" of the first matching 'pssh' -// box will be set in |pssh_data|. -// 2. Only PSSH boxes are allowed in |input|. -MEDIA_EXPORT bool GetPsshData(const std::vector<uint8_t>& input, - const std::vector<uint8_t>& system_id, - std::vector<uint8_t>* pssh_data); - } // namespace media #endif // MEDIA_CDM_CENC_UTILS_H_ diff --git a/media/cdm/cenc_utils_unittest.cc b/media/cdm/cenc_utils_unittest.cc index 2e7ead2..9923619 100644 --- a/media/cdm/cenc_utils_unittest.cc +++ b/media/cdm/cenc_utils_unittest.cc @@ -25,10 +25,6 @@ const uint8_t kKey4Data[] = { 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x06, 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x06, }; -const uint8_t kCommonSystemSystemId[] = { - 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, - 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B -}; class CencUtilsTest : public testing::Test { public: @@ -36,10 +32,7 @@ class CencUtilsTest : public testing::Test { : key1_(kKey1Data, kKey1Data + arraysize(kKey1Data)), key2_(kKey2Data, kKey2Data + arraysize(kKey2Data)), key3_(kKey3Data, kKey3Data + arraysize(kKey3Data)), - key4_(kKey4Data, kKey4Data + arraysize(kKey4Data)), - common_system_system_id_( - kCommonSystemSystemId, - kCommonSystemSystemId + arraysize(kCommonSystemSystemId)) {} + key4_(kKey4Data, kKey4Data + arraysize(kKey4Data)) {} protected: // Initialize the start of the 'pssh' box (up to key_count) @@ -65,9 +58,23 @@ class CencUtilsTest : public testing::Test { box->push_back(0); box->push_back(0); box->push_back(0); - // Add Common Encryption SystemID. - box->insert(box->end(), common_system_system_id_.begin(), - common_system_system_id_.end()); + // Add Clear Key SystemID. + box->push_back(0x10); + box->push_back(0x77); + box->push_back(0xEF); + box->push_back(0xEC); + box->push_back(0xC0); + box->push_back(0xB2); + box->push_back(0x4D); + box->push_back(0x02); + box->push_back(0xAC); + box->push_back(0xE3); + box->push_back(0x3C); + box->push_back(0x1E); + box->push_back(0x52); + box->push_back(0xE2); + box->push_back(0xFB); + box->push_back(0x4B); } std::vector<uint8_t> MakePSSHBox(uint8_t version) { @@ -105,7 +112,7 @@ class CencUtilsTest : public testing::Test { box.push_back(1); // Add key1. - for (uint i = 0; i < key1.size(); ++i) + for (int i = 0; i < 16; ++i) box.push_back(key1[i]); // Add data_size (= 0). @@ -134,11 +141,11 @@ class CencUtilsTest : public testing::Test { box.push_back(2); // Add key1. - for (uint i = 0; i < key1.size(); ++i) + for (int i = 0; i < 16; ++i) box.push_back(key1[i]); // Add key2. - for (uint i = 0; i < key2.size(); ++i) + for (int i = 0; i < 16; ++i) box.push_back(key2[i]); // Add data_size (= 0). @@ -149,32 +156,16 @@ class CencUtilsTest : public testing::Test { return box; } - void AppendData(std::vector<uint8_t>& pssh_box, - const std::vector<uint8_t>& data) { - // This assumes that |pssh_box| has been created using the routines above, - // and simply appends the data to the end of it. It updates the box size - // and sets the data size. - DCHECK(data.size() < 100); - pssh_box[3] += data.size(); - pssh_box.pop_back(); - pssh_box.push_back(data.size()); - pssh_box.insert(pssh_box.end(), data.begin(), data.end()); - } - const std::vector<uint8_t>& Key1() { return key1_; } const std::vector<uint8_t>& Key2() { return key2_; } const std::vector<uint8_t>& Key3() { return key3_; } const std::vector<uint8_t>& Key4() { return key4_; } - const std::vector<uint8_t>& CommonSystemSystemId() { - return common_system_system_id_; - } private: std::vector<uint8_t> key1_; std::vector<uint8_t> key2_; std::vector<uint8_t> key3_; std::vector<uint8_t> key4_; - std::vector<uint8_t> common_system_system_id_; }; TEST_F(CencUtilsTest, EmptyPSSH) { @@ -223,8 +214,9 @@ TEST_F(CencUtilsTest, PSSHVersion0Plus1) { std::vector<uint8_t> box0 = MakePSSHBox(0); std::vector<uint8_t> box1 = MakePSSHBox(1, Key1()); - // Concatentate box1 onto end of box0. - box0.insert(box0.end(), box1.begin(), box1.end()); + // Concatentate box1 into box0. + for (const auto& value : box1) + box0.push_back(value); KeyIdList key_ids; EXPECT_TRUE(ValidatePsshInput(box0)); @@ -237,8 +229,9 @@ TEST_F(CencUtilsTest, PSSHVersion1Plus0) { std::vector<uint8_t> box0 = MakePSSHBox(0); std::vector<uint8_t> box1 = MakePSSHBox(1, Key1()); - // Concatentate box0 onto end of box1. - box1.insert(box1.end(), box0.begin(), box0.end()); + // Concatentate box0 into box1. + for (const auto& value : box0) + box1.push_back(value); KeyIdList key_ids; EXPECT_TRUE(ValidatePsshInput(box1)); @@ -252,9 +245,12 @@ TEST_F(CencUtilsTest, MultiplePSSHVersion1) { std::vector<uint8_t> box1 = MakePSSHBox(1, Key3()); std::vector<uint8_t> box2 = MakePSSHBox(1, Key4()); - // Concatentate box1 and box2 onto end of box. - box.insert(box.end(), box1.begin(), box1.end()); - box.insert(box.end(), box2.begin(), box2.end()); + // Concatentate box1 into box. + for (const auto& value : box1) + box.push_back(value); + // Concatentate box2 into box. + for (const auto& value : box2) + box.push_back(value); KeyIdList key_ids; EXPECT_TRUE(ValidatePsshInput(box)); @@ -272,12 +268,11 @@ TEST_F(CencUtilsTest, InvalidPSSH) { for (uint32 i = 1; i < box.size(); ++i) { // Modify size of data passed to be less than real size. std::vector<uint8_t> truncated(&box[0], &box[0] + i); - EXPECT_FALSE(ValidatePsshInput(truncated)) << "Failed for length " << i; + EXPECT_FALSE(ValidatePsshInput(truncated)); EXPECT_FALSE(GetKeyIdsForCommonSystemId(truncated, &key_ids)); // Modify starting point. std::vector<uint8_t> changed_offset(&box[i], &box[i] + box.size() - i); - EXPECT_FALSE(ValidatePsshInput(changed_offset)) << "Failed for offset " - << i; + EXPECT_FALSE(ValidatePsshInput(changed_offset)); EXPECT_FALSE(GetKeyIdsForCommonSystemId(changed_offset, &key_ids)); } } @@ -300,7 +295,9 @@ TEST_F(CencUtilsTest, InvalidFlags) { box[10] = 3; KeyIdList key_ids; - EXPECT_FALSE(GetKeyIdsForCommonSystemId(box, &key_ids)); + // TODO(jrummell): This should fail as the 'pssh' box is skipped. + EXPECT_TRUE(GetKeyIdsForCommonSystemId(box, &key_ids)); + EXPECT_EQ(0u, key_ids.size()); } TEST_F(CencUtilsTest, LongSize) { @@ -376,140 +373,4 @@ TEST_F(CencUtilsTest, HugeSize) { std::vector<uint8_t>(data, data + arraysize(data)), &key_ids)); } -TEST_F(CencUtilsTest, GetPsshData_Version0) { - const uint8_t data_bytes[] = {0x01, 0x02, 0x03, 0x04}; - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(0); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(0u, pssh_data.size()); - - std::vector<uint8_t> data(data_bytes, data_bytes + arraysize(data_bytes)); - AppendData(box, data); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(data, pssh_data); -} - -TEST_F(CencUtilsTest, GetPsshData_Version1NoKeys) { - const uint8_t data_bytes[] = {0x05, 0x06, 0x07, 0x08}; - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(1); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(0u, pssh_data.size()); - - std::vector<uint8_t> data(data_bytes, data_bytes + arraysize(data_bytes)); - AppendData(box, data); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(data, pssh_data); -} - -TEST_F(CencUtilsTest, GetPsshData_Version1WithKeys) { - const uint8_t data_bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(1, Key1()); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(0u, pssh_data.size()); - - std::vector<uint8_t> data(data_bytes, data_bytes + arraysize(data_bytes)); - AppendData(box, data); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(data, pssh_data); -} - -TEST_F(CencUtilsTest, GetPsshData_Version2) { - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(1, Key1()); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - - // Change the version manually, since we don't know what v2 will contain. - box[8] = 2; - EXPECT_FALSE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); -} - -TEST_F(CencUtilsTest, GetPsshData_Version2ThenVersion1) { - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box_v1 = MakePSSHBox(1, Key1()); - std::vector<uint8_t> box_v2 = MakePSSHBox(2, Key2(), Key3()); - - // Concatentate the boxes together (v2 first). - std::vector<uint8_t> boxes; - boxes.insert(boxes.end(), box_v2.begin(), box_v2.end()); - boxes.insert(boxes.end(), box_v1.begin(), box_v1.end()); - EXPECT_TRUE(GetPsshData(boxes, CommonSystemSystemId(), &pssh_data)); - - // GetKeyIdsForCommonSystemId() should return the single key from the v1 - // 'pssh' box. - KeyIdList key_ids; - EXPECT_TRUE(GetKeyIdsForCommonSystemId(boxes, &key_ids)); - EXPECT_EQ(1u, key_ids.size()); - EXPECT_EQ(key_ids[0], Key1()); -} - -TEST_F(CencUtilsTest, GetPsshData_Version1ThenVersion2) { - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box_v1 = MakePSSHBox(1, Key3()); - std::vector<uint8_t> box_v2 = MakePSSHBox(2, Key4()); - - // Concatentate the boxes together (v1 first). - std::vector<uint8_t> boxes; - boxes.insert(boxes.end(), box_v1.begin(), box_v1.end()); - boxes.insert(boxes.end(), box_v2.begin(), box_v2.end()); - EXPECT_TRUE(GetPsshData(boxes, CommonSystemSystemId(), &pssh_data)); - - // GetKeyIdsForCommonSystemId() should return the single key from the v1 - // 'pssh' box. - KeyIdList key_ids; - EXPECT_TRUE(GetKeyIdsForCommonSystemId(boxes, &key_ids)); - EXPECT_EQ(1u, key_ids.size()); - EXPECT_EQ(key_ids[0], Key3()); -} - -TEST_F(CencUtilsTest, GetPsshData_DifferentSystemID) { - std::vector<uint8_t> unknown_system_id(kKey1Data, - kKey1Data + arraysize(kKey1Data)); - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(1, Key1()); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - EXPECT_FALSE(GetPsshData(box, unknown_system_id, &pssh_data)); -} - -TEST_F(CencUtilsTest, GetPsshData_MissingData) { - const uint8_t data_bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box = MakePSSHBox(1, Key1()); - std::vector<uint8_t> data(data_bytes, data_bytes + arraysize(data_bytes)); - AppendData(box, data); - EXPECT_TRUE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); - - // Remove some data from the end, so now the size is incorrect. - box.pop_back(); - box.pop_back(); - EXPECT_FALSE(GetPsshData(box, CommonSystemSystemId(), &pssh_data)); -} - -TEST_F(CencUtilsTest, GetPsshData_MultiplePssh) { - const uint8_t data1_bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - const uint8_t data2_bytes[] = {0xa1, 0xa2, 0xa3, 0xa4}; - std::vector<uint8_t> pssh_data; - - std::vector<uint8_t> box1 = MakePSSHBox(1, Key1()); - std::vector<uint8_t> data1(data1_bytes, data1_bytes + arraysize(data1_bytes)); - AppendData(box1, data1); - - std::vector<uint8_t> box2 = MakePSSHBox(0); - std::vector<uint8_t> data2(data2_bytes, data2_bytes + arraysize(data2_bytes)); - AppendData(box2, data2); - - box1.insert(box1.end(), box2.begin(), box2.end()); - EXPECT_TRUE(GetPsshData(box1, CommonSystemSystemId(), &pssh_data)); - EXPECT_EQ(data1, pssh_data); - EXPECT_NE(data2, pssh_data); -} } // namespace media diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc index 72809cf..5a15240 100644 --- a/media/formats/mp4/box_definitions.cc +++ b/media/formats/mp4/box_definitions.cc @@ -26,65 +26,16 @@ ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {} FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; } bool ProtectionSystemSpecificHeader::Parse(BoxReader* reader) { - // Don't bother validating the box's contents. + // Validate the box's contents and hang on to the system ID. + RCHECK(reader->ReadFullBoxHeader() && + reader->ReadVec(&system_id, 16)); + // Copy the entire box, including the header, for passing to EME as initData. DCHECK(raw_box.empty()); raw_box.assign(reader->data(), reader->data() + reader->size()); return true; } -FullProtectionSystemSpecificHeader::FullProtectionSystemSpecificHeader() {} -FullProtectionSystemSpecificHeader::~FullProtectionSystemSpecificHeader() {} -FourCC FullProtectionSystemSpecificHeader::BoxType() const { - return FOURCC_PSSH; -} - -// 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; - -bool FullProtectionSystemSpecificHeader::Parse(mp4::BoxReader* reader) { - RCHECK(reader->type() == BoxType() && reader->ReadFullBoxHeader()); - - // Only versions 0 and 1 of the 'pssh' boxes are supported. Any other - // versions are ignored. - RCHECK(reader->version() == 0 || reader->version() == 1); - RCHECK(reader->flags() == 0); - RCHECK(reader->ReadVec(&system_id, 16)); - - if (reader->version() > 0) { - uint32_t kid_count; - RCHECK(reader->Read4(&kid_count)); - for (uint32_t i = 0; i < kid_count; ++i) { - std::vector<uint8_t> kid; - RCHECK(reader->ReadVec(&kid, 16)); - key_ids.push_back(kid); - } - } - - uint32_t data_size; - RCHECK(reader->Read4(&data_size)); - RCHECK(reader->ReadVec(&data, data_size)); - return true; -} - SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {} SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {} FourCC SampleAuxiliaryInformationOffset::BoxType() const { return FOURCC_SAIO; } diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h index 2dfab63..026effe 100644 --- a/media/formats/mp4/box_definitions.h +++ b/media/formats/mp4/box_definitions.h @@ -44,21 +44,11 @@ struct MEDIA_EXPORT FileType : Box { uint32 minor_version; }; -// If only copying the 'pssh' boxes, use ProtectionSystemSpecificHeader. -// If access to the individual fields is needed, use -// FullProtectionSystemSpecificHeader. struct MEDIA_EXPORT ProtectionSystemSpecificHeader : Box { DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader); - std::vector<uint8> raw_box; -}; - -struct MEDIA_EXPORT FullProtectionSystemSpecificHeader : Box { - DECLARE_BOX_METHODS(FullProtectionSystemSpecificHeader); - std::vector<uint8> system_id; - std::vector<std::vector<uint8>> key_ids; - std::vector<uint8> data; + std::vector<uint8> raw_box; }; struct MEDIA_EXPORT SampleAuxiliaryInformationOffset : Box { diff --git a/media/formats/mp4/box_reader.cc b/media/formats/mp4/box_reader.cc index 4368d8d..5105726 100644 --- a/media/formats/mp4/box_reader.cc +++ b/media/formats/mp4/box_reader.cc @@ -75,17 +75,15 @@ bool BufferReader::Read4sInto8s(int64* v) { return true; } -BoxReader::BoxReader(const uint8* buf, - const int size, - const LogCB& log_cb, - bool is_EOS) + +BoxReader::BoxReader(const uint8* buf, const int size, + const LogCB& log_cb) : BufferReader(buf, size), log_cb_(log_cb), type_(FOURCC_NULL), version_(0), flags_(0), - scanned_(false), - is_EOS_(is_EOS) { + scanned_(false) { } BoxReader::~BoxReader() { @@ -102,8 +100,7 @@ BoxReader* BoxReader::ReadTopLevelBox(const uint8* buf, const int buf_size, const LogCB& log_cb, bool* err) { - scoped_ptr<BoxReader> reader( - new BoxReader(buf, buf_size, log_cb, false)); + scoped_ptr<BoxReader> reader(new BoxReader(buf, buf_size, log_cb)); if (!reader->ReadHeader(err)) return NULL; @@ -125,7 +122,7 @@ bool BoxReader::StartTopLevelBox(const uint8* buf, FourCC* type, int* box_size, bool* err) { - BoxReader reader(buf, buf_size, log_cb, false); + BoxReader reader(buf, buf_size, log_cb); if (!reader.ReadHeader(err)) return false; if (!IsValidTopLevelBox(reader.type(), log_cb)) { *err = true; @@ -137,12 +134,6 @@ bool BoxReader::StartTopLevelBox(const uint8* buf, } // static -BoxReader* BoxReader::ReadConcatentatedBoxes(const uint8* buf, - const int buf_size) { - return new BoxReader(buf, buf_size, LogCB(), true); -} - -// static bool BoxReader::IsValidTopLevelBox(const FourCC& type, const LogCB& log_cb) { switch (type) { @@ -178,7 +169,7 @@ bool BoxReader::ScanChildren() { bool err = false; while (pos() < size()) { - BoxReader child(&buf_[pos_], size_ - pos_, log_cb_, is_EOS_); + BoxReader child(&buf_[pos_], size_ - pos_, log_cb_); if (!child.ReadHeader(&err)) break; children_.insert(std::pair<FourCC, BoxReader>(child.type(), child)); @@ -224,30 +215,16 @@ bool BoxReader::ReadHeader(bool* err) { uint64 size = 0; *err = false; - if (!HasBytes(8)) { - // If EOS is known, then this is an error. If not, additional data may be - // appended later, so this is a soft error. - *err = is_EOS_; - return false; - } + if (!HasBytes(8)) return false; CHECK(Read4Into8(&size) && ReadFourCC(&type_)); if (size == 0) { - if (is_EOS_) { - // All the data bytes are expected to be provided. - size = size_; - } else { - MEDIA_LOG(DEBUG, log_cb_) - << "ISO BMFF boxes that run to EOS are not supported"; - *err = true; - return false; - } + MEDIA_LOG(DEBUG, log_cb_) << "Media Source Extensions do not support ISO " + "BMFF boxes that run to EOS"; + *err = true; + return false; } else if (size == 1) { - if (!HasBytes(8)) { - // If EOS is known, then this is an error. If not, it's a soft error. - *err = is_EOS_; - return false; - } + if (!HasBytes(8)) return false; CHECK(Read8(&size)); } @@ -259,13 +236,6 @@ bool BoxReader::ReadHeader(bool* err) { return false; } - // Make sure the buffer contains at least the expected number of bytes. - // Since the data may be appended in pieces, this can only be checked if EOS. - if (is_EOS_ && size > static_cast<uint64>(size_)) { - *err = true; - return false; - } - // Note that the pos_ head has advanced to the byte immediately after the // header, which is where we want it. size_ = size; diff --git a/media/formats/mp4/box_reader.h b/media/formats/mp4/box_reader.h index 92e85fc..6b59361 100644 --- a/media/formats/mp4/box_reader.h +++ b/media/formats/mp4/box_reader.h @@ -101,14 +101,6 @@ class MEDIA_EXPORT BoxReader : public BufferReader { int* box_size, bool* err) WARN_UNUSED_RESULT; - // Create a BoxReader from a buffer. |buf| must be the complete buffer, as - // errors are returned when sufficient data is not available. |buf| can start - // with any type of box -- it does not have to be IsValidTopLevelBox(). - // - // |buf| is retained but not owned, and must outlive the BoxReader instance. - static BoxReader* ReadConcatentatedBoxes(const uint8* buf, - const int buf_size); - // Returns true if |type| is recognized to be a top-level box, false // otherwise. This returns true for some boxes which we do not parse. // Helpful in debugging misaligned appends. @@ -156,9 +148,7 @@ class MEDIA_EXPORT BoxReader : public BufferReader { const LogCB& log_cb() const { return log_cb_; } private: - // Create a BoxReader from |buf|. |is_EOS| should be true if |buf| is - // complete stream (i.e. no additional data is expected to be appended). - BoxReader(const uint8* buf, const int size, const LogCB& log_cb, bool is_EOS); + BoxReader(const uint8* buf, const int size, const LogCB& log_cb); // Must be called immediately after init. If the return is false, this // indicates that the box header and its contents were not available in the @@ -180,9 +170,6 @@ class MEDIA_EXPORT BoxReader : public BufferReader { // valid if scanned_ is true. ChildMap children_; bool scanned_; - - // True if the buffer provided to the reader is the complete stream. - const bool is_EOS_; }; // Template definitions @@ -220,8 +207,8 @@ bool BoxReader::ReadAllChildren(std::vector<T>* children) { scanned_ = true; bool err = false; - while (pos_ < size_) { - BoxReader child_reader(&buf_[pos_], size_ - pos_, log_cb_, is_EOS_); + while (pos() < size()) { + BoxReader child_reader(&buf_[pos_], size_ - pos_, log_cb_); if (!child_reader.ReadHeader(&err)) break; T child; RCHECK(child.Parse(&child_reader)); |