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

Side by Side Diff: webkit/media/crypto/ppapi/cdm_wrapper.cc

Issue 10914028: Add CDM allocator interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix double delete, and possible KeyMessage leak. Created 8 years, 3 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 <cstring> // For memcpy. 5 #include <cstring>
6 #include <vector> 6 #include <vector>
7 7
8 #include "base/compiler_specific.h" // For OVERRIDE. 8 #include "base/compiler_specific.h"
9 #include "ppapi/c/pp_errors.h" 9 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/c/pp_stdint.h" 10 #include "ppapi/c/pp_stdint.h"
11 #include "ppapi/c/private/pp_content_decryptor.h" 11 #include "ppapi/c/private/pp_content_decryptor.h"
12 #include "ppapi/cpp/completion_callback.h" 12 #include "ppapi/cpp/completion_callback.h"
13 #include "ppapi/cpp/core.h" 13 #include "ppapi/cpp/core.h"
14 #include "ppapi/cpp/instance.h" 14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/logging.h" 15 #include "ppapi/cpp/logging.h"
16 #include "ppapi/cpp/module.h" 16 #include "ppapi/cpp/module.h"
17 #include "ppapi/cpp/pass_ref.h" 17 #include "ppapi/cpp/pass_ref.h"
18 #include "ppapi/cpp/resource.h" 18 #include "ppapi/cpp/resource.h"
(...skipping 29 matching lines...) Expand all
48 if (IsMainThread()) 48 if (IsMainThread())
49 cb.Run(PP_OK); 49 cb.Run(PP_OK);
50 else 50 else
51 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); 51 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
52 } 52 }
53 53
54 } // namespace 54 } // namespace
55 55
56 namespace webkit_media { 56 namespace webkit_media {
57 57
58 // Provides access to memory owned by a pp::Buffer_Dev handle by storing the
ddorwin 2012/09/13 19:47:00 How about: Provides access to memory owned by a pp
Tom Finegan 2012/09/15 08:03:14 Done.
59 // buffer instance for callers of CdmAllocatorImpl::Allocate.
60 class PpbCdmBuffer : public cdm::Buffer {
61 public:
62 explicit PpbCdmBuffer(pp::Buffer_Dev buffer) : buffer_(buffer) {}
63 virtual ~PpbCdmBuffer() {}
ddorwin 2012/09/13 19:47:00 To force ReleaseBuffer() to be called instead of d
Tom Finegan 2012/09/15 08:03:14 Done.
64
65 uint8_t* buffer() const OVERRIDE {
ddorwin 2012/09/14 00:20:39 I don't think this method should be const since th
Tom Finegan 2012/09/15 08:03:14 Done.
66 return static_cast<uint8_t*>(buffer_.data());
67 }
68 int32_t size() const OVERRIDE { return buffer_.size(); }
69
70 PP_Resource id() const { return buffer_.pp_resource(); }
71
72 private:
73 pp::Buffer_Dev buffer_;
74
75 // DISALLOW_COPY_AND_ASSIGN.
xhwang 2012/09/13 14:35:45 Make this a sentence? This comment will look stran
ddorwin 2012/09/13 19:47:00 This is Chromium (not CDM) code, though. Is there
Tom Finegan 2012/09/15 08:03:14 Done. I was avoiding bringing in base/basictypes.h
76 PpbCdmBuffer(const PpbCdmBuffer&);
77 void operator=(const PpbCdmBuffer&);
78 };
79
80 class CdmAllocatorImpl : public cdm::Allocator {
xhwang 2012/09/13 14:35:45 Since this is a PpbCdmBuffer specific Allocator im
ddorwin 2012/09/13 19:47:00 I wonder if we should just drop "Cdm" from both cl
Tom Finegan 2012/09/15 08:03:14 I think I've got both of these comments taken care
81 public:
82 explicit CdmAllocatorImpl(pp::Instance* instance);
83 virtual ~CdmAllocatorImpl();
84
85 // CdmAllocator methods.
86 // Creates a PpbCdmBuffer* and returns it as a cdm::Buffer*. Returns NULL on
ddorwin 2012/09/13 19:47:00 How about: Allocates a pp::Buffer_Dev of the speci
Tom Finegan 2012/09/15 08:03:14 Done.
87 // failure. Caller owns the buffer upon success.
88 virtual cdm::Buffer* Allocate(int32_t size) OVERRIDE;
89
90 // Deletes the cdm::Buffer*.
91 virtual void ReleaseBuffer(const cdm::Buffer* buffer) OVERRIDE {
ddorwin 2012/09/13 19:47:00 This and Allocate() should have consistent naming.
Tom Finegan 2012/09/15 08:03:14 Done.
92 delete buffer;
ddorwin 2012/09/13 19:47:00 Since no other functions are defined inline, we sh
Tom Finegan 2012/09/15 08:03:14 Done.
93 }
94
95 private:
96 pp::Instance* instance_;
ddorwin 2012/09/14 00:20:39 *const
Tom Finegan 2012/09/15 08:03:14 Done.
97 };
98
58 // A wrapper class for abstracting away PPAPI interaction and threading for a 99 // A wrapper class for abstracting away PPAPI interaction and threading for a
59 // Content Decryption Module (CDM). 100 // Content Decryption Module (CDM).
60 class CdmWrapper : public pp::Instance, 101 class CdmWrapper : public pp::Instance,
61 public pp::ContentDecryptor_Private { 102 public pp::ContentDecryptor_Private {
62 public: 103 public:
63 CdmWrapper(PP_Instance instance, pp::Module* module); 104 CdmWrapper(PP_Instance instance, pp::Module* module);
64 virtual ~CdmWrapper(); 105 virtual ~CdmWrapper();
65
66 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { 106 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
67 return true; 107 return true;
68 } 108 }
69 109
70 // PPP_ContentDecryptor_Private methods 110 // PPP_ContentDecryptor_Private methods
71 // Note: As per comments in PPP_ContentDecryptor_Private, these calls should 111 // Note: As per comments in PPP_ContentDecryptor_Private, these calls should
72 // return false if the call was not forwarded to the CDM and should return 112 // return false if the call was not forwarded to the CDM and should return
73 // true otherwise. Once the call reaches the CDM, the call result/status 113 // true otherwise. Once the call reaches the CDM, the call result/status
74 // should be reported through the PPB_ContentDecryptor_Private interface. 114 // should be reported through the PPB_ContentDecryptor_Private interface.
75 virtual void GenerateKeyRequest(const std::string& key_system, 115 virtual void GenerateKeyRequest(const std::string& key_system,
76 pp::VarArrayBuffer init_data) OVERRIDE; 116 pp::VarArrayBuffer init_data) OVERRIDE;
77 virtual void AddKey(const std::string& session_id, 117 virtual void AddKey(const std::string& session_id,
78 pp::VarArrayBuffer key, 118 pp::VarArrayBuffer key,
79 pp::VarArrayBuffer init_data) OVERRIDE; 119 pp::VarArrayBuffer init_data) OVERRIDE;
80 virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE; 120 virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE;
81 virtual void Decrypt( 121 virtual void Decrypt(
82 pp::Buffer_Dev encrypted_buffer, 122 pp::Buffer_Dev encrypted_buffer,
83 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; 123 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
84 virtual void DecryptAndDecode( 124 virtual void DecryptAndDecode(
85 pp::Buffer_Dev encrypted_buffer, 125 pp::Buffer_Dev encrypted_buffer,
86 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; 126 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
87 127
88 private: 128 private:
89 // Creates a PP_Resource containing a PPB_Buffer_Impl, copies |data| into the
90 // buffer resource, and returns it. Returns a an invalid PP_Resource with an
91 // ID of 0 on failure. Upon success, the returned Buffer resource has a
92 // reference count of 1.
93 pp::Buffer_Dev MakeBufferResource(const uint8_t* data, uint32_t data_size);
94
95 // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to 129 // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
96 // <code>callback_factory_</code> to ensure that calls into 130 // <code>callback_factory_</code> to ensure that calls into
97 // <code>PPP_ContentDecryptor_Private</code> are asynchronous. 131 // <code>PPP_ContentDecryptor_Private</code> are asynchronous.
98 void KeyAdded(int32_t result, const std::string& session_id); 132 void KeyAdded(int32_t result, const std::string& session_id);
99 void KeyMessage(int32_t result, cdm::KeyMessage& key_message); 133 void KeyMessage(int32_t result, cdm::KeyMessage& key_message);
100 void KeyError(int32_t result, const std::string& session_id); 134 void KeyError(int32_t result, const std::string& session_id);
101 void DeliverBlock(int32_t result, 135 void DeliverBlock(int32_t result,
102 const cdm::Status& status, 136 const cdm::Status& status,
103 cdm::OutputBuffer& output_buffer, 137 cdm::OutputBuffer& output_buffer,
104 const PP_DecryptTrackingInfo& tracking_info); 138 const PP_DecryptTrackingInfo& tracking_info);
105 139
140 CdmAllocatorImpl allocator_;
106 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_; 141 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_;
107 cdm::ContentDecryptionModule* cdm_; 142 cdm::ContentDecryptionModule* cdm_;
108 std::string key_system_; 143 std::string key_system_;
109 }; 144 };
110 145
146 CdmAllocatorImpl::CdmAllocatorImpl(pp::Instance* instance)
147 : instance_(instance) {
148 }
149
150 CdmAllocatorImpl::~CdmAllocatorImpl() {
151 }
152
153 cdm::Buffer* CdmAllocatorImpl::Allocate(int32_t size) {
154 PP_DCHECK(size > 0);
155
156 pp::Buffer_Dev buffer(instance_, size);
157 if (buffer.is_null())
158 return NULL;
159
160 return new PpbCdmBuffer(buffer);
161 }
162
111 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module) 163 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module)
112 : pp::Instance(instance), 164 : pp::Instance(instance),
113 pp::ContentDecryptor_Private(this), 165 pp::ContentDecryptor_Private(this),
166 allocator_(this),
114 cdm_(NULL) { 167 cdm_(NULL) {
115 callback_factory_.Initialize(this); 168 callback_factory_.Initialize(this);
116 } 169 }
117 170
118 CdmWrapper::~CdmWrapper() { 171 CdmWrapper::~CdmWrapper() {
119 if (cdm_) 172 if (cdm_)
120 DestroyCdmInstance(cdm_); 173 DestroyCdmInstance(cdm_);
121 } 174 }
122 175
123 void CdmWrapper::GenerateKeyRequest(const std::string& key_system, 176 void CdmWrapper::GenerateKeyRequest(const std::string& key_system,
124 pp::VarArrayBuffer init_data) { 177 pp::VarArrayBuffer init_data) {
125 PP_DCHECK(!key_system.empty()); 178 PP_DCHECK(!key_system.empty());
126 179
127 if (!cdm_) { 180 if (!cdm_) {
128 cdm_ = CreateCdmInstance(); 181 cdm_ = CreateCdmInstance(&allocator_);
129 if (!cdm_) 182 if (!cdm_)
130 return; 183 return;
131 } 184 }
132 185
133 cdm::KeyMessage key_request; 186 cdm::KeyMessage key_request(&allocator_);
134 cdm::Status status = cdm_->GenerateKeyRequest( 187 cdm::Status status = cdm_->GenerateKeyRequest(
135 reinterpret_cast<const uint8_t*>(init_data.Map()), 188 reinterpret_cast<const uint8_t*>(init_data.Map()),
136 init_data.ByteLength(), 189 init_data.ByteLength(),
137 &key_request); 190 &key_request);
ddorwin 2012/09/13 19:47:00 Any new buffers assigned to key_request by the CDM
Tom Finegan 2012/09/15 08:03:14 Had a bit of fun with this today/tonight. pp::Comp
138 191
139 if (status != cdm::kSuccess || 192 if (status != cdm::kSuccess ||
140 !key_request.message || 193 !key_request.message ||
141 key_request.message_size == 0) { 194 key_request.message->size() == 0) {
142 CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError, 195 CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError,
143 std::string())); 196 std::string()));
144 return; 197 return;
145 } 198 }
146 199
147 // TODO(xhwang): Remove unnecessary CallOnMain calls here and below once we 200 // TODO(xhwang): Remove unnecessary CallOnMain calls here and below once we
148 // only support out-of-process. 201 // only support out-of-process.
149 // If running out-of-process, PPB calls will always behave asynchronously 202 // If running out-of-process, PPB calls will always behave asynchronously
150 // since IPC is involved. In that case, if we are already on main thread, 203 // since IPC is involved. In that case, if we are already on main thread,
151 // we don't need to use CallOnMain to help us call PPB call on main thread, 204 // we don't need to use CallOnMain to help us call PPB call on main thread,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 input_buffer.num_subsamples = encrypted_block_info.num_subsamples; 263 input_buffer.num_subsamples = encrypted_block_info.num_subsamples;
211 std::vector<cdm::SubsampleEntry> subsamples; 264 std::vector<cdm::SubsampleEntry> subsamples;
212 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) { 265 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
213 subsamples.push_back(cdm::SubsampleEntry( 266 subsamples.push_back(cdm::SubsampleEntry(
214 encrypted_block_info.subsamples[i].clear_bytes, 267 encrypted_block_info.subsamples[i].clear_bytes,
215 encrypted_block_info.subsamples[i].cipher_bytes)); 268 encrypted_block_info.subsamples[i].cipher_bytes));
216 } 269 }
217 input_buffer.subsamples = &subsamples[0]; 270 input_buffer.subsamples = &subsamples[0];
218 input_buffer.timestamp = encrypted_block_info.tracking_info.timestamp; 271 input_buffer.timestamp = encrypted_block_info.tracking_info.timestamp;
219 272
220 cdm::OutputBuffer output_buffer; 273 cdm::OutputBuffer output_buffer(&allocator_);
221 cdm::Status status = cdm_->Decrypt(input_buffer, &output_buffer); 274 cdm::Status status = cdm_->Decrypt(input_buffer, &output_buffer);
275 PP_DCHECK(status == cdm::kSuccess);
222 276
223 CallOnMain(callback_factory_.NewCallback( 277 CallOnMain(callback_factory_.NewCallback(
224 &CdmWrapper::DeliverBlock, 278 &CdmWrapper::DeliverBlock,
225 status, 279 status,
226 output_buffer, 280 output_buffer,
227 encrypted_block_info.tracking_info)); 281 encrypted_block_info.tracking_info));
228 } 282 }
229 283
230 void CdmWrapper::DecryptAndDecode( 284 void CdmWrapper::DecryptAndDecode(
231 pp::Buffer_Dev encrypted_buffer, 285 pp::Buffer_Dev encrypted_buffer,
232 const PP_EncryptedBlockInfo& encrypted_block_info) { 286 const PP_EncryptedBlockInfo& encrypted_block_info) {
233 } 287 }
234 288
235 pp::Buffer_Dev CdmWrapper::MakeBufferResource(const uint8_t* data,
236 uint32_t data_size) {
237 if (!data || !data_size)
238 return pp::Buffer_Dev();
239
240 pp::Buffer_Dev buffer(this, data_size);
241 if (!buffer.data())
242 return pp::Buffer_Dev();
243
244 memcpy(buffer.data(), data, data_size);
245 return buffer;
246 }
247
248 void CdmWrapper::KeyAdded(int32_t result, const std::string& session_id) { 289 void CdmWrapper::KeyAdded(int32_t result, const std::string& session_id) {
249 pp::ContentDecryptor_Private::KeyAdded(key_system_, session_id); 290 pp::ContentDecryptor_Private::KeyAdded(key_system_, session_id);
250 } 291 }
251 292
252 void CdmWrapper::KeyMessage(int32_t result, 293 void CdmWrapper::KeyMessage(int32_t result,
253 cdm::KeyMessage& key_message) { 294 cdm::KeyMessage& key_message) {
254 pp::Buffer_Dev message_buffer(MakeBufferResource(key_message.message, 295 PpbCdmBuffer* cdm_buffer =
255 key_message.message_size)); 296 static_cast<PpbCdmBuffer*>(key_message.message);
297 pp::Buffer_Dev message_buffer(pp::Buffer_Dev(cdm_buffer->id()));
ddorwin 2012/09/13 19:47:00 Would it be better to just expose the Buffer_Dev s
Tom Finegan 2012/09/15 08:03:14 Done. I added buffer_dev()
256 pp::ContentDecryptor_Private::KeyMessage( 298 pp::ContentDecryptor_Private::KeyMessage(
257 key_system_, 299 key_system_,
258 std::string(key_message.session_id, key_message.session_id_size), 300 std::string(key_message.session_id, key_message.session_id_size),
259 message_buffer, 301 message_buffer,
260 std::string(key_message.default_url, key_message.default_url_size)); 302 std::string(key_message.default_url, key_message.default_url_size));
261
262 // TODO(xhwang): Fix this. This is not always safe as the memory is allocated
263 // in another shared object.
264 delete [] key_message.session_id;
265 key_message.session_id = NULL;
266 delete [] key_message.message;
267 key_message.message = NULL;
268 delete [] key_message.default_url;
269 key_message.default_url = NULL;
270 } 303 }
271 304
272 // TODO(xhwang): Support MediaKeyError (see spec: http://goo.gl/rbdnR) in CDM 305 // TODO(xhwang): Support MediaKeyError (see spec: http://goo.gl/rbdnR) in CDM
273 // interface and in this function. 306 // interface and in this function.
274 void CdmWrapper::KeyError(int32_t result, const std::string& session_id) { 307 void CdmWrapper::KeyError(int32_t result, const std::string& session_id) {
275 pp::ContentDecryptor_Private::KeyError(key_system_, 308 pp::ContentDecryptor_Private::KeyError(key_system_,
276 session_id, 309 session_id,
277 kUnknownError, 310 kUnknownError,
278 0); 311 0);
279 } 312 }
280 313
281 void CdmWrapper::DeliverBlock(int32_t result, 314 void CdmWrapper::DeliverBlock(int32_t result,
282 const cdm::Status& status, 315 const cdm::Status& status,
283 cdm::OutputBuffer& output_buffer, 316 cdm::OutputBuffer& output_buffer,
284 const PP_DecryptTrackingInfo& tracking_info) { 317 const PP_DecryptTrackingInfo& tracking_info) {
285 pp::Buffer_Dev decrypted_buffer(MakeBufferResource(output_buffer.data,
286 output_buffer.data_size));
287 PP_DecryptedBlockInfo decrypted_block_info; 318 PP_DecryptedBlockInfo decrypted_block_info;
288 decrypted_block_info.tracking_info.request_id = tracking_info.request_id; 319 decrypted_block_info.tracking_info.request_id = tracking_info.request_id;
289 decrypted_block_info.tracking_info.timestamp = output_buffer.timestamp; 320 decrypted_block_info.tracking_info.timestamp = output_buffer.timestamp;
290 321
291 switch (status) { 322 switch (status) {
292 case cdm::kSuccess: 323 case cdm::kSuccess:
293 decrypted_block_info.result = PP_DECRYPTRESULT_SUCCESS; 324 decrypted_block_info.result = PP_DECRYPTRESULT_SUCCESS;
294 break; 325 break;
295 case cdm::kNoKey: 326 case cdm::kNoKey:
296 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_NOKEY; 327 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_NOKEY;
297 break; 328 break;
298 default: 329 default:
299 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 330 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
300 } 331 }
301 332
302 pp::ContentDecryptor_Private::DeliverBlock(decrypted_buffer, 333 const PpbCdmBuffer* const cdm_buffer =
303 decrypted_block_info); 334 static_cast<PpbCdmBuffer*>(output_buffer.buffer);
335 PP_DCHECK(cdm_buffer);
ddorwin 2012/09/13 19:47:00 Remove or DCHECK after 296 too.
Tom Finegan 2012/09/15 08:03:14 Done.
304 336
305 // TODO(xhwang): Fix this. This is not always safe as the memory is allocated 337 pp::ContentDecryptor_Private::DeliverBlock(
306 // in another shared object. 338 pp::Buffer_Dev(cdm_buffer->id()),
307 delete [] output_buffer.data; 339 decrypted_block_info);
308 output_buffer.data = NULL;
309 } 340 }
310 341
311 // This object is the global object representing this plugin library as long 342 // This object is the global object representing this plugin library as long
312 // as it is loaded. 343 // as it is loaded.
313 class MyModule : public pp::Module { 344 class CdmWrapperModule : public pp::Module {
314 public: 345 public:
315 MyModule() : pp::Module() {} 346 CdmWrapperModule() : pp::Module() {}
316 virtual ~MyModule() {} 347 virtual ~CdmWrapperModule() {}
317 348
318 virtual pp::Instance* CreateInstance(PP_Instance instance) { 349 virtual pp::Instance* CreateInstance(PP_Instance instance) {
319 return new CdmWrapper(instance, this); 350 return new CdmWrapper(instance, this);
320 } 351 }
321 }; 352 };
322 353
323 } // namespace webkit_media 354 } // namespace webkit_media
324 355
325 namespace pp { 356 namespace pp {
326 357
327 // Factory function for your specialization of the Module object. 358 // Factory function for your specialization of the Module object.
328 Module* CreateModule() { 359 Module* CreateModule() {
329 return new webkit_media::MyModule(); 360 return new webkit_media::CdmWrapperModule();
330 } 361 }
331 362
332 } // namespace pp 363 } // namespace pp
OLDNEW
« no previous file with comments | « no previous file | webkit/media/crypto/ppapi/clear_key_cdm.h » ('j') | webkit/media/crypto/ppapi/clear_key_cdm.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698