summaryrefslogtreecommitdiffstats
path: root/webkit/media
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-28 18:57:40 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-28 18:57:40 +0000
commitd341e33493ca212af3fa5947afa5fcfaef76503e (patch)
treecd05fbde518ad841003327b04c7b45c6d33d31eb /webkit/media
parenta224c54fa4fc25f8f51c285b510cd850a2c48472 (diff)
downloadchromium_src-d341e33493ca212af3fa5947afa5fcfaef76503e.zip
chromium_src-d341e33493ca212af3fa5947afa5fcfaef76503e.tar.gz
chromium_src-d341e33493ca212af3fa5947afa5fcfaef76503e.tar.bz2
Hook up CDM calls in CdmWrapper.
Updated pp::ContentDecryptor_Private methods in CdmWrapper to call into the CDM. Also updated the event firing through pp::ContentDecryptor_Private interface in CdmWrapper. BUG=138139 TEST=none Review URL: https://chromiumcodereview.appspot.com/10876014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153704 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/media')
-rw-r--r--webkit/media/crypto/key_systems.cc2
-rw-r--r--webkit/media/crypto/ppapi/cdm_wrapper.cc345
-rw-r--r--webkit/media/crypto/ppapi/content_decryption_module.h44
3 files changed, 255 insertions, 136 deletions
diff --git a/webkit/media/crypto/key_systems.cc b/webkit/media/crypto/key_systems.cc
index 11a307c..b85c9c4 100644
--- a/webkit/media/crypto/key_systems.cc
+++ b/webkit/media/crypto/key_systems.cc
@@ -48,7 +48,7 @@ supported_format_key_system_combinations[] = {
static const KeySystemPluginTypePair key_system_to_plugin_type_mapping[] = {
// TODO(xhwang): Update this with the real plugin name.
- { kExternalClearKeyKeySystem, "application/x-ppapi-example" }
+ { kExternalClearKeyKeySystem, "application/x-ppapi-clearkey-cdm" }
};
static bool IsSupportedKeySystemWithContainerAndCodec(
diff --git a/webkit/media/crypto/ppapi/cdm_wrapper.cc b/webkit/media/crypto/ppapi/cdm_wrapper.cc
index 8faee29..88baa44 100644
--- a/webkit/media/crypto/ppapi/cdm_wrapper.cc
+++ b/webkit/media/crypto/ppapi/cdm_wrapper.cc
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <cstring> // For std::memcpy.
+#include <cstring> // For memcpy.
+#include <vector>
#include "base/compiler_specific.h" // For OVERRIDE.
#include "ppapi/c/pp_errors.h"
@@ -20,27 +21,21 @@
#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/content_decryption_module.h"
namespace {
-struct DecryptorMessage {
- DecryptorMessage() : media_error(0), system_code(0) {}
- std::string key_system;
- std::string session_id;
- std::string default_url;
- std::string message_data;
- int32_t media_error;
- int32_t system_code;
-};
-
-struct DecryptedBlock {
- DecryptedBlock() {
- std::memset(reinterpret_cast<void*>(&decrypted_block_info),
- 0,
- sizeof(decrypted_block_info));
- }
- std::string decrypted_data;
- PP_DecryptedBlockInfo decrypted_block_info;
+// This must be consistent with MediaKeyError defined in the spec:
+// http://goo.gl/rbdnR
+// TODO(xhwang): Add PP_MediaKeyError enum to avoid later static_cast in
+// PluginInstance.
+enum MediaKeyError {
+ kUnknownError = 1,
+ kClientError,
+ kServiceError,
+ kOutputError,
+ kHardwareChangeError,
+ kDomainError
};
bool IsMainThread() {
@@ -58,16 +53,25 @@ void CallOnMain(pp::CompletionCallback cb) {
} // namespace
+namespace webkit_media {
// A wrapper class for abstracting away PPAPI interaction and threading for a
// Content Decryption Module (CDM).
-class CDMWrapper : public pp::Instance,
+class CdmWrapper : public pp::Instance,
public pp::ContentDecryptor_Private {
public:
- CDMWrapper(PP_Instance instance, pp::Module* module);
- virtual ~CDMWrapper() {}
+ CdmWrapper(PP_Instance instance, pp::Module* module);
+ virtual ~CdmWrapper();
+
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
+ return true;
+ }
// PPP_ContentDecryptor_Private methods
+ // Note: As per comments in PPP_ContentDecryptor_Private, these calls should
+ // return false if the call was not forwarded to the CDM and should return
+ // true otherwise. Once the call reaches the CDM, the call result/status
+ // should be reported through the PPB_ContentDecryptor_Private interface.
virtual bool GenerateKeyRequest(const std::string& key_system,
pp::VarArrayBuffer init_data) OVERRIDE;
virtual bool AddKey(const std::string& session_id,
@@ -77,163 +81,244 @@ class CDMWrapper : public pp::Instance,
virtual bool Decrypt(
pp::Buffer_Dev encrypted_buffer,
const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
-
virtual bool DecryptAndDecode(
pp::Buffer_Dev encrypted_buffer,
- const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE {
- return false;
- }
-
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
- return true;
- }
+ const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
private:
- PP_Resource StringToBufferResource(const std::string& str);
+ // 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_Resource MakeBufferResource(const uint8_t* data, uint32_t data_size);
// <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 NeedKey(int32_t result, const DecryptorMessage& decryptor_message);
- void KeyAdded(int32_t result, const DecryptorMessage& decryptor_message);
- void KeyMessage(int32_t result, const DecryptorMessage& decryptor_message);
- void KeyError(int32_t result, const DecryptorMessage& decryptor_message);
- void DeliverBlock(int32_t result, const DecryptedBlock& decrypted_block);
-
- pp::CompletionCallbackFactory<CDMWrapper> callback_factory_;
+ void KeyAdded(int32_t result, const std::string& session_id);
+ void KeyMessage(int32_t result, cdm::KeyMessage& key_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 PP_DecryptTrackingInfo& tracking_info);
+
+ pp::CompletionCallbackFactory<CdmWrapper> callback_factory_;
+ cdm::ContentDecryptionModule* cdm_;
+ std::string key_system_;
};
-CDMWrapper::CDMWrapper(PP_Instance instance,
- pp::Module* module)
+CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module)
: pp::Instance(instance),
- pp::ContentDecryptor_Private(this) {
+ pp::ContentDecryptor_Private(this),
+ cdm_(NULL) {
callback_factory_.Initialize(this);
}
-bool CDMWrapper::GenerateKeyRequest(const std::string& key_system,
+CdmWrapper::~CdmWrapper() {
+ if (cdm_)
+ DestroyCdmInstance(cdm_);
+}
+
+bool CdmWrapper::GenerateKeyRequest(const std::string& key_system,
pp::VarArrayBuffer init_data) {
- PP_DCHECK(!key_system.empty() && init_data.ByteLength());
+ PP_DCHECK(!key_system.empty());
+
+ if (!cdm_) {
+ cdm_ = CreateCdmInstance();
+ if (!cdm_)
+ return false;
+ }
- DecryptorMessage decryptor_message;
- decryptor_message.key_system = key_system;
- decryptor_message.session_id = "0";
- decryptor_message.default_url = "http://www.google.com";
- decryptor_message.message_data = "GenerateKeyRequest";
+ cdm::KeyMessage key_request;
+ cdm::Status status = cdm_->GenerateKeyRequest(
+ reinterpret_cast<const uint8_t*>(init_data.Map()),
+ init_data.ByteLength(),
+ &key_request);
+
+ if (status != cdm::kSuccess ||
+ !key_request.message ||
+ key_request.message_size == 0) {
+ CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError,
+ std::string()));
+ return true;
+ }
+
+ // TODO(xhwang): Remove unnecessary CallOnMain calls here and below once we
+ // only support out-of-process.
+ // If running out-of-process, PPB calls will always behave asynchronously
+ // since IPC is involved. In that case, if we are already on main thread,
+ // we don't need to use CallOnMain to help us call PPB call on main thread,
+ // or to help call PPB asynchronously.
+ key_system_ = key_system;
+ CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyMessage,
+ key_request));
- CallOnMain(callback_factory_.NewCallback(&CDMWrapper::KeyMessage,
- decryptor_message));
return true;
}
-bool CDMWrapper::AddKey(const std::string& session_id,
+bool CdmWrapper::AddKey(const std::string& session_id,
pp::VarArrayBuffer key,
pp::VarArrayBuffer init_data) {
- const std::string key_string(reinterpret_cast<char*>(key.Map()),
- key.ByteLength());
- const std::string init_data_string(reinterpret_cast<char*>(init_data.Map()),
- init_data.ByteLength());
-
- PP_DCHECK(!session_id.empty() && !key_string.empty());
-
- DecryptorMessage decryptor_message;
- decryptor_message.key_system = "AddKey";
- decryptor_message.session_id = "0";
- decryptor_message.default_url = "http://www.google.com";
- decryptor_message.message_data = "AddKey";
- CallOnMain(callback_factory_.NewCallback(&CDMWrapper::KeyAdded,
- decryptor_message));
+ const uint8_t* key_ptr = reinterpret_cast<const uint8_t*>(key.Map());
+ int key_size = key.ByteLength();
+ const uint8_t* init_data_ptr =
+ reinterpret_cast<const uint8_t*>(init_data.Map());
+ int init_data_size = init_data.ByteLength();
+
+ if (!key_ptr || key_size <= 0 || !init_data_ptr || init_data_size <= 0)
+ return false;
+
+ PP_DCHECK(cdm_);
+ cdm::Status status = cdm_->AddKey(session_id.data(), session_id.size(),
+ key_ptr, key_size,
+ init_data_ptr, init_data_size);
+
+ if (status != cdm::kSuccess) {
+ CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError,
+ session_id));
+ return true;
+ }
+
+ CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyAdded, session_id));
return true;
}
-bool CDMWrapper::CancelKeyRequest(const std::string& session_id) {
- // TODO(tomfinegan): cancel pending key request in CDM.
+bool CdmWrapper::CancelKeyRequest(const std::string& session_id) {
+ PP_DCHECK(cdm_);
- PP_DCHECK(!session_id.empty());
+ cdm::Status status = cdm_->CancelKeyRequest(session_id.data(),
+ session_id.size());
- DecryptorMessage decryptor_message;
- decryptor_message.key_system = "CancelKeyRequest";
- decryptor_message.session_id = "0";
- decryptor_message.default_url = "http://www.google.com";
- decryptor_message.message_data = "CancelKeyRequest";
+ if (status != cdm::kSuccess) {
+ CallOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError,
+ session_id));
+ return true;
+ }
- CallOnMain(callback_factory_.NewCallback(&CDMWrapper::KeyMessage,
- decryptor_message));
return true;
}
-bool CDMWrapper::Decrypt(pp::Buffer_Dev encrypted_buffer,
+bool CdmWrapper::Decrypt(pp::Buffer_Dev encrypted_buffer,
const PP_EncryptedBlockInfo& encrypted_block_info) {
PP_DCHECK(!encrypted_buffer.is_null());
+ PP_DCHECK(cdm_);
+
+ // TODO(xhwang): Simplify the following data conversion.
+ cdm::InputBuffer input_buffer;
+ input_buffer.data = reinterpret_cast<uint8_t*>(encrypted_buffer.data());
+ input_buffer.data_size = encrypted_buffer.size();
+ input_buffer.data_offset = encrypted_block_info.data_offset;
+ input_buffer.key_id = encrypted_block_info.key_id;
+ input_buffer.key_id_size = encrypted_block_info.key_id_size;
+ input_buffer.iv = encrypted_block_info.iv;
+ input_buffer.iv_size = encrypted_block_info.iv_size;
+ input_buffer.checksum = encrypted_block_info.checksum;
+ input_buffer.checksum_size = encrypted_block_info.checksum_size;
+ input_buffer.num_subsamples = encrypted_block_info.num_subsamples;
+ std::vector<cdm::SubsampleEntry> subsamples;
+ for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
+ subsamples.push_back(cdm::SubsampleEntry(
+ encrypted_block_info.subsamples[i].clear_bytes,
+ encrypted_block_info.subsamples[i].cipher_bytes));
+ }
+ input_buffer.subsamples = &subsamples[0];
+ input_buffer.timestamp = encrypted_block_info.tracking_info.timestamp;
+
+ cdm::OutputBuffer output_buffer;
+ cdm::Status status = cdm_->Decrypt(input_buffer, &output_buffer);
+
+ CallOnMain(callback_factory_.NewCallback(
+ &CdmWrapper::DeliverBlock,
+ status,
+ output_buffer,
+ encrypted_block_info.tracking_info));
- DecryptedBlock decrypted_block;
- decrypted_block.decrypted_data = "Pretend I'm decrypted data!";
- decrypted_block.decrypted_block_info.result = PP_DECRYPTRESULT_SUCCESS;
- decrypted_block.decrypted_block_info.tracking_info =
- encrypted_block_info.tracking_info;
-
- // TODO(tomfinegan): This would end up copying a lot of data in the real
- // implementation if we continue passing std::strings around. It *might* not
- // be such a big deal w/a real CDM. We may be able to simply pass a pointer
- // into the CDM. Otherwise we could look into using std::tr1::shared_ptr
- // instead of passing a giant std::string filled with encrypted data.
- CallOnMain(callback_factory_.NewCallback(&CDMWrapper::DeliverBlock,
- decrypted_block));
return true;
}
-PP_Resource CDMWrapper::StringToBufferResource(const std::string& str) {
- if (str.empty())
+bool CdmWrapper::DecryptAndDecode(
+ pp::Buffer_Dev encrypted_buffer,
+ const PP_EncryptedBlockInfo& encrypted_block_info) {
+ return false;
+}
+
+PP_Resource CdmWrapper::MakeBufferResource(const uint8_t* data,
+ uint32_t data_size) {
+ if (!data || !data_size)
return 0;
- pp::Buffer_Dev buffer(this, str.size());
+ pp::Buffer_Dev buffer(this, data_size);
if (!buffer.data())
return 0;
- std::memcpy(buffer.data(), str.data(), str.size());
+ memcpy(buffer.data(), data, data_size);
+
return buffer.detach();
}
-void CDMWrapper::NeedKey(int32_t result,
- const DecryptorMessage& decryptor_message) {
- const std::string& message_data = decryptor_message.message_data;
- pp::VarArrayBuffer init_data(message_data.size());
- std::memcpy(init_data.Map(), message_data.data(), message_data.size());
- pp::ContentDecryptor_Private::NeedKey(decryptor_message.key_system,
- decryptor_message.session_id,
- init_data);
+void CdmWrapper::KeyAdded(int32_t result, const std::string& session_id) {
+ pp::ContentDecryptor_Private::KeyAdded(key_system_, session_id);
}
-void CDMWrapper::KeyAdded(int32_t result,
- const DecryptorMessage& decryptor_message) {
- pp::ContentDecryptor_Private::KeyAdded(decryptor_message.key_system,
- decryptor_message.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));
+ pp::ContentDecryptor_Private::KeyMessage(
+ key_system_,
+ std::string(key_message.session_id, key_message.session_id_size),
+ 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;
}
-void CDMWrapper::KeyMessage(int32_t result,
- const DecryptorMessage& decryptor_message) {
- pp::Buffer_Dev message_buffer(
- StringToBufferResource(decryptor_message.message_data));
- pp::ContentDecryptor_Private::KeyMessage(decryptor_message.key_system,
- decryptor_message.session_id,
- message_buffer,
- decryptor_message.default_url);
+// TODO(xhwang): Support MediaKeyError (see spec: http://goo.gl/rbdnR) in CDM
+// interface and in this function.
+void CdmWrapper::KeyError(int32_t result, const std::string& session_id) {
+ pp::ContentDecryptor_Private::KeyError(key_system_,
+ session_id,
+ kUnknownError,
+ 0);
}
-void CDMWrapper::KeyError(int32_t result,
- const DecryptorMessage& decryptor_message) {
- pp::ContentDecryptor_Private::KeyError(decryptor_message.key_system,
- decryptor_message.session_id,
- decryptor_message.media_error,
- decryptor_message.system_code);
-}
+void CdmWrapper::DeliverBlock(int32_t result,
+ const cdm::Status& status,
+ cdm::OutputBuffer& output_buffer,
+ const PP_DecryptTrackingInfo& tracking_info) {
+ pp::Buffer_Dev decrypted_buffer(MakeBufferResource(output_buffer.data,
+ output_buffer.data_size));
-void CDMWrapper::DeliverBlock(int32_t result,
- const DecryptedBlock& decrypted_block) {
- pp::Buffer_Dev decrypted_buffer(
- StringToBufferResource(decrypted_block.decrypted_data));
- pp::ContentDecryptor_Private::DeliverBlock(
- decrypted_buffer,
- decrypted_block.decrypted_block_info);
+ 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;
+
+ switch (status) {
+ case cdm::kSuccess:
+ decrypted_block_info.result = PP_DECRYPTRESULT_SUCCESS;
+ break;
+ case cdm::kErrorNoKey:
+ decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_NOKEY;
+ break;
+ default:
+ 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;
}
// This object is the global object representing this plugin library as long
@@ -244,15 +329,17 @@ class MyModule : public pp::Module {
virtual ~MyModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new CDMWrapper(instance, this);
+ return new CdmWrapper(instance, this);
}
};
+} // namespace webkit_media
+
namespace pp {
// Factory function for your specialization of the Module object.
Module* CreateModule() {
- return new MyModule();
+ return new webkit_media::MyModule();
}
} // namespace pp
diff --git a/webkit/media/crypto/ppapi/content_decryption_module.h b/webkit/media/crypto/ppapi/content_decryption_module.h
index 0023d49..cb21258 100644
--- a/webkit/media/crypto/ppapi/content_decryption_module.h
+++ b/webkit/media/crypto/ppapi/content_decryption_module.h
@@ -33,7 +33,17 @@ enum Status {
kErrorNoKey
};
+// TODO(xhwang): Use int32_t instead of uint32_t for sizes here and below and
+// update checks to include <0.
struct KeyMessage {
+ KeyMessage()
+ : session_id(NULL),
+ session_id_size(0),
+ message(NULL),
+ message_size(0),
+ default_url(NULL),
+ default_url_size(0) {}
+
char* session_id;
uint32_t session_id_size;
uint8_t* message;
@@ -65,33 +75,55 @@ struct KeyMessage {
//
// TODO(xhwang): Add checks to make sure these structs have fixed layout.
struct SubsampleEntry {
+ SubsampleEntry(uint32_t clear_bytes, uint32_t cipher_bytes)
+ : clear_bytes(clear_bytes), cipher_bytes(cipher_bytes) {}
+
uint32_t clear_bytes;
uint32_t cipher_bytes;
};
struct InputBuffer {
- uint8_t* data; // Pointer to the beginning of the input data.
+ InputBuffer()
+ : data(NULL),
+ data_size(0),
+ data_offset(0),
+ key_id(NULL),
+ key_id_size(0),
+ iv(NULL),
+ iv_size(0),
+ checksum(NULL),
+ checksum_size(0),
+ subsamples(NULL),
+ num_subsamples(0),
+ timestamp(0) {}
+
+ const uint8_t* data; // Pointer to the beginning of the input data.
uint32_t data_size; // Size (in bytes) of |data|.
uint32_t data_offset; // Number of bytes to be discarded before decryption.
- uint8_t* key_id; // Key ID to identify the decryption key.
+ const uint8_t* key_id; // Key ID to identify the decryption key.
uint32_t key_id_size; // Size (in bytes) of |key_id|.
- uint8_t* iv; // Initialization vector.
+ const uint8_t* iv; // Initialization vector.
uint32_t iv_size; // Size (in bytes) of |iv|.
- uint8_t* checksum;
+ const uint8_t* checksum;
uint32_t checksum_size; // Size (in bytes) of the |checksum|.
- struct SubsampleEntry* subsamples;
+ const struct SubsampleEntry* subsamples;
uint32_t num_subsamples; // Number of subsamples in |subsamples|.
int64_t timestamp; // Presentation timestamp in microseconds.
};
struct OutputBuffer {
- uint8_t* data; // Pointer to the beginning of the output data.
+ OutputBuffer()
+ : data(NULL),
+ data_size(0),
+ timestamp(0) {}
+
+ const uint8_t* data; // Pointer to the beginning of the output data.
uint32_t data_size; // Size (in bytes) of |data|.
int64_t timestamp; // Presentation timestamp in microseconds.