Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: webkit/media/crypto/proxy_decryptor.cc

Issue 10822026: Implement "Key Presence" step in "Encrypted Block Encounted" algorithm in EME. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add unit test. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698