Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / media / crypto / ppapi / cdm_wrapper.cc
blobcd5b9170394ff8d3fcd38ecfb1af7145272a099f
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
3 // found in the LICENSE file.
5 #include <cstring>
6 #include <map>
7 #include <string>
8 #include <utility>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/compiler_specific.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/c/pp_stdint.h"
15 #include "ppapi/c/private/pp_content_decryptor.h"
16 #include "ppapi/cpp/completion_callback.h"
17 #include "ppapi/cpp/core.h"
18 #include "ppapi/cpp/instance.h"
19 #include "ppapi/cpp/logging.h"
20 #include "ppapi/cpp/module.h"
21 #include "ppapi/cpp/pass_ref.h"
22 #include "ppapi/cpp/resource.h"
23 #include "ppapi/cpp/var.h"
24 #include "ppapi/cpp/var_array_buffer.h"
25 #include "ppapi/cpp/dev/buffer_dev.h"
26 #include "ppapi/cpp/private/content_decryptor_private.h"
27 #include "ppapi/utility/completion_callback_factory.h"
28 #include "webkit/media/crypto/ppapi/cdm/content_decryption_module.h"
29 #include "webkit/media/crypto/ppapi/linked_ptr.h"
31 #if defined(CHECK_ORIGIN_URL)
32 #include "ppapi/cpp/private/instance_private.h"
33 #include "ppapi/cpp/private/var_private.h"
34 #endif // defined(CHECK_ORIGIN_URL)
36 namespace {
38 bool IsMainThread() {
39 return pp::Module::Get()->core()->IsMainThread();
42 // Posts a task to run |cb| on the main thread. The task is posted even if the
43 // current thread is the main thread.
44 void PostOnMain(pp::CompletionCallback cb) {
45 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
48 // Ensures |cb| is called on the main thread, either because the current thread
49 // is the main thread or by posting it to the main thread.
50 void CallOnMain(pp::CompletionCallback cb) {
51 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
52 // off the main thread yet. Remove this once the change lands.
53 if (IsMainThread())
54 cb.Run(PP_OK);
55 else
56 PostOnMain(cb);
59 // Configures a cdm::InputBuffer. |subsamples| must exist as long as
60 // |input_buffer| is in use.
61 void ConfigureInputBuffer(
62 const pp::Buffer_Dev& encrypted_buffer,
63 const PP_EncryptedBlockInfo& encrypted_block_info,
64 std::vector<cdm::SubsampleEntry>* subsamples,
65 cdm::InputBuffer* input_buffer) {
66 PP_DCHECK(subsamples);
67 PP_DCHECK(!encrypted_buffer.is_null());
69 input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
70 input_buffer->data_size = encrypted_block_info.data_size;
71 PP_DCHECK(encrypted_buffer.size() >=
72 static_cast<uint32_t>(input_buffer->data_size));
73 input_buffer->data_offset = encrypted_block_info.data_offset;
75 PP_DCHECK(encrypted_block_info.key_id_size <=
76 arraysize(encrypted_block_info.key_id));
77 input_buffer->key_id_size = encrypted_block_info.key_id_size;
78 input_buffer->key_id = input_buffer->key_id_size > 0 ?
79 encrypted_block_info.key_id : NULL;
81 PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv));
82 input_buffer->iv_size = encrypted_block_info.iv_size;
83 input_buffer->iv = encrypted_block_info.iv_size > 0 ?
84 encrypted_block_info.iv : NULL;
86 input_buffer->num_subsamples = encrypted_block_info.num_subsamples;
87 if (encrypted_block_info.num_subsamples > 0) {
88 subsamples->reserve(encrypted_block_info.num_subsamples);
90 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
91 subsamples->push_back(cdm::SubsampleEntry(
92 encrypted_block_info.subsamples[i].clear_bytes,
93 encrypted_block_info.subsamples[i].cipher_bytes));
96 input_buffer->subsamples = &(*subsamples)[0];
99 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp;
102 PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) {
103 switch (status) {
104 case cdm::kSuccess:
105 return PP_DECRYPTRESULT_SUCCESS;
106 case cdm::kNoKey:
107 return PP_DECRYPTRESULT_DECRYPT_NOKEY;
108 case cdm::kNeedMoreData:
109 return PP_DECRYPTRESULT_NEEDMOREDATA;
110 case cdm::kDecryptError:
111 return PP_DECRYPTRESULT_DECRYPT_ERROR;
112 case cdm::kDecodeError:
113 return PP_DECRYPTRESULT_DECODE_ERROR;
114 default:
115 PP_NOTREACHED();
116 return PP_DECRYPTRESULT_DECODE_ERROR;
120 PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
121 cdm::VideoFormat format) {
122 switch (format) {
123 case cdm::kYv12:
124 return PP_DECRYPTEDFRAMEFORMAT_YV12;
125 case cdm::kI420:
126 return PP_DECRYPTEDFRAMEFORMAT_I420;
127 default:
128 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
132 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
133 PP_AudioCodec codec) {
134 switch (codec) {
135 case PP_AUDIOCODEC_VORBIS:
136 return cdm::AudioDecoderConfig::kCodecVorbis;
137 case PP_AUDIOCODEC_AAC:
138 return cdm::AudioDecoderConfig::kCodecAac;
139 default:
140 return cdm::AudioDecoderConfig::kUnknownAudioCodec;
144 cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec(
145 PP_VideoCodec codec) {
146 switch (codec) {
147 case PP_VIDEOCODEC_VP8:
148 return cdm::VideoDecoderConfig::kCodecVp8;
149 case PP_VIDEOCODEC_H264:
150 return cdm::VideoDecoderConfig::kCodecH264;
151 default:
152 return cdm::VideoDecoderConfig::kUnknownVideoCodec;
156 cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile(
157 PP_VideoCodecProfile profile) {
158 switch (profile) {
159 case PP_VIDEOCODECPROFILE_VP8_MAIN:
160 return cdm::VideoDecoderConfig::kVp8ProfileMain;
161 case PP_VIDEOCODECPROFILE_H264_BASELINE:
162 return cdm::VideoDecoderConfig::kH264ProfileBaseline;
163 case PP_VIDEOCODECPROFILE_H264_MAIN:
164 return cdm::VideoDecoderConfig::kH264ProfileMain;
165 case PP_VIDEOCODECPROFILE_H264_EXTENDED:
166 return cdm::VideoDecoderConfig::kH264ProfileExtended;
167 case PP_VIDEOCODECPROFILE_H264_HIGH:
168 return cdm::VideoDecoderConfig::kH264ProfileHigh;
169 case PP_VIDEOCODECPROFILE_H264_HIGH_10:
170 return cdm::VideoDecoderConfig::kH264ProfileHigh10;
171 case PP_VIDEOCODECPROFILE_H264_HIGH_422:
172 return cdm::VideoDecoderConfig::kH264ProfileHigh422;
173 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE:
174 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive;
175 default:
176 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
180 cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
181 PP_DecryptedFrameFormat format) {
182 switch (format) {
183 case PP_DECRYPTEDFRAMEFORMAT_YV12:
184 return cdm::kYv12;
185 case PP_DECRYPTEDFRAMEFORMAT_I420:
186 return cdm::kI420;
187 default:
188 return cdm::kUnknownVideoFormat;
192 cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
193 PP_DecryptorStreamType stream_type) {
194 switch (stream_type) {
195 case PP_DECRYPTORSTREAMTYPE_AUDIO:
196 return cdm::kStreamTypeAudio;
197 case PP_DECRYPTORSTREAMTYPE_VIDEO:
198 return cdm::kStreamTypeVideo;
201 PP_NOTREACHED();
202 return cdm::kStreamTypeVideo;
205 } // namespace
207 namespace webkit_media {
209 // cdm::Buffer implementation that provides access to memory owned by a
210 // pp::Buffer_Dev.
211 // This class holds a reference to the Buffer_Dev throughout its lifetime.
212 // TODO(xhwang): Find a better name. It's confusing to have PpbBuffer,
213 // pp::Buffer_Dev and PPB_Buffer_Dev.
214 class PpbBuffer : public cdm::Buffer {
215 public:
216 static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id) {
217 PP_DCHECK(buffer.data());
218 PP_DCHECK(buffer.size());
219 PP_DCHECK(buffer_id);
220 return new PpbBuffer(buffer, buffer_id);
223 // cdm::Buffer implementation.
224 virtual void Destroy() OVERRIDE { delete this; }
226 virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); }
228 virtual uint8_t* Data() OVERRIDE {
229 return static_cast<uint8_t*>(buffer_.data());
232 virtual void SetSize(int32_t size) OVERRIDE {
233 PP_DCHECK(size >= 0);
234 PP_DCHECK(size < Capacity());
235 if (size < 0 || size > Capacity()) {
236 size_ = 0;
237 return;
240 size_ = size;
243 virtual int32_t Size() const OVERRIDE { return size_; }
245 pp::Buffer_Dev buffer_dev() const { return buffer_; }
247 uint32_t buffer_id() const { return buffer_id_; }
249 private:
250 PpbBuffer(pp::Buffer_Dev buffer, uint32_t buffer_id)
251 : buffer_(buffer),
252 buffer_id_(buffer_id),
253 size_(0) {}
254 virtual ~PpbBuffer() {}
256 pp::Buffer_Dev buffer_;
257 uint32_t buffer_id_;
258 int32_t size_;
260 DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
263 class PpbBufferAllocator {
264 public:
265 explicit PpbBufferAllocator(pp::Instance* instance)
266 : instance_(instance),
267 next_buffer_id_(1) {}
268 ~PpbBufferAllocator() {}
270 cdm::Buffer* Allocate(int32_t capacity);
272 // Releases the buffer with |buffer_id|. A buffer can be recycled after
273 // it is released.
274 void Release(uint32_t buffer_id);
276 private:
277 typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
278 typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> >
279 FreeBufferMap;
281 // Always pad new allocated buffer so that we don't need to reallocate
282 // buffers frequently if requested sizes fluctuate slightly.
283 static const int kBufferPadding = 512;
285 // Maximum number of free buffers we can keep when allocating new buffers.
286 static const int kFreeLimit = 3;
288 pp::Buffer_Dev AllocateNewBuffer(int capacity);
290 pp::Instance* const instance_;
291 uint32_t next_buffer_id_;
292 AllocatedBufferMap allocated_buffers_;
293 FreeBufferMap free_buffers_;
295 DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator);
298 cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) {
299 PP_DCHECK(IsMainThread());
301 if (capacity <= 0)
302 return NULL;
304 pp::Buffer_Dev buffer;
305 uint32_t buffer_id = 0;
307 // Reuse a buffer in the free list if there is one that fits |capacity|.
308 // Otherwise, create a new one.
309 FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity);
310 if (found == free_buffers_.end()) {
311 // TODO(xhwang): Report statistics about how many new buffers are allocated.
312 buffer = AllocateNewBuffer(capacity);
313 if (buffer.is_null())
314 return NULL;
315 buffer_id = next_buffer_id_++;
316 } else {
317 buffer = found->second.second;
318 buffer_id = found->second.first;
319 free_buffers_.erase(found);
322 allocated_buffers_.insert(std::make_pair(buffer_id, buffer));
324 return PpbBuffer::Create(buffer, buffer_id);
327 void PpbBufferAllocator::Release(uint32_t buffer_id) {
328 if (!buffer_id)
329 return;
331 AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id);
332 if (found == allocated_buffers_.end())
333 return;
335 pp::Buffer_Dev& buffer = found->second;
336 free_buffers_.insert(
337 std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer)));
339 allocated_buffers_.erase(found);
342 pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) {
343 // Destroy the smallest buffer before allocating a new bigger buffer if the
344 // number of free buffers exceeds a limit. This mechanism helps avoid ending
345 // up with too many small buffers, which could happen if the size to be
346 // allocated keeps increasing.
347 if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit))
348 free_buffers_.erase(free_buffers_.begin());
350 // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls.
351 // That's why we try to avoid AllocateNewBuffer() as much as we can.
352 return pp::Buffer_Dev(instance_, capacity + kBufferPadding);
355 class DecryptedBlockImpl : public cdm::DecryptedBlock {
356 public:
357 DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {}
358 virtual ~DecryptedBlockImpl() { if (buffer_) buffer_->Destroy(); }
360 virtual void SetDecryptedBuffer(cdm::Buffer* buffer) OVERRIDE {
361 buffer_ = static_cast<PpbBuffer*>(buffer);
363 virtual cdm::Buffer* DecryptedBuffer() OVERRIDE { return buffer_; }
365 virtual void SetTimestamp(int64_t timestamp) OVERRIDE {
366 timestamp_ = timestamp;
368 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; }
370 private:
371 PpbBuffer* buffer_;
372 int64_t timestamp_;
374 DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl);
377 class VideoFrameImpl : public cdm::VideoFrame {
378 public:
379 VideoFrameImpl();
380 virtual ~VideoFrameImpl();
382 virtual void SetFormat(cdm::VideoFormat format) OVERRIDE {
383 format_ = format;
385 virtual cdm::VideoFormat Format() const OVERRIDE { return format_; }
387 virtual void SetSize(cdm::Size size) OVERRIDE { size_ = size; }
388 virtual cdm::Size Size() const OVERRIDE { return size_; }
390 virtual void SetFrameBuffer(cdm::Buffer* frame_buffer) OVERRIDE {
391 frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer);
393 virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; }
395 virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
396 int32_t offset) OVERRIDE {
397 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
398 PP_DCHECK(offset >= 0);
399 plane_offsets_[plane] = offset;
401 virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE {
402 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
403 return plane_offsets_[plane];
406 virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE {
407 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
408 strides_[plane] = stride;
410 virtual int32_t Stride(VideoPlane plane) OVERRIDE {
411 PP_DCHECK(0 <= plane && plane < kMaxPlanes);
412 return strides_[plane];
415 virtual void SetTimestamp(int64_t timestamp) OVERRIDE {
416 timestamp_ = timestamp;
418 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; }
420 private:
421 // The video buffer format.
422 cdm::VideoFormat format_;
424 // Width and height of the video frame.
425 cdm::Size size_;
427 // The video frame buffer.
428 PpbBuffer* frame_buffer_;
430 // Array of data pointers to each plane in the video frame buffer.
431 int32_t plane_offsets_[kMaxPlanes];
433 // Array of strides for each plane, typically greater or equal to the width
434 // of the surface divided by the horizontal sampling period. Note that
435 // strides can be negative.
436 int32_t strides_[kMaxPlanes];
438 // Presentation timestamp in microseconds.
439 int64_t timestamp_;
441 DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl);
444 VideoFrameImpl::VideoFrameImpl()
445 : format_(cdm::kUnknownVideoFormat),
446 frame_buffer_(NULL),
447 timestamp_(0) {
448 for (int32_t i = 0; i < kMaxPlanes; ++i) {
449 plane_offsets_[i] = 0;
450 strides_[i] = 0;
454 VideoFrameImpl::~VideoFrameImpl() {
455 if (frame_buffer_)
456 frame_buffer_->Destroy();
459 class AudioFramesImpl : public cdm::AudioFrames {
460 public:
461 AudioFramesImpl() : buffer_(NULL) {}
462 virtual ~AudioFramesImpl() {
463 if (buffer_)
464 buffer_->Destroy();
467 // AudioFrames implementation.
468 virtual void SetFrameBuffer(cdm::Buffer* buffer) OVERRIDE {
469 buffer_ = static_cast<PpbBuffer*>(buffer);
471 virtual cdm::Buffer* FrameBuffer() OVERRIDE {
472 return buffer_;
475 private:
476 PpbBuffer* buffer_;
478 DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl);
481 // GetCdmHostFunc implementation.
482 void* GetCdmHost(int host_interface_version, void* user_data);
484 // A wrapper class for abstracting away PPAPI interaction and threading for a
485 // Content Decryption Module (CDM).
486 class CdmWrapper : public pp::Instance,
487 public pp::ContentDecryptor_Private,
488 public cdm::Host {
489 public:
490 CdmWrapper(PP_Instance instance, pp::Module* module);
491 virtual ~CdmWrapper();
493 // pp::Instance implementation.
494 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
495 return true;
498 // PPP_ContentDecryptor_Private implementation.
499 // Note: Results of calls to these methods must be reported through the
500 // PPB_ContentDecryptor_Private interface.
501 virtual void GenerateKeyRequest(const std::string& key_system,
502 const std::string& type,
503 pp::VarArrayBuffer init_data) OVERRIDE;
504 virtual void AddKey(const std::string& session_id,
505 pp::VarArrayBuffer key,
506 pp::VarArrayBuffer init_data) OVERRIDE;
507 virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE;
508 virtual void Decrypt(
509 pp::Buffer_Dev encrypted_buffer,
510 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
511 virtual void InitializeAudioDecoder(
512 const PP_AudioDecoderConfig& decoder_config,
513 pp::Buffer_Dev extra_data_buffer) OVERRIDE;
514 virtual void InitializeVideoDecoder(
515 const PP_VideoDecoderConfig& decoder_config,
516 pp::Buffer_Dev extra_data_buffer) OVERRIDE;
517 virtual void DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
518 uint32_t request_id) OVERRIDE;
519 virtual void ResetDecoder(PP_DecryptorStreamType decoder_type,
520 uint32_t request_id) OVERRIDE;
521 virtual void DecryptAndDecode(
522 PP_DecryptorStreamType decoder_type,
523 pp::Buffer_Dev encrypted_buffer,
524 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
526 // cdm::Host implementation.
527 virtual cdm::Buffer* Allocate(int32_t capacity) OVERRIDE;
528 virtual void SetTimer(int64_t delay_ms, void* context) OVERRIDE;
529 virtual double GetCurrentWallTimeInSeconds() OVERRIDE;
530 virtual void SendKeyMessage(
531 const char* session_id, int32_t session_id_length,
532 const char* message, int32_t message_length,
533 const char* default_url, int32_t default_url_length) OVERRIDE;
534 virtual void SendKeyError(const char* session_id,
535 int32_t session_id_length,
536 cdm::MediaKeyError error_code,
537 uint32_t system_code) OVERRIDE;
538 virtual void GetPrivateData(int32_t* instance,
539 GetPrivateInterface* get_interface) OVERRIDE;
541 private:
542 struct SessionInfo {
543 SessionInfo(const std::string& key_system_in,
544 const std::string& session_id_in)
545 : key_system(key_system_in),
546 session_id(session_id_in) {}
547 const std::string key_system;
548 const std::string session_id;
551 typedef linked_ptr<DecryptedBlockImpl> LinkedDecryptedBlock;
552 typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame;
553 typedef linked_ptr<AudioFramesImpl> LinkedAudioFrames;
555 bool CreateCdmInstance(const std::string& key_system);
557 void SendUnknownKeyError(const std::string& key_system,
558 const std::string& session_id);
560 void SendKeyAdded(const std::string& key_system,
561 const std::string& session_id);
563 void SendKeyErrorInternal(const std::string& key_system,
564 const std::string& session_id,
565 cdm::MediaKeyError error_code,
566 uint32_t system_code);
568 // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
569 // <code>callback_factory_</code> to ensure that calls into
570 // <code>PPP_ContentDecryptor_Private</code> are asynchronous.
571 void KeyAdded(int32_t result, const SessionInfo& session_info);
572 void KeyMessage(int32_t result,
573 const SessionInfo& session_info,
574 const std::string& message,
575 const std::string& default_url);
576 void KeyError(int32_t result,
577 const SessionInfo& session_info,
578 cdm::MediaKeyError error_code,
579 uint32_t system_code);
580 void DeliverBlock(int32_t result,
581 const cdm::Status& status,
582 const LinkedDecryptedBlock& decrypted_block,
583 const PP_DecryptTrackingInfo& tracking_info);
584 void DecoderInitializeDone(int32_t result,
585 PP_DecryptorStreamType decoder_type,
586 uint32_t request_id,
587 bool success);
588 void DecoderDeinitializeDone(int32_t result,
589 PP_DecryptorStreamType decoder_type,
590 uint32_t request_id);
591 void DecoderResetDone(int32_t result,
592 PP_DecryptorStreamType decoder_type,
593 uint32_t request_id);
594 void DeliverFrame(int32_t result,
595 const cdm::Status& status,
596 const LinkedVideoFrame& video_frame,
597 const PP_DecryptTrackingInfo& tracking_info);
598 void DeliverSamples(int32_t result,
599 const cdm::Status& status,
600 const LinkedAudioFrames& audio_frames,
601 const PP_DecryptTrackingInfo& tracking_info);
603 // Helper for SetTimer().
604 void TimerExpired(int32_t result, void* context);
606 bool IsValidVideoFrame(const LinkedVideoFrame& video_frame);
608 PpbBufferAllocator allocator_;
609 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_;
610 cdm::ContentDecryptionModule* cdm_;
611 std::string key_system_;
613 DISALLOW_COPY_AND_ASSIGN(CdmWrapper);
616 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module)
617 : pp::Instance(instance),
618 pp::ContentDecryptor_Private(this),
619 allocator_(this),
620 cdm_(NULL) {
621 callback_factory_.Initialize(this);
624 CdmWrapper::~CdmWrapper() {
625 if (cdm_)
626 cdm_->Destroy();
629 bool CdmWrapper::CreateCdmInstance(const std::string& key_system) {
630 PP_DCHECK(!cdm_);
631 cdm_ = static_cast<cdm::ContentDecryptionModule*>(
632 ::CreateCdmInstance(cdm::kCdmInterfaceVersion,
633 key_system.data(), key_system.size(),
634 GetCdmHost, this));
636 return (cdm_ != NULL);
639 void CdmWrapper::GenerateKeyRequest(const std::string& key_system,
640 const std::string& type,
641 pp::VarArrayBuffer init_data) {
642 PP_DCHECK(!key_system.empty());
643 PP_DCHECK(key_system_.empty() || key_system_ == key_system);
645 #if defined(CHECK_ORIGIN_URL)
646 pp::InstancePrivate instance_private(pp_instance());
647 pp::VarPrivate window = instance_private.GetWindowObject();
648 std::string origin = window.GetProperty("top").GetProperty("location")
649 .GetProperty("origin").AsString();
650 PP_DCHECK(origin != "null");
651 #endif // defined(CHECK_ORIGIN_URL)
653 if (!cdm_) {
654 if (!CreateCdmInstance(key_system)) {
655 SendUnknownKeyError(key_system, std::string());
656 return;
659 PP_DCHECK(cdm_);
661 // Must be set here in case the CDM synchronously calls a cdm::Host method.
662 // Clear below on error.
663 // TODO(ddorwin): Set/clear key_system_ & cdm_ at same time; clear both on
664 // error below.
665 key_system_ = key_system;
666 cdm::Status status = cdm_->GenerateKeyRequest(
667 type.data(), type.size(),
668 static_cast<const uint8_t*>(init_data.Map()),
669 init_data.ByteLength());
670 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError);
671 if (status != cdm::kSuccess) {
672 key_system_.clear(); // See comment above.
673 return;
676 key_system_ = key_system;
679 void CdmWrapper::AddKey(const std::string& session_id,
680 pp::VarArrayBuffer key,
681 pp::VarArrayBuffer init_data) {
682 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
683 if (!cdm_) {
684 SendUnknownKeyError(key_system_, session_id);
685 return;
688 const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map());
689 int key_size = key.ByteLength();
690 const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map());
691 int init_data_size = init_data.ByteLength();
692 PP_DCHECK(!init_data_ptr == !init_data_size);
694 if (!key_ptr || key_size <= 0) {
695 SendUnknownKeyError(key_system_, session_id);
696 return;
699 cdm::Status status = cdm_->AddKey(session_id.data(), session_id.size(),
700 key_ptr, key_size,
701 init_data_ptr, init_data_size);
702 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError);
703 if (status != cdm::kSuccess) {
704 SendUnknownKeyError(key_system_, session_id);
705 return;
708 SendKeyAdded(key_system_, session_id);
711 void CdmWrapper::CancelKeyRequest(const std::string& session_id) {
712 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
713 if (!cdm_) {
714 SendUnknownKeyError(key_system_, session_id);
715 return;
718 cdm::Status status = cdm_->CancelKeyRequest(session_id.data(),
719 session_id.size());
720 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError);
721 if (status != cdm::kSuccess)
722 SendUnknownKeyError(key_system_, session_id);
725 // Note: In the following decryption/decoding related functions, errors are NOT
726 // reported via KeyError, but are reported via corresponding PPB calls.
728 void CdmWrapper::Decrypt(pp::Buffer_Dev encrypted_buffer,
729 const PP_EncryptedBlockInfo& encrypted_block_info) {
730 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
731 PP_DCHECK(!encrypted_buffer.is_null());
733 // Release a buffer that the caller indicated it is finished with.
734 allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
736 cdm::Status status = cdm::kDecryptError;
737 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
739 if (cdm_) {
740 cdm::InputBuffer input_buffer;
741 std::vector<cdm::SubsampleEntry> subsamples;
742 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
743 &input_buffer);
744 status = cdm_->Decrypt(input_buffer, decrypted_block.get());
745 PP_DCHECK(status != cdm::kSuccess ||
746 (decrypted_block->DecryptedBuffer() &&
747 decrypted_block->DecryptedBuffer()->Size()));
750 CallOnMain(callback_factory_.NewCallback(
751 &CdmWrapper::DeliverBlock,
752 status,
753 decrypted_block,
754 encrypted_block_info.tracking_info));
757 void CdmWrapper::InitializeAudioDecoder(
758 const PP_AudioDecoderConfig& decoder_config,
759 pp::Buffer_Dev extra_data_buffer) {
760 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
762 cdm::Status status = cdm::kSessionError;
763 if (cdm_) {
764 cdm::AudioDecoderConfig cdm_decoder_config;
765 cdm_decoder_config.codec =
766 PpAudioCodecToCdmAudioCodec(decoder_config.codec);
767 cdm_decoder_config.channel_count = decoder_config.channel_count;
768 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
769 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
770 cdm_decoder_config.extra_data =
771 static_cast<uint8_t*>(extra_data_buffer.data());
772 cdm_decoder_config.extra_data_size =
773 static_cast<int32_t>(extra_data_buffer.size());
774 status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
777 CallOnMain(callback_factory_.NewCallback(
778 &CdmWrapper::DecoderInitializeDone,
779 PP_DECRYPTORSTREAMTYPE_AUDIO,
780 decoder_config.request_id,
781 status == cdm::kSuccess));
784 void CdmWrapper::InitializeVideoDecoder(
785 const PP_VideoDecoderConfig& decoder_config,
786 pp::Buffer_Dev extra_data_buffer) {
787 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
789 cdm::Status status = cdm::kSessionError;
790 if (cdm_) {
791 cdm::VideoDecoderConfig cdm_decoder_config;
792 cdm_decoder_config.codec =
793 PpVideoCodecToCdmVideoCodec(decoder_config.codec);
794 cdm_decoder_config.profile =
795 PpVCProfileToCdmVCProfile(decoder_config.profile);
796 cdm_decoder_config.format =
797 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
798 cdm_decoder_config.coded_size.width = decoder_config.width;
799 cdm_decoder_config.coded_size.height = decoder_config.height;
800 cdm_decoder_config.extra_data =
801 static_cast<uint8_t*>(extra_data_buffer.data());
802 cdm_decoder_config.extra_data_size =
803 static_cast<int32_t>(extra_data_buffer.size());
804 status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
807 CallOnMain(callback_factory_.NewCallback(
808 &CdmWrapper::DecoderInitializeDone,
809 PP_DECRYPTORSTREAMTYPE_VIDEO,
810 decoder_config.request_id,
811 status == cdm::kSuccess));
814 void CdmWrapper::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
815 uint32_t request_id) {
816 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
817 if (cdm_) {
818 cdm_->DeinitializeDecoder(
819 PpDecryptorStreamTypeToCdmStreamType(decoder_type));
822 CallOnMain(callback_factory_.NewCallback(
823 &CdmWrapper::DecoderDeinitializeDone,
824 decoder_type,
825 request_id));
828 void CdmWrapper::ResetDecoder(PP_DecryptorStreamType decoder_type,
829 uint32_t request_id) {
830 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
831 if (cdm_)
832 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
834 CallOnMain(callback_factory_.NewCallback(&CdmWrapper::DecoderResetDone,
835 decoder_type,
836 request_id));
839 void CdmWrapper::DecryptAndDecode(
840 PP_DecryptorStreamType decoder_type,
841 pp::Buffer_Dev encrypted_buffer,
842 const PP_EncryptedBlockInfo& encrypted_block_info) {
843 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded.
845 // Release a buffer that the caller indicated it is finished with.
846 allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
848 cdm::InputBuffer input_buffer;
849 std::vector<cdm::SubsampleEntry> subsamples;
850 if (cdm_ && !encrypted_buffer.is_null()) {
851 ConfigureInputBuffer(encrypted_buffer,
852 encrypted_block_info,
853 &subsamples,
854 &input_buffer);
857 cdm::Status status = cdm::kDecodeError;
859 switch (decoder_type) {
860 case PP_DECRYPTORSTREAMTYPE_VIDEO: {
861 LinkedVideoFrame video_frame(new VideoFrameImpl());
862 if (cdm_)
863 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
864 CallOnMain(callback_factory_.NewCallback(
865 &CdmWrapper::DeliverFrame,
866 status,
867 video_frame,
868 encrypted_block_info.tracking_info));
869 return;
872 case PP_DECRYPTORSTREAMTYPE_AUDIO: {
873 LinkedAudioFrames audio_frames(new AudioFramesImpl());
874 if (cdm_) {
875 status = cdm_->DecryptAndDecodeSamples(input_buffer,
876 audio_frames.get());
878 CallOnMain(callback_factory_.NewCallback(
879 &CdmWrapper::DeliverSamples,
880 status,
881 audio_frames,
882 encrypted_block_info.tracking_info));
883 return;
886 default:
887 PP_NOTREACHED();
888 return;
892 cdm::Buffer* CdmWrapper::Allocate(int32_t capacity) {
893 return allocator_.Allocate(capacity);
896 void CdmWrapper::SetTimer(int64_t delay_ms, void* context) {
897 // NOTE: doesn't really need to run on the main thread; could just as well run
898 // on a helper thread if |cdm_| were thread-friendly and care was taken. We
899 // only use CallOnMainThread() here to get delayed-execution behavior.
900 pp::Module::Get()->core()->CallOnMainThread(
901 delay_ms,
902 callback_factory_.NewCallback(&CdmWrapper::TimerExpired, context),
903 PP_OK);
906 void CdmWrapper::TimerExpired(int32_t result, void* context) {
907 PP_DCHECK(result == PP_OK);
908 cdm_->TimerExpired(context);
911 double CdmWrapper::GetCurrentWallTimeInSeconds() {
912 return pp::Module::Get()->core()->GetTime();
915 void CdmWrapper::SendKeyMessage(
916 const char* session_id, int32_t session_id_length,
917 const char* message, int32_t message_length,
918 const char* default_url, int32_t default_url_length) {
919 PP_DCHECK(!key_system_.empty());
920 PostOnMain(callback_factory_.NewCallback(
921 &CdmWrapper::KeyMessage,
922 SessionInfo(key_system_,
923 std::string(session_id, session_id_length)),
924 std::string(message, message_length),
925 std::string(default_url, default_url_length)));
928 void CdmWrapper::SendKeyError(const char* session_id,
929 int32_t session_id_length,
930 cdm::MediaKeyError error_code,
931 uint32_t system_code) {
932 SendKeyErrorInternal(key_system_,
933 std::string(session_id, session_id_length),
934 error_code,
935 system_code);
938 void CdmWrapper::GetPrivateData(int32_t* instance,
939 cdm::Host::GetPrivateInterface* get_interface) {
940 *instance = pp_instance();
941 *get_interface = pp::Module::Get()->get_browser_interface();
944 void CdmWrapper::SendUnknownKeyError(const std::string& key_system,
945 const std::string& session_id) {
946 SendKeyErrorInternal(key_system, session_id, cdm::kUnknownError, 0);
949 void CdmWrapper::SendKeyAdded(const std::string& key_system,
950 const std::string& session_id) {
951 PostOnMain(callback_factory_.NewCallback(
952 &CdmWrapper::KeyAdded,
953 SessionInfo(key_system_, session_id)));
956 void CdmWrapper::SendKeyErrorInternal(const std::string& key_system,
957 const std::string& session_id,
958 cdm::MediaKeyError error_code,
959 uint32_t system_code) {
960 PP_DCHECK(!key_system.empty());
961 PostOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError,
962 SessionInfo(key_system_, session_id),
963 error_code,
964 system_code));
967 void CdmWrapper::KeyAdded(int32_t result, const SessionInfo& session_info) {
968 PP_DCHECK(result == PP_OK);
969 PP_DCHECK(!session_info.key_system.empty());
970 pp::ContentDecryptor_Private::KeyAdded(session_info.key_system,
971 session_info.session_id);
974 void CdmWrapper::KeyMessage(int32_t result,
975 const SessionInfo& session_info,
976 const std::string& message,
977 const std::string& default_url) {
978 PP_DCHECK(result == PP_OK);
979 PP_DCHECK(!session_info.key_system.empty());
981 pp::VarArrayBuffer message_array_buffer(message.size());
982 if (message.size() > 0) {
983 memcpy(message_array_buffer.Map(), message.data(), message.size());
986 pp::ContentDecryptor_Private::KeyMessage(
987 session_info.key_system, session_info.session_id,
988 message_array_buffer, default_url);
991 void CdmWrapper::KeyError(int32_t result,
992 const SessionInfo& session_info,
993 cdm::MediaKeyError error_code,
994 uint32_t system_code) {
995 PP_DCHECK(result == PP_OK);
996 PP_DCHECK(!session_info.key_system.empty());
997 pp::ContentDecryptor_Private::KeyError(
998 session_info.key_system, session_info.session_id,
999 error_code, system_code);
1002 void CdmWrapper::DeliverBlock(int32_t result,
1003 const cdm::Status& status,
1004 const LinkedDecryptedBlock& decrypted_block,
1005 const PP_DecryptTrackingInfo& tracking_info) {
1006 PP_DCHECK(result == PP_OK);
1007 PP_DecryptedBlockInfo decrypted_block_info;
1008 decrypted_block_info.tracking_info = tracking_info;
1009 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
1010 decrypted_block_info.tracking_info.buffer_id = 0;
1011 decrypted_block_info.data_size = 0;
1012 decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
1014 pp::Buffer_Dev buffer;
1016 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
1017 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
1018 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
1019 PP_NOTREACHED();
1020 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
1021 } else {
1022 PpbBuffer* ppb_buffer =
1023 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
1024 buffer = ppb_buffer->buffer_dev();
1025 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
1026 decrypted_block_info.data_size = ppb_buffer->Size();
1030 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
1033 void CdmWrapper::DecoderInitializeDone(int32_t result,
1034 PP_DecryptorStreamType decoder_type,
1035 uint32_t request_id,
1036 bool success) {
1037 PP_DCHECK(result == PP_OK);
1038 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
1039 request_id,
1040 success);
1043 void CdmWrapper::DecoderDeinitializeDone(int32_t result,
1044 PP_DecryptorStreamType decoder_type,
1045 uint32_t request_id) {
1046 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
1047 request_id);
1050 void CdmWrapper::DecoderResetDone(int32_t result,
1051 PP_DecryptorStreamType decoder_type,
1052 uint32_t request_id) {
1053 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
1056 void CdmWrapper::DeliverFrame(
1057 int32_t result,
1058 const cdm::Status& status,
1059 const LinkedVideoFrame& video_frame,
1060 const PP_DecryptTrackingInfo& tracking_info) {
1061 PP_DCHECK(result == PP_OK);
1062 PP_DecryptedFrameInfo decrypted_frame_info;
1063 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
1064 decrypted_frame_info.tracking_info.buffer_id = 0;
1065 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
1067 pp::Buffer_Dev buffer;
1069 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
1070 if (!IsValidVideoFrame(video_frame)) {
1071 PP_NOTREACHED();
1072 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
1073 } else {
1074 PpbBuffer* ppb_buffer =
1075 static_cast<PpbBuffer*>(video_frame->FrameBuffer());
1077 buffer = ppb_buffer->buffer_dev();
1079 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
1080 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
1081 decrypted_frame_info.format =
1082 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
1083 decrypted_frame_info.width = video_frame->Size().width;
1084 decrypted_frame_info.height = video_frame->Size().height;
1085 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
1086 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
1087 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
1088 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
1089 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
1090 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
1091 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
1092 video_frame->Stride(cdm::VideoFrame::kYPlane);
1093 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
1094 video_frame->Stride(cdm::VideoFrame::kUPlane);
1095 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
1096 video_frame->Stride(cdm::VideoFrame::kVPlane);
1099 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
1102 void CdmWrapper::DeliverSamples(int32_t result,
1103 const cdm::Status& status,
1104 const LinkedAudioFrames& audio_frames,
1105 const PP_DecryptTrackingInfo& tracking_info) {
1106 PP_DCHECK(result == PP_OK);
1108 PP_DecryptedBlockInfo decrypted_block_info;
1109 decrypted_block_info.tracking_info = tracking_info;
1110 decrypted_block_info.tracking_info.timestamp = 0;
1111 decrypted_block_info.tracking_info.buffer_id = 0;
1112 decrypted_block_info.data_size = 0;
1113 decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
1115 pp::Buffer_Dev buffer;
1117 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
1118 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
1119 if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
1120 PP_NOTREACHED();
1121 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
1122 } else {
1123 PpbBuffer* ppb_buffer =
1124 static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
1125 buffer = ppb_buffer->buffer_dev();
1126 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
1127 decrypted_block_info.data_size = ppb_buffer->Size();
1131 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info);
1134 bool CdmWrapper::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
1135 if (!video_frame.get() ||
1136 !video_frame->FrameBuffer() ||
1137 (video_frame->Format() != cdm::kI420 &&
1138 video_frame->Format() != cdm::kYv12)) {
1139 return false;
1142 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
1144 for (int i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
1145 int plane_height = (i == cdm::VideoFrame::kYPlane) ?
1146 video_frame->Size().height : (video_frame->Size().height + 1) / 2;
1147 cdm::VideoFrame::VideoPlane plane =
1148 static_cast<cdm::VideoFrame::VideoPlane>(i);
1149 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
1150 plane_height * video_frame->Stride(plane)) {
1151 return false;
1155 return true;
1158 void* GetCdmHost(int host_interface_version, void* user_data) {
1159 if (!host_interface_version || !user_data)
1160 return NULL;
1162 if (host_interface_version != cdm::kHostInterfaceVersion)
1163 return NULL;
1165 CdmWrapper* cdm_wrapper = static_cast<CdmWrapper*>(user_data);
1166 return static_cast<cdm::Host*>(cdm_wrapper);
1169 // This object is the global object representing this plugin library as long
1170 // as it is loaded.
1171 class CdmWrapperModule : public pp::Module {
1172 public:
1173 CdmWrapperModule() : pp::Module() {
1174 // This function blocks the renderer thread (PluginInstance::Initialize()).
1175 // Move this call to other places if this may be a concern in the future.
1176 INITIALIZE_CDM_MODULE();
1178 virtual ~CdmWrapperModule() {
1179 DeinitializeCdmModule();
1182 virtual pp::Instance* CreateInstance(PP_Instance instance) {
1183 return new CdmWrapper(instance, this);
1187 } // namespace webkit_media
1189 namespace pp {
1191 // Factory function for your specialization of the Module object.
1192 Module* CreateModule() {
1193 return new webkit_media::CdmWrapperModule();
1196 } // namespace pp