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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cdm/cenc_utils.h" 5 #include "media/cdm/cenc_utils.h"
6 6
7 #include "base/stl_util.h" 7 #include "media/base/bit_reader.h"
8 #include "media/formats/mp4/box_definitions.h"
9 #include "media/formats/mp4/box_reader.h"
10 8
11 namespace media { 9 namespace media {
12 10
13 // The initialization data for encrypted media files using the ISO Common 11 // The initialization data for encrypted media files using the ISO Common
14 // Encryption ('cenc') protection scheme may contain one or more protection 12 // Encryption ('cenc') protection scheme may contain one or more protection
15 // system specific header ('pssh') boxes. 13 // system specific header ('pssh') boxes.
16 // ref: https://w3c.github.io/encrypted-media/cenc-format.html 14 // ref: https://w3c.github.io/encrypted-media/cenc-format.html
15 //
16 // The format of a 'pssh' box is as follows:
17 // unsigned int(32) size;
18 // unsigned int(32) type = "pssh";
19 // if (size==1) {
20 // unsigned int(64) largesize;
21 // } else if (size==0) {
22 // -- box extends to end of file
23 // }
24 // unsigned int(8) version;
25 // bit(24) flags;
26 // unsigned int(8)[16] SystemID;
27 // if (version > 0)
28 // {
29 // unsigned int(32) KID_count;
30 // {
31 // unsigned int(8)[16] KID;
32 // } [KID_count]
33 // }
34 // unsigned int(32) DataSize;
35 // unsigned int(8)[DataSize] Data;
36
37 // Minimum size of a 'pssh' box includes all the required fields (size, type,
38 // version, flags, SystemID, DataSize).
39 const int kMinimumBoxSizeInBytes = 32;
17 40
18 // SystemID for the Common System. 41 // SystemID for the Common System.
19 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system 42 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system
20 const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec, 43 const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec,
21 0xc0, 0xb2, 0x4d, 0x02, 44 0xc0, 0xb2, 0x4d, 0x02,
22 0xac, 0xe3, 0x3c, 0x1e, 45 0xac, 0xe3, 0x3c, 0x1e,
23 0x52, 0xe2, 0xfb, 0x4b }; 46 0x52, 0xe2, 0xfb, 0x4b };
24 47
25 static bool ReadAllPsshBoxes( 48 #define RCHECK(x) \
26 const std::vector<uint8_t>& input, 49 do { \
27 std::vector<mp4::FullProtectionSystemSpecificHeader>* pssh_boxes) { 50 if (!(x)) \
28 DCHECK(!input.empty()); 51 return false; \
52 } while (0)
29 53
30 // Verify that |input| contains only 'pssh' boxes. ReadAllChildren() is 54 // Helper function to read up to 32 bits from a bit stream.
31 // templated, so it checks that each box in |input| matches the box type of 55 static uint32_t ReadBits(BitReader* reader, int num_bits) {
32 // the parameter (in this case mp4::ProtectionSystemSpecificHeader is a 56 DCHECK_GE(reader->bits_available(), num_bits);
33 // 'pssh' box). mp4::ProtectionSystemSpecificHeader doesn't validate the 57 DCHECK((num_bits > 0) && (num_bits <= 32));
34 // 'pssh' contents, so this simply verifies that |input| only contains 58 uint32_t value;
35 // 'pssh' boxes and nothing else. 59 reader->ReadBits(num_bits, &value);
36 scoped_ptr<mp4::BoxReader> input_reader( 60 return value;
37 mp4::BoxReader::ReadConcatentatedBoxes( 61 }
38 vector_as_array(&input), input.size()));
39 std::vector<mp4::ProtectionSystemSpecificHeader> raw_pssh_boxes;
40 if (!input_reader->ReadAllChildren(&raw_pssh_boxes))
41 return false;
42 62
43 // Now that we have |input| parsed into |raw_pssh_boxes|, reparse each one 63 // Checks whether the next 16 bytes matches the Common SystemID.
44 // into a mp4::FullProtectionSystemSpecificHeader, which extracts all the 64 // Assumes |reader| has enough data.
45 // relevant fields from the box. Since there may be unparseable 'pssh' boxes 65 static bool IsCommonSystemID(BitReader* reader) {
46 // (due to unsupported version, for example), this is done one by one, 66 for (uint32_t i = 0; i < arraysize(kCommonSystemId); ++i) {
47 // ignoring any boxes that can't be parsed. 67 if (ReadBits(reader, 8) != kCommonSystemId[i])
48 for (const auto& raw_pssh_box : raw_pssh_boxes) { 68 return false;
49 scoped_ptr<mp4::BoxReader> raw_pssh_reader( 69 }
50 mp4::BoxReader::ReadConcatentatedBoxes( 70 return true;
51 vector_as_array(&raw_pssh_box.raw_box), 71 }
52 raw_pssh_box.raw_box.size())); 72
53 // ReadAllChildren() appends any successfully parsed box onto it's 73 // Checks that |reader| contains a valid 'ppsh' box header. |reader| is updated
54 // parameter, so |pssh_boxes| will contain the collection of successfully 74 // to point to the content immediately following the box header. Returns true
55 // parsed 'pssh' boxes. If an error occurs, try the next box. 75 // if the header looks valid and |reader| contains enough data for the size of
56 if (!raw_pssh_reader->ReadAllChildren(pssh_boxes)) 76 // header. |size| is updated as the computed size of the box header. Otherwise
57 continue; 77 // false is returned.
78 static bool ValidBoxHeader(BitReader* reader, uint32* size) {
79 // Enough data for a miniumum size 'pssh' box?
80 uint32 available_bytes = reader->bits_available() / 8;
81 RCHECK(available_bytes >= kMinimumBoxSizeInBytes);
82
83 *size = ReadBits(reader, 32);
84
85 // Must be a 'pssh' box or else fail.
86 RCHECK(ReadBits(reader, 8) == 'p');
87 RCHECK(ReadBits(reader, 8) == 's');
88 RCHECK(ReadBits(reader, 8) == 's');
89 RCHECK(ReadBits(reader, 8) == 'h');
90
91 if (*size == 1) {
92 // If largesize > 2**32 it is too big.
93 RCHECK(ReadBits(reader, 32) == 0);
94 *size = ReadBits(reader, 32);
95 } else if (*size == 0) {
96 *size = available_bytes;
58 } 97 }
59 98
60 // Must have successfully parsed at least one 'pssh' box. 99 // Check that the buffer contains at least size bytes.
61 return pssh_boxes->size() > 0; 100 return available_bytes >= *size;
62 } 101 }
63 102
64 bool ValidatePsshInput(const std::vector<uint8_t>& input) { 103 bool ValidatePsshInput(const std::vector<uint8_t>& input) {
65 // No 'pssh' boxes is considered valid. 104 size_t offset = 0;
66 if (input.empty()) 105 while (offset < input.size()) {
67 return true; 106 // Create a BitReader over the remaining part of the buffer.
107 BitReader reader(&input[offset], input.size() - offset);
108 uint32 size;
109 RCHECK(ValidBoxHeader(&reader, &size));
68 110
69 std::vector<mp4::FullProtectionSystemSpecificHeader> children; 111 // Update offset to point at the next 'pssh' box (may not be one).
70 return ReadAllPsshBoxes(input, &children); 112 offset += size;
113 }
114
115 // Only valid if this contains 0 or more 'pssh' boxes.
116 return offset == input.size();
71 } 117 }
72 118
73 bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input, 119 bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
74 KeyIdList* key_ids) { 120 KeyIdList* key_ids) {
121 size_t offset = 0;
75 KeyIdList result; 122 KeyIdList result;
76 std::vector<uint8_t> common_system_id(
77 kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
78 123
79 if (!input.empty()) { 124 while (offset < input.size()) {
80 std::vector<mp4::FullProtectionSystemSpecificHeader> children; 125 BitReader reader(&input[offset], input.size() - offset);
81 if (!ReadAllPsshBoxes(input, &children)) 126 uint32 size;
82 return false; 127 RCHECK(ValidBoxHeader(&reader, &size));
83 128
84 // Check all children for an appropriate 'pssh' box, concatenating any 129 // Update offset to point at the next 'pssh' box (may not be one).
85 // key IDs found. 130 offset += size;
86 for (const auto& child : children) { 131
87 if (child.system_id == common_system_id && child.key_ids.size() > 0) 132 // Check the version, as KIDs only available if version > 0.
88 result.insert(result.end(), child.key_ids.begin(), child.key_ids.end()); 133 uint8_t version = ReadBits(&reader, 8);
134 if (version == 0)
135 continue;
136
137 // flags must be 0. If not, assume incorrect 'pssh' box and move to the
138 // next one.
139 if (ReadBits(&reader, 24) != 0)
140 continue;
141
142 // Validate SystemID
143 RCHECK(static_cast<uint32_t>(reader.bits_available()) >=
144 arraysize(kCommonSystemId) * 8);
145 if (!IsCommonSystemID(&reader))
146 continue; // Not Common System, so try the next pssh box.
147
148 // Since version > 0, next field is the KID_count.
149 RCHECK(static_cast<uint32_t>(reader.bits_available()) >=
150 sizeof(uint32_t) * 8);
151 uint32_t count = ReadBits(&reader, 32);
152
153 if (count == 0)
154 continue;
155
156 // Make sure there is enough data for all the KIDs specified, and then
157 // extract them.
158 RCHECK(static_cast<uint32_t>(reader.bits_available()) > count * 16 * 8);
159 while (count > 0) {
160 std::vector<uint8_t> key;
161 key.reserve(16);
162 for (int i = 0; i < 16; ++i) {
163 key.push_back(ReadBits(&reader, 8));
164 }
165 result.push_back(key);
166 --count;
89 } 167 }
168
169 // Don't bother checking DataSize and Data.
90 } 170 }
91 171
92 // No matching 'pssh' box found. 172 key_ids->swap(result);
173
93 // TODO(jrummell): This should return true only if there was at least one 174 // TODO(jrummell): This should return true only if there was at least one
94 // key ID present. However, numerous test files don't contain the 'pssh' box 175 // key ID present. However, numerous test files don't contain the 'pssh' box
95 // for Common Format, so no keys are found. http://crbug.com/460308 176 // for Common Format, so no keys are found. http://crbug.com/460308
96 key_ids->swap(result);
97 return true; 177 return true;
98 } 178 }
99 179
100 bool GetPsshData(const std::vector<uint8_t>& input,
101 const std::vector<uint8_t>& system_id,
102 std::vector<uint8_t>* pssh_data) {
103 if (input.empty())
104 return false;
105
106 std::vector<mp4::FullProtectionSystemSpecificHeader> children;
107 if (!ReadAllPsshBoxes(input, &children))
108 return false;
109
110 // Check all children for an appropriate 'pssh' box, returning |data| from
111 // the first one found.
112 for (const auto& child : children) {
113 if (child.system_id == system_id) {
114 pssh_data->assign(child.data.begin(), child.data.end());
115 return true;
116 }
117 }
118
119 // No matching 'pssh' box found.
120 return false;
121 }
122
123 } // namespace media 180 } // namespace media
OLDNEW
« 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