OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "webkit/media/crypto/proxy_decryptor.h" | 5 #include "webkit/media/crypto/proxy_decryptor.h" |
6 | 6 |
7 #include <algorithm> | |
8 | |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/location.h" | 10 #include "base/location.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
11 #include "media/base/decoder_buffer.h" | 13 #include "media/base/decoder_buffer.h" |
12 #include "media/base/decryptor_client.h" | 14 #include "media/base/decryptor_client.h" |
13 #include "media/crypto/aes_decryptor.h" | 15 #include "media/crypto/aes_decryptor.h" |
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
15 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | 17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" |
16 #include "webkit/media/crypto/key_systems.h" | 18 #include "webkit/media/crypto/key_systems.h" |
17 #include "webkit/media/crypto/ppapi_decryptor.h" | 19 #include "webkit/media/crypto/ppapi_decryptor.h" |
18 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 20 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
19 #include "webkit/plugins/ppapi/ppapi_webplugin_impl.h" | 21 #include "webkit/plugins/ppapi/ppapi_webplugin_impl.h" |
20 // TODO(xhwang): Put this include after "ppapi_plugin_instance.h" for definition | 22 // TODO(xhwang): Put this include after "ppapi_plugin_instance.h" for definition |
21 // of "uint8_t", which WebMediaPlayer.h uses without including a header for it. | 23 // of "uint8_t", which WebMediaPlayer.h uses without including a header for it. |
22 // See: https://bugs.webkit.org/show_bug.cgi?id=92031 | 24 // See: https://bugs.webkit.org/show_bug.cgi?id=92031 |
23 // Fix include order here when the bug is fixed. | 25 // Fix include order here when the bug is fixed. |
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient. h" | 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient. h" |
25 | 27 |
26 using media::Decryptor; | |
27 using media::DecoderBuffer; | |
28 | |
29 namespace webkit_media { | 28 namespace webkit_media { |
30 | 29 |
31 static scoped_refptr<webkit::ppapi::PluginInstance> CreatePluginInstance( | 30 static scoped_refptr<webkit::ppapi::PluginInstance> CreatePluginInstance( |
32 const std::string& plugin_type, | 31 const std::string& plugin_type, |
33 WebKit::WebMediaPlayerClient* web_media_player_client, | 32 WebKit::WebMediaPlayerClient* web_media_player_client, |
34 WebKit::WebFrame* web_frame) { | 33 WebKit::WebFrame* web_frame) { |
35 DCHECK(web_media_player_client); | 34 DCHECK(web_media_player_client); |
36 DCHECK(web_frame); | 35 DCHECK(web_frame); |
37 | 36 |
38 WebKit::WebPlugin* web_plugin = web_media_player_client->createHelperPlugin( | 37 WebKit::WebPlugin* web_plugin = web_media_player_client->createHelperPlugin( |
39 WebKit::WebString::fromUTF8(plugin_type), web_frame); | 38 WebKit::WebString::fromUTF8(plugin_type), web_frame); |
40 if (!web_plugin) | 39 if (!web_plugin) |
41 return NULL; | 40 return NULL; |
42 | 41 |
43 DCHECK(!web_plugin->isPlaceholder()); // Prevented by WebKit. | 42 DCHECK(!web_plugin->isPlaceholder()); // Prevented by WebKit. |
44 // Only Pepper plugins are supported, so it must be a ppapi object. | 43 // Only Pepper plugins are supported, so it must be a ppapi object. |
45 webkit::ppapi::WebPluginImpl* ppapi_plugin = | 44 webkit::ppapi::WebPluginImpl* ppapi_plugin = |
46 static_cast<webkit::ppapi::WebPluginImpl*>(web_plugin); | 45 static_cast<webkit::ppapi::WebPluginImpl*>(web_plugin); |
47 return ppapi_plugin->instance(); | 46 return ppapi_plugin->instance(); |
48 } | 47 } |
49 | 48 |
50 // TODO(xhwang): Simplify this function. This is mostly caused by the fact that | 49 // TODO(xhwang): Simplify this function. This is mostly caused by the fact that |
51 // we need to copy a scoped_array<uint8>. | 50 // we need to copy a scoped_array<uint8>. |
52 static void FireNeedKey(media::DecryptorClient* client, | 51 static void FireNeedKey(media::DecryptorClient* client, |
53 const scoped_refptr<DecoderBuffer>& encrypted) { | 52 const scoped_refptr<media::DecoderBuffer>& encrypted) { |
54 DCHECK(client); | 53 DCHECK(client); |
55 DCHECK(encrypted); | 54 DCHECK(encrypted); |
56 DCHECK(encrypted->GetDecryptConfig()); | 55 DCHECK(encrypted->GetDecryptConfig()); |
57 const uint8* key_id = encrypted->GetDecryptConfig()->key_id(); | 56 std::string key_id = encrypted->GetDecryptConfig()->key_id(); |
58 const int key_id_size = encrypted->GetDecryptConfig()->key_id_size(); | 57 scoped_array<uint8> key_id_array(new uint8[key_id.size()]); |
59 scoped_array<uint8> key_id_array(new uint8[key_id_size]); | 58 memcpy(key_id_array.get(), key_id.data(), key_id.size()); |
60 memcpy(key_id_array.get(), key_id, key_id_size); | 59 client->NeedKey("", "", key_id_array.Pass(), key_id.size()); |
61 client->NeedKey("", "", key_id_array.Pass(), key_id_size); | |
62 } | 60 } |
63 | 61 |
64 ProxyDecryptor::ProxyDecryptor( | 62 ProxyDecryptor::ProxyDecryptor( |
65 media::DecryptorClient* decryptor_client, | 63 media::DecryptorClient* decryptor_client, |
66 WebKit::WebMediaPlayerClient* web_media_player_client, | 64 WebKit::WebMediaPlayerClient* web_media_player_client, |
67 WebKit::WebFrame* web_frame) | 65 WebKit::WebFrame* web_frame) |
68 : client_(decryptor_client), | 66 : client_(decryptor_client), |
69 web_media_player_client_(web_media_player_client), | 67 web_media_player_client_(web_media_player_client), |
70 web_frame_(web_frame) { | 68 web_frame_(web_frame), |
69 is_shutting_down_(false) { | |
71 } | 70 } |
72 | 71 |
73 ProxyDecryptor::~ProxyDecryptor() { | 72 ProxyDecryptor::~ProxyDecryptor() { |
74 } | 73 } |
75 | 74 |
76 void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system, | 75 void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system, |
77 const uint8* init_data, | 76 const uint8* init_data, |
78 int init_data_length) { | 77 int init_data_length) { |
79 // We do not support run-time switching of decryptors. GenerateKeyRequest() | 78 // We do not support run-time switching of decryptors. GenerateKeyRequest() |
80 // only creates a new decryptor when |decryptor_| is not initialized. | 79 // only creates a new decryptor when |decryptor_| is not initialized. |
81 DVLOG(1) << "GenerateKeyRequest: key_system = " << key_system; | 80 DVLOG(1) << "GenerateKeyRequest: key_system = " << key_system; |
82 if (!decryptor_.get()) { | 81 if (!decryptor_.get()) { |
83 base::AutoLock auto_lock(decryptor_lock_); | 82 base::AutoLock auto_lock(lock_); |
84 decryptor_ = CreateDecryptor(key_system); | 83 decryptor_ = CreateDecryptor(key_system); |
85 } | 84 } |
86 | 85 |
87 if (!decryptor_.get()) { | 86 if (!decryptor_.get()) { |
88 DCHECK(client_); | 87 client_->KeyError(key_system, "", media::Decryptor::kUnknownError, 0); |
89 client_->KeyError(key_system, "", Decryptor::kUnknownError, 0); | |
90 return; | 88 return; |
91 } | 89 } |
92 | 90 |
93 decryptor_->GenerateKeyRequest(key_system, init_data, init_data_length); | 91 decryptor_->GenerateKeyRequest(key_system, init_data, init_data_length); |
94 } | 92 } |
95 | 93 |
96 void ProxyDecryptor::AddKey(const std::string& key_system, | 94 void ProxyDecryptor::AddKey(const std::string& key_system, |
97 const uint8* key, | 95 const uint8* key, |
98 int key_length, | 96 int key_length, |
99 const uint8* init_data, | 97 const uint8* init_data, |
100 int init_data_length, | 98 int init_data_length, |
101 const std::string& session_id) { | 99 const std::string& session_id) { |
102 DVLOG(1) << "AddKey()"; | 100 DVLOG(1) << "AddKey()"; |
103 | 101 |
104 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. | 102 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. |
105 DCHECK(decryptor_.get()); | 103 DCHECK(decryptor_.get()); |
106 decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length, | 104 decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length, |
107 session_id); | 105 session_id); |
108 | 106 |
109 std::vector<base::Closure> closures_to_run; | 107 std::vector<base::Closure> closures_to_run; |
110 { | 108 { |
111 base::AutoLock auto_lock(pending_decrypt_closures_lock_); | 109 base::AutoLock auto_lock(lock_); |
112 std::swap(pending_decrypt_closures_, closures_to_run); | 110 std::swap(pending_decrypt_closures_, closures_to_run); |
113 } | 111 } |
114 | 112 |
113 // Fire all pending callbacks here because only the |decryptor_| knows if the | |
114 // pending buffers can be decrypted or not. | |
115 for (std::vector<base::Closure>::iterator iter = closures_to_run.begin(); | 115 for (std::vector<base::Closure>::iterator iter = closures_to_run.begin(); |
116 iter != closures_to_run.end(); | 116 iter != closures_to_run.end(); |
117 ++iter) { | 117 ++iter) { |
118 iter->Run(); | 118 iter->Run(); |
119 } | 119 } |
120 } | 120 } |
121 | 121 |
122 void ProxyDecryptor::CancelKeyRequest(const std::string& key_system, | 122 void ProxyDecryptor::CancelKeyRequest(const std::string& key_system, |
123 const std::string& session_id) { | 123 const std::string& session_id) { |
124 DVLOG(1) << "CancelKeyRequest()"; | 124 DVLOG(1) << "CancelKeyRequest()"; |
125 | 125 |
126 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. | 126 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. |
127 DCHECK(decryptor_.get()); | 127 DCHECK(decryptor_.get()); |
128 decryptor_->CancelKeyRequest(key_system, session_id); | 128 decryptor_->CancelKeyRequest(key_system, session_id); |
129 } | 129 } |
130 | 130 |
131 void ProxyDecryptor::Decrypt( | 131 void ProxyDecryptor::Decrypt( |
132 const scoped_refptr<DecoderBuffer>& encrypted, | 132 const scoped_refptr<media::DecoderBuffer>& encrypted, |
133 const DecryptCB& decrypt_cb) { | 133 const DecryptCB& decrypt_cb) { |
134 DVLOG(2) << "Decrypt()"; | |
135 | |
136 // This is safe as we do not replace/delete an existing decryptor at run-time. | 134 // This is safe as we do not replace/delete an existing decryptor at run-time. |
137 Decryptor* decryptor = NULL; | 135 media::Decryptor* decryptor = NULL; |
138 { | 136 { |
139 base::AutoLock auto_lock(decryptor_lock_); | 137 base::AutoLock auto_lock(lock_); |
138 if (is_shutting_down_) { | |
139 DVLOG(1) << "Decrypt(): fire decrypt callbacks with kError."; | |
140 decrypt_cb.Run(kError, NULL); | |
141 return; | |
142 } | |
140 decryptor = decryptor_.get(); | 143 decryptor = decryptor_.get(); |
141 } | 144 if (!decryptor) { |
142 | 145 DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized."; |
143 if (!decryptor) { | 146 pending_decrypt_closures_.push_back( |
144 DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized."; | 147 base::Bind(&ProxyDecryptor::DecryptOnMessageLoop, |
145 { | 148 base::Unretained(this), |
146 base::AutoLock auto_lock(pending_decrypt_closures_lock_); | 149 base::MessageLoopProxy::current(), encrypted, |
147 pending_decrypt_closures_.push_back(base::Bind( | 150 decrypt_cb)); |
148 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), | 151 // TODO(xhwang): The same NeedKey may be fired here and multiple times in |
149 base::MessageLoopProxy::current(), encrypted, decrypt_cb)); | 152 // OnBufferDecrypted(). While the spec says only one NeedKey should be |
153 // fired. Leave them as is since the spec about this may change. | |
154 FireNeedKey(client_, encrypted); | |
155 return; | |
150 } | 156 } |
151 // TODO(xhwang): The same NeedKey may be fired here and multiple times in | |
152 // OnBufferDecrypted(). While the spec says only one NeedKey should be | |
153 // fired. Leave them as is since the spec about this may change. | |
154 FireNeedKey(client_, encrypted); | |
155 return; | |
156 } | 157 } |
157 | 158 |
158 decryptor->Decrypt(encrypted, base::Bind( | 159 decryptor->Decrypt(encrypted, base::Bind( |
159 &ProxyDecryptor::OnBufferDecrypted, base::Unretained(this), | 160 &ProxyDecryptor::OnBufferDecrypted, base::Unretained(this), |
160 base::MessageLoopProxy::current(), encrypted, decrypt_cb)); | 161 base::MessageLoopProxy::current(), encrypted, decrypt_cb)); |
161 } | 162 } |
162 | 163 |
163 scoped_ptr<Decryptor> ProxyDecryptor::CreatePpapiDecryptor( | 164 void ProxyDecryptor::Stop() { |
165 DVLOG(1) << "AddKey()"; | |
166 | |
167 std::vector<base::Closure> closures_to_run; | |
168 { | |
169 base::AutoLock auto_lock(lock_); | |
170 if (decryptor_.get()) | |
171 decryptor_->Stop(); | |
172 is_shutting_down_ = true; | |
173 std::swap(pending_decrypt_closures_, closures_to_run); | |
174 } | |
175 | |
176 for (std::vector<base::Closure>::iterator iter = closures_to_run.begin(); | |
177 iter != closures_to_run.end(); | |
178 ++iter) { | |
179 iter->Run(); | |
180 } | |
181 } | |
182 | |
183 scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor( | |
164 const std::string& key_system) { | 184 const std::string& key_system) { |
165 DCHECK(client_); | 185 DCHECK(client_); |
166 DCHECK(web_media_player_client_); | 186 DCHECK(web_media_player_client_); |
167 DCHECK(web_frame_); | 187 DCHECK(web_frame_); |
168 | 188 |
169 std::string plugin_type = GetPluginType(key_system); | 189 std::string plugin_type = GetPluginType(key_system); |
170 DCHECK(!plugin_type.empty()); | 190 DCHECK(!plugin_type.empty()); |
171 const scoped_refptr<webkit::ppapi::PluginInstance>& plugin_instance = | 191 const scoped_refptr<webkit::ppapi::PluginInstance>& plugin_instance = |
172 CreatePluginInstance(plugin_type, web_media_player_client_, web_frame_); | 192 CreatePluginInstance(plugin_type, web_media_player_client_, web_frame_); |
173 if (!plugin_instance) { | 193 if (!plugin_instance) { |
174 DVLOG(1) << "PpapiDecryptor: plugin instance creation failed."; | 194 DVLOG(1) << "PpapiDecryptor: plugin instance creation failed."; |
175 return scoped_ptr<Decryptor>(); | 195 return scoped_ptr<media::Decryptor>(); |
176 } | 196 } |
177 | 197 |
178 return scoped_ptr<Decryptor>(new PpapiDecryptor(client_, plugin_instance)); | 198 return scoped_ptr<media::Decryptor>(new PpapiDecryptor(client_, |
199 plugin_instance)); | |
179 } | 200 } |
180 | 201 |
181 scoped_ptr<Decryptor> ProxyDecryptor::CreateDecryptor( | 202 scoped_ptr<media::Decryptor> ProxyDecryptor::CreateDecryptor( |
182 const std::string& key_system) { | 203 const std::string& key_system) { |
183 DCHECK(client_); | 204 DCHECK(client_); |
184 | 205 |
185 if (CanUseAesDecryptor(key_system)) | 206 if (CanUseAesDecryptor(key_system)) |
186 return scoped_ptr<Decryptor>(new media::AesDecryptor(client_)); | 207 return scoped_ptr<media::Decryptor>(new media::AesDecryptor(client_)); |
187 | 208 |
188 // We only support AesDecryptor and PpapiDecryptor. So if we cannot | 209 // We only support AesDecryptor and PpapiDecryptor. So if we cannot |
189 // use the AesDecryptor, then we'll try to create a PpapiDecryptor for given | 210 // use the AesDecryptor, then we'll try to create a PpapiDecryptor for given |
190 // |key_system|. | 211 // |key_system|. |
191 return CreatePpapiDecryptor(key_system); | 212 return CreatePpapiDecryptor(key_system); |
192 } | 213 } |
193 | 214 |
194 void ProxyDecryptor::DecryptOnMessageLoop( | 215 void ProxyDecryptor::DecryptOnMessageLoop( |
195 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | 216 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
196 const scoped_refptr<DecoderBuffer>& encrypted, | 217 const scoped_refptr<media::DecoderBuffer>& encrypted, |
197 const Decryptor::DecryptCB& decrypt_cb) { | 218 const media::Decryptor::DecryptCB& decrypt_cb) { |
198 DVLOG(2) << "DecryptOnMessageLoop()"; | |
199 DCHECK(decryptor_.get()); | 219 DCHECK(decryptor_.get()); |
200 | 220 |
201 if (!message_loop_proxy->BelongsToCurrentThread()) { | 221 if (!message_loop_proxy->BelongsToCurrentThread()) { |
202 message_loop_proxy->PostTask(FROM_HERE, base::Bind( | 222 message_loop_proxy->PostTask(FROM_HERE, base::Bind( |
203 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), | 223 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
204 message_loop_proxy, encrypted, decrypt_cb)); | 224 message_loop_proxy, encrypted, decrypt_cb)); |
205 return; | 225 return; |
206 } | 226 } |
207 | 227 |
228 { | |
229 base::AutoLock auto_lock(lock_); | |
230 if (is_shutting_down_) { | |
231 DVLOG(1) << "DecryptOnMessageLoop(): fire decrypt callbacks with kError."; | |
232 decrypt_cb.Run(kError, NULL); | |
233 return; | |
234 } | |
235 } | |
236 | |
208 decryptor_->Decrypt(encrypted, base::Bind(&ProxyDecryptor::OnBufferDecrypted, | 237 decryptor_->Decrypt(encrypted, base::Bind(&ProxyDecryptor::OnBufferDecrypted, |
scherkus (not reviewing)
2012/08/02 18:05:32
nit: technically this is mixing style: params on n
xhwang
2012/08/03 20:08:10
Done.
| |
209 base::Unretained(this), message_loop_proxy, encrypted, decrypt_cb)); | 238 base::Unretained(this), message_loop_proxy, encrypted, decrypt_cb)); |
210 } | 239 } |
211 | 240 |
212 void ProxyDecryptor::OnBufferDecrypted( | 241 void ProxyDecryptor::OnBufferDecrypted( |
213 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | 242 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
214 const scoped_refptr<DecoderBuffer>& encrypted, | 243 const scoped_refptr<media::DecoderBuffer>& encrypted, |
215 const Decryptor::DecryptCB& decrypt_cb, | 244 const media::Decryptor::DecryptCB& decrypt_cb, |
216 Decryptor::DecryptStatus status, | 245 media::Decryptor::DecryptStatus status, |
217 const scoped_refptr<DecoderBuffer>& decrypted) { | 246 const scoped_refptr<media::DecoderBuffer>& decrypted) { |
218 DVLOG(2) << "OnBufferDecrypted()"; | 247 if (status == media::Decryptor::kSuccess || |
219 | 248 status == media::Decryptor::kError) { |
220 if (status == Decryptor::kSuccess || status == Decryptor::kError) { | |
221 decrypt_cb.Run(status, decrypted); | 249 decrypt_cb.Run(status, decrypted); |
222 return; | 250 return; |
223 } | 251 } |
224 | 252 |
225 DCHECK_EQ(status, Decryptor::kNoKey); | 253 DCHECK_EQ(status, media::Decryptor::kNoKey); |
226 DVLOG(1) << "OnBufferDecrypted(): kNoKey fired"; | 254 DVLOG(1) << "OnBufferDecrypted(): kNoKey fired"; |
227 { | 255 { |
228 base::AutoLock auto_lock(pending_decrypt_closures_lock_); | 256 base::AutoLock auto_lock(lock_); |
257 if (is_shutting_down_) { | |
258 DVLOG(1) << "OnBufferDecrypted(): fire decrypt callbacks with kError."; | |
259 decrypt_cb.Run(kError, NULL); | |
260 return; | |
261 } | |
229 pending_decrypt_closures_.push_back(base::Bind( | 262 pending_decrypt_closures_.push_back(base::Bind( |
230 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), | 263 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
231 message_loop_proxy, encrypted, decrypt_cb)); | 264 message_loop_proxy, encrypted, decrypt_cb)); |
232 } | 265 } |
233 // TODO(xhwang): The same NeedKey may be fired multiple times here and also | 266 // TODO(xhwang): The same NeedKey may be fired multiple times here and also |
234 // in Decrypt(). While the spec says only one NeedKey should be fired. Leave | 267 // in Decrypt(). While the spec says only one NeedKey should be fired. Leave |
235 // them as is since the spec about this may change. | 268 // them as is since the spec about this may change. |
236 FireNeedKey(client_, encrypted); | 269 FireNeedKey(client_, encrypted); |
237 } | 270 } |
238 | 271 |
239 } // namespace webkit_media | 272 } // namespace webkit_media |
OLD | NEW |