OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |