Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / media / cdm / cenc_utils.cc
blob357bb6a688fb5e445457727ff8c86ce50b12bd7a
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
3 // found in the LICENSE file.
5 #include "media/cdm/cenc_utils.h"
7 #include "base/stl_util.h"
8 #include "media/formats/mp4/box_definitions.h"
9 #include "media/formats/mp4/box_reader.h"
11 namespace media {
13 // The initialization data for encrypted media files using the ISO Common
14 // Encryption ('cenc') protection scheme may contain one or more protection
15 // system specific header ('pssh') boxes.
16 // ref: https://w3c.github.io/encrypted-media/cenc-format.html
18 // CENC SystemID for the Common System.
19 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system
20 const uint8_t kCencCommonSystemId[] = {0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2,
21 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
22 0x52, 0xe2, 0xfb, 0x4b};
24 // Returns true if |input| contains only 1 or more valid 'pssh' boxes, false
25 // otherwise. |pssh_boxes| is updated as the set of parsed 'pssh' boxes.
26 // Note: All boxes in |input| must be 'pssh' boxes. However, if they can't be
27 // properly parsed (e.g. unsupported version), then they will be skipped.
28 static bool ReadAllPsshBoxes(
29 const std::vector<uint8_t>& input,
30 std::vector<mp4::FullProtectionSystemSpecificHeader>* pssh_boxes) {
31 DCHECK(!input.empty());
33 // Verify that |input| contains only 'pssh' boxes.
34 // ReadAllChildrenAndCheckFourCC() is templated, so it checks that each
35 // box in |input| matches the box type of the parameter (in this case
36 // mp4::ProtectionSystemSpecificHeader is a 'pssh' box).
37 // mp4::ProtectionSystemSpecificHeader doesn't validate the 'pssh' contents,
38 // so this simply verifies that |input| only contains 'pssh' boxes and
39 // nothing else.
40 scoped_ptr<mp4::BoxReader> input_reader(
41 mp4::BoxReader::ReadConcatentatedBoxes(
42 vector_as_array(&input), input.size()));
43 std::vector<mp4::ProtectionSystemSpecificHeader> raw_pssh_boxes;
44 if (!input_reader->ReadAllChildrenAndCheckFourCC(&raw_pssh_boxes))
45 return false;
47 // Now that we have |input| parsed into |raw_pssh_boxes|, reparse each one
48 // into a mp4::FullProtectionSystemSpecificHeader, which extracts all the
49 // relevant fields from the box. Since there may be unparseable 'pssh' boxes
50 // (due to unsupported version, for example), this is done one by one,
51 // ignoring any boxes that can't be parsed.
52 for (const auto& raw_pssh_box : raw_pssh_boxes) {
53 scoped_ptr<mp4::BoxReader> raw_pssh_reader(
54 mp4::BoxReader::ReadConcatentatedBoxes(
55 vector_as_array(&raw_pssh_box.raw_box),
56 raw_pssh_box.raw_box.size()));
57 // ReadAllChildren() appends any successfully parsed box onto it's
58 // parameter, so |pssh_boxes| will contain the collection of successfully
59 // parsed 'pssh' boxes. If an error occurs, try the next box.
60 if (!raw_pssh_reader->ReadAllChildrenAndCheckFourCC(pssh_boxes))
61 continue;
64 // Must have successfully parsed at least one 'pssh' box.
65 return pssh_boxes->size() > 0;
68 bool ValidatePsshInput(const std::vector<uint8_t>& input) {
69 // No 'pssh' boxes is considered valid.
70 if (input.empty())
71 return true;
73 std::vector<mp4::FullProtectionSystemSpecificHeader> children;
74 return ReadAllPsshBoxes(input, &children);
77 bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& pssh_boxes,
78 KeyIdList* key_ids) {
79 // If there are no 'pssh' boxes then no key IDs found.
80 if (pssh_boxes.empty())
81 return false;
83 std::vector<mp4::FullProtectionSystemSpecificHeader> children;
84 if (!ReadAllPsshBoxes(pssh_boxes, &children))
85 return false;
87 // Check all children for an appropriate 'pssh' box, returning the
88 // key IDs found.
89 KeyIdList result;
90 std::vector<uint8_t> common_system_id(
91 kCencCommonSystemId,
92 kCencCommonSystemId + arraysize(kCencCommonSystemId));
93 for (const auto& child : children) {
94 if (child.system_id == common_system_id) {
95 key_ids->assign(child.key_ids.begin(), child.key_ids.end());
96 return key_ids->size() > 0;
100 // No matching 'pssh' box found.
101 return false;
104 bool GetPsshData(const std::vector<uint8_t>& input,
105 const std::vector<uint8_t>& system_id,
106 std::vector<uint8_t>* pssh_data) {
107 if (input.empty())
108 return false;
110 std::vector<mp4::FullProtectionSystemSpecificHeader> children;
111 if (!ReadAllPsshBoxes(input, &children))
112 return false;
114 // Check all children for an appropriate 'pssh' box, returning |data| from
115 // the first one found.
116 for (const auto& child : children) {
117 if (child.system_id == system_id) {
118 pssh_data->assign(child.data.begin(), child.data.end());
119 return true;
123 // No matching 'pssh' box found.
124 return false;
127 } // namespace media