OLD | NEW |
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 "media/base/bit_reader.h" | 7 #include "media/base/bit_reader.h" |
8 | 8 |
9 namespace media { | 9 namespace media { |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 // unsigned int(8)[16] SystemID; | 26 // unsigned int(8)[16] SystemID; |
27 // if (version > 0) | 27 // if (version > 0) |
28 // { | 28 // { |
29 // unsigned int(32) KID_count; | 29 // unsigned int(32) KID_count; |
30 // { | 30 // { |
31 // unsigned int(8)[16] KID; | 31 // unsigned int(8)[16] KID; |
32 // } [KID_count] | 32 // } [KID_count] |
33 // } | 33 // } |
34 // unsigned int(32) DataSize; | 34 // unsigned int(32) DataSize; |
35 // unsigned int(8)[DataSize] Data; | 35 // unsigned int(8)[DataSize] Data; |
| 36 // Only versions 0 and 1 of the 'pssh' boxes are supported. Any other versions |
| 37 // are ignored. |
36 | 38 |
37 // Minimum size of a 'pssh' box includes all the required fields (size, type, | 39 // Minimum size of a 'pssh' box includes all the required fields (size, type, |
38 // version, flags, SystemID, DataSize). | 40 // version, flags, SystemID, DataSize). |
39 const int kMinimumBoxSizeInBytes = 32; | 41 const uint32_t kMinimumBoxSizeInBytes = 32; |
| 42 |
| 43 // Size of a SystemID field in bytes. |
| 44 const uint32_t kSystemIDSizeInBytes = 16; |
| 45 |
| 46 // Size of a KID field in bytes. |
| 47 const uint32_t kKIDSizeInBytes = 16; |
40 | 48 |
41 // SystemID for the Common System. | 49 // SystemID for the Common System. |
42 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system | 50 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system |
43 const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec, | 51 const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec, |
44 0xc0, 0xb2, 0x4d, 0x02, | 52 0xc0, 0xb2, 0x4d, 0x02, |
45 0xac, 0xe3, 0x3c, 0x1e, | 53 0xac, 0xe3, 0x3c, 0x1e, |
46 0x52, 0xe2, 0xfb, 0x4b }; | 54 0x52, 0xe2, 0xfb, 0x4b }; |
47 | 55 |
48 #define RCHECK(x) \ | 56 #define RCHECK(x) \ |
49 do { \ | 57 do { \ |
50 if (!(x)) \ | 58 if (!(x)) \ |
51 return false; \ | 59 return false; \ |
52 } while (0) | 60 } while (0) |
53 | 61 |
54 // Helper function to read up to 32 bits from a bit stream. | 62 // Helper function to read up to 32 bits from a bit stream. |
55 static uint32_t ReadBits(BitReader* reader, int num_bits) { | 63 static uint32_t ReadBits(BitReader* reader, int num_bits) { |
56 DCHECK_GE(reader->bits_available(), num_bits); | 64 DCHECK_GE(reader->bits_available(), num_bits); |
57 DCHECK((num_bits > 0) && (num_bits <= 32)); | 65 DCHECK((num_bits > 0) && (num_bits <= 32)); |
58 uint32_t value; | 66 uint32_t value; |
59 reader->ReadBits(num_bits, &value); | 67 reader->ReadBits(num_bits, &value); |
60 return value; | 68 return value; |
61 } | 69 } |
62 | 70 |
63 // Checks whether the next 16 bytes matches the Common SystemID. | 71 // Return the number of bytes available in |reader|. |
64 // Assumes |reader| has enough data. | 72 static uint32_t BytesAvailable(BitReader* reader) { |
65 static bool IsCommonSystemID(BitReader* reader) { | 73 return reader->bits_available() / 8; |
66 for (uint32_t i = 0; i < arraysize(kCommonSystemId); ++i) { | 74 } |
67 if (ReadBits(reader, 8) != kCommonSystemId[i]) | 75 |
| 76 // Checks whether the next bytes in |reader| match the specified |system_id|. |
| 77 static bool MatchSystemID(BitReader* reader, |
| 78 const std::vector<uint8_t>& system_id) { |
| 79 RCHECK(BytesAvailable(reader) >= system_id.size()); |
| 80 for (const auto& data : system_id) { |
| 81 if (ReadBits(reader, 8) != data) |
68 return false; | 82 return false; |
69 } | 83 } |
70 return true; | 84 return true; |
71 } | 85 } |
72 | 86 |
73 // Checks that |reader| contains a valid 'ppsh' box header. |reader| is updated | 87 // Checks that |reader| contains a valid 'ppsh' box header. |reader| is updated |
74 // to point to the content immediately following the box header. Returns true | 88 // to point to the content immediately following the box header. Returns true |
75 // if the header looks valid and |reader| contains enough data for the size of | 89 // if the header looks valid and |reader| contains enough data for the size of |
76 // header. |size| is updated as the computed size of the box header. Otherwise | 90 // header. |size| is updated as the computed size of the box header. Otherwise |
77 // false is returned. | 91 // false is returned. |
78 static bool ValidBoxHeader(BitReader* reader, uint32* size) { | 92 static bool ValidBoxHeader(BitReader* reader, uint32_t* size) { |
79 // Enough data for a miniumum size 'pssh' box? | 93 // Enough data for a miniumum size 'pssh' box? |
80 uint32 available_bytes = reader->bits_available() / 8; | 94 uint32_t available_bytes = BytesAvailable(reader); |
81 RCHECK(available_bytes >= kMinimumBoxSizeInBytes); | 95 RCHECK(available_bytes >= kMinimumBoxSizeInBytes); |
82 | 96 |
83 *size = ReadBits(reader, 32); | 97 *size = ReadBits(reader, 32); |
84 | 98 |
85 // Must be a 'pssh' box or else fail. | 99 // Must be a 'pssh' box or else fail. |
86 RCHECK(ReadBits(reader, 8) == 'p'); | 100 RCHECK(ReadBits(reader, 8) == 'p'); |
87 RCHECK(ReadBits(reader, 8) == 's'); | 101 RCHECK(ReadBits(reader, 8) == 's'); |
88 RCHECK(ReadBits(reader, 8) == 's'); | 102 RCHECK(ReadBits(reader, 8) == 's'); |
89 RCHECK(ReadBits(reader, 8) == 'h'); | 103 RCHECK(ReadBits(reader, 8) == 'h'); |
90 | 104 |
91 if (*size == 1) { | 105 if (*size == 1) { |
92 // If largesize > 2**32 it is too big. | 106 // If largesize > 2**32 it is too big. |
93 RCHECK(ReadBits(reader, 32) == 0); | 107 RCHECK(ReadBits(reader, 32) == 0); |
94 *size = ReadBits(reader, 32); | 108 *size = ReadBits(reader, 32); |
95 } else if (*size == 0) { | 109 } else if (*size == 0) { |
96 *size = available_bytes; | 110 *size = available_bytes; |
97 } | 111 } |
98 | 112 |
99 // Check that the buffer contains at least size bytes. | 113 // Check that the buffer contains at least size bytes. |
100 return available_bytes >= *size; | 114 return available_bytes >= *size; |
101 } | 115 } |
102 | 116 |
103 bool ValidatePsshInput(const std::vector<uint8_t>& input) { | 117 bool ValidatePsshInput(const std::vector<uint8_t>& input) { |
104 size_t offset = 0; | 118 size_t offset = 0; |
105 while (offset < input.size()) { | 119 while (offset < input.size()) { |
106 // Create a BitReader over the remaining part of the buffer. | 120 // Create a BitReader over the remaining part of the buffer. |
107 BitReader reader(&input[offset], input.size() - offset); | 121 BitReader reader(&input[offset], input.size() - offset); |
108 uint32 size; | 122 uint32_t size; |
109 RCHECK(ValidBoxHeader(&reader, &size)); | 123 RCHECK(ValidBoxHeader(&reader, &size)); |
110 | 124 |
111 // Update offset to point at the next 'pssh' box (may not be one). | 125 // Update offset to point at the next 'pssh' box (may not be one). |
112 offset += size; | 126 offset += size; |
113 } | 127 } |
114 | 128 |
115 // Only valid if this contains 0 or more 'pssh' boxes. | 129 // Only valid if this contains 0 or more 'pssh' boxes. |
116 return offset == input.size(); | 130 return offset == input.size(); |
117 } | 131 } |
118 | 132 |
119 bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input, | 133 bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input, |
120 KeyIdList* key_ids) { | 134 KeyIdList* key_ids) { |
121 size_t offset = 0; | 135 size_t offset = 0; |
122 KeyIdList result; | 136 KeyIdList result; |
| 137 std::vector<uint8_t> common_system_id( |
| 138 kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId)); |
123 | 139 |
124 while (offset < input.size()) { | 140 while (offset < input.size()) { |
125 BitReader reader(&input[offset], input.size() - offset); | 141 BitReader reader(&input[offset], input.size() - offset); |
126 uint32 size; | 142 uint32_t size; |
127 RCHECK(ValidBoxHeader(&reader, &size)); | 143 RCHECK(ValidBoxHeader(&reader, &size)); |
128 | 144 |
129 // Update offset to point at the next 'pssh' box (may not be one). | 145 // Update offset to point at the next 'pssh' box (may not be one). |
130 offset += size; | 146 offset += size; |
131 | 147 |
132 // Check the version, as KIDs only available if version > 0. | 148 // Check the version. Only version 0 and 1 'pssh' boxes are supported. |
| 149 // However, KIDs only available if version > 0, so skip if version != 1. |
133 uint8_t version = ReadBits(&reader, 8); | 150 uint8_t version = ReadBits(&reader, 8); |
134 if (version == 0) | 151 if (version != 1) |
135 continue; | 152 continue; |
136 | 153 |
137 // flags must be 0. If not, assume incorrect 'pssh' box and move to the | 154 // flags must be 0. If not, assume incorrect 'pssh' box and move to the |
138 // next one. | 155 // next one. |
139 if (ReadBits(&reader, 24) != 0) | 156 if (ReadBits(&reader, 24) != 0) |
140 continue; | 157 continue; |
141 | 158 |
142 // Validate SystemID | 159 // Validate SystemID |
143 RCHECK(static_cast<uint32_t>(reader.bits_available()) >= | 160 if (!MatchSystemID(&reader, common_system_id)) |
144 arraysize(kCommonSystemId) * 8); | |
145 if (!IsCommonSystemID(&reader)) | |
146 continue; // Not Common System, so try the next pssh box. | 161 continue; // Not Common System, so try the next pssh box. |
147 | 162 |
148 // Since version > 0, next field is the KID_count. | 163 // Since version > 0, next field is the KID_count. |
149 RCHECK(static_cast<uint32_t>(reader.bits_available()) >= | 164 RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t)); |
150 sizeof(uint32_t) * 8); | |
151 uint32_t count = ReadBits(&reader, 32); | 165 uint32_t count = ReadBits(&reader, 32); |
152 | 166 |
153 if (count == 0) | 167 if (count == 0) |
154 continue; | 168 continue; |
155 | 169 |
156 // Make sure there is enough data for all the KIDs specified, and then | 170 // Make sure there is enough data for all the KIDs specified, and then |
157 // extract them. | 171 // extract them. |
158 RCHECK(static_cast<uint32_t>(reader.bits_available()) > count * 16 * 8); | 172 RCHECK(BytesAvailable(&reader) > count * kKIDSizeInBytes); |
159 while (count > 0) { | 173 while (count > 0) { |
160 std::vector<uint8_t> key; | 174 std::vector<uint8_t> key; |
161 key.reserve(16); | 175 key.reserve(kKIDSizeInBytes); |
162 for (int i = 0; i < 16; ++i) { | 176 for (uint32_t i = 0; i < kKIDSizeInBytes; ++i) { |
163 key.push_back(ReadBits(&reader, 8)); | 177 key.push_back(ReadBits(&reader, 8)); |
164 } | 178 } |
165 result.push_back(key); | 179 result.push_back(key); |
166 --count; | 180 --count; |
167 } | 181 } |
168 | 182 |
169 // Don't bother checking DataSize and Data. | 183 // Don't bother checking DataSize and Data. |
170 } | 184 } |
171 | 185 |
172 key_ids->swap(result); | 186 key_ids->swap(result); |
173 | 187 |
174 // TODO(jrummell): This should return true only if there was at least one | 188 // TODO(jrummell): This should return true only if there was at least one |
175 // key ID present. However, numerous test files don't contain the 'pssh' box | 189 // key ID present. However, numerous test files don't contain the 'pssh' box |
176 // for Common Format, so no keys are found. http://crbug.com/460308 | 190 // for Common Format, so no keys are found. http://crbug.com/460308 |
177 return true; | 191 return true; |
178 } | 192 } |
179 | 193 |
| 194 bool GetPsshData(const std::vector<uint8_t>& input, |
| 195 const std::vector<uint8_t>& system_id, |
| 196 std::vector<uint8_t>* pssh_data) { |
| 197 DCHECK_EQ(system_id.size(), kSystemIDSizeInBytes); |
| 198 size_t offset = 0; |
| 199 |
| 200 while (offset < input.size()) { |
| 201 // Create a BitReader over the remaining part of the buffer. |
| 202 BitReader reader(&input[offset], input.size() - offset); |
| 203 uint32_t size; |
| 204 RCHECK(ValidBoxHeader(&reader, &size)); |
| 205 |
| 206 // Update offset to point at the next 'pssh' box (may not be one). |
| 207 offset += size; |
| 208 |
| 209 // Check the version. Only version 0 and 1 'pssh' boxes are supported. |
| 210 // Other versions are skipped. |
| 211 uint8_t version = ReadBits(&reader, 8); |
| 212 if (version > 1) |
| 213 continue; |
| 214 |
| 215 // flags must be 0. If not, assume incorrect 'pssh' box and move to the |
| 216 // next one. |
| 217 if (ReadBits(&reader, 24) != 0) |
| 218 continue; |
| 219 |
| 220 // Validate SystemID. If not, try the next 'pssh' box. |
| 221 if (!MatchSystemID(&reader, system_id)) |
| 222 continue; |
| 223 |
| 224 // If version > 0, next field is the KID_count. Skip any KIDs in the |
| 225 // 'pssh' box. |
| 226 if (version > 0) { |
| 227 RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t)); |
| 228 uint32_t count = ReadBits(&reader, 32); |
| 229 RCHECK(reader.SkipBits(count * kKIDSizeInBytes * 8)); |
| 230 } |
| 231 |
| 232 // Now get the datasize. |
| 233 RCHECK(BytesAvailable(&reader) >= sizeof(uint32_t)); |
| 234 uint32_t datasize = ReadBits(&reader, 32); |
| 235 |
| 236 // Now get the data and return it. |
| 237 RCHECK(BytesAvailable(&reader) >= datasize); |
| 238 for (uint32_t i = 0; i < datasize; ++i) { |
| 239 pssh_data->push_back(ReadBits(&reader, 8)); |
| 240 } |
| 241 return true; |
| 242 } |
| 243 |
| 244 // No matching 'pssh' box found, so fail. |
| 245 return false; |
| 246 } |
| 247 |
180 } // namespace media | 248 } // namespace media |
OLD | NEW |