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 "components/cdm/browser/widevine_drm_delegate_android.h" | 5 #include "components/cdm/browser/widevine_drm_delegate_android.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "media/cdm/cenc_utils.h" |
8 #include "base/numerics/safe_conversions.h" | |
9 | 8 |
10 namespace cdm { | 9 namespace cdm { |
11 | 10 |
12 namespace { | 11 namespace { |
13 | 12 |
14 uint32_t ReadUint32(const uint8_t* data) { | |
15 uint32_t value = 0; | |
16 for (int i = 0; i < 4; ++i) | |
17 value = (value << 8) | data[i]; | |
18 return value; | |
19 } | |
20 | |
21 uint64_t ReadUint64(const uint8_t* data) { | |
22 uint64_t value = 0; | |
23 for (int i = 0; i < 8; ++i) | |
24 value = (value << 8) | data[i]; | |
25 return value; | |
26 } | |
27 | |
28 // The structure of an ISO CENC Protection System Specific Header (PSSH) box is | |
29 // as follows. (See ISO/IEC FDIS 23001-7:2011(E).) | |
30 // Note: ISO boxes use big-endian values. | |
31 // | |
32 // PSSH { | |
33 // uint32 Size | |
34 // uint32 Type | |
35 // uint64 LargeSize # Field is only present if value(Size) == 1. | |
36 // uint8 Version | |
37 // uint24 Flags | |
38 // uint8[16] SystemId | |
39 // if (version > 0) { | |
40 // uint32 KID_count; | |
41 // uint8[16][KID_Count] KID; | |
42 // } | |
43 // uint32 DataSize | |
44 // uint8[DataSize] Data | |
45 // } | |
46 const int kBoxHeaderSize = 8; // Box's header contains Size and Type. | |
47 const int kBoxLargeSizeSize = 8; | |
48 const int kPsshVersionFlagSize = 4; | |
49 const uint32_t k24BitMask = 0x00ffffff; | |
50 const int kPsshSystemIdSize = 16; | |
51 const int kPsshKidCountSize = 4; | |
52 const int kPsshKidSize = 16; | |
53 const int kPsshDataSizeSize = 4; | |
54 const uint32_t kPsshType = 0x70737368; | |
55 | |
56 const uint8_t kWidevineUuid[16] = { | 13 const uint8_t kWidevineUuid[16] = { |
57 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, | 14 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, |
58 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; | 15 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; |
59 | 16 |
60 // Tries to find a PSSH box with the Widevine UUID, parses the | 17 } // namespace |
61 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is | |
62 // found and successfully parsed. Returns false otherwise. | |
63 // Notes: | |
64 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box | |
65 // will be set in |pssh_data|. | |
66 // 2, Only PSSH boxes are allowed in |data|. | |
67 bool GetPsshData(const std::vector<uint8_t>& data, | |
68 std::vector<uint8_t>* pssh_data) { | |
69 int bytes_left = base::checked_cast<int>(data.size()); | |
70 const uint8_t* cur = &data[0]; | |
71 const uint8_t* data_end = cur + bytes_left; | |
72 | |
73 while (bytes_left > 0) { | |
74 const uint8_t* box_head = cur; | |
75 | |
76 if (bytes_left < kBoxHeaderSize) | |
77 return false; | |
78 | |
79 uint64_t box_size = ReadUint32(cur); | |
80 uint32_t type = ReadUint32(cur + 4); | |
81 cur += kBoxHeaderSize; | |
82 bytes_left -= kBoxHeaderSize; | |
83 | |
84 if (box_size == 1) { // LargeSize is present. | |
85 if (bytes_left < kBoxLargeSizeSize) | |
86 return false; | |
87 | |
88 box_size = ReadUint64(cur); | |
89 cur += kBoxLargeSizeSize; | |
90 bytes_left -= kBoxLargeSizeSize; | |
91 } else if (box_size == 0) { | |
92 box_size = bytes_left + kBoxHeaderSize; | |
93 } | |
94 | |
95 const uint8_t* box_end = box_head + box_size; | |
96 if (data_end < box_end) | |
97 return false; | |
98 | |
99 if (type != kPsshType) | |
100 return false; | |
101 | |
102 const int kPsshBoxMinimumSize = | |
103 kPsshVersionFlagSize + kPsshSystemIdSize + kPsshDataSizeSize; | |
104 if (box_end < cur + kPsshBoxMinimumSize) | |
105 return false; | |
106 | |
107 uint8_t version = cur[0]; | |
108 uint32_t flags = ReadUint32(cur) & k24BitMask; | |
109 cur += kPsshVersionFlagSize; | |
110 bytes_left -= kPsshVersionFlagSize; | |
111 if (flags != 0) | |
112 return false; | |
113 | |
114 DCHECK_GE(bytes_left, kPsshSystemIdSize); | |
115 if (!std::equal(kWidevineUuid, | |
116 kWidevineUuid + sizeof(kWidevineUuid), cur)) { | |
117 cur = box_end; | |
118 bytes_left = data_end - cur; | |
119 continue; | |
120 } | |
121 | |
122 cur += kPsshSystemIdSize; | |
123 bytes_left -= kPsshSystemIdSize; | |
124 | |
125 // If KeyIDs specified, skip them. | |
126 if (version > 0) { | |
127 DCHECK_GE(bytes_left, kPsshKidCountSize); | |
128 uint32_t kid_count = ReadUint32(cur); | |
129 cur += kPsshKidCountSize + kid_count * kPsshKidSize; | |
130 bytes_left -= kPsshKidCountSize + kid_count * kPsshKidSize; | |
131 // Must be bytes left in this box for data_size. | |
132 if (box_end < cur + kPsshDataSizeSize) | |
133 return false; | |
134 } | |
135 | |
136 DCHECK_GE(bytes_left, kPsshDataSizeSize); | |
137 uint32_t data_size = ReadUint32(cur); | |
138 cur += kPsshDataSizeSize; | |
139 bytes_left -= kPsshDataSizeSize; | |
140 | |
141 if (box_end < cur + data_size) | |
142 return false; | |
143 | |
144 pssh_data->assign(cur, cur + data_size); | |
145 return true; | |
146 } | |
147 | |
148 return false; | |
149 } | |
150 | |
151 } | |
152 | 18 |
153 WidevineDrmDelegateAndroid::WidevineDrmDelegateAndroid() { | 19 WidevineDrmDelegateAndroid::WidevineDrmDelegateAndroid() { |
154 } | 20 } |
155 | 21 |
156 WidevineDrmDelegateAndroid::~WidevineDrmDelegateAndroid() { | 22 WidevineDrmDelegateAndroid::~WidevineDrmDelegateAndroid() { |
157 } | 23 } |
158 | 24 |
159 const std::vector<uint8_t> WidevineDrmDelegateAndroid::GetUUID() const { | 25 const std::vector<uint8_t> WidevineDrmDelegateAndroid::GetUUID() const { |
160 return std::vector<uint8_t>(kWidevineUuid, | 26 return std::vector<uint8_t>(kWidevineUuid, |
161 kWidevineUuid + arraysize(kWidevineUuid)); | 27 kWidevineUuid + arraysize(kWidevineUuid)); |
162 } | 28 } |
163 | 29 |
164 bool WidevineDrmDelegateAndroid::OnCreateSession( | 30 bool WidevineDrmDelegateAndroid::OnCreateSession( |
165 const media::EmeInitDataType init_data_type, | 31 const media::EmeInitDataType init_data_type, |
166 const std::vector<uint8_t>& init_data, | 32 const std::vector<uint8_t>& init_data, |
167 std::vector<uint8_t>* init_data_out, | 33 std::vector<uint8_t>* init_data_out, |
168 std::vector<std::string>* /* optional_parameters_out */) { | 34 std::vector<std::string>* /* optional_parameters_out */) { |
169 if (init_data_type != media::EmeInitDataType::CENC) | 35 if (init_data_type != media::EmeInitDataType::CENC) |
170 return true; | 36 return true; |
171 | 37 |
172 // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as | 38 // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as |
173 // the init data when using MP4 container. | 39 // the init data when using MP4 container. |
174 return GetPsshData(init_data, init_data_out); | 40 return media::GetPsshData(init_data, GetUUID(), init_data_out); |
175 } | 41 } |
176 | 42 |
177 } // namespace cdm | 43 } // namespace cdm |
OLD | NEW |