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 |
| 9 #include "base/bind.h" |
| 10 #include "base/location.h" |
7 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop_proxy.h" |
8 #include "media/base/decoder_buffer.h" | 13 #include "media/base/decoder_buffer.h" |
9 #include "media/base/decryptor_client.h" | 14 #include "media/base/decryptor_client.h" |
10 #include "media/crypto/aes_decryptor.h" | 15 #include "media/crypto/aes_decryptor.h" |
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
12 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | 17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" |
13 #include "webkit/media/crypto/key_systems.h" | 18 #include "webkit/media/crypto/key_systems.h" |
14 #include "webkit/media/crypto/ppapi_decryptor.h" | 19 #include "webkit/media/crypto/ppapi_decryptor.h" |
15 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 20 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
16 #include "webkit/plugins/ppapi/ppapi_webplugin_impl.h" | 21 #include "webkit/plugins/ppapi/ppapi_webplugin_impl.h" |
17 // 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 |
(...skipping 16 matching lines...) Expand all Loading... |
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<media::DecoderBuffer>& encrypted) { |
| 53 DCHECK(client); |
| 54 DCHECK(encrypted); |
| 55 DCHECK(encrypted->GetDecryptConfig()); |
| 56 std::string key_id = encrypted->GetDecryptConfig()->key_id(); |
| 57 scoped_array<uint8> key_id_array(new uint8[key_id.size()]); |
| 58 memcpy(key_id_array.get(), key_id.data(), key_id.size()); |
| 59 client->NeedKey("", "", key_id_array.Pass(), key_id.size()); |
| 60 } |
| 61 |
44 ProxyDecryptor::ProxyDecryptor( | 62 ProxyDecryptor::ProxyDecryptor( |
45 media::DecryptorClient* decryptor_client, | 63 media::DecryptorClient* decryptor_client, |
46 WebKit::WebMediaPlayerClient* web_media_player_client, | 64 WebKit::WebMediaPlayerClient* web_media_player_client, |
47 WebKit::WebFrame* web_frame) | 65 WebKit::WebFrame* web_frame) |
48 : client_(decryptor_client), | 66 : client_(decryptor_client), |
49 web_media_player_client_(web_media_player_client), | 67 web_media_player_client_(web_media_player_client), |
50 web_frame_(web_frame) { | 68 web_frame_(web_frame) { |
51 } | 69 } |
52 | 70 |
53 ProxyDecryptor::~ProxyDecryptor() { | 71 ProxyDecryptor::~ProxyDecryptor() { |
54 } | 72 } |
55 | 73 |
56 void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system, | 74 void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system, |
57 const uint8* init_data, | 75 const uint8* init_data, |
58 int init_data_length) { | 76 int init_data_length) { |
59 // We do not support run-time switching of decryptors. GenerateKeyRequest() | 77 // We do not support run-time switching of decryptors. GenerateKeyRequest() |
60 // only creates a new decryptor when |decryptor_| is not initialized. | 78 // only creates a new decryptor when |decryptor_| is not initialized. |
| 79 DVLOG(1) << "GenerateKeyRequest: key_system = " << key_system; |
61 if (!decryptor_.get()) { | 80 if (!decryptor_.get()) { |
62 base::AutoLock auto_lock(lock_); | 81 base::AutoLock auto_lock(lock_); |
63 decryptor_ = CreateDecryptor(key_system); | 82 decryptor_ = CreateDecryptor(key_system); |
64 } | 83 } |
65 | 84 |
66 DCHECK(client_); | |
67 if (!decryptor_.get()) { | 85 if (!decryptor_.get()) { |
68 client_->KeyError(key_system, "", media::Decryptor::kUnknownError, 0); | 86 client_->KeyError(key_system, "", media::Decryptor::kUnknownError, 0); |
69 return; | 87 return; |
70 } | 88 } |
71 | 89 |
72 decryptor_->GenerateKeyRequest(key_system, init_data, init_data_length); | 90 decryptor_->GenerateKeyRequest(key_system, init_data, init_data_length); |
73 } | 91 } |
74 | 92 |
75 void ProxyDecryptor::AddKey(const std::string& key_system, | 93 void ProxyDecryptor::AddKey(const std::string& key_system, |
76 const uint8* key, | 94 const uint8* key, |
77 int key_length, | 95 int key_length, |
78 const uint8* init_data, | 96 const uint8* init_data, |
79 int init_data_length, | 97 int init_data_length, |
80 const std::string& session_id) { | 98 const std::string& session_id) { |
| 99 DVLOG(1) << "AddKey()"; |
| 100 |
81 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. | 101 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. |
82 DCHECK(decryptor_.get()); | 102 DCHECK(decryptor_.get()); |
83 decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length, | 103 decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length, |
84 session_id); | 104 session_id); |
| 105 |
| 106 std::vector<base::Closure> closures_to_run; |
| 107 { |
| 108 base::AutoLock auto_lock(lock_); |
| 109 std::swap(pending_decrypt_closures_, closures_to_run); |
| 110 } |
| 111 |
| 112 // Fire all pending callbacks here because only the |decryptor_| knows if the |
| 113 // pending buffers can be decrypted or not. |
| 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()"; |
| 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<media::DecoderBuffer>& encrypted, |
96 const DecryptCB& decrypt_cb) { | 132 const DecryptCB& decrypt_cb) { |
97 // This is safe as we do not replace/delete an existing decryptor at run-time. | 133 // This is safe as we do not replace/delete an existing decryptor at run-time. |
98 media::Decryptor* decryptor = NULL; | 134 media::Decryptor* decryptor = NULL; |
99 { | 135 { |
100 base::AutoLock auto_lock(lock_); | 136 base::AutoLock auto_lock(lock_); |
101 decryptor = decryptor_.get(); | 137 decryptor = decryptor_.get(); |
102 } | 138 if (!decryptor) { |
103 if (!decryptor) { | 139 DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized."; |
104 DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized."; | 140 pending_decrypt_closures_.push_back( |
105 decrypt_cb.Run(kError, NULL); | 141 base::Bind(&ProxyDecryptor::DecryptOnMessageLoop, |
106 return; | 142 base::Unretained(this), |
| 143 base::MessageLoopProxy::current(), encrypted, |
| 144 decrypt_cb)); |
| 145 // TODO(xhwang): The same NeedKey may be fired here and multiple times in |
| 146 // OnBufferDecrypted(). While the spec says only one NeedKey should be |
| 147 // fired. Leave them as is since the spec about this may change. |
| 148 FireNeedKey(client_, encrypted); |
| 149 return; |
| 150 } |
107 } | 151 } |
108 | 152 |
109 decryptor->Decrypt(encrypted, decrypt_cb); | 153 decryptor->Decrypt(encrypted, base::Bind( |
| 154 &ProxyDecryptor::OnBufferDecrypted, base::Unretained(this), |
| 155 base::MessageLoopProxy::current(), encrypted, decrypt_cb)); |
110 } | 156 } |
111 | 157 |
112 scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor( | 158 scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor( |
113 const std::string& key_system) { | 159 const std::string& key_system) { |
114 DCHECK(client_); | 160 DCHECK(client_); |
115 DCHECK(web_media_player_client_); | 161 DCHECK(web_media_player_client_); |
116 DCHECK(web_frame_); | 162 DCHECK(web_frame_); |
117 | 163 |
118 std::string plugin_type = GetPluginType(key_system); | 164 std::string plugin_type = GetPluginType(key_system); |
119 DCHECK(!plugin_type.empty()); | 165 DCHECK(!plugin_type.empty()); |
(...skipping 14 matching lines...) Expand all Loading... |
134 | 180 |
135 if (CanUseAesDecryptor(key_system)) | 181 if (CanUseAesDecryptor(key_system)) |
136 return scoped_ptr<media::Decryptor>(new media::AesDecryptor(client_)); | 182 return scoped_ptr<media::Decryptor>(new media::AesDecryptor(client_)); |
137 | 183 |
138 // We only support AesDecryptor and PpapiDecryptor. So if we cannot | 184 // We only support AesDecryptor and PpapiDecryptor. So if we cannot |
139 // use the AesDecryptor, then we'll try to create a PpapiDecryptor for given | 185 // use the AesDecryptor, then we'll try to create a PpapiDecryptor for given |
140 // |key_system|. | 186 // |key_system|. |
141 return CreatePpapiDecryptor(key_system); | 187 return CreatePpapiDecryptor(key_system); |
142 } | 188 } |
143 | 189 |
| 190 void ProxyDecryptor::DecryptOnMessageLoop( |
| 191 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 192 const scoped_refptr<media::DecoderBuffer>& encrypted, |
| 193 const media::Decryptor::DecryptCB& decrypt_cb) { |
| 194 DCHECK(decryptor_.get()); |
| 195 |
| 196 if (!message_loop_proxy->BelongsToCurrentThread()) { |
| 197 message_loop_proxy->PostTask(FROM_HERE, base::Bind( |
| 198 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
| 199 message_loop_proxy, encrypted, decrypt_cb)); |
| 200 return; |
| 201 } |
| 202 |
| 203 decryptor_->Decrypt(encrypted, base::Bind(&ProxyDecryptor::OnBufferDecrypted, |
| 204 base::Unretained(this), message_loop_proxy, encrypted, decrypt_cb)); |
| 205 } |
| 206 |
| 207 void ProxyDecryptor::OnBufferDecrypted( |
| 208 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 209 const scoped_refptr<media::DecoderBuffer>& encrypted, |
| 210 const media::Decryptor::DecryptCB& decrypt_cb, |
| 211 media::Decryptor::DecryptStatus status, |
| 212 const scoped_refptr<media::DecoderBuffer>& decrypted) { |
| 213 if (status == media::Decryptor::kSuccess || |
| 214 status == media::Decryptor::kError) { |
| 215 decrypt_cb.Run(status, decrypted); |
| 216 return; |
| 217 } |
| 218 |
| 219 DCHECK_EQ(status, media::Decryptor::kNoKey); |
| 220 DVLOG(1) << "OnBufferDecrypted(): kNoKey fired"; |
| 221 { |
| 222 base::AutoLock auto_lock(lock_); |
| 223 pending_decrypt_closures_.push_back(base::Bind( |
| 224 &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this), |
| 225 message_loop_proxy, encrypted, decrypt_cb)); |
| 226 } |
| 227 // TODO(xhwang): The same NeedKey may be fired multiple times here and also |
| 228 // in Decrypt(). While the spec says only one NeedKey should be fired. Leave |
| 229 // them as is since the spec about this may change. |
| 230 FireNeedKey(client_, encrypted); |
| 231 } |
| 232 |
144 } // namespace webkit_media | 233 } // namespace webkit_media |
OLD | NEW |