diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-27 22:38:39 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-27 22:38:39 +0000 |
commit | 17d3bcadcfbbf52b7691a5b0a2443e260e90018a (patch) | |
tree | dc9770d9284a8320366678f2796de4cceeb86f79 | |
parent | 152183033a7390fe7eac2bf46df1bb2d03ea12ef (diff) | |
download | chromium_src-17d3bcadcfbbf52b7691a5b0a2443e260e90018a.zip chromium_src-17d3bcadcfbbf52b7691a5b0a2443e260e90018a.tar.gz chromium_src-17d3bcadcfbbf52b7691a5b0a2443e260e90018a.tar.bz2 |
Update CDM interface and add clear key CDM.
The ClearKeyCdm implements the ContentDecryptionModule. It's a wrapping of the media::AesDecryptor to do real decryption work. The wrapping layer only translates input/output parameters and convert the async calls in media::AesDecryptor to sync calls.
TBR=scherkus@chromium.org
BUG=none
TEST=none
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=152672
Review URL: https://chromiumcodereview.appspot.com/10837252
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153566 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/media/crypto/ppapi/cdm_export.h | 27 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/clear_key_cdm.cc | 219 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/clear_key_cdm.h | 104 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/content_decryption_module.h | 58 | ||||
-rw-r--r-- | webkit/media/webkit_media.gypi | 24 |
5 files changed, 400 insertions, 32 deletions
diff --git a/webkit/media/crypto/ppapi/cdm_export.h b/webkit/media/crypto/ppapi/cdm_export.h new file mode 100644 index 0000000..3fef094 --- /dev/null +++ b/webkit/media/crypto/ppapi/cdm_export.h @@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_MEDIA_CRYPTO_PPAPI_CDM_EXPORT_H_ +#define WEBKIT_MEDIA_CRYPTO_PPAPI_CDM_EXPORT_H_ + +// Define CDM_EXPORT so that functionality implemented by the CDM module +// can be exported to consumers. + +#if defined(WIN32) + +#if defined(CDM_IMPLEMENTATION) +#define CDM_EXPORT __declspec(dllexport) +#else +#define CDM_EXPORT __declspec(dllimport) +#endif // defined(CDM_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(CDM_IMPLEMENTATION) +#define CDM_EXPORT __attribute__((visibility("default"))) +#else +#define CDM_EXPORT +#endif +#endif + +#endif // WEBKIT_MEDIA_CRYPTO_PPAPI_CDM_EXPORT_H_ diff --git a/webkit/media/crypto/ppapi/clear_key_cdm.cc b/webkit/media/crypto/ppapi/clear_key_cdm.cc new file mode 100644 index 0000000..835d062 --- /dev/null +++ b/webkit/media/crypto/ppapi/clear_key_cdm.cc @@ -0,0 +1,219 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/media/crypto/ppapi/clear_key_cdm.h" + +#include <vector> + +#include "base/bind.h" +#include "base/logging.h" +#include "base/time.h" +#include "media/base/decoder_buffer.h" + +static const char kClearKeyCdmVersion[] = "0.1.0.0"; + +static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( + const cdm::InputBuffer& input_buffer) { + scoped_refptr<media::DecoderBuffer> output_buffer = + media::DecoderBuffer::CopyFrom(input_buffer.data, input_buffer.data_size); + + std::vector<media::SubsampleEntry> subsamples; + for (uint32_t i = 0; i < input_buffer.num_subsamples; ++i) { + media::SubsampleEntry subsample; + subsample.clear_bytes = input_buffer.subsamples[i].clear_bytes; + subsample.cypher_bytes = input_buffer.subsamples[i].cipher_bytes; + subsamples.push_back(subsample); + } + + scoped_ptr<media::DecryptConfig> decrypt_config(new media::DecryptConfig( + std::string(reinterpret_cast<const char*>(input_buffer.key_id), + input_buffer.key_id_size), + std::string(reinterpret_cast<const char*>(input_buffer.iv), + input_buffer.iv_size), + std::string(reinterpret_cast<const char*>(input_buffer.checksum), + input_buffer.checksum_size), + input_buffer.data_offset, + subsamples)); + + output_buffer->SetDecryptConfig(decrypt_config.Pass()); + output_buffer->SetTimestamp( + base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); + + return output_buffer; +} + +template<typename Type> +class ScopedResetter { + public: + explicit ScopedResetter(Type* object) : object_(object) {} + ~ScopedResetter() { + object_->Reset(); + } + + private: + Type* const object_; +}; + +template<typename Type> +static Type* AllocateAndCopy(const Type* data, int size) { + COMPILE_ASSERT(sizeof(Type) == 1, type_size_is_not_one); + Type* copy = new Type[size]; + memcpy(copy, data, size); + return copy; +} + +cdm::ContentDecryptionModule* CreateCdmInstance() { + return new webkit_media::ClearKeyCdm(); +} + +void DestroyCdmInstance(cdm::ContentDecryptionModule* instance) { + delete instance; +} + +const char* GetCdmVersion() { + return kClearKeyCdmVersion; +} + +namespace webkit_media { + +ClearKeyCdm::Client::Client() : status_(kKeyError), key_message_length_(0) {} + +ClearKeyCdm::Client::~Client() {} + +void ClearKeyCdm::Client::Reset() { + status_ = kKeyError; + session_id_.clear(); + key_message_.reset(); + key_message_length_ = 0; + default_url_.clear(); +} + +void ClearKeyCdm::Client::KeyAdded(const std::string& key_system, + const std::string& session_id) { + status_ = kKeyAdded; + session_id_ = session_id; +} + +void ClearKeyCdm::Client::KeyError(const std::string& key_system, + const std::string& session_id, + media::Decryptor::KeyError error_code, + int system_code) { + status_ = kKeyError; + session_id_ = session_id; +} + +void ClearKeyCdm::Client::KeyMessage(const std::string& key_system, + const std::string& session_id, + scoped_array<uint8> message, + int message_length, + const std::string& default_url) { + status_ = kKeyMessage; + session_id_ = session_id; + key_message_ = message.Pass(); + key_message_length_ = message_length; +} + +void ClearKeyCdm::Client::NeedKey(const std::string& key_system, + const std::string& session_id, + scoped_array<uint8> init_data, + int init_data_length) { + // In the current implementation of AesDecryptor, NeedKey is not used. + // If no key is available to decrypt an input buffer, it returns kNoKey to + // the caller instead of firing NeedKey. + NOTREACHED(); +} + +ClearKeyCdm::ClearKeyCdm() : decryptor_(&client_) {} + +ClearKeyCdm::~ClearKeyCdm() {} + +cdm::Status ClearKeyCdm::GenerateKeyRequest(const uint8_t* init_data, + int init_data_size, + cdm::KeyMessage* key_request) { + DVLOG(1) << "GenerateKeyRequest()"; + base::AutoLock auto_lock(client_lock_); + ScopedResetter<Client> auto_resetter(&client_); + decryptor_.GenerateKeyRequest("", init_data, init_data_size); + + if (client_.status() != Client::kKeyMessage) + return cdm::kErrorUnknown; + + DCHECK(key_request); + key_request->session_id = AllocateAndCopy(client_.session_id().data(), + client_.session_id().size()); + key_request->session_id_size = client_.session_id().size(); + key_request->message = AllocateAndCopy(client_.key_message(), + client_.key_message_length()); + key_request->message_size = client_.key_message_length(); + key_request->default_url = AllocateAndCopy(client_.default_url().data(), + client_.default_url().size()); + key_request->default_url_size = client_.default_url().size(); + return cdm::kSuccess; +} + +cdm::Status ClearKeyCdm::AddKey(const char* session_id, + int session_id_size, + const uint8_t* key, + int key_size, + const uint8_t* key_id, + int key_id_size) { + DVLOG(1) << "AddKey()"; + base::AutoLock auto_lock(client_lock_); + ScopedResetter<Client> auto_resetter(&client_); + decryptor_.AddKey("", key, key_size, key_id, key_id_size, + std::string(session_id, session_id_size)); + + if (client_.status() != Client::kKeyAdded) + return cdm::kErrorUnknown; + + return cdm::kSuccess; +} + +cdm::Status ClearKeyCdm::CancelKeyRequest(const char* session_id, + int session_id_size) { + DVLOG(1) << "CancelKeyRequest()"; + base::AutoLock auto_lock(client_lock_); + ScopedResetter<Client> auto_resetter(&client_); + decryptor_.CancelKeyRequest("", std::string(session_id, session_id_size)); + return cdm::kSuccess; +} + +static void CopyDecryptResults( + media::Decryptor::Status* status_copy, + scoped_refptr<media::DecoderBuffer>* buffer_copy, + media::Decryptor::Status status, + const scoped_refptr<media::DecoderBuffer>& buffer) { + *status_copy = status; + *buffer_copy = buffer; +} + +cdm::Status ClearKeyCdm::Decrypt( + const cdm::InputBuffer& encrypted_buffer, + cdm::OutputBuffer* decrypted_buffer) { + DVLOG(1) << "Decrypt()"; + + scoped_refptr<media::DecoderBuffer> decoder_buffer = + CopyDecoderBufferFrom(encrypted_buffer); + + // Callback is called synchronously, so we can use variables on the stack. + media::Decryptor::Status status; + scoped_refptr<media::DecoderBuffer> buffer; + decryptor_.Decrypt(decoder_buffer, + base::Bind(&CopyDecryptResults, &status, &buffer)); + + if (status == media::Decryptor::kError) + return cdm::kErrorUnknown; + + if (status == media::Decryptor::kNoKey) + return cdm::kErrorNoKey; + + DCHECK(buffer); + int data_size = buffer->GetDataSize(); + decrypted_buffer->data = AllocateAndCopy(buffer->GetData(), data_size); + decrypted_buffer->data_size = data_size; + decrypted_buffer->timestamp = buffer->GetTimestamp().InMicroseconds(); + return cdm::kSuccess; +} + +} // namespace webkit_media diff --git a/webkit/media/crypto/ppapi/clear_key_cdm.h b/webkit/media/crypto/ppapi/clear_key_cdm.h new file mode 100644 index 0000000..eaad45d --- /dev/null +++ b/webkit/media/crypto/ppapi/clear_key_cdm.h @@ -0,0 +1,104 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_MEDIA_CRYPTO_PPAPI_CLEAR_KEY_CDM_H_ +#define WEBKIT_MEDIA_CRYPTO_PPAPI_CLEAR_KEY_CDM_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "media/base/decryptor_client.h" +#include "media/crypto/aes_decryptor.h" +#include "webkit/media/crypto/ppapi/content_decryption_module.h" + +namespace media { +class DecoderBuffer; +} + +namespace webkit_media { + +// Clear key implementation of the cdm::ContentDecryptionModule interface. +class ClearKeyCdm : public cdm::ContentDecryptionModule { + public: + ClearKeyCdm(); + virtual ~ClearKeyCdm(); + + // ContentDecryptionModule implementation. + virtual cdm::Status GenerateKeyRequest(const uint8_t* init_data, + int init_data_size, + cdm::KeyMessage* key_request) OVERRIDE; + + virtual cdm::Status AddKey(const char* session_id, + int session_id_size, + const uint8_t* key, + int key_size, + const uint8_t* key_id, + int key_id_size) OVERRIDE; + + virtual cdm::Status CancelKeyRequest(const char* session_id, + int session_id_size) OVERRIDE; + + virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, + cdm::OutputBuffer* decrypted_buffer) OVERRIDE; + + private: + class Client : public media::DecryptorClient { + public: + enum Status { + kKeyAdded, + kKeyError, + kKeyMessage, + kNeedKey + }; + + Client(); + virtual ~Client(); + + Status status() { return status_; } + const std::string& session_id() { return session_id_; } + const uint8* key_message() { return key_message_.get(); } + int key_message_length() { return key_message_length_; } + const std::string& default_url() { return default_url_; } + + // Resets the Client to a clean state. + void Reset(); + + // media::DecryptorClient implementation. + virtual void KeyAdded(const std::string& key_system, + const std::string& session_id) OVERRIDE; + virtual void KeyError(const std::string& key_system, + const std::string& session_id, + media::Decryptor::KeyError error_code, + int system_code) OVERRIDE; + virtual void KeyMessage(const std::string& key_system, + const std::string& session_id, + scoped_array<uint8> message, + int message_length, + const std::string& default_url) OVERRIDE; + virtual void NeedKey(const std::string& key_system, + const std::string& session_id, + scoped_array<uint8> init_data, + int init_data_length) OVERRIDE; + + private: + Status status_; + std::string session_id_; + scoped_array<uint8> key_message_; + int key_message_length_; + std::string default_url_; + }; + + Client client_; + media::AesDecryptor decryptor_; + // Protects the |client_| from being accessed by the |decryptor_| + // simultaneously. + base::Lock client_lock_; +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_CRYPTO_PPAPI_CLEAR_KEY_CDM_H_ diff --git a/webkit/media/crypto/ppapi/content_decryption_module.h b/webkit/media/crypto/ppapi/content_decryption_module.h index 491c064..0023d49 100644 --- a/webkit/media/crypto/ppapi/content_decryption_module.h +++ b/webkit/media/crypto/ppapi/content_decryption_module.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WEBKIT_MEDIA_CRYPTO_CONTENT_DECRYPTION_MODULE_H_ -#define WEBKIT_MEDIA_CRYPTO_CONTENT_DECRYPTION_MODULE_H_ +#ifndef WEBKIT_MEDIA_CRYPTO_PPAPI_CONTENT_DECRYPTION_MODULE_H_ +#define WEBKIT_MEDIA_CRYPTO_PPAPI_CONTENT_DECRYPTION_MODULE_H_ #if defined(_MSC_VER) typedef unsigned char uint8_t; @@ -13,18 +13,35 @@ typedef __int64 int64_t; #include <stdint.h> #endif +#include "webkit/media/crypto/ppapi/cdm_export.h" + namespace cdm { class ContentDecryptionModule; } extern "C" { -cdm::ContentDecryptionModule* CreateCdmInstance(); -void DestroyCdmInstance(cdm::ContentDecryptionModule* instance); -const char* GetCdmVersion(); +CDM_EXPORT cdm::ContentDecryptionModule* CreateCdmInstance(); +CDM_EXPORT void DestroyCdmInstance(cdm::ContentDecryptionModule* instance); +CDM_EXPORT const char* GetCdmVersion(); } namespace cdm { +enum Status { + kSuccess = 0, + kErrorUnknown, + kErrorNoKey +}; + +struct KeyMessage { + char* session_id; + uint32_t session_id_size; + uint8_t* message; + uint32_t message_size; + char* default_url; + uint32_t default_url_size; +}; + // An input buffer can be split into several continuous subsamples. // A SubsampleEntry specifies the number of clear and cipher bytes in each // subsample. For example, the following buffer has three subsamples: @@ -82,31 +99,20 @@ struct OutputBuffer { class ContentDecryptionModule { public: - enum Status { - kSuccess = 0, - kErrorUnknown, - kErrorNoKey - }; - - // Generates a |key_request| as well as a |session_id| given the |init_data|. - // The CDM may also extract a |default_url|. + // Generates a |key_request| given the |init_data|. // Returns kSuccess if the key request was successfully generated, // in which case the callee should have allocated memory for the output - // parameters (e.g |session_id|) and passed the ownership to the caller. - // Returns kErrorUnknown otherwise, in which case the output - // parameters should not be used by the caller. + // parameters (e.g |session_id| in |key_request|) and passed the ownership + // to the caller. + // Returns kErrorUnknown otherwise, in which case the output parameters should + // not be used by the caller. // // TODO(xhwang): It's not safe to pass the ownership of the dynamically // allocated memory over library boundaries. Fix it after related PPAPI change // and sample CDM are landed. virtual Status GenerateKeyRequest(const uint8_t* init_data, int init_data_size, - char** session_id, - int* session_id_size, - uint8_t** key_request, - int* key_request_size, - char** default_url, - int* default_url_size) = 0; + KeyMessage* key_request) = 0; // Adds the |key| to the CDM to be associated with |key_id|. // Returns kSuccess if the key was successfully added. @@ -137,14 +143,12 @@ class ContentDecryptionModule { // TODO(xhwang): It's not safe to pass the ownership of the dynamically // allocated memory over library boundaries. Fix it after related PPAPI change // and sample CDM are landed. - virtual Status Decrypt(const char* session_id, - int session_id_size, - const InputBuffer& encrypted_buffer, + virtual Status Decrypt(const InputBuffer& encrypted_buffer, OutputBuffer* decrypted_buffer) = 0; - virtual ~ContentDecryptionModule() {}; + virtual ~ContentDecryptionModule() {} }; } // namespace cdm -#endif // WEBKIT_MEDIA_CRYPTO_CONTENT_DECRYPTION_MODULE_H_ +#endif // WEBKIT_MEDIA_CRYPTO_PPAPI_CONTENT_DECRYPTION_MODULE_H_ diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi index 834ba48..7ac9b9b 100644 --- a/webkit/media/webkit_media.gypi +++ b/webkit/media/webkit_media.gypi @@ -84,10 +84,27 @@ ], }, { - 'target_name': 'ppapi_cdm_wrapper', + 'target_name': 'clearkeycdm', + 'type': 'shared_library', + 'defines': ['CDM_IMPLEMENTATION'], + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/media/media.gyp:media' + ], + 'sources': [ + 'crypto/ppapi/clear_key_cdm.cc', + 'crypto/ppapi/clear_key_cdm.h', + ], + }, + { + 'target_name': 'clearkeycdmplugin', 'type': 'none', 'dependencies': [ - '<(DEPTH)/ppapi/ppapi.gyp:ppapi_cpp' + '<(DEPTH)/ppapi/ppapi.gyp:ppapi_cpp', + 'clearkeycdm', + ], + 'sources': [ + 'crypto/ppapi/cdm_wrapper.cc', ], 'conditions': [ ['os_posix==1 and OS!="mac"', { @@ -113,9 +130,6 @@ ]}, }], ], - 'sources': [ - 'crypto/ppapi/cdm_wrapper.cc', - ], } ], } |