summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-27 22:38:39 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-27 22:38:39 +0000
commit17d3bcadcfbbf52b7691a5b0a2443e260e90018a (patch)
treedc9770d9284a8320366678f2796de4cceeb86f79
parent152183033a7390fe7eac2bf46df1bb2d03ea12ef (diff)
downloadchromium_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.h27
-rw-r--r--webkit/media/crypto/ppapi/clear_key_cdm.cc219
-rw-r--r--webkit/media/crypto/ppapi/clear_key_cdm.h104
-rw-r--r--webkit/media/crypto/ppapi/content_decryption_module.h58
-rw-r--r--webkit/media/webkit_media.gypi24
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',
- ],
}
],
}