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