OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "content/renderer/media/crypto/key_systems.h" | 5 #include "content/renderer/media/crypto/key_systems.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "content/renderer/media/crypto/key_systems_info.h" | 12 #include "content/renderer/media/crypto/key_systems_info.h" |
13 #include "net/base/mime_util.h" | 13 #include "net/base/mime_util.h" |
14 #include "third_party/WebKit/public/platform/WebCString.h" | 14 #include "third_party/WebKit/public/platform/WebCString.h" |
15 #include "third_party/WebKit/public/platform/WebString.h" | 15 #include "third_party/WebKit/public/platform/WebString.h" |
16 | 16 |
17 namespace content { | 17 namespace content { |
18 | 18 |
19 // Convert a WebString to ASCII, falling back on an empty string in the case | 19 // Convert a WebString to ASCII, falling back on an empty string in the case |
20 // of a non-ASCII string. | 20 // of a non-ASCII string. |
21 static std::string ToASCIIOrEmpty(const WebKit::WebString& string) { | 21 static std::string ToASCIIOrEmpty(const WebKit::WebString& string) { |
22 return IsStringASCII(string) ? UTF16ToASCII(string) : std::string(); | 22 return IsStringASCII(string) ? UTF16ToASCII(string) : std::string(); |
23 } | 23 } |
24 | 24 |
25 class KeySystems { | 25 class KeySystems { |
26 public: | 26 public: |
27 bool IsSupportedKeySystem(const std::string& key_system); | 27 static KeySystems* GetInstance(); |
| 28 |
| 29 void AddConcreteSupportedKeySystem( |
| 30 const std::string& key_system, |
| 31 #if defined(ENABLE_PEPPER_CDMS) |
| 32 const std::string& pepper_type, |
| 33 #elif defined(OS_ANDROID) |
| 34 const uint8 uuid[16], |
| 35 #endif // defined(ENABLE_PEPPER_CDMS) |
| 36 bool use_aes_decryptor); |
| 37 |
| 38 void AddParentKeySystem(const std::string& parent_key_system, |
| 39 const std::string& concrete_key_system); |
| 40 |
| 41 void AddSupportedType(const std::string& key_system, |
| 42 const std::string& mime_type, |
| 43 const std::string& codecs_list); |
| 44 |
| 45 bool IsConcreteSupportedKeySystem(const std::string& key_system); |
28 | 46 |
29 bool IsSupportedKeySystemWithMediaMimeType( | 47 bool IsSupportedKeySystemWithMediaMimeType( |
30 const std::string& mime_type, | 48 const std::string& mime_type, |
31 const std::vector<std::string>& codecs, | 49 const std::vector<std::string>& codecs, |
32 const std::string& key_system); | 50 const std::string& key_system); |
33 | 51 |
| 52 bool UseAesDecryptor(const std::string& concrete_key_system); |
| 53 |
| 54 #if defined(ENABLE_PEPPER_CDMS) |
| 55 std::string GetPepperType(const std::string& concrete_key_system); |
| 56 #endif // defined(ENABLE_PEPPER_CDMS) |
| 57 |
| 58 #if defined(OS_ANDROID) |
| 59 std::vector<uint8> GetUUID(const std::string& concrete_key_system); |
| 60 #endif // defined(OS_ANDROID) |
| 61 |
34 private: | 62 private: |
35 friend struct base::DefaultLazyInstanceTraits<KeySystems>; | 63 friend struct base::DefaultLazyInstanceTraits<KeySystems>; |
36 | 64 |
37 typedef base::hash_set<std::string> CodecMappings; | 65 typedef base::hash_set<std::string> CodecMappings; |
38 typedef std::map<std::string, CodecMappings> MimeTypeMappings; | 66 typedef std::map<std::string, CodecMappings> MimeTypeMappings; |
39 typedef std::map<std::string, MimeTypeMappings> KeySystemMappings; | |
40 | 67 |
41 KeySystems(); | 68 struct KeySystemProperties { |
| 69 KeySystemProperties() : use_aes_decryptor(false) {} |
| 70 |
| 71 #if defined(ENABLE_PEPPER_CDMS) |
| 72 std::string pepper_type; |
| 73 #elif defined(OS_ANDROID) |
| 74 std::vector<uint8> uuid; |
| 75 #endif // defined(ENABLE_PEPPER_CDMS) |
| 76 bool use_aes_decryptor; |
| 77 MimeTypeMappings types; |
| 78 }; |
| 79 |
| 80 typedef std::map<std::string, KeySystemProperties> KeySystemMappings; |
| 81 |
| 82 typedef std::map<std::string, std::string> ParentKeySystemMappings; |
| 83 |
| 84 KeySystems() {} |
42 | 85 |
43 bool IsSupportedKeySystemWithContainerAndCodec( | 86 bool IsSupportedKeySystemWithContainerAndCodec( |
44 const std::string& mime_type, | 87 const std::string& mime_type, |
45 const std::string& codec, | 88 const std::string& codec, |
46 const std::string& key_system); | 89 const std::string& key_system); |
47 | 90 |
| 91 // Map from key system string to capabilities. |
48 KeySystemMappings key_system_map_; | 92 KeySystemMappings key_system_map_; |
49 | 93 |
| 94 // Map from parent key system to the concrete key system that should be used |
| 95 // to represent its capabilities. |
| 96 ParentKeySystemMappings parent_key_system_map_; |
| 97 |
50 DISALLOW_COPY_AND_ASSIGN(KeySystems); | 98 DISALLOW_COPY_AND_ASSIGN(KeySystems); |
51 }; | 99 }; |
52 | 100 |
53 static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER; | 101 static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER; |
54 | 102 |
55 KeySystems::KeySystems() { | 103 KeySystems* KeySystems::GetInstance() { |
56 // Initialize the supported media type/key system combinations. | 104 KeySystems* key_systems = &g_key_systems.Get(); |
57 for (int i = 0; i < kNumSupportedFormatKeySystemCombinations; ++i) { | 105 // TODO(ddorwin): Call out to ContentClient to register key systems. |
58 const MediaFormatAndKeySystem& combination = | 106 static bool is_registered = false; |
59 kSupportedFormatKeySystemCombinations[i]; | 107 if (!is_registered) { |
60 std::vector<std::string> mime_type_codecs; | 108 is_registered = true; // Prevent reentrancy when Add*() is called. |
61 net::ParseCodecString(combination.codecs_list, | 109 RegisterKeySystems(); |
62 &mime_type_codecs, | |
63 false); | |
64 | |
65 CodecMappings codecs; | |
66 for (size_t j = 0; j < mime_type_codecs.size(); ++j) | |
67 codecs.insert(mime_type_codecs[j]); | |
68 // Support the MIME type string alone, without codec(s) specified. | |
69 codecs.insert(std::string()); | |
70 | |
71 // Key systems can be repeated, so there may already be an entry. | |
72 KeySystemMappings::iterator key_system_iter = | |
73 key_system_map_.find(combination.key_system); | |
74 if (key_system_iter == key_system_map_.end()) { | |
75 MimeTypeMappings mime_types_map; | |
76 mime_types_map[combination.mime_type] = codecs; | |
77 key_system_map_[combination.key_system] = mime_types_map; | |
78 } else { | |
79 MimeTypeMappings& mime_types_map = key_system_iter->second; | |
80 // mime_types_map may not be repeated for a given key system. | |
81 DCHECK(mime_types_map.find(combination.mime_type) == | |
82 mime_types_map.end()); | |
83 mime_types_map[combination.mime_type] = codecs; | |
84 } | |
85 } | 110 } |
| 111 return key_systems; |
86 } | 112 } |
87 | 113 |
88 bool KeySystems::IsSupportedKeySystem(const std::string& key_system) { | 114 void KeySystems::AddConcreteSupportedKeySystem( |
89 bool is_supported = key_system_map_.find(key_system) != key_system_map_.end(); | 115 const std::string& key_system, |
90 return is_supported && !IsOSIncompatible(key_system); | 116 #if defined(ENABLE_PEPPER_CDMS) |
| 117 const std::string& pepper_type, |
| 118 #elif defined(OS_ANDROID) |
| 119 const uint8 uuid[16], |
| 120 #endif // defined(ENABLE_PEPPER_CDMS) |
| 121 bool use_aes_decryptor) { |
| 122 KeySystemMappings::iterator key_system_iter = |
| 123 key_system_map_.find(key_system); |
| 124 DCHECK(key_system_iter == key_system_map_.end()) |
| 125 << "Key system already registered"; |
| 126 |
| 127 KeySystemProperties properties; |
| 128 #if defined(ENABLE_PEPPER_CDMS) |
| 129 properties.pepper_type = pepper_type; |
| 130 #elif defined(OS_ANDROID) |
| 131 properties.uuid.assign(uuid, uuid + 16); |
| 132 #endif // defined(ENABLE_PEPPER_CDMS) |
| 133 properties.use_aes_decryptor = use_aes_decryptor; |
| 134 key_system_map_[key_system] = properties; |
| 135 } |
| 136 |
| 137 void KeySystems::AddParentKeySystem(const std::string& parent_key_system, |
| 138 const std::string& concrete_key_system) { |
| 139 DCHECK(key_system_map_.find(concrete_key_system) != key_system_map_.end()); |
| 140 parent_key_system_map_[parent_key_system] = concrete_key_system; |
| 141 } |
| 142 |
| 143 void KeySystems::AddSupportedType(const std::string& key_system, |
| 144 const std::string& mime_type, |
| 145 const std::string& codecs_list) { |
| 146 std::vector<std::string> mime_type_codecs; |
| 147 net::ParseCodecString(codecs_list, |
| 148 &mime_type_codecs, |
| 149 false); |
| 150 |
| 151 CodecMappings codecs; |
| 152 for (size_t j = 0; j < mime_type_codecs.size(); ++j) |
| 153 codecs.insert(mime_type_codecs[j]); |
| 154 // Support the MIME type string alone, without codec(s) specified. |
| 155 codecs.insert(std::string()); |
| 156 |
| 157 KeySystemMappings::iterator key_system_iter = |
| 158 key_system_map_.find(key_system); |
| 159 DCHECK(key_system_iter != key_system_map_.end()); |
| 160 MimeTypeMappings& mime_types_map = key_system_iter->second.types; |
| 161 // mime_types_map may not be repeated for a given key system. |
| 162 DCHECK(mime_types_map.find(mime_type) == mime_types_map.end()); |
| 163 mime_types_map[mime_type] = codecs; |
| 164 } |
| 165 |
| 166 bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) { |
| 167 return key_system_map_.find(key_system) != key_system_map_.end(); |
91 } | 168 } |
92 | 169 |
93 bool KeySystems::IsSupportedKeySystemWithContainerAndCodec( | 170 bool KeySystems::IsSupportedKeySystemWithContainerAndCodec( |
94 const std::string& mime_type, | 171 const std::string& mime_type, |
95 const std::string& codec, | 172 const std::string& codec, |
96 const std::string& key_system) { | 173 const std::string& key_system) { |
97 KeySystemMappings::const_iterator key_system_iter = | 174 KeySystemMappings::const_iterator key_system_iter = |
98 key_system_map_.find(key_system); | 175 key_system_map_.find(key_system); |
99 if (key_system_iter == key_system_map_.end()) | 176 if (key_system_iter == key_system_map_.end()) |
100 return false; | 177 return false; |
101 | 178 |
102 const MimeTypeMappings& mime_types_map = key_system_iter->second; | 179 const MimeTypeMappings& mime_types_map = key_system_iter->second.types; |
103 MimeTypeMappings::const_iterator mime_iter = mime_types_map.find(mime_type); | 180 MimeTypeMappings::const_iterator mime_iter = mime_types_map.find(mime_type); |
104 if (mime_iter == mime_types_map.end()) | 181 if (mime_iter == mime_types_map.end()) |
105 return false; | 182 return false; |
106 | 183 |
107 const CodecMappings& codecs = mime_iter->second; | 184 const CodecMappings& codecs = mime_iter->second; |
108 return (codecs.find(codec) != codecs.end()) && !IsOSIncompatible(key_system); | 185 return (codecs.find(codec) != codecs.end()); |
109 } | 186 } |
110 | 187 |
111 bool KeySystems::IsSupportedKeySystemWithMediaMimeType( | 188 bool KeySystems::IsSupportedKeySystemWithMediaMimeType( |
112 const std::string& mime_type, | 189 const std::string& mime_type, |
113 const std::vector<std::string>& codecs, | 190 const std::vector<std::string>& codecs, |
114 const std::string& key_system) { | 191 const std::string& key_system) { |
| 192 // If |key_system| is a parent key_system, use its concrete child. |
| 193 // Otherwise, use |key_system|. |
| 194 std::string concrete_key_system; |
| 195 ParentKeySystemMappings::iterator parent_key_system_iter = |
| 196 parent_key_system_map_.find(key_system); |
| 197 if (parent_key_system_iter != parent_key_system_map_.end()) |
| 198 concrete_key_system = parent_key_system_iter->second; |
| 199 else |
| 200 concrete_key_system = key_system; |
| 201 |
115 // This method is only used by the canPlaytType() path (not the EME methods), | 202 // This method is only used by the canPlaytType() path (not the EME methods), |
116 // so we check for suppressed key_systems here. | 203 // so we check for suppressed key_systems here. |
117 if(IsCanPlayTypeSuppressed(key_system)) | 204 if(IsCanPlayTypeSuppressed(concrete_key_system)) |
118 return false; | 205 return false; |
119 | 206 |
120 if (codecs.empty()) | 207 if (codecs.empty()) |
121 return IsSupportedKeySystemWithContainerAndCodec( | 208 return IsSupportedKeySystemWithContainerAndCodec( |
122 mime_type, std::string(), key_system); | 209 mime_type, std::string(), concrete_key_system); |
123 | 210 |
124 for (size_t i = 0; i < codecs.size(); ++i) { | 211 for (size_t i = 0; i < codecs.size(); ++i) { |
125 if (!IsSupportedKeySystemWithContainerAndCodec( | 212 if (!IsSupportedKeySystemWithContainerAndCodec( |
126 mime_type, codecs[i], key_system)) | 213 mime_type, codecs[i], concrete_key_system)) |
127 return false; | 214 return false; |
128 } | 215 } |
129 | 216 |
130 return true; | 217 return true; |
131 } | 218 } |
132 | 219 |
133 static inline bool IsConcreteSupportedKeySystem(const std::string& key_system) { | 220 bool KeySystems::UseAesDecryptor(const std::string& concrete_key_system) { |
134 bool result = g_key_systems.Get().IsSupportedKeySystem(key_system); | 221 KeySystemMappings::iterator key_system_iter = |
135 // Verify the two "Concrete" lists are in sync. | 222 key_system_map_.find(concrete_key_system); |
136 DCHECK_EQ(result, IsConcreteKeySystem(key_system)); | 223 DCHECK(key_system_iter != key_system_map_.end()) |
137 return result; | 224 << concrete_key_system << " is not a known concrete system"; |
| 225 return key_system_iter->second.use_aes_decryptor; |
| 226 } |
| 227 |
| 228 #if defined(ENABLE_PEPPER_CDMS) |
| 229 std::string KeySystems::GetPepperType(const std::string& concrete_key_system) { |
| 230 KeySystemMappings::iterator key_system_iter = |
| 231 key_system_map_.find(concrete_key_system); |
| 232 DCHECK(key_system_iter != key_system_map_.end()) |
| 233 << concrete_key_system << " is not a known concrete system"; |
| 234 const std::string& type = key_system_iter->second.pepper_type; |
| 235 DCHECK(!type.empty()) << concrete_key_system << " is not Pepper-based"; |
| 236 return type; |
| 237 } |
| 238 #endif // defined(ENABLE_PEPPER_CDMS) |
| 239 |
| 240 #if defined(OS_ANDROID) |
| 241 std::vector<uint8> KeySystems::GetUUID(const std::string& concrete_key_system) { |
| 242 KeySystemMappings::iterator key_system_iter = |
| 243 key_system_map_.find(concrete_key_system); |
| 244 DCHECK(key_system_iter != key_system_map_.end()) |
| 245 << concrete_key_system << " is not a known concrete system"; |
| 246 return key_system_iter->second.uuid; |
| 247 } |
| 248 #endif // defined(OS_ANDROID) |
| 249 |
| 250 //------------------------------------------------------------------------------ |
| 251 |
| 252 void AddConcreteSupportedKeySystem( |
| 253 const std::string& key_system, |
| 254 #if defined(ENABLE_PEPPER_CDMS) |
| 255 const std::string& pepper_type, |
| 256 #elif defined(OS_ANDROID) |
| 257 const uint8 uuid[16], |
| 258 #endif |
| 259 bool use_aes_decryptor) { |
| 260 KeySystems::GetInstance()->AddConcreteSupportedKeySystem(key_system, |
| 261 #if defined(ENABLE_PEPPER_CDMS) |
| 262 pepper_type, |
| 263 #elif defined(OS_ANDROID) |
| 264 uuid, |
| 265 #endif |
| 266 use_aes_decryptor); |
| 267 } |
| 268 |
| 269 void AddParentKeySystem(const std::string& parent_key_system, |
| 270 const std::string& concrete_key_system) { |
| 271 KeySystems::GetInstance()->AddParentKeySystem(parent_key_system, |
| 272 concrete_key_system); |
| 273 } |
| 274 |
| 275 void AddSupportedType(const std::string& key_system, |
| 276 const std::string& mime_type, |
| 277 const std::string& codecs_list) { |
| 278 KeySystems::GetInstance()->AddSupportedType(key_system, |
| 279 mime_type, codecs_list); |
138 } | 280 } |
139 | 281 |
140 bool IsConcreteSupportedKeySystem(const WebKit::WebString& key_system) { | 282 bool IsConcreteSupportedKeySystem(const WebKit::WebString& key_system) { |
141 return IsConcreteSupportedKeySystem(ToASCIIOrEmpty(key_system)); | 283 return KeySystems::GetInstance()->IsConcreteSupportedKeySystem( |
| 284 ToASCIIOrEmpty(key_system)); |
142 } | 285 } |
143 | 286 |
144 bool IsSupportedKeySystemWithMediaMimeType( | 287 bool IsSupportedKeySystemWithMediaMimeType( |
145 const std::string& mime_type, | 288 const std::string& mime_type, |
146 const std::vector<std::string>& codecs, | 289 const std::vector<std::string>& codecs, |
147 const std::string& key_system) { | 290 const std::string& key_system) { |
148 std::string concrete_key_system = EnsureConcreteKeySystem(key_system); | 291 return KeySystems::GetInstance()->IsSupportedKeySystemWithMediaMimeType( |
149 return g_key_systems.Get().IsSupportedKeySystemWithMediaMimeType( | 292 mime_type, codecs, key_system); |
150 mime_type, codecs, concrete_key_system); | |
151 } | 293 } |
152 | 294 |
153 std::string KeySystemNameForUMA(const WebKit::WebString& key_system) { | 295 std::string KeySystemNameForUMA(const WebKit::WebString& key_system) { |
154 return KeySystemNameForUMAInternal(key_system); | 296 return KeySystemNameForUMAInternal(key_system); |
155 } | 297 } |
156 | 298 |
157 bool CanUseAesDecryptor(const std::string& key_system) { | 299 bool CanUseAesDecryptor(const std::string& concrete_key_system) { |
158 return CanUseAesDecryptorInternal(key_system); | 300 return KeySystems::GetInstance()->UseAesDecryptor(concrete_key_system); |
159 } | 301 } |
160 | 302 |
161 #if defined(ENABLE_PEPPER_CDMS) | 303 #if defined(ENABLE_PEPPER_CDMS) |
162 std::string GetPepperType(const std::string& concrete_key_system) { | 304 std::string GetPepperType(const std::string& concrete_key_system) { |
163 DCHECK(IsConcreteKeySystem(concrete_key_system)) | 305 return KeySystems::GetInstance()->GetPepperType(concrete_key_system); |
164 << concrete_key_system << " is not a concrete system"; | |
165 for (int i = 0; i < kNumKeySystemToPepperTypeMapping; ++i) { | |
166 if (kKeySystemToPepperTypeMapping[i].key_system == concrete_key_system) | |
167 return kKeySystemToPepperTypeMapping[i].type; | |
168 } | |
169 | |
170 return std::string(); | |
171 } | 306 } |
172 #endif // defined(ENABLE_PEPPER_CDMS) | 307 #endif // defined(ENABLE_PEPPER_CDMS) |
173 | 308 |
174 #if defined(OS_ANDROID) | 309 #if defined(OS_ANDROID) |
175 std::vector<uint8> GetUUID(const std::string& concrete_key_system) { | 310 std::vector<uint8> GetUUID(const std::string& concrete_key_system) { |
176 DCHECK(IsConcreteKeySystem(concrete_key_system)) | 311 return KeySystems::GetInstance()->GetUUID(concrete_key_system); |
177 << concrete_key_system << " is not a concrete system"; | |
178 for (int i = 0; i < kNumKeySystemToUUIDMapping; ++i) { | |
179 if (kKeySystemToUUIDMapping[i].key_system == concrete_key_system) | |
180 return std::vector<uint8>(kKeySystemToUUIDMapping[i].uuid, | |
181 kKeySystemToUUIDMapping[i].uuid + 16); | |
182 } | |
183 return std::vector<uint8>(); | |
184 } | 312 } |
185 #endif // defined(OS_ANDROID) | 313 #endif // defined(OS_ANDROID) |
186 | 314 |
187 } // namespace content | 315 } // namespace content |
OLD | NEW |