Chromium Code Reviews| 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 |