| 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 ef9afddc39fa755ae0abfc35821f05ba2d6cd628..8300171af8cdac37082c92f3c6f783c0f8020245 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,155 @@ 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.
|
| + virtual void Destroy() OVERRIDE { delete this; }
|
| +
|
| + virtual uint8_t* buffer() OVERRIDE {
|
| + return static_cast<uint8_t*>(buffer_.data());
|
| + }
|
| +
|
| + virtual 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 +214,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 +237,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 +292,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;
|
| @@ -222,9 +389,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,
|
| @@ -237,41 +411,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
|
| @@ -285,13 +437,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:
|
| @@ -304,21 +454,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);
|
| @@ -331,7 +477,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
|
|
|