OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/base/android/media_drm_bridge.h" | 5 #include "media/base/android/media_drm_bridge.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/android/build_info.h" | 9 #include "base/android/build_info.h" |
10 #include "base/android/jni_array.h" | 10 #include "base/android/jni_array.h" |
11 #include "base/android/jni_string.h" | 11 #include "base/android/jni_string.h" |
12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/message_loop/message_loop_proxy.h" | 15 #include "base/message_loop/message_loop_proxy.h" |
16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
17 #include "jni/MediaDrmBridge_jni.h" | 17 #include "jni/MediaDrmBridge_jni.h" |
18 #include "media/base/android/media_player_manager.h" | 18 #include "media/base/android/media_player_manager.h" |
19 | 19 |
20 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. | 20 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. |
21 | 21 |
22 using base::android::AttachCurrentThread; | 22 using base::android::AttachCurrentThread; |
23 using base::android::ConvertUTF8ToJavaString; | 23 using base::android::ConvertUTF8ToJavaString; |
24 using base::android::ConvertJavaStringToUTF8; | 24 using base::android::ConvertJavaStringToUTF8; |
25 using base::android::JavaByteArrayToByteVector; | 25 using base::android::JavaByteArrayToByteVector; |
26 using base::android::ScopedJavaLocalRef; | 26 using base::android::ScopedJavaLocalRef; |
27 | 27 |
28 namespace media { | 28 namespace media { |
29 | 29 |
30 static uint32 ReadUint32(const uint8_t* data) { | 30 namespace { |
xhwang
2014/05/15 15:10:29
In media code, we use "static" a lot. Some people
ycheo (away)
2014/05/16 04:53:38
Got it. I'll revert it to static.
| |
31 | |
32 uint32 ReadUint32(const uint8_t* data) { | |
31 uint32 value = 0; | 33 uint32 value = 0; |
32 for (int i = 0; i < 4; ++i) | 34 for (int i = 0; i < 4; ++i) |
33 value = (value << 8) | data[i]; | 35 value = (value << 8) | data[i]; |
34 return value; | 36 return value; |
35 } | 37 } |
36 | 38 |
37 static uint64 ReadUint64(const uint8_t* data) { | 39 uint64 ReadUint64(const uint8_t* data) { |
38 uint64 value = 0; | 40 uint64 value = 0; |
39 for (int i = 0; i < 8; ++i) | 41 for (int i = 0; i < 8; ++i) |
40 value = (value << 8) | data[i]; | 42 value = (value << 8) | data[i]; |
41 return value; | 43 return value; |
42 } | 44 } |
43 | 45 |
44 // The structure of an ISO CENC Protection System Specific Header (PSSH) box is | 46 // The structure of an ISO CENC Protection System Specific Header (PSSH) box is |
45 // as follows. (See ISO/IEC FDIS 23001-7:2011(E).) | 47 // as follows. (See ISO/IEC FDIS 23001-7:2011(E).) |
46 // Note: ISO boxes use big-endian values. | 48 // Note: ISO boxes use big-endian values. |
47 // | 49 // |
(...skipping 10 matching lines...) Expand all Loading... | |
58 const int kBoxLargeSizeSize = 8; | 60 const int kBoxLargeSizeSize = 8; |
59 const int kPsshVersionFlagSize = 4; | 61 const int kPsshVersionFlagSize = 4; |
60 const int kPsshSystemIdSize = 16; | 62 const int kPsshSystemIdSize = 16; |
61 const int kPsshDataSizeSize = 4; | 63 const int kPsshDataSizeSize = 4; |
62 const uint32 kTencType = 0x74656e63; | 64 const uint32 kTencType = 0x74656e63; |
63 const uint32 kPsshType = 0x70737368; | 65 const uint32 kPsshType = 0x70737368; |
64 const uint8 kWidevineUuid[16] = { | 66 const uint8 kWidevineUuid[16] = { |
65 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, | 67 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, |
66 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; | 68 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; |
67 | 69 |
68 static std::vector<uint8> GetUUID(const std::string& key_system) { | 70 typedef std::pair<std::string, std::vector<uint8> > KeySystemUuidPair; |
69 // For security reasons, we only do exact string comparisons here - we don't | 71 // Use std::vector<>, not std::map<> since the size of the table will be |
70 // try to parse the |key_system| in any way. | 72 // expected to be resonably small. |
71 if (key_system == kWidevineKeySystem) { | 73 typedef std::vector<KeySystemUuidPair> KeySystemUuidTable; |
xhwang
2014/05/15 15:10:29
Since we use UUID a lot now, how about
typedef st
ddorwin
2014/05/15 19:00:45
This would also allow s/Table/Map/. "Map" is used
ycheo (away)
2014/05/16 04:53:38
Done.
ycheo (away)
2014/05/16 04:53:38
Done.
| |
72 return std::vector<uint8>(kWidevineUuid, | 74 KeySystemUuidTable* key_system_uuid_table = NULL; |
xhwang
2014/05/15 15:10:29
global variable needs to be named as g_foo
ycheo (away)
2014/05/16 04:53:38
Done.
| |
73 kWidevineUuid + arraysize(kWidevineUuid)); | 75 |
76 void InitializeKeySystemUuidTable() { | |
77 key_system_uuid_table = new KeySystemUuidTable(); | |
78 | |
79 key_system_uuid_table->push_back(make_pair( | |
80 kWidevineKeySystem, | |
81 std::vector<uint8>(kWidevineUuid, | |
82 kWidevineUuid + arraysize(kWidevineUuid)))); | |
83 } | |
84 | |
85 KeySystemUuidTable::iterator FindKeySystem(const std::string& key_system) { | |
ddorwin
2014/05/15 19:00:45
This name does not accurately describe the behavio
ycheo (away)
2014/05/16 04:53:38
The method is removed by using hash_map.
| |
86 KeySystemUuidTable::iterator it; | |
87 for (it = key_system_uuid_table->begin(); | |
88 it != key_system_uuid_table->end(); ++it) { | |
89 // For security reasons, we only do exact string comparisons here - we don't | |
90 // try to parse the |key_system| in any way. | |
91 if (key_system == it->first) | |
92 return it; | |
74 } | 93 } |
94 return it; | |
95 } | |
xhwang
2014/05/15 15:10:29
If you use a hashmap, you don't need this function
ycheo (away)
2014/05/16 04:53:38
Done.
| |
96 | |
97 std::vector<uint8> GetUUID(const std::string& key_system) { | |
98 if (key_system_uuid_table == NULL) | |
ddorwin
2014/05/15 19:00:45
This code appears twice. Why not initialize the ta
ycheo (away)
2014/05/16 04:53:38
Removed by using the lazy initializer.
| |
99 InitializeKeySystemUuidTable(); | |
100 | |
101 KeySystemUuidTable::iterator it = FindKeySystem(key_system); | |
102 if (it != key_system_uuid_table->end()) | |
103 return it->second; | |
75 return std::vector<uint8>(); | 104 return std::vector<uint8>(); |
xhwang
2014/05/15 15:10:29
nit: we like to handle abnormal cases first, i.e.
ycheo (away)
2014/05/16 04:53:38
Done.
| |
76 } | 105 } |
77 | 106 |
78 // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the | 107 // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the |
79 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is | 108 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is |
80 // found and successfully parsed. Returns false otherwise. | 109 // found and successfully parsed. Returns false otherwise. |
81 // Notes: | 110 // Notes: |
82 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box | 111 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box |
83 // will be set in |pssh_data|. | 112 // will be set in |pssh_data|. |
84 // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. | 113 // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. |
85 static bool GetPsshData(const uint8* data, int data_size, | 114 bool GetPsshData(const uint8* data, int data_size, |
86 const std::vector<uint8>& uuid, | 115 const std::vector<uint8>& uuid, |
87 std::vector<uint8>* pssh_data) { | 116 std::vector<uint8>* pssh_data) { |
88 const uint8* cur = data; | 117 const uint8* cur = data; |
89 const uint8* data_end = data + data_size; | 118 const uint8* data_end = data + data_size; |
90 int bytes_left = data_size; | 119 int bytes_left = data_size; |
91 | 120 |
92 while (bytes_left > 0) { | 121 while (bytes_left > 0) { |
93 const uint8* box_head = cur; | 122 const uint8* box_head = cur; |
94 | 123 |
95 if (bytes_left < kBoxHeaderSize) | 124 if (bytes_left < kBoxHeaderSize) |
96 return false; | 125 return false; |
97 | 126 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 if (box_end < cur + data_size) | 181 if (box_end < cur + data_size) |
153 return false; | 182 return false; |
154 | 183 |
155 pssh_data->assign(cur, cur + data_size); | 184 pssh_data->assign(cur, cur + data_size); |
156 return true; | 185 return true; |
157 } | 186 } |
158 | 187 |
159 return false; | 188 return false; |
160 } | 189 } |
161 | 190 |
162 static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( | 191 MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( |
163 const std::string& security_level_str) { | 192 const std::string& security_level_str) { |
164 if (0 == security_level_str.compare("L1")) | 193 if (0 == security_level_str.compare("L1")) |
165 return MediaDrmBridge::SECURITY_LEVEL_1; | 194 return MediaDrmBridge::SECURITY_LEVEL_1; |
166 if (0 == security_level_str.compare("L3")) | 195 if (0 == security_level_str.compare("L3")) |
167 return MediaDrmBridge::SECURITY_LEVEL_3; | 196 return MediaDrmBridge::SECURITY_LEVEL_3; |
168 DCHECK(security_level_str.empty()); | 197 DCHECK(security_level_str.empty()); |
169 return MediaDrmBridge::SECURITY_LEVEL_NONE; | 198 return MediaDrmBridge::SECURITY_LEVEL_NONE; |
170 } | 199 } |
171 | 200 |
172 static std::string GetSecurityLevelString( | 201 std::string GetSecurityLevelString( |
173 MediaDrmBridge::SecurityLevel security_level) { | 202 MediaDrmBridge::SecurityLevel security_level) { |
174 switch (security_level) { | 203 switch (security_level) { |
175 case MediaDrmBridge::SECURITY_LEVEL_NONE: | 204 case MediaDrmBridge::SECURITY_LEVEL_NONE: |
176 return ""; | 205 return ""; |
177 case MediaDrmBridge::SECURITY_LEVEL_1: | 206 case MediaDrmBridge::SECURITY_LEVEL_1: |
178 return "L1"; | 207 return "L1"; |
179 case MediaDrmBridge::SECURITY_LEVEL_3: | 208 case MediaDrmBridge::SECURITY_LEVEL_3: |
180 return "L3"; | 209 return "L3"; |
181 } | 210 } |
182 return ""; | 211 return ""; |
183 } | 212 } |
184 | 213 |
185 // Checks whether |key_system| is supported with |container_mime_type|. Only | 214 // Checks whether |key_system| is supported with |container_mime_type|. Only |
186 // checks |key_system| support if |container_mime_type| is empty. | 215 // checks |key_system| support if |container_mime_type| is empty. |
187 // TODO(xhwang): The |container_mime_type| is not the same as contentType in | 216 // TODO(xhwang): The |container_mime_type| is not the same as contentType in |
188 // the EME spec. Revisit this once the spec issue with initData type is | 217 // the EME spec. Revisit this once the spec issue with initData type is |
189 // resolved. | 218 // resolved. |
190 static bool IsKeySystemSupportedWithTypeImpl( | 219 bool IsKeySystemSupportedWithTypeImpl( |
191 const std::string& key_system, | 220 const std::string& key_system, |
192 const std::string& container_mime_type) { | 221 const std::string& container_mime_type) { |
193 if (!MediaDrmBridge::IsAvailable()) | 222 if (!MediaDrmBridge::IsAvailable()) |
194 return false; | 223 return false; |
195 | 224 |
196 std::vector<uint8> scheme_uuid = GetUUID(key_system); | 225 std::vector<uint8> scheme_uuid = GetUUID(key_system); |
197 if (scheme_uuid.empty()) | 226 if (scheme_uuid.empty()) |
198 return false; | 227 return false; |
199 | 228 |
200 JNIEnv* env = AttachCurrentThread(); | 229 JNIEnv* env = AttachCurrentThread(); |
201 ScopedJavaLocalRef<jbyteArray> j_scheme_uuid = | 230 ScopedJavaLocalRef<jbyteArray> j_scheme_uuid = |
202 base::android::ToJavaByteArray(env, &scheme_uuid[0], scheme_uuid.size()); | 231 base::android::ToJavaByteArray(env, &scheme_uuid[0], scheme_uuid.size()); |
203 ScopedJavaLocalRef<jstring> j_container_mime_type = | 232 ScopedJavaLocalRef<jstring> j_container_mime_type = |
204 ConvertUTF8ToJavaString(env, container_mime_type); | 233 ConvertUTF8ToJavaString(env, container_mime_type); |
205 return Java_MediaDrmBridge_isCryptoSchemeSupported( | 234 return Java_MediaDrmBridge_isCryptoSchemeSupported( |
206 env, j_scheme_uuid.obj(), j_container_mime_type.obj()); | 235 env, j_scheme_uuid.obj(), j_container_mime_type.obj()); |
207 } | 236 } |
208 | 237 |
238 } // namespace | |
239 | |
209 // static | 240 // static |
210 bool MediaDrmBridge::IsAvailable() { | 241 bool MediaDrmBridge::IsAvailable() { |
211 return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; | 242 return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; |
212 } | 243 } |
213 | 244 |
214 // static | 245 // static |
215 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level) { | 246 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level) { |
216 DCHECK(IsAvailable()); | 247 DCHECK(IsAvailable()); |
217 return SECURITY_LEVEL_1 == security_level; | 248 return SECURITY_LEVEL_1 == security_level; |
218 } | 249 } |
219 | 250 |
220 // static | 251 // static |
221 bool MediaDrmBridge::IsSecurityLevelSupported(const std::string& key_system, | 252 bool MediaDrmBridge::IsSecurityLevelSupported(const std::string& key_system, |
222 SecurityLevel security_level) { | 253 SecurityLevel security_level) { |
223 if (!IsAvailable()) | 254 if (!IsAvailable()) |
224 return false; | 255 return false; |
225 | 256 |
226 // Pass 0 as |cdm_id| and NULL as |manager| as they are not used in | 257 // Pass 0 as |cdm_id| and NULL as |manager| as they are not used in |
227 // creation time of MediaDrmBridge. | 258 // creation time of MediaDrmBridge. |
228 scoped_ptr<MediaDrmBridge> media_drm_bridge = | 259 scoped_ptr<MediaDrmBridge> media_drm_bridge = |
229 MediaDrmBridge::Create(0, key_system, GURL(), NULL); | 260 MediaDrmBridge::Create(0, key_system, GURL(), NULL); |
230 if (!media_drm_bridge) | 261 if (!media_drm_bridge) |
231 return false; | 262 return false; |
232 | 263 |
233 return media_drm_bridge->SetSecurityLevel(security_level); | 264 return media_drm_bridge->SetSecurityLevel(security_level); |
234 } | 265 } |
235 | 266 |
267 //static | |
268 void MediaDrmBridge::AddKeySystem(const std::string& key_system, | |
xhwang
2014/05/15 15:10:29
nit: This name is ambiguous. People may think that
ycheo (away)
2014/05/16 04:53:38
Renamed AddKeySystemUuidMapping().
| |
269 const std::vector<uint8>& uuid) { | |
270 if (key_system_uuid_table == NULL) | |
271 InitializeKeySystemUuidTable(); | |
272 | |
273 KeySystemUuidTable::iterator it = FindKeySystem(key_system); | |
274 // Shouldn't overwrite the existing keysystem. | |
xhwang
2014/05/15 15:10:29
DCHECK this condition as well?
ycheo (away)
2014/05/16 04:53:38
Done.
| |
275 if (it == key_system_uuid_table->end()) | |
276 key_system_uuid_table->push_back(make_pair(key_system, uuid)); | |
277 } | |
278 | |
236 // static | 279 // static |
237 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { | 280 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { |
238 DCHECK(!key_system.empty()); | 281 DCHECK(!key_system.empty()); |
239 return IsKeySystemSupportedWithTypeImpl(key_system, ""); | 282 return IsKeySystemSupportedWithTypeImpl(key_system, ""); |
240 } | 283 } |
241 | 284 |
242 // static | 285 // static |
243 bool MediaDrmBridge::IsKeySystemSupportedWithType( | 286 bool MediaDrmBridge::IsKeySystemSupportedWithType( |
244 const std::string& key_system, | 287 const std::string& key_system, |
245 const std::string& container_mime_type) { | 288 const std::string& container_mime_type) { |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
457 JNIEnv* env = AttachCurrentThread(); | 500 JNIEnv* env = AttachCurrentThread(); |
458 Java_MediaDrmBridge_resetDeviceCredentials(env, j_media_drm_.obj()); | 501 Java_MediaDrmBridge_resetDeviceCredentials(env, j_media_drm_.obj()); |
459 } | 502 } |
460 | 503 |
461 void MediaDrmBridge::OnResetDeviceCredentialsCompleted( | 504 void MediaDrmBridge::OnResetDeviceCredentialsCompleted( |
462 JNIEnv* env, jobject, bool success) { | 505 JNIEnv* env, jobject, bool success) { |
463 base::ResetAndReturn(&reset_credentials_cb_).Run(success); | 506 base::ResetAndReturn(&reset_credentials_cb_).Run(success); |
464 } | 507 } |
465 | 508 |
466 } // namespace media | 509 } // namespace media |
OLD | NEW |