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

Side by Side Diff: media/cdm/ppapi/cdm_wrapper.cc

Issue 26155003: Add CdmWrapper to support multiple CDM versions in CdmAdapter. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add cdm_helpers.h Created 7 years, 2 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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> 5 #include <cstring>
6 #include <map>
7 #include <string> 6 #include <string>
8 #include <utility>
9 #include <vector> 7 #include <vector>
10 8
11 #include "base/basictypes.h" 9 #include "base/basictypes.h"
12 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
13 #include "build/build_config.h" 11 #include "build/build_config.h"
14 #include "media/cdm/ppapi/api/content_decryption_module.h" 12 #include "media/cdm/ppapi/api/content_decryption_module.h"
13 #include "media/cdm/ppapi/cdm_adapter.h"
14 #include "media/cdm/ppapi/cdm_helpers.h"
15 #include "media/cdm/ppapi/linked_ptr.h" 15 #include "media/cdm/ppapi/linked_ptr.h"
16 #include "ppapi/c/pp_completion_callback.h" 16 #include "ppapi/c/pp_completion_callback.h"
17 #include "ppapi/c/pp_errors.h" 17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/c/pp_stdint.h" 18 #include "ppapi/c/pp_stdint.h"
19 #include "ppapi/c/private/pp_content_decryptor.h" 19 #include "ppapi/c/private/pp_content_decryptor.h"
20 #include "ppapi/cpp/completion_callback.h" 20 #include "ppapi/cpp/completion_callback.h"
21 #include "ppapi/cpp/core.h" 21 #include "ppapi/cpp/core.h"
22 #include "ppapi/cpp/dev/buffer_dev.h"
23 #include "ppapi/cpp/instance.h" 22 #include "ppapi/cpp/instance.h"
24 #include "ppapi/cpp/logging.h" 23 #include "ppapi/cpp/logging.h"
25 #include "ppapi/cpp/module.h" 24 #include "ppapi/cpp/module.h"
26 #include "ppapi/cpp/pass_ref.h" 25 #include "ppapi/cpp/pass_ref.h"
27 #include "ppapi/cpp/private/content_decryptor_private.h" 26 #include "ppapi/cpp/private/content_decryptor_private.h"
28 #include "ppapi/cpp/resource.h" 27 #include "ppapi/cpp/resource.h"
29 #include "ppapi/cpp/var.h" 28 #include "ppapi/cpp/var.h"
30 #include "ppapi/cpp/var_array_buffer.h" 29 #include "ppapi/cpp/var_array_buffer.h"
31 #include "ppapi/utility/completion_callback_factory.h" 30 #include "ppapi/utility/completion_callback_factory.h"
32 31
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 } 205 }
207 206
208 PP_NOTREACHED(); 207 PP_NOTREACHED();
209 return cdm::kStreamTypeVideo; 208 return cdm::kStreamTypeVideo;
210 } 209 }
211 210
212 } // namespace 211 } // namespace
213 212
214 namespace media { 213 namespace media {
215 214
216 // cdm::Buffer implementation that provides access to memory owned by a
217 // pp::Buffer_Dev.
218 // This class holds a reference to the Buffer_Dev throughout its lifetime.
219 // TODO(xhwang): Find a better name. It's confusing to have PpbBuffer,
220 // pp::Buffer_Dev and PPB_Buffer_Dev.
221 class PpbBuffer : public cdm::Buffer {
222 public:
223 static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id) {
224 PP_DCHECK(buffer.data());
225 PP_DCHECK(buffer.size());
226 PP_DCHECK(buffer_id);
227 return new PpbBuffer(buffer, buffer_id);
228 }
229
230 // cdm::Buffer implementation.
231 virtual void Destroy() OVERRIDE { delete this; }
232
233 virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); }
234
235 virtual uint8_t* Data() OVERRIDE {
236 return static_cast<uint8_t*>(buffer_.data());
237 }
238
239 virtual void SetSize(int32_t size) OVERRIDE {
240 PP_DCHECK(size >= 0);
241 PP_DCHECK(size < Capacity());
242 if (size < 0 || size > Capacity()) {
243 size_ = 0;
244 return;
245 }
246
247 size_ = size;
248 }
249
250 virtual int32_t Size() const OVERRIDE { return size_; }
251
252 pp::Buffer_Dev buffer_dev() const { return buffer_; }
253
254 uint32_t buffer_id() const { return buffer_id_; }
255
256 private:
257 PpbBuffer(pp::Buffer_Dev buffer, uint32_t buffer_id)
258 : buffer_(buffer),
259 buffer_id_(buffer_id),
260 size_(0) {}
261 virtual ~PpbBuffer() {}
262
263 pp::Buffer_Dev buffer_;
264 uint32_t buffer_id_;
265 int32_t size_;
266
267 DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
268 };
269
270 class PpbBufferAllocator {
271 public:
272 explicit PpbBufferAllocator(pp::Instance* instance)
273 : instance_(instance),
274 next_buffer_id_(1) {}
275 ~PpbBufferAllocator() {}
276
277 cdm::Buffer* Allocate(int32_t capacity);
278
279 // Releases the buffer with |buffer_id|. A buffer can be recycled after
280 // it is released.
281 void Release(uint32_t buffer_id);
282
283 private:
284 typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
285 typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> >
286 FreeBufferMap;
287
288 // Always pad new allocated buffer so that we don't need to reallocate
289 // buffers frequently if requested sizes fluctuate slightly.
290 static const int kBufferPadding = 512;
291
292 // Maximum number of free buffers we can keep when allocating new buffers.
293 static const int kFreeLimit = 3;
294
295 pp::Buffer_Dev AllocateNewBuffer(int capacity);
296
297 pp::Instance* const instance_;
298 uint32_t next_buffer_id_;
299 AllocatedBufferMap allocated_buffers_;
300 FreeBufferMap free_buffers_;
301
302 DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator);
303 };
304
305 cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) {
306 PP_DCHECK(IsMainThread());
307
308 if (capacity <= 0)
309 return NULL;
310
311 pp::Buffer_Dev buffer;
312 uint32_t buffer_id = 0;
313
314 // Reuse a buffer in the free list if there is one that fits |capacity|.
315 // Otherwise, create a new one.
316 FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity);
317 if (found == free_buffers_.end()) {
318 // TODO(xhwang): Report statistics about how many new buffers are allocated.
319 buffer = AllocateNewBuffer(capacity);
320 if (buffer.is_null())
321 return NULL;
322 buffer_id = next_buffer_id_++;
323 } else {
324 buffer = found->second.second;
325 buffer_id = found->second.first;
326 free_buffers_.erase(found);
327 }
328
329 allocated_buffers_.insert(std::make_pair(buffer_id, buffer));
330
331 return PpbBuffer::Create(buffer, buffer_id);
332 }
333
334 void PpbBufferAllocator::Release(uint32_t buffer_id) {
335 if (!buffer_id)
336 return;
337
338 AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id);
339 if (found == allocated_buffers_.end())
340 return;
341
342 pp::Buffer_Dev& buffer = found->second;
343 free_buffers_.insert(
344 std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer)));
345
346 allocated_buffers_.erase(found);
347 }
348
349 pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) {
350 // Destroy the smallest buffer before allocating a new bigger buffer if the
351 // number of free buffers exceeds a limit. This mechanism helps avoid ending
352 // up with too many small buffers, which could happen if the size to be
353 // allocated keeps increasing.
354 if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit))
355 free_buffers_.erase(free_buffers_.begin());
356
357 // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls.
358 // That's why we try to avoid AllocateNewBuffer() as much as we can.
359 return pp::Buffer_Dev(instance_, capacity + kBufferPadding);
360 }
361
362 class DecryptedBlockImpl : public cdm::DecryptedBlock {
363 public:
364 DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {}
365 virtual ~DecryptedBlockImpl() { if (buffer_) buffer_->Destroy(); }
366
367 virtual void SetDecryptedBuffer(cdm::Buffer* buffer) OVERRIDE {
368 buffer_ = static_cast<PpbBuffer*>(buffer);
369 }
370 virtual cdm::Buffer* DecryptedBuffer() OVERRIDE { return buffer_; }
371
372 virtual void SetTimestamp(int64_t timestamp) OVERRIDE {
373 timestamp_ = timestamp;
374 }
375 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; }
376
377 private:
378 PpbBuffer* buffer_;
379 int64_t timestamp_;
380
381 DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl);
382 };
383
384 class VideoFrameImpl : public cdm::VideoFrame {
385 public:
386 VideoFrameImpl();
387 virtual ~VideoFrameImpl();
388
389 virtual void SetFormat(cdm::VideoFormat format) OVERRIDE {
390 format_ = format;
391 }
392 virtual cdm::VideoFormat Format() const OVERRIDE { return format_; }
393
394 virtual void SetSize(cdm::Size size) OVERRIDE { size_ = size; }
395 virtual cdm::Size Size() const OVERRIDE { return size_; }
396
397 virtual void SetFrameBuffer(cdm::Buffer* frame_buffer) OVERRIDE {
398 frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer);
399 }
400 virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; }
401
402 virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
403 int32_t offset) OVERRIDE {
404 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
405 PP_DCHECK(offset >= 0);
406 plane_offsets_[plane] = offset;
407 }
408 virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE {
409 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
410 return plane_offsets_[plane];
411 }
412
413 virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE {
414 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
415 strides_[plane] = stride;
416 }
417 virtual int32_t Stride(VideoPlane plane) OVERRIDE {
418 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
419 return strides_[plane];
420 }
421
422 virtual void SetTimestamp(int64_t timestamp) OVERRIDE {
423 timestamp_ = timestamp;
424 }
425 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; }
426
427 private:
428 // The video buffer format.
429 cdm::VideoFormat format_;
430
431 // Width and height of the video frame.
432 cdm::Size size_;
433
434 // The video frame buffer.
435 PpbBuffer* frame_buffer_;
436
437 // Array of data pointers to each plane in the video frame buffer.
438 int32_t plane_offsets_[kMaxPlanes];
439
440 // Array of strides for each plane, typically greater or equal to the width
441 // of the surface divided by the horizontal sampling period. Note that
442 // strides can be negative.
443 int32_t strides_[kMaxPlanes];
444
445 // Presentation timestamp in microseconds.
446 int64_t timestamp_;
447
448 DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl);
449 };
450
451 VideoFrameImpl::VideoFrameImpl()
452 : format_(cdm::kUnknownVideoFormat),
453 frame_buffer_(NULL),
454 timestamp_(0) {
455 for (int32_t i = 0; i < kMaxPlanes; ++i) {
456 plane_offsets_[i] = 0;
457 strides_[i] = 0;
458 }
459 }
460
461 VideoFrameImpl::~VideoFrameImpl() {
462 if (frame_buffer_)
463 frame_buffer_->Destroy();
464 }
465
466 class AudioFramesImpl : public cdm::AudioFrames_1,
467 public cdm::AudioFrames_2 {
468 public:
469 AudioFramesImpl() : buffer_(NULL), format_(cdm::kAudioFormatS16) {}
470 virtual ~AudioFramesImpl() {
471 if (buffer_)
472 buffer_->Destroy();
473 }
474
475 // AudioFrames implementation.
476 virtual void SetFrameBuffer(cdm::Buffer* buffer) OVERRIDE {
477 buffer_ = static_cast<PpbBuffer*>(buffer);
478 }
479 virtual cdm::Buffer* FrameBuffer() OVERRIDE {
480 return buffer_;
481 }
482 virtual void SetFormat(cdm::AudioFormat format) OVERRIDE {
483 format_ = format;
484 }
485 virtual cdm::AudioFormat Format() const OVERRIDE {
486 return format_;
487 }
488
489 private:
490 PpbBuffer* buffer_;
491 cdm::AudioFormat format_;
492
493 DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl);
494 };
495
496 // GetCdmHostFunc implementation. 215 // GetCdmHostFunc implementation.
497 void* GetCdmHost(int host_interface_version, void* user_data); 216 void* GetCdmHost(int host_interface_version, void* user_data);
498 217
499 // A wrapper class for abstracting away PPAPI interaction and threading for a 218 // A wrapper class for abstracting away PPAPI interaction and threading for a
500 // Content Decryption Module (CDM). 219 // Content Decryption Module (CDM).
501 class CdmWrapper : public pp::Instance, 220 class CdmWrapper : public pp::Instance,
DaleCurtis 2013/10/17 20:31:58 This being the prototype I'm talking about...
502 public pp::ContentDecryptor_Private, 221 public pp::ContentDecryptor_Private,
503 public cdm::Host_1, 222 public cdm::Host_1,
504 public cdm::Host_2 { 223 public cdm::Host_2 {
505 public: 224 public:
506 CdmWrapper(PP_Instance instance, pp::Module* module); 225 CdmWrapper(PP_Instance instance, pp::Module* module);
507 virtual ~CdmWrapper(); 226 virtual ~CdmWrapper();
508 227
509 // pp::Instance implementation. 228 // pp::Instance implementation.
510 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { 229 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
511 return true; 230 return true;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 bool challenge_in_progress_; 374 bool challenge_in_progress_;
656 375
657 // Same as above, these are only read by QueryOutputProtectionStatusDone(). 376 // Same as above, these are only read by QueryOutputProtectionStatusDone().
658 uint32_t output_link_mask_; 377 uint32_t output_link_mask_;
659 uint32_t output_protection_mask_; 378 uint32_t output_protection_mask_;
660 bool query_output_protection_in_progress_; 379 bool query_output_protection_in_progress_;
661 #endif 380 #endif
662 381
663 PpbBufferAllocator allocator_; 382 PpbBufferAllocator allocator_;
664 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_; 383 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_;
665 cdm::ContentDecryptionModule* cdm_; 384 linked_ptr<CdmAdapter> cdm_;
666 std::string key_system_; 385 std::string key_system_;
667 386
668 DISALLOW_COPY_AND_ASSIGN(CdmWrapper); 387 DISALLOW_COPY_AND_ASSIGN(CdmWrapper);
669 }; 388 };
670 389
671 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module) 390 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module)
672 : pp::Instance(instance), 391 : pp::Instance(instance),
673 pp::ContentDecryptor_Private(this), 392 pp::ContentDecryptor_Private(this),
674 #if defined(OS_CHROMEOS) 393 #if defined(OS_CHROMEOS)
675 output_protection_(this), 394 output_protection_(this),
676 platform_verification_(this), 395 platform_verification_(this),
677 // Err on the side of the most common case... 396 // Err on the side of the most common case...
678 can_challenge_platform_(true), 397 can_challenge_platform_(true),
679 challenge_in_progress_(false), 398 challenge_in_progress_(false),
680 output_link_mask_(0), 399 output_link_mask_(0),
681 output_protection_mask_(0), 400 output_protection_mask_(0),
682 query_output_protection_in_progress_(false), 401 query_output_protection_in_progress_(false),
683 #endif 402 #endif
684 allocator_(this), 403 allocator_(this),
685 cdm_(NULL) { 404 cdm_(NULL) {
686 callback_factory_.Initialize(this); 405 callback_factory_.Initialize(this);
687 #if defined(OS_CHROMEOS) 406 #if defined(OS_CHROMEOS)
688 // Preemptively retrieve the platform challenge status. It will not change. 407 // Preemptively retrieve the platform challenge status. It will not change.
689 platform_verification_.CanChallengePlatform( 408 platform_verification_.CanChallengePlatform(
690 callback_factory_.NewCallbackWithOutput( 409 callback_factory_.NewCallbackWithOutput(
691 &CdmWrapper::CanChallengePlatformDone)); 410 &CdmWrapper::CanChallengePlatformDone));
692 #endif 411 #endif
693 } 412 }
694 413
695 CdmWrapper::~CdmWrapper() { 414 CdmWrapper::~CdmWrapper() {}
696 if (cdm_)
697 cdm_->Destroy();
698 }
699 415
700 bool CdmWrapper::CreateCdmInstance(const std::string& key_system) { 416 bool CdmWrapper::CreateCdmInstance(const std::string& key_system) {
701 PP_DCHECK(!cdm_); 417 PP_DCHECK(!cdm_);
702 cdm_ = static_cast<cdm::ContentDecryptionModule*>( 418 cdm_ = make_linked_ptr(CdmAdapter::Create(
703 ::CreateCdmInstance(cdm::kCdmInterfaceVersion, 419 key_system.data(), key_system.size(), GetCdmHost, this));
704 key_system.data(), key_system.size(),
705 GetCdmHost, this));
706
707 return (cdm_ != NULL); 420 return (cdm_ != NULL);
708 } 421 }
709 422
710 void CdmWrapper::Initialize(const std::string& key_system, 423 void CdmWrapper::Initialize(const std::string& key_system,
711 bool can_challenge_platform) { 424 bool can_challenge_platform) {
712 PP_DCHECK(!key_system.empty()); 425 PP_DCHECK(!key_system.empty());
713 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); 426 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_));
714 427
715 if (!cdm_) { 428 if (!cdm_) {
716 if (!CreateCdmInstance(key_system)) { 429 if (!CreateCdmInstance(key_system)) {
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after
1393 } // namespace media 1106 } // namespace media
1394 1107
1395 namespace pp { 1108 namespace pp {
1396 1109
1397 // Factory function for your specialization of the Module object. 1110 // Factory function for your specialization of the Module object.
1398 Module* CreateModule() { 1111 Module* CreateModule() {
1399 return new media::CdmWrapperModule(); 1112 return new media::CdmWrapperModule();
1400 } 1113 }
1401 1114
1402 } // namespace pp 1115 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698