Chromium Code Reviews| Index: webkit/media/crypto/proxy_decryptor.cc |
| diff --git a/webkit/media/crypto/proxy_decryptor.cc b/webkit/media/crypto/proxy_decryptor.cc |
| index 0b786552b577ea199d042517195a2a20ffb05cb1..a8a20210c039aaf4db092fcec5b7d16a69e9d04f 100644 |
| --- a/webkit/media/crypto/proxy_decryptor.cc |
| +++ b/webkit/media/crypto/proxy_decryptor.cc |
| @@ -4,7 +4,9 @@ |
| #include "webkit/media/crypto/proxy_decryptor.h" |
| +#include "base/bind.h" |
| #include "base/logging.h" |
| +#include "base/message_loop.h" |
| #include "media/base/decoder_buffer.h" |
| #include "media/base/decryptor_client.h" |
| #include "media/crypto/aes_decryptor.h" |
| @@ -20,6 +22,9 @@ |
| // Fix include order here when the bug is fixed. |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h" |
| +using media::Decryptor; |
| +using media::DecoderBuffer; |
| + |
| namespace webkit_media { |
| static scoped_refptr<webkit::ppapi::PluginInstance> CreatePluginInstance( |
| @@ -41,6 +46,20 @@ static scoped_refptr<webkit::ppapi::PluginInstance> CreatePluginInstance( |
| return ppapi_plugin->instance(); |
| } |
| +// TODO(xhwang): Simplify this function. This is mostly caused by the fact that |
| +// we need to copy a scoped_array<uint8>. |
| +static void FireNeedKey(media::DecryptorClient* client, |
| + const scoped_refptr<DecoderBuffer>& encrypted) { |
| + DCHECK(client); |
| + DCHECK(encrypted); |
| + DCHECK(encrypted->GetDecryptConfig()); |
| + const uint8* key_id = encrypted->GetDecryptConfig()->key_id(); |
| + const int key_id_size = encrypted->GetDecryptConfig()->key_id_size(); |
| + scoped_array<uint8> key_id_array(new uint8[key_id_size]); |
| + memcpy(key_id_array.get(), key_id, key_id_size); |
| + client->NeedKey("", "", key_id_array.Pass(), key_id_size); |
| +} |
| + |
| ProxyDecryptor::ProxyDecryptor( |
| media::DecryptorClient* decryptor_client, |
| WebKit::WebMediaPlayerClient* web_media_player_client, |
| @@ -58,14 +77,15 @@ void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system, |
| int init_data_length) { |
| // We do not support run-time switching of decryptors. GenerateKeyRequest() |
| // only creates a new decryptor when |decryptor_| is not initialized. |
| + DVLOG(1) << "GenerateKeyRequest: key_system = " << key_system; |
| if (!decryptor_.get()) { |
| - base::AutoLock auto_lock(lock_); |
| + base::AutoLock auto_lock(decryptor_lock_); |
| decryptor_ = CreateDecryptor(key_system); |
| } |
| - DCHECK(client_); |
| if (!decryptor_.get()) { |
| - client_->KeyError(key_system, "", media::Decryptor::kUnknownError, 0); |
| + DCHECK(client_); |
| + client_->KeyError(key_system, "", Decryptor::kUnknownError, 0); |
| return; |
| } |
| @@ -78,38 +98,67 @@ void ProxyDecryptor::AddKey(const std::string& key_system, |
| const uint8* init_data, |
| int init_data_length, |
| const std::string& session_id) { |
| + DVLOG(1) << "AddKey()"; |
| + |
| // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. |
| DCHECK(decryptor_.get()); |
| decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length, |
| session_id); |
| + |
| + std::vector<base::Closure> closures_to_run; |
| + { |
| + base::AutoLock auto_lock(pending_decrypt_closures_lock_); |
| + 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@
|
| + } |
| + |
| + for (std::vector<base::Closure>::iterator iter = closures_to_run.begin(); |
| + iter != closures_to_run.end(); |
| + ++iter) { |
| + iter->Run(); |
| + } |
| } |
| void ProxyDecryptor::CancelKeyRequest(const std::string& key_system, |
| const std::string& session_id) { |
| + 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
|
| + |
| // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. |
| DCHECK(decryptor_.get()); |
| decryptor_->CancelKeyRequest(key_system, session_id); |
| } |
| void ProxyDecryptor::Decrypt( |
| - const scoped_refptr<media::DecoderBuffer>& encrypted, |
| + const scoped_refptr<DecoderBuffer>& encrypted, |
| const DecryptCB& decrypt_cb) { |
| + DVLOG(2) << "Decrypt()"; |
| + |
| // This is safe as we do not replace/delete an existing decryptor at run-time. |
| - media::Decryptor* decryptor = NULL; |
| + Decryptor* decryptor = NULL; |
| { |
| - base::AutoLock auto_lock(lock_); |
| + base::AutoLock auto_lock(decryptor_lock_); |
| decryptor = decryptor_.get(); |
| } |
| + |
| 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
|
| DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized."; |
| - decrypt_cb.Run(kError, NULL); |
| + { |
| + base::AutoLock auto_lock(pending_decrypt_closures_lock_); |
| + pending_decrypt_closures_.push_back(base::Bind( |
| + &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
| + MessageLoop::current(), encrypted, decrypt_cb)); |
| + } |
| + // TODO(xhwang): The same NeedKey may be fired here and multiple times in |
| + // OnBufferDecrypted(). While the spec says only one NeedKey should be |
| + // fired. Leave them as is since the spec about this may change. |
| + FireNeedKey(client_, encrypted); |
| return; |
| } |
| - decryptor->Decrypt(encrypted, decrypt_cb); |
| + decryptor->Decrypt(encrypted, base::Bind(&ProxyDecryptor::OnBufferDecrypted, |
| + 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.
|
| } |
| -scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor( |
| +scoped_ptr<Decryptor> ProxyDecryptor::CreatePpapiDecryptor( |
| const std::string& key_system) { |
| DCHECK(client_); |
| DCHECK(web_media_player_client_); |
| @@ -121,19 +170,18 @@ scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor( |
| CreatePluginInstance(plugin_type, web_media_player_client_, web_frame_); |
| if (!plugin_instance) { |
| DVLOG(1) << "PpapiDecryptor: plugin instance creation failed."; |
| - return scoped_ptr<media::Decryptor>(); |
| + return scoped_ptr<Decryptor>(); |
| } |
| - return scoped_ptr<media::Decryptor>(new PpapiDecryptor(client_, |
| - plugin_instance)); |
| + return scoped_ptr<Decryptor>(new PpapiDecryptor(client_, plugin_instance)); |
| } |
| -scoped_ptr<media::Decryptor> ProxyDecryptor::CreateDecryptor( |
| +scoped_ptr<Decryptor> ProxyDecryptor::CreateDecryptor( |
| const std::string& key_system) { |
| DCHECK(client_); |
| if (CanUseAesDecryptor(key_system)) |
| - return scoped_ptr<media::Decryptor>(new media::AesDecryptor(client_)); |
| + return scoped_ptr<Decryptor>(new media::AesDecryptor(client_)); |
| // We only support AesDecryptor and PpapiDecryptor. So if we cannot |
| // use the AesDecryptor, then we'll try to create a PpapiDecryptor for given |
| @@ -141,4 +189,49 @@ scoped_ptr<media::Decryptor> ProxyDecryptor::CreateDecryptor( |
| return CreatePpapiDecryptor(key_system); |
| } |
| +void ProxyDecryptor::DecryptOnMessageLoop( |
| + MessageLoop* message_loop, |
| + const scoped_refptr<DecoderBuffer>& encrypted, |
| + const Decryptor::DecryptCB& decrypt_cb) { |
| + DVLOG(2) << "DecryptOnMessageLoop()"; |
| + DCHECK(decryptor_.get()); |
| + |
| + if (MessageLoop::current() != message_loop) { |
| + message_loop->PostTask(FROM_HERE, base::Bind( |
| + &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
| + message_loop, encrypted, decrypt_cb)); |
| + return; |
| + } |
| + |
| + decryptor_->Decrypt(encrypted, base::Bind(&ProxyDecryptor::OnBufferDecrypted, |
| + base::Unretained(this), message_loop, encrypted, decrypt_cb)); |
| +} |
| + |
| +void ProxyDecryptor::OnBufferDecrypted( |
| + MessageLoop* message_loop, |
| + const scoped_refptr<DecoderBuffer>& encrypted, |
| + const Decryptor::DecryptCB& decrypt_cb, |
| + Decryptor::DecryptStatus status, |
| + const scoped_refptr<DecoderBuffer>& decrypted) { |
| + DVLOG(2) << "OnBufferDecrypted()"; |
| + |
| + if (status == Decryptor::kSuccess || status == Decryptor::kError) { |
| + decrypt_cb.Run(status, decrypted); |
| + return; |
| + } |
| + |
| + DCHECK_EQ(status, Decryptor::kNoKey); |
| + DVLOG(1) << "OnBufferDecrypted(): kNoKey fired"; |
| + { |
| + base::AutoLock auto_lock(pending_decrypt_closures_lock_); |
| + pending_decrypt_closures_.push_back(base::Bind( |
| + &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
| + message_loop, encrypted, decrypt_cb)); |
| + } |
| + // TODO(xhwang): The same NeedKey may be fired multiple times here and also |
| + // in Decrypt(). While the spec says only one NeedKey should be fired. Leave |
| + // them as is since the spec about this may change. |
| + FireNeedKey(client_, encrypted); |
| +} |
| + |
| } // namespace webkit_media |