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