Chromium Code Reviews| Index: webkit/media/crypto/ppapi/cdm_wrapper.cc |
| diff --git a/webkit/media/crypto/ppapi/cdm_wrapper.cc b/webkit/media/crypto/ppapi/cdm_wrapper.cc |
| index 9098065b8632036f726f6e0c0c8b3dc02bf565e0..066c5bf9dff1741efb537cb50e0303b5a40fd2a1 100644 |
| --- a/webkit/media/crypto/ppapi/cdm_wrapper.cc |
| +++ b/webkit/media/crypto/ppapi/cdm_wrapper.cc |
| @@ -2,10 +2,12 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include <cstring> // For memcpy. |
| +#include <cstring> |
| +#include <string> |
| #include <vector> |
| -#include "base/compiler_specific.h" // For OVERRIDE. |
| +#include "base/basictypes.h" |
| +#include "base/compiler_specific.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/c/pp_stdint.h" |
| #include "ppapi/c/private/pp_content_decryptor.h" |
| @@ -21,6 +23,7 @@ |
| #include "ppapi/cpp/dev/buffer_dev.h" |
| #include "ppapi/cpp/private/content_decryptor_private.h" |
| #include "ppapi/utility/completion_callback_factory.h" |
| +#include "webkit/media/crypto/ppapi/linked_ptr.h" |
| #include "webkit/media/crypto/ppapi/content_decryption_module.h" |
| namespace { |
| @@ -55,6 +58,151 @@ void CallOnMain(pp::CompletionCallback cb) { |
| namespace webkit_media { |
| +// Provides access to memory owned by a pp::Buffer_Dev created by |
| +// PpbBufferAllocator::Allocate(). This class holds a reference to the |
| +// Buffer_Dev throughout its lifetime. |
| +class PpbBuffer : public cdm::Buffer { |
| + public: |
| + // cdm::Buffer methods. |
| + void Destroy() OVERRIDE { delete this; } |
|
ddorwin
2012/09/18 04:53:14
These 3 should be virtual.
Tom Finegan
2012/09/18 06:02:31
Done. Ugh.. can't believe I didn't notice that.
|
| + uint8_t* buffer() OVERRIDE { return static_cast<uint8_t*>(buffer_.data()); } |
| + int32_t size() const OVERRIDE { return buffer_.size(); } |
| + |
| + pp::Buffer_Dev buffer_dev() const { return buffer_; } |
| + |
| + private: |
| + explicit PpbBuffer(pp::Buffer_Dev buffer) : buffer_(buffer) {} |
| + virtual ~PpbBuffer() {} |
| + |
| + pp::Buffer_Dev buffer_; |
| + |
| + friend class PpbBufferAllocator; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PpbBuffer); |
| +}; |
| + |
| +class PpbBufferAllocator : public cdm::Allocator { |
| + public: |
| + explicit PpbBufferAllocator(pp::Instance* instance); |
| + virtual ~PpbBufferAllocator(); |
| + |
| + // cdm::Allocator methods. |
| + // Allocates a pp::Buffer_Dev of the specified size and wraps it in a |
| + // PpbBuffer, which it returns. The caller own the returned buffer and must |
| + // free it by calling ReleaseBuffer(). Returns NULL on failure. |
| + virtual cdm::Buffer* Allocate(int32_t size) OVERRIDE; |
| + |
| + private: |
| + pp::Instance* const instance_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator); |
| +}; |
| + |
| +class KeyMessageImpl : public cdm::KeyMessage { |
| + public: |
| + KeyMessageImpl() : message_(NULL) {} |
| + virtual ~KeyMessageImpl(); |
| + |
| + // cdm::KeyMessage methods. |
| + virtual void set_session_id(const char* session_id, int32_t length) OVERRIDE; |
| + virtual const char* session_id() const OVERRIDE; |
| + virtual int32_t session_id_length() const OVERRIDE; |
| + |
| + virtual void set_message(cdm::Buffer* message) OVERRIDE; |
| + virtual cdm::Buffer* message() const OVERRIDE; |
| + |
| + virtual void set_default_url(const char* default_url, |
| + int32_t length) OVERRIDE; |
| + virtual const char* default_url() const OVERRIDE; |
| + virtual int32_t default_url_length() const OVERRIDE; |
| + |
| + std::string session_id_string() const { return session_id_; } |
| + std::string default_url_string() const { return default_url_; } |
| + |
| + private: |
| + PpbBuffer* message_; |
| + std::string session_id_; |
| + std::string default_url_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(KeyMessageImpl); |
| +}; |
| + |
| +class OutputBufferImpl : public cdm::OutputBuffer { |
| + public: |
| + OutputBufferImpl() : buffer_(NULL), timestamp_(0) {} |
| + virtual ~OutputBufferImpl(); |
| + |
| + virtual void set_buffer(cdm::Buffer* buffer) OVERRIDE; |
| + virtual cdm::Buffer* buffer() const OVERRIDE; |
| + |
| + virtual void set_timestamp(int64_t timestamp) OVERRIDE; |
| + virtual int64_t timestamp() const OVERRIDE; |
| + |
| + private: |
| + PpbBuffer* buffer_; |
| + int64_t timestamp_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(OutputBufferImpl); |
| +}; |
| + |
| +KeyMessageImpl::~KeyMessageImpl() { |
| + if (message_) |
| + message_->Destroy(); |
| +} |
| + |
| +void KeyMessageImpl::set_session_id(const char* session_id, int32_t length) { |
| + session_id_.assign(session_id, length); |
| +} |
| + |
| +const char* KeyMessageImpl::session_id() const { |
| + return session_id_.c_str(); |
| +} |
| + |
| +int32_t KeyMessageImpl::session_id_length() const { |
| + return session_id_.length(); |
| +} |
| + |
| +void KeyMessageImpl::set_message(cdm::Buffer* buffer) { |
| + message_ = static_cast<PpbBuffer*>(buffer); |
| +} |
| + |
| +cdm::Buffer* KeyMessageImpl::message() const { |
| + return message_; |
| +} |
| + |
| +void KeyMessageImpl::set_default_url(const char* default_url, int32_t length) { |
| + default_url_.assign(default_url, length); |
| +} |
| + |
| +const char* KeyMessageImpl::default_url() const { |
| + return default_url_.c_str(); |
| +} |
| + |
| +int32_t KeyMessageImpl::default_url_length() const { |
| + return default_url_.length(); |
| +} |
| + |
| +OutputBufferImpl::~OutputBufferImpl() { |
| + if (buffer_) |
| + buffer_->Destroy(); |
| +} |
| + |
| +void OutputBufferImpl::set_buffer(cdm::Buffer* buffer) { |
| + buffer_ = static_cast<PpbBuffer*>(buffer); |
| +} |
| + |
| +cdm::Buffer* OutputBufferImpl::buffer() const { |
| + return buffer_; |
| +} |
| + |
| +void OutputBufferImpl::set_timestamp(int64_t timestamp) { |
| + timestamp_ = timestamp; |
| +} |
| + |
| +int64_t OutputBufferImpl::timestamp() const { |
| + return timestamp_; |
| +} |
| + |
| // A wrapper class for abstracting away PPAPI interaction and threading for a |
| // Content Decryption Module (CDM). |
| class CdmWrapper : public pp::Instance, |
| @@ -62,7 +210,6 @@ class CdmWrapper : public pp::Instance, |
| public: |
| CdmWrapper(PP_Instance instance, pp::Module* module); |
| virtual ~CdmWrapper(); |
| - |
| virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
| return true; |
| } |
| @@ -86,31 +233,47 @@ class CdmWrapper : public pp::Instance, |
| const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; |
| private: |
| - // Creates a PP_Resource containing a PPB_Buffer_Impl, copies |data| into the |
| - // buffer resource, and returns it. Returns a an invalid PP_Resource with an |
| - // ID of 0 on failure. Upon success, the returned Buffer resource has a |
| - // reference count of 1. |
| - pp::Buffer_Dev MakeBufferResource(const uint8_t* data, uint32_t data_size); |
| + typedef linked_ptr<KeyMessageImpl> LinkedKeyMessage; |
| + typedef linked_ptr<OutputBufferImpl> LinkedOutputBuffer; |
| // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to |
| // <code>callback_factory_</code> to ensure that calls into |
| // <code>PPP_ContentDecryptor_Private</code> are asynchronous. |
| void KeyAdded(int32_t result, const std::string& session_id); |
| - void KeyMessage(int32_t result, cdm::KeyMessage& key_message); |
| + void KeyMessage(int32_t result, const LinkedKeyMessage& message); |
| void KeyError(int32_t result, const std::string& session_id); |
| void DeliverBlock(int32_t result, |
| const cdm::Status& status, |
| - cdm::OutputBuffer& output_buffer, |
| + const LinkedOutputBuffer& output_buffer, |
| const PP_DecryptTrackingInfo& tracking_info); |
| + PpbBufferAllocator allocator_; |
| pp::CompletionCallbackFactory<CdmWrapper> callback_factory_; |
| cdm::ContentDecryptionModule* cdm_; |
| std::string key_system_; |
| }; |
| +PpbBufferAllocator::PpbBufferAllocator(pp::Instance* instance) |
| + : instance_(instance) { |
| +} |
| + |
| +PpbBufferAllocator::~PpbBufferAllocator() { |
| +} |
| + |
| +cdm::Buffer* PpbBufferAllocator::Allocate(int32_t size) { |
| + PP_DCHECK(size > 0); |
| + |
| + pp::Buffer_Dev buffer(instance_, size); |
| + if (buffer.is_null()) |
| + return NULL; |
| + |
| + return new PpbBuffer(buffer); |
| +} |
| + |
| CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module) |
| : pp::Instance(instance), |
| pp::ContentDecryptor_Private(this), |
| + allocator_(this), |
| cdm_(NULL) { |
| callback_factory_.Initialize(this); |
| } |
| @@ -125,20 +288,20 @@ void CdmWrapper::GenerateKeyRequest(const std::string& key_system, |
| PP_DCHECK(!key_system.empty()); |
| if (!cdm_) { |
| - cdm_ = CreateCdmInstance(); |
| + cdm_ = CreateCdmInstance(&allocator_); |
| if (!cdm_) |
| return; |
| } |
| - cdm::KeyMessage key_request; |
| + LinkedKeyMessage key_request(new KeyMessageImpl()); |
| cdm::Status status = cdm_->GenerateKeyRequest( |
| reinterpret_cast<const uint8_t*>(init_data.Map()), |
| init_data.ByteLength(), |
| - &key_request); |
| + key_request.get()); |
| if (status != cdm::kSuccess || |
| - !key_request.message || |
| - key_request.message_size == 0) { |
| + !key_request->message() || |
| + key_request->message()->size() == 0) { |
| CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError, |
| std::string())); |
| return; |
| @@ -224,9 +387,16 @@ void CdmWrapper::Decrypt(pp::Buffer_Dev encrypted_buffer, |
| input_buffer.timestamp = encrypted_block_info.tracking_info.timestamp; |
| - cdm::OutputBuffer output_buffer; |
| - cdm::Status status = cdm_->Decrypt(input_buffer, &output_buffer); |
| + LinkedOutputBuffer output_buffer(new OutputBufferImpl()); |
| + cdm::Status status = cdm_->Decrypt(input_buffer, output_buffer.get()); |
| + if (status != cdm::kSuccess || !output_buffer->buffer()) { |
| + CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError, |
| + std::string())); |
| + return; |
| + } |
| + |
| + PP_DCHECK(output_buffer->buffer()); |
| CallOnMain(callback_factory_.NewCallback( |
| &CdmWrapper::DeliverBlock, |
| status, |
| @@ -239,41 +409,19 @@ void CdmWrapper::DecryptAndDecode( |
| const PP_EncryptedBlockInfo& encrypted_block_info) { |
| } |
| -pp::Buffer_Dev CdmWrapper::MakeBufferResource(const uint8_t* data, |
| - uint32_t data_size) { |
| - if (!data || !data_size) |
| - return pp::Buffer_Dev(); |
| - |
| - pp::Buffer_Dev buffer(this, data_size); |
| - if (!buffer.data()) |
| - return pp::Buffer_Dev(); |
| - |
| - memcpy(buffer.data(), data, data_size); |
| - return buffer; |
| -} |
| - |
| void CdmWrapper::KeyAdded(int32_t result, const std::string& session_id) { |
| pp::ContentDecryptor_Private::KeyAdded(key_system_, session_id); |
| } |
| void CdmWrapper::KeyMessage(int32_t result, |
| - cdm::KeyMessage& key_message) { |
| - pp::Buffer_Dev message_buffer(MakeBufferResource(key_message.message, |
| - key_message.message_size)); |
| + const LinkedKeyMessage& key_message) { |
| + pp::Buffer_Dev message_buffer = |
| + static_cast<const PpbBuffer*>(key_message->message())->buffer_dev(); |
| pp::ContentDecryptor_Private::KeyMessage( |
| key_system_, |
| - std::string(key_message.session_id, key_message.session_id_size), |
| + key_message->session_id_string(), |
| message_buffer, |
| - std::string(key_message.default_url, key_message.default_url_size)); |
| - |
| - // TODO(xhwang): Fix this. This is not always safe as the memory is allocated |
| - // in another shared object. |
| - delete [] key_message.session_id; |
| - key_message.session_id = NULL; |
| - delete [] key_message.message; |
| - key_message.message = NULL; |
| - delete [] key_message.default_url; |
| - key_message.default_url = NULL; |
| + key_message->default_url_string()); |
| } |
| // TODO(xhwang): Support MediaKeyError (see spec: http://goo.gl/rbdnR) in CDM |
| @@ -287,13 +435,11 @@ void CdmWrapper::KeyError(int32_t result, const std::string& session_id) { |
| void CdmWrapper::DeliverBlock(int32_t result, |
| const cdm::Status& status, |
| - cdm::OutputBuffer& output_buffer, |
| + const LinkedOutputBuffer& output_buffer, |
| const PP_DecryptTrackingInfo& tracking_info) { |
| - pp::Buffer_Dev decrypted_buffer(MakeBufferResource(output_buffer.data, |
| - output_buffer.data_size)); |
| PP_DecryptedBlockInfo decrypted_block_info; |
| decrypted_block_info.tracking_info.request_id = tracking_info.request_id; |
| - decrypted_block_info.tracking_info.timestamp = output_buffer.timestamp; |
| + decrypted_block_info.tracking_info.timestamp = output_buffer->timestamp(); |
| switch (status) { |
| case cdm::kSuccess: |
| @@ -306,21 +452,17 @@ void CdmWrapper::DeliverBlock(int32_t result, |
| decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; |
| } |
| - pp::ContentDecryptor_Private::DeliverBlock(decrypted_buffer, |
| - decrypted_block_info); |
| - |
| - // TODO(xhwang): Fix this. This is not always safe as the memory is allocated |
| - // in another shared object. |
| - delete [] output_buffer.data; |
| - output_buffer.data = NULL; |
| + pp::ContentDecryptor_Private::DeliverBlock( |
| + static_cast<PpbBuffer*>(output_buffer->buffer())->buffer_dev(), |
| + decrypted_block_info); |
| } |
| // This object is the global object representing this plugin library as long |
| // as it is loaded. |
| -class MyModule : public pp::Module { |
| +class CdmWrapperModule : public pp::Module { |
| public: |
| - MyModule() : pp::Module() {} |
| - virtual ~MyModule() {} |
| + CdmWrapperModule() : pp::Module() {} |
| + virtual ~CdmWrapperModule() {} |
| virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| return new CdmWrapper(instance, this); |
| @@ -333,7 +475,7 @@ namespace pp { |
| // Factory function for your specialization of the Module object. |
| Module* CreateModule() { |
| - return new webkit_media::MyModule(); |
| + return new webkit_media::CdmWrapperModule(); |
| } |
| } // namespace pp |