| Index: webkit/media/crypto/ppapi/clear_key_cdm.cc
|
| 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 0000000000000000000000000000000000000000..835d06258a28020d9ae7612b75ed15c63a2293a9
|
| --- /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
|
|
|