diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-07 01:05:02 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-07 01:05:02 +0000 |
commit | 16902dc7bceafb0cba762bca221669618a9c5dbb (patch) | |
tree | f8c26ee10ecb274df6f3de7c9c47362d2e74ac05 /webkit/plugins | |
parent | 6cb6d7760a1f0d0b4c1b9a2676a2eb139d9bdd10 (diff) | |
download | chromium_src-16902dc7bceafb0cba762bca221669618a9c5dbb.zip chromium_src-16902dc7bceafb0cba762bca221669618a9c5dbb.tar.gz chromium_src-16902dc7bceafb0cba762bca221669618a9c5dbb.tar.bz2 |
Add ContentDecryptorDelegate.
ContentDecryptorDelegate provides accessors to PPP_ContentDecryptor_Private calls and handles PPB_ContentDecryptor_Private calls for the PluginInstance. With this new class, we can move most content decryptor related code out of PluginInstance. This makes the PluginInstance much cleaner, and make content decryptor related code much easier to manage.
With this change, now PpapiDecrytor holds a pointer to the ContentDecryptorDelegate directly.
TBR=brettw@chromium.org
BUG=none
TEST=content_browsertests:EncryptedMedia tests pass. Demo pages still work.
Review URL: https://chromiumcodereview.appspot.com/11312054
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166323 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins')
-rw-r--r-- | webkit/plugins/ppapi/content_decryptor_delegate.cc | 871 | ||||
-rw-r--r-- | webkit/plugins/ppapi/content_decryptor_delegate.h | 132 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.cc | 859 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.h | 84 |
4 files changed, 1052 insertions, 894 deletions
diff --git a/webkit/plugins/ppapi/content_decryptor_delegate.cc b/webkit/plugins/ppapi/content_decryptor_delegate.cc new file mode 100644 index 0000000..3c00865 --- /dev/null +++ b/webkit/plugins/ppapi/content_decryptor_delegate.cc @@ -0,0 +1,871 @@ +// 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/plugins/ppapi/content_decryptor_delegate.h" + +#include "base/callback_helpers.h" +#include "base/debug/trace_event.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/channel_layout.h" +#include "media/base/data_buffer.h" +#include "media/base/decoder_buffer.h" +#include "media/base/decryptor_client.h" +#include "media/base/video_decoder_config.h" +#include "media/base/video_frame.h" +#include "media/base/video_util.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_buffer_api.h" +#include "webkit/plugins/ppapi/ppb_buffer_impl.h" + +using ppapi::PpapiGlobals; +using ppapi::ScopedPPResource; +using ppapi::StringVar; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Buffer_API; + +namespace webkit { +namespace ppapi { + +namespace { + +// 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(PP_Instance instance, + const uint8* data, int size) { + if (!data || !size) + return 0; + + ScopedPPResource resource(PPB_Buffer_Impl::Create(instance, size)); + if (!resource.get()) + return 0; + + EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); + if (enter.failed()) + return 0; + + BufferAutoMapper mapper(enter.object()); + if (!mapper.data() || mapper.size() < static_cast<size_t>(size)) + return 0; + + memcpy(mapper.data(), data, size); + return resource.get(); +} + +// Copies the content of |str| into |array|. +// Returns true if copy succeeded. Returns false if copy failed, e.g. if the +// |array_size| is smaller than the |str| length. +template <uint32_t array_size> +bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) { + if (array_size < str.size()) + return false; + + memcpy(array, str.data(), str.size()); + return true; +} + +// Fills the |block_info| with information from |decrypt_config|, |timestamp| +// and |request_id|. |decrypt_config| can be NULL if the block is not encrypted. +// This is useful for end-of-stream blocks. +// Returns true if |block_info| is successfully filled. Returns false +// otherwise. +bool MakeEncryptedBlockInfo( + const media::DecryptConfig* decrypt_config, + int64_t timestamp, + uint32_t request_id, + PP_EncryptedBlockInfo* block_info) { + DCHECK(block_info); + + // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and + // anywhere else. + memset(block_info, 0, sizeof(*block_info)); + + block_info->tracking_info.request_id = request_id; + block_info->tracking_info.timestamp = timestamp; + + if (!decrypt_config) + return true; + + block_info->data_offset = decrypt_config->data_offset(); + + if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) || + !CopyStringToArray(decrypt_config->iv(), block_info->iv)) + return false; + + block_info->key_id_size = decrypt_config->key_id().size(); + block_info->iv_size = decrypt_config->iv().size(); + + if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples)) + return false; + + block_info->num_subsamples = decrypt_config->subsamples().size(); + for (uint32_t i = 0; i < block_info->num_subsamples; ++i) { + block_info->subsamples[i].clear_bytes = + decrypt_config->subsamples()[i].clear_bytes; + block_info->subsamples[i].cipher_bytes = + decrypt_config->subsamples()[i].cypher_bytes; + } + + return true; +} + +// Deserializes audio data stored in |audio_frames| into individual audio +// buffers in |frames|. Returns true upon success. +bool DeserializeAudioFrames(PP_Resource audio_frames, + media::Decryptor::AudioBuffers* frames) { + DCHECK(frames); + EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true); + if (!enter.succeeded()) + return false; + + BufferAutoMapper mapper(enter.object()); + if (!mapper.data() || !mapper.size()) + return false; + + const uint8* cur = static_cast<uint8*>(mapper.data()); + int bytes_left = mapper.size(); + + do { + int64 timestamp = 0; + int64 frame_size = -1; + const int kHeaderSize = sizeof(timestamp) + sizeof(frame_size); + + if (bytes_left < kHeaderSize) + return false; + + memcpy(×tamp, cur, sizeof(timestamp)); + cur += sizeof(timestamp); + bytes_left -= sizeof(timestamp); + + memcpy(&frame_size, cur, sizeof(frame_size)); + cur += sizeof(frame_size); + bytes_left -= sizeof(frame_size); + + // We should *not* have empty frame in the list. + if (frame_size <= 0 || bytes_left < frame_size) + return false; + + scoped_refptr<media::DataBuffer> frame(new media::DataBuffer(cur, + frame_size)); + frame->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); + frames->push_back(frame); + + cur += frame_size; + bytes_left -= frame_size; + } while (bytes_left > 0); + + return true; +} + +PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) { + switch (codec) { + case media::kCodecVorbis: + return PP_AUDIOCODEC_VORBIS; + case media::kCodecAAC: + return PP_AUDIOCODEC_AAC; + default: + return PP_AUDIOCODEC_UNKNOWN; + } +} + +PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) { + switch (codec) { + case media::kCodecVP8: + return PP_VIDEOCODEC_VP8; + case media::kCodecH264: + return PP_VIDEOCODEC_H264; + default: + return PP_VIDEOCODEC_UNKNOWN; + } +} + +PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile( + media::VideoCodecProfile profile) { + switch (profile) { + case media::VP8PROFILE_MAIN: + return PP_VIDEOCODECPROFILE_VP8_MAIN; + case media::H264PROFILE_BASELINE: + return PP_VIDEOCODECPROFILE_H264_BASELINE; + case media::H264PROFILE_MAIN: + return PP_VIDEOCODECPROFILE_H264_MAIN; + case media::H264PROFILE_EXTENDED: + return PP_VIDEOCODECPROFILE_H264_EXTENDED; + case media::H264PROFILE_HIGH: + return PP_VIDEOCODECPROFILE_H264_HIGH; + case media::H264PROFILE_HIGH10PROFILE: + return PP_VIDEOCODECPROFILE_H264_HIGH_10; + case media::H264PROFILE_HIGH422PROFILE: + return PP_VIDEOCODECPROFILE_H264_HIGH_422; + case media::H264PROFILE_HIGH444PREDICTIVEPROFILE: + return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE; + default: + return PP_VIDEOCODECPROFILE_UNKNOWN; + } +} + +PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat( + media::VideoFrame::Format format) { + switch (format) { + case media::VideoFrame::YV12: + return PP_DECRYPTEDFRAMEFORMAT_YV12; + case media::VideoFrame::I420: + return PP_DECRYPTEDFRAMEFORMAT_I420; + default: + return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; + } +} + +media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus( + PP_DecryptResult result) { + switch (result) { + case PP_DECRYPTRESULT_SUCCESS: + return media::Decryptor::kSuccess; + case PP_DECRYPTRESULT_DECRYPT_NOKEY: + return media::Decryptor::kNoKey; + case PP_DECRYPTRESULT_NEEDMOREDATA: + return media::Decryptor::kNeedMoreData; + case PP_DECRYPTRESULT_DECRYPT_ERROR: + return media::Decryptor::kError; + case PP_DECRYPTRESULT_DECODE_ERROR: + return media::Decryptor::kError; + default: + NOTREACHED(); + return media::Decryptor::kError; + } +} + +PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType( + media::Decryptor::StreamType stream_type) { + switch (stream_type) { + case media::Decryptor::kAudio: + return PP_DECRYPTORSTREAMTYPE_AUDIO; + case media::Decryptor::kVideo: + return PP_DECRYPTORSTREAMTYPE_VIDEO; + default: + NOTREACHED(); + return PP_DECRYPTORSTREAMTYPE_VIDEO; + } +} + +} // namespace + +ContentDecryptorDelegate::ContentDecryptorDelegate( + PP_Instance pp_instance, + const PPP_ContentDecryptor_Private* plugin_decryption_interface) + : pp_instance_(pp_instance), + plugin_decryption_interface_(plugin_decryption_interface), + decryptor_client_(NULL), + next_decryption_request_id_(1), + pending_audio_decrypt_request_id_(0), + pending_video_decrypt_request_id_(0), + pending_audio_decoder_init_request_id_(0), + pending_video_decoder_init_request_id_(0), + pending_audio_decode_request_id_(0), + pending_video_decode_request_id_(0) { +} + +void ContentDecryptorDelegate::set_decrypt_client( + media::DecryptorClient* decryptor_client) { + decryptor_client_ = decryptor_client; +} + +bool ContentDecryptorDelegate::GenerateKeyRequest( + const std::string& key_system, + const std::string& type, + const std::string& init_data) { + if (key_system.empty()) + return false; + + PP_Var init_data_array = + PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + init_data.size(), init_data.data()); + + plugin_decryption_interface_->GenerateKeyRequest( + pp_instance_, + StringVar::StringToPPVar(key_system), + StringVar::StringToPPVar(type), + init_data_array); + return true; +} + +bool ContentDecryptorDelegate::AddKey(const std::string& session_id, + const std::string& key, + const std::string& init_data) { + PP_Var key_array = + PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(key.size(), + key.data()); + PP_Var init_data_array = + PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + init_data.size(), + init_data.data()); + + plugin_decryption_interface_->AddKey( + pp_instance_, + StringVar::StringToPPVar(session_id), + key_array, + init_data_array); + return true; +} + +bool ContentDecryptorDelegate::CancelKeyRequest(const std::string& session_id) { + plugin_decryption_interface_->CancelKeyRequest( + pp_instance_, + StringVar::StringToPPVar(session_id)); + return true; +} + +// TODO(xhwang): Remove duplication of code in Decrypt(), +// DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). +bool ContentDecryptorDelegate::Decrypt( + media::Decryptor::StreamType stream_type, + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::DecryptCB& decrypt_cb) { + DVLOG(3) << "Decrypt() - stream_type: " << stream_type; + ScopedPPResource encrypted_resource( + ScopedPPResource::PassRef(), + MakeBufferResource(pp_instance_, + encrypted_buffer->GetData(), + encrypted_buffer->GetDataSize())); + if (!encrypted_resource.get()) + return false; + + const uint32_t request_id = next_decryption_request_id_++; + DVLOG(2) << "Decrypt() - request_id " << request_id; + + PP_EncryptedBlockInfo block_info; + DCHECK(encrypted_buffer->GetDecryptConfig()); + if (!MakeEncryptedBlockInfo(encrypted_buffer->GetDecryptConfig(), + encrypted_buffer->GetTimestamp().InMicroseconds(), + request_id, + &block_info)) { + return false; + } + + // There is only one pending decrypt request at any time per stream. This is + // enforced by the media pipeline. + switch (stream_type) { + case media::Decryptor::kAudio: + DCHECK_EQ(pending_audio_decrypt_request_id_, 0u); + DCHECK(pending_audio_decrypt_cb_.is_null()); + pending_audio_decrypt_request_id_ = request_id; + pending_audio_decrypt_cb_ = decrypt_cb; + break; + case media::Decryptor::kVideo: + DCHECK_EQ(pending_video_decrypt_request_id_, 0u); + DCHECK(pending_video_decrypt_cb_.is_null()); + pending_video_decrypt_request_id_ = request_id; + pending_video_decrypt_cb_ = decrypt_cb; + break; + default: + NOTREACHED(); + return false; + } + + plugin_decryption_interface_->Decrypt(pp_instance_, + encrypted_resource, + &block_info); + return true; +} + +bool ContentDecryptorDelegate::CancelDecrypt( + media::Decryptor::StreamType stream_type) { + DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type; + + media::Decryptor::DecryptCB decrypt_cb; + switch (stream_type) { + case media::Decryptor::kAudio: + pending_audio_decrypt_request_id_ = 0; + decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); + break; + case media::Decryptor::kVideo: + pending_video_decrypt_request_id_ = 0; + decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); + break; + default: + NOTREACHED(); + return false; + } + + if (!decrypt_cb.is_null()) + decrypt_cb.Run(media::Decryptor::kSuccess, NULL); + + return true; +} + +bool ContentDecryptorDelegate::InitializeAudioDecoder( + const media::AudioDecoderConfig& decoder_config, + const media::Decryptor::DecoderInitCB& init_cb) { + PP_AudioDecoderConfig pp_decoder_config; + pp_decoder_config.codec = + MediaAudioCodecToPpAudioCodec(decoder_config.codec()); + pp_decoder_config.channel_count = + media::ChannelLayoutToChannelCount(decoder_config.channel_layout()); + pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel(); + pp_decoder_config.samples_per_second = decoder_config.samples_per_second(); + pp_decoder_config.request_id = next_decryption_request_id_++; + + ScopedPPResource extra_data_resource( + ScopedPPResource::PassRef(), + MakeBufferResource(pp_instance_, + decoder_config.extra_data(), + decoder_config.extra_data_size())); + + DCHECK_EQ(pending_audio_decoder_init_request_id_, 0u); + DCHECK(pending_audio_decoder_init_cb_.is_null()); + pending_audio_decoder_init_request_id_ = pp_decoder_config.request_id; + pending_audio_decoder_init_cb_ = init_cb; + + plugin_decryption_interface_->InitializeAudioDecoder(pp_instance_, + &pp_decoder_config, + extra_data_resource); + return true; +} + +bool ContentDecryptorDelegate::InitializeVideoDecoder( + const media::VideoDecoderConfig& decoder_config, + const media::Decryptor::DecoderInitCB& init_cb) { + PP_VideoDecoderConfig pp_decoder_config; + pp_decoder_config.codec = + MediaVideoCodecToPpVideoCodec(decoder_config.codec()); + pp_decoder_config.profile = + MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile()); + pp_decoder_config.format = + MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format()); + pp_decoder_config.width = decoder_config.coded_size().width(); + pp_decoder_config.height = decoder_config.coded_size().height(); + pp_decoder_config.request_id = next_decryption_request_id_++; + + ScopedPPResource extra_data_resource( + ScopedPPResource::PassRef(), + MakeBufferResource(pp_instance_, + decoder_config.extra_data(), + decoder_config.extra_data_size())); + + DCHECK_EQ(pending_video_decoder_init_request_id_, 0u); + DCHECK(pending_video_decoder_init_cb_.is_null()); + pending_video_decoder_init_request_id_ = pp_decoder_config.request_id; + pending_video_decoder_init_cb_ = init_cb; + + plugin_decryption_interface_->InitializeVideoDecoder(pp_instance_, + &pp_decoder_config, + extra_data_resource); + return true; +} + +bool ContentDecryptorDelegate::DeinitializeDecoder( + media::Decryptor::StreamType stream_type) { + CancelDecode(stream_type); + + // TODO(tomfinegan): Add decoder deinitialize request tracking, and get + // stream type from media stack. + plugin_decryption_interface_->DeinitializeDecoder( + pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); + return true; +} + +bool ContentDecryptorDelegate::ResetDecoder( + media::Decryptor::StreamType stream_type) { + CancelDecode(stream_type); + + // TODO(tomfinegan): Add decoder reset request tracking. + plugin_decryption_interface_->ResetDecoder( + pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); + return true; +} + +bool ContentDecryptorDelegate::DecryptAndDecodeAudio( + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::AudioDecodeCB& audio_decode_cb) { + // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() + // return NULL and 0 respectively. In that case, we'll just create a 0 + // resource. + ScopedPPResource encrypted_resource( + ScopedPPResource::PassRef(), + MakeBufferResource(pp_instance_, + encrypted_buffer->GetData(), + encrypted_buffer->GetDataSize())); + if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) + return false; + + const uint32_t request_id = next_decryption_request_id_++; + DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id; + + PP_EncryptedBlockInfo block_info; + if (!MakeEncryptedBlockInfo( + encrypted_buffer->GetDecryptConfig(), + encrypted_buffer->GetTimestamp().InMicroseconds(), + request_id, + &block_info)) { + return false; + } + + // There is only one pending audio decode request at any time. This is + // enforced by the media pipeline. + DCHECK_EQ(pending_audio_decode_request_id_, 0u); + DCHECK(pending_audio_decode_cb_.is_null()); + pending_audio_decode_request_id_ = request_id; + pending_audio_decode_cb_ = audio_decode_cb; + + plugin_decryption_interface_->DecryptAndDecode(pp_instance_, + PP_DECRYPTORSTREAMTYPE_AUDIO, + encrypted_resource, + &block_info); + return true; +} + +bool ContentDecryptorDelegate::DecryptAndDecodeVideo( + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::VideoDecodeCB& video_decode_cb) { + // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() + // return NULL and 0 respectively. In that case, we'll just create a 0 + // resource. + ScopedPPResource encrypted_resource( + ScopedPPResource::PassRef(), + MakeBufferResource(pp_instance_, + encrypted_buffer->GetData(), + encrypted_buffer->GetDataSize())); + if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) + return false; + + const uint32_t request_id = next_decryption_request_id_++; + DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; + TRACE_EVENT_ASYNC_BEGIN0( + "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); + + PP_EncryptedBlockInfo block_info; + if (!MakeEncryptedBlockInfo( + encrypted_buffer->GetDecryptConfig(), + encrypted_buffer->GetTimestamp().InMicroseconds(), + request_id, + &block_info)) { + return false; + } + + // Only one pending video decode request at any time. This is enforced by the + // media pipeline. + DCHECK_EQ(pending_video_decode_request_id_, 0u); + DCHECK(pending_video_decode_cb_.is_null()); + pending_video_decode_request_id_ = request_id; + pending_video_decode_cb_ = video_decode_cb; + + // TODO(tomfinegan): Need to get stream type from media stack. + plugin_decryption_interface_->DecryptAndDecode(pp_instance_, + PP_DECRYPTORSTREAMTYPE_VIDEO, + encrypted_resource, + &block_info); + return true; +} + +void ContentDecryptorDelegate::NeedKey(PP_Var key_system_var, + PP_Var session_id_var, + PP_Var init_data_var) { + // TODO(tomfinegan): send the data to media stack. +} + +void ContentDecryptorDelegate::KeyAdded(PP_Var key_system_var, + PP_Var session_id_var) { + if (!decryptor_client_) + return; + + StringVar* key_system_string = StringVar::FromPPVar(key_system_var); + StringVar* session_id_string = StringVar::FromPPVar(session_id_var); + if (!key_system_string || !session_id_string) { + decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); + return; + } + + decryptor_client_->KeyAdded(key_system_string->value(), + session_id_string->value()); +} + +void ContentDecryptorDelegate::KeyMessage(PP_Var key_system_var, + PP_Var session_id_var, + PP_Resource message_resource, + PP_Var default_url_var) { + if (!decryptor_client_) + return; + + StringVar* key_system_string = StringVar::FromPPVar(key_system_var); + StringVar* session_id_string = StringVar::FromPPVar(session_id_var); + StringVar* default_url_string = StringVar::FromPPVar(default_url_var); + + if (!key_system_string || !session_id_string || !default_url_string) { + decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); + return; + } + + EnterResourceNoLock<PPB_Buffer_API> enter(message_resource, true); + if (!enter.succeeded()) { + decryptor_client_->KeyError(key_system_string->value(), + session_id_string->value(), + media::Decryptor::kUnknownError, + 0); + return; + } + + BufferAutoMapper mapper(enter.object()); + scoped_array<uint8> message_array(new uint8[mapper.size()]); + if (mapper.data() && mapper.size()) + memcpy(message_array.get(), mapper.data(), mapper.size()); + + decryptor_client_->KeyMessage(key_system_string->value(), + session_id_string->value(), + message_array.Pass(), + mapper.size(), + default_url_string->value()); +} + +void ContentDecryptorDelegate::KeyError(PP_Var key_system_var, + PP_Var session_id_var, + int32_t media_error, + int32_t system_code) { + if (!decryptor_client_) + return; + + StringVar* key_system_string = StringVar::FromPPVar(key_system_var); + StringVar* session_id_string = StringVar::FromPPVar(session_id_var); + if (!key_system_string || !session_id_string) { + decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); + return; + } + + decryptor_client_->KeyError( + key_system_string->value(), + session_id_string->value(), + static_cast<media::Decryptor::KeyError>(media_error), + system_code); +} + +void ContentDecryptorDelegate::DecoderInitializeDone( + PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success) { + if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) { + // If the request ID is not valid or does not match what's saved, do + // nothing. + if (request_id == 0 || + request_id != pending_audio_decoder_init_request_id_) + return; + + DCHECK(!pending_audio_decoder_init_cb_.is_null()); + pending_audio_decoder_init_request_id_ = 0; + base::ResetAndReturn( + &pending_audio_decoder_init_cb_).Run(PP_ToBool(success)); + } else { + if (request_id == 0 || + request_id != pending_video_decoder_init_request_id_) + return; + + DCHECK(!pending_video_decoder_init_cb_.is_null()); + pending_video_decoder_init_request_id_ = 0; + base::ResetAndReturn( + &pending_video_decoder_init_cb_).Run(PP_ToBool(success)); + } +} + +void ContentDecryptorDelegate::DecoderDeinitializeDone( + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + // TODO(tomfinegan): Add decoder stop completion handling. +} + +void ContentDecryptorDelegate::DecoderResetDone( + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + // TODO(tomfinegan): Add decoder reset completion handling. +} + +void ContentDecryptorDelegate::DeliverBlock( + PP_Resource decrypted_block, + const PP_DecryptedBlockInfo* block_info) { + DCHECK(block_info); + const uint32_t request_id = block_info->tracking_info.request_id; + DVLOG(2) << "DeliverBlock() - request_id: " << request_id; + + // If the request ID is not valid or does not match what's saved, do nothing. + if (request_id == 0) { + DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id; + return; + } + + media::Decryptor::DecryptCB decrypt_cb; + if (request_id == pending_audio_decrypt_request_id_) { + DCHECK(!pending_audio_decrypt_cb_.is_null()); + pending_audio_decrypt_request_id_ = 0; + decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); + } else if (request_id == pending_video_decrypt_request_id_) { + DCHECK(!pending_video_decrypt_cb_.is_null()); + pending_video_decrypt_request_id_ = 0; + decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); + } else { + DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found"; + return; + } + + media::Decryptor::Status status = + PpDecryptResultToMediaDecryptorStatus(block_info->result); + if (status != media::Decryptor::kSuccess) { + decrypt_cb.Run(status, NULL); + return; + } + + EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true); + if (!enter.succeeded()) { + decrypt_cb.Run(media::Decryptor::kError, NULL); + return; + } + BufferAutoMapper mapper(enter.object()); + if (!mapper.data() || !mapper.size()) { + decrypt_cb.Run(media::Decryptor::kError, NULL); + return; + } + + // TODO(tomfinegan): Find a way to take ownership of the shared memory + // managed by the PPB_Buffer_Dev, and avoid the extra copy. + scoped_refptr<media::DecoderBuffer> decrypted_buffer( + media::DecoderBuffer::CopyFrom( + static_cast<uint8*>(mapper.data()), mapper.size())); + decrypted_buffer->SetTimestamp(base::TimeDelta::FromMicroseconds( + block_info->tracking_info.timestamp)); + decrypt_cb.Run(media::Decryptor::kSuccess, decrypted_buffer); +} + +void ContentDecryptorDelegate::DeliverFrame( + PP_Resource decrypted_frame, + const PP_DecryptedFrameInfo* frame_info) { + DCHECK(frame_info); + const uint32_t request_id = frame_info->tracking_info.request_id; + DVLOG(2) << "DeliverFrame() - request_id: " << request_id; + + // If the request ID is not valid or does not match what's saved, do nothing. + if (request_id == 0 || request_id != pending_video_decode_request_id_) { + DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; + return; + } + + TRACE_EVENT_ASYNC_END0( + "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); + + DCHECK(!pending_video_decode_cb_.is_null()); + pending_video_decode_request_id_ = 0; + media::Decryptor::VideoDecodeCB video_decode_cb = + base::ResetAndReturn(&pending_video_decode_cb_); + + media::Decryptor::Status status = + PpDecryptResultToMediaDecryptorStatus(frame_info->result); + if (status != media::Decryptor::kSuccess) { + video_decode_cb.Run(status, NULL); + return; + } + + EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_frame, true); + if (!enter.succeeded()) { + video_decode_cb.Run(media::Decryptor::kError, NULL); + return; + } + BufferAutoMapper mapper(enter.object()); + if (!mapper.data() || !mapper.size()) { + video_decode_cb.Run(media::Decryptor::kError, NULL); + return; + } + + const uint8* frame_data = static_cast<uint8*>(mapper.data()); + gfx::Size frame_size(frame_info->width, frame_info->height); + + DCHECK(frame_info->format == PP_DECRYPTEDFRAMEFORMAT_YV12); + const media::VideoFrame::Format format = media::VideoFrame::YV12; + + // TODO(tomfinegan): Find a way to take ownership of the shared memory + // managed by the PPB_Buffer_Dev, and avoid the extra copy. + scoped_refptr<media::VideoFrame> decoded_frame( + media::VideoFrame::CreateFrame( + format, frame_size, frame_size, + base::TimeDelta::FromMicroseconds( + frame_info->tracking_info.timestamp))); + + media::CopyYPlane( + frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y], + frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y], + frame_info->height, + decoded_frame.get()); + + media::CopyUPlane( + frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U], + frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U], + frame_info->height, + decoded_frame.get()); + + media::CopyVPlane( + frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V], + frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V], + frame_info->height, + decoded_frame.get()); + + video_decode_cb.Run(media::Decryptor::kSuccess, decoded_frame); +} + +void ContentDecryptorDelegate::DeliverSamples( + PP_Resource audio_frames, + const PP_DecryptedBlockInfo* block_info) { + DCHECK(block_info); + const uint32_t request_id = block_info->tracking_info.request_id; + DVLOG(2) << "DeliverSamples() - request_id: " << request_id; + + // If the request ID is not valid or does not match what's saved, do nothing. + if (request_id == 0 || request_id != pending_audio_decode_request_id_) { + DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found"; + return; + } + + DCHECK(!pending_audio_decode_cb_.is_null()); + pending_audio_decode_request_id_ = 0; + media::Decryptor::AudioDecodeCB audio_decode_cb = + base::ResetAndReturn(&pending_audio_decode_cb_); + + const media::Decryptor::AudioBuffers empty_frames; + + media::Decryptor::Status status = + PpDecryptResultToMediaDecryptorStatus(block_info->result); + if (status != media::Decryptor::kSuccess) { + audio_decode_cb.Run(status, empty_frames); + return; + } + + media::Decryptor::AudioBuffers audio_frame_list; + if (!DeserializeAudioFrames(audio_frames, &audio_frame_list)) { + NOTREACHED() << "CDM did not serialize the buffer correctly."; + audio_decode_cb.Run(media::Decryptor::kError, empty_frames); + return; + } + + audio_decode_cb.Run(media::Decryptor::kSuccess, audio_frame_list); +} + +// TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt(). +void ContentDecryptorDelegate::CancelDecode( + media::Decryptor::StreamType stream_type) { + switch (stream_type) { + case media::Decryptor::kAudio: + pending_audio_decode_request_id_ = 0; + if (!pending_audio_decode_cb_.is_null()) + base::ResetAndReturn(&pending_audio_decode_cb_).Run( + media::Decryptor::kSuccess, media::Decryptor::AudioBuffers()); + break; + case media::Decryptor::kVideo: + pending_video_decode_request_id_ = 0; + if (!pending_video_decode_cb_.is_null()) + base::ResetAndReturn(&pending_video_decode_cb_).Run( + media::Decryptor::kSuccess, NULL); + break; + default: + NOTREACHED(); + } +} + +} // namespace ppapi +} // namespace webkit diff --git a/webkit/plugins/ppapi/content_decryptor_delegate.h b/webkit/plugins/ppapi/content_decryptor_delegate.h new file mode 100644 index 0000000..9d2d331 --- /dev/null +++ b/webkit/plugins/ppapi/content_decryptor_delegate.h @@ -0,0 +1,132 @@ +// 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_PLUGINS_PPAPI_CONTENT_DECRYPTOR_DELEGATE_H_ +#define WEBKIT_PLUGINS_PPAPI_CONTENT_DECRYPTOR_DELEGATE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "media/base/decryptor.h" +#include "ppapi/c/private/pp_content_decryptor.h" +#include "ppapi/c/private/ppp_content_decryptor_private.h" +#include "webkit/plugins/webkit_plugins_export.h" + +namespace media { +class AudioDecoderConfig; +class DecoderBuffer; +class DecryptorClient; +class VideoDecoderConfig; +} + +namespace webkit { +namespace ppapi { + +class WEBKIT_PLUGINS_EXPORT ContentDecryptorDelegate { + public: + // ContentDecryptorDelegate does not take ownership of + // |plugin_decryption_interface|. Therefore |plugin_decryption_interface| + // must outlive this object. + ContentDecryptorDelegate( + PP_Instance pp_instance, + const PPP_ContentDecryptor_Private* plugin_decryption_interface); + + // Provides access to PPP_ContentDecryptor_Private. + void set_decrypt_client(media::DecryptorClient* decryptor_client); + bool GenerateKeyRequest(const std::string& key_system, + const std::string& type, + const std::string& init_data); + bool AddKey(const std::string& session_id, + const std::string& key, + const std::string& init_data); + bool CancelKeyRequest(const std::string& session_id); + bool Decrypt(media::Decryptor::StreamType stream_type, + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::DecryptCB& decrypt_cb); + bool CancelDecrypt(media::Decryptor::StreamType stream_type); + bool InitializeAudioDecoder( + const media::AudioDecoderConfig& decoder_config, + const media::Decryptor::DecoderInitCB& decoder_init_cb); + bool InitializeVideoDecoder( + const media::VideoDecoderConfig& decoder_config, + const media::Decryptor::DecoderInitCB& decoder_init_cb); + // TODO(tomfinegan): Add callback args for DeinitializeDecoder() and + // ResetDecoder() + bool DeinitializeDecoder(media::Decryptor::StreamType stream_type); + bool ResetDecoder(media::Decryptor::StreamType stream_type); + // Note: These methods can be used with unencrypted data. + bool DecryptAndDecodeAudio( + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::AudioDecodeCB& audio_decode_cb); + bool DecryptAndDecodeVideo( + const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + const media::Decryptor::VideoDecodeCB& video_decode_cb); + + // PPB_ContentDecryptor_Private dispatching methods. + void NeedKey(PP_Var key_system, PP_Var session_id, PP_Var init_data); + void KeyAdded(PP_Var key_system, PP_Var session_id); + void KeyMessage(PP_Var key_system, + PP_Var session_id, + PP_Resource message, + PP_Var default_url); + void KeyError(PP_Var key_system, + PP_Var session_id, + int32_t media_error, + int32_t system_code); + void DeliverBlock(PP_Resource decrypted_block, + const PP_DecryptedBlockInfo* block_info); + void DecoderInitializeDone(PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success); + void DecoderDeinitializeDone(PP_DecryptorStreamType decoder_type, + uint32_t request_id); + void DecoderResetDone(PP_DecryptorStreamType decoder_type, + uint32_t request_id); + void DeliverFrame(PP_Resource decrypted_frame, + const PP_DecryptedFrameInfo* frame_info); + void DeliverSamples(PP_Resource audio_frames, + const PP_DecryptedBlockInfo* block_info); + + private: + // Cancels the pending decrypt-and-decode callback for |stream_type|. + void CancelDecode(media::Decryptor::StreamType stream_type); + + const PP_Instance pp_instance_; + const PPP_ContentDecryptor_Private* const plugin_decryption_interface_; + + media::DecryptorClient* decryptor_client_; + + // Request ID for tracking pending content decryption callbacks. + // Note that zero indicates an invalid request ID. + // TODO(xhwang): Add completion callbacks for Reset/Stop and remove the use + // of request IDs. + uint32_t next_decryption_request_id_; + + uint32_t pending_audio_decrypt_request_id_; + media::Decryptor::DecryptCB pending_audio_decrypt_cb_; + + uint32_t pending_video_decrypt_request_id_; + media::Decryptor::DecryptCB pending_video_decrypt_cb_; + + uint32_t pending_audio_decoder_init_request_id_; + media::Decryptor::DecoderInitCB pending_audio_decoder_init_cb_; + + uint32_t pending_video_decoder_init_request_id_; + media::Decryptor::DecoderInitCB pending_video_decoder_init_cb_; + + uint32_t pending_audio_decode_request_id_; + media::Decryptor::AudioDecodeCB pending_audio_decode_cb_; + + uint32_t pending_video_decode_request_id_; + media::Decryptor::VideoDecodeCB pending_video_decode_cb_; + + DISALLOW_COPY_AND_ASSIGN(ContentDecryptorDelegate); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_CONTENT_DECRYPTOR_DELEGATE_H_ diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index 795a00e..4aa3f99 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -15,15 +15,6 @@ #include "base/time.h" #include "base/utf_offset_string_conversions.h" #include "base/utf_string_conversions.h" -// TODO(xhwang): Move media specific code out of this class. -#include "media/base/audio_decoder_config.h" -#include "media/base/channel_layout.h" -#include "media/base/data_buffer.h" -#include "media/base/decoder_buffer.h" -#include "media/base/decryptor_client.h" -#include "media/base/video_decoder_config.h" -#include "media/base/video_frame.h" -#include "media/base/video_util.h" #include "ppapi/c/dev/ppb_find_dev.h" #include "ppapi/c/dev/ppb_zoom_dev.h" #include "ppapi/c/dev/ppp_find_dev.h" @@ -38,7 +29,6 @@ #include "ppapi/c/ppp_instance.h" #include "ppapi/c/ppp_messaging.h" #include "ppapi/c/ppp_mouse_lock.h" -#include "ppapi/c/private/pp_content_decryptor.h" #include "ppapi/c/private/ppp_instance_private.h" #include "ppapi/shared_impl/ppapi_preferences.h" #include "ppapi/shared_impl/ppb_gamepad_shared.h" @@ -77,6 +67,7 @@ #include "ui/gfx/rect_conversions.h" #include "webkit/plugins/plugin_constants.h" #include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/content_decryptor_delegate.h" #include "webkit/plugins/ppapi/event_conversion.h" #include "webkit/plugins/ppapi/fullscreen_container.h" #include "webkit/plugins/ppapi/gfx_conversion.h" @@ -90,8 +81,8 @@ #include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" #include "webkit/plugins/ppapi/ppb_image_data_impl.h" #include "webkit/plugins/ppapi/ppb_url_loader_impl.h" -#include "webkit/plugins/ppapi/url_request_info_util.h" #include "webkit/plugins/ppapi/ppp_pdf.h" +#include "webkit/plugins/ppapi/url_request_info_util.h" #include "webkit/plugins/sad_plugin.h" #if defined(OS_MACOSX) @@ -312,226 +303,6 @@ scoped_array<const char*> StringVectorToArgArray( return array.Pass(); } -// 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(PP_Instance instance, - const uint8* data, int size) { - if (!data || !size) - return 0; - - ScopedPPResource resource(PPB_Buffer_Impl::Create(instance, size)); - if (!resource.get()) - return 0; - - EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); - if (enter.failed()) - return 0; - - BufferAutoMapper mapper(enter.object()); - if (!mapper.data() || mapper.size() < static_cast<size_t>(size)) - return 0; - - memcpy(mapper.data(), data, size); - return resource.get(); -} - -// Copies the content of |str| into |array|. -// Returns true if copy succeeded. Returns false if copy failed, e.g. if the -// |array_size| is smaller than the |str| length. -template <uint32_t array_size> -bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) { - if (array_size < str.size()) - return false; - - memcpy(array, str.data(), str.size()); - return true; -} - -// Fills the |block_info| with information from |decrypt_config|, |timestamp| -// and |request_id|. |decrypt_config| can be NULL if the block is not encrypted. -// This is useful for end-of-stream blocks. -// Returns true if |block_info| is successfully filled. Returns false -// otherwise. -bool MakeEncryptedBlockInfo( - const media::DecryptConfig* decrypt_config, - int64_t timestamp, - uint32_t request_id, - PP_EncryptedBlockInfo* block_info) { - DCHECK(block_info); - - // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and - // anywhere else. - memset(block_info, 0, sizeof(*block_info)); - - block_info->tracking_info.request_id = request_id; - block_info->tracking_info.timestamp = timestamp; - - if (!decrypt_config) - return true; - - block_info->data_offset = decrypt_config->data_offset(); - - if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) || - !CopyStringToArray(decrypt_config->iv(), block_info->iv)) - return false; - - block_info->key_id_size = decrypt_config->key_id().size(); - block_info->iv_size = decrypt_config->iv().size(); - - if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples)) - return false; - - block_info->num_subsamples = decrypt_config->subsamples().size(); - for (uint32_t i = 0; i < block_info->num_subsamples; ++i) { - block_info->subsamples[i].clear_bytes = - decrypt_config->subsamples()[i].clear_bytes; - block_info->subsamples[i].cipher_bytes = - decrypt_config->subsamples()[i].cypher_bytes; - } - - return true; -} - -// Deserializes audio data stored in |audio_frames| into individual audio -// buffers in |frames|. Returns true upon success. -bool DeserializeAudioFrames(PP_Resource audio_frames, - media::Decryptor::AudioBuffers* frames) { - DCHECK(frames); - EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true); - if (!enter.succeeded()) - return false; - - BufferAutoMapper mapper(enter.object()); - if (!mapper.data() || !mapper.size()) - return false; - - const uint8* cur = static_cast<uint8*>(mapper.data()); - int bytes_left = mapper.size(); - - do { - int64 timestamp = 0; - int64 frame_size = -1; - const int kHeaderSize = sizeof(timestamp) + sizeof(frame_size); - - if (bytes_left < kHeaderSize) - return false; - - memcpy(×tamp, cur, sizeof(timestamp)); - cur += sizeof(timestamp); - bytes_left -= sizeof(timestamp); - - memcpy(&frame_size, cur, sizeof(frame_size)); - cur += sizeof(frame_size); - bytes_left -= sizeof(frame_size); - - // We should *not* have empty frame in the list. - if (frame_size <= 0 || bytes_left < frame_size) - return false; - - scoped_refptr<media::DataBuffer> frame(new media::DataBuffer(cur, - frame_size)); - frame->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); - frames->push_back(frame); - - cur += frame_size; - bytes_left -= frame_size; - } while (bytes_left > 0); - - return true; -} - -PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) { - switch (codec) { - case media::kCodecVorbis: - return PP_AUDIOCODEC_VORBIS; - case media::kCodecAAC: - return PP_AUDIOCODEC_AAC; - default: - return PP_AUDIOCODEC_UNKNOWN; - } -} - -PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) { - switch (codec) { - case media::kCodecVP8: - return PP_VIDEOCODEC_VP8; - case media::kCodecH264: - return PP_VIDEOCODEC_H264; - default: - return PP_VIDEOCODEC_UNKNOWN; - } -} - -PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile( - media::VideoCodecProfile profile) { - switch (profile) { - case media::VP8PROFILE_MAIN: - return PP_VIDEOCODECPROFILE_VP8_MAIN; - case media::H264PROFILE_BASELINE: - return PP_VIDEOCODECPROFILE_H264_BASELINE; - case media::H264PROFILE_MAIN: - return PP_VIDEOCODECPROFILE_H264_MAIN; - case media::H264PROFILE_EXTENDED: - return PP_VIDEOCODECPROFILE_H264_EXTENDED; - case media::H264PROFILE_HIGH: - return PP_VIDEOCODECPROFILE_H264_HIGH; - case media::H264PROFILE_HIGH10PROFILE: - return PP_VIDEOCODECPROFILE_H264_HIGH_10; - case media::H264PROFILE_HIGH422PROFILE: - return PP_VIDEOCODECPROFILE_H264_HIGH_422; - case media::H264PROFILE_HIGH444PREDICTIVEPROFILE: - return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE; - default: - return PP_VIDEOCODECPROFILE_UNKNOWN; - } -} - -PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat( - media::VideoFrame::Format format) { - switch (format) { - case media::VideoFrame::YV12: - return PP_DECRYPTEDFRAMEFORMAT_YV12; - case media::VideoFrame::I420: - return PP_DECRYPTEDFRAMEFORMAT_I420; - default: - return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; - } -} - -media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus( - PP_DecryptResult result) { - switch (result) { - case PP_DECRYPTRESULT_SUCCESS: - return media::Decryptor::kSuccess; - case PP_DECRYPTRESULT_DECRYPT_NOKEY: - return media::Decryptor::kNoKey; - case PP_DECRYPTRESULT_NEEDMOREDATA: - return media::Decryptor::kNeedMoreData; - case PP_DECRYPTRESULT_DECRYPT_ERROR: - return media::Decryptor::kError; - case PP_DECRYPTRESULT_DECODE_ERROR: - return media::Decryptor::kError; - default: - NOTREACHED(); - return media::Decryptor::kError; - } -} - -PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType( - media::Decryptor::StreamType stream_type) { - switch (stream_type) { - case media::Decryptor::kAudio: - return PP_DECRYPTORSTREAMTYPE_AUDIO; - case media::Decryptor::kVideo: - return PP_DECRYPTORSTREAMTYPE_VIDEO; - default: - NOTREACHED(); - return PP_DECRYPTORSTREAMTYPE_VIDEO; - } -} - } // namespace // static @@ -572,7 +343,6 @@ PluginInstance::PluginInstance( has_webkit_focus_(false), has_content_area_focus_(false), find_identifier_(-1), - plugin_decryption_interface_(NULL), plugin_find_interface_(NULL), plugin_input_event_interface_(NULL), plugin_messaging_interface_(NULL), @@ -603,15 +373,7 @@ PluginInstance::PluginInstance( selection_caret_(0), selection_anchor_(0), pending_user_gesture_(0.0), - flash_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), - decryptor_client_(NULL), - next_decryption_request_id_(1), - pending_audio_decrypt_request_id_(0), - pending_video_decrypt_request_id_(0), - pending_audio_decoder_init_request_id_(0), - pending_video_decoder_init_request_id_(0), - pending_audio_decode_request_id_(0), - pending_video_decode_request_id_(0) { + flash_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { pp_instance_ = HostGlobals::Get()->AddInstance(this); memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); @@ -1295,16 +1057,6 @@ void PluginInstance::StopFind() { plugin_find_interface_->StopFind(pp_instance()); } -bool PluginInstance::LoadContentDecryptorInterface() { - if (!plugin_decryption_interface_) { - plugin_decryption_interface_ = - static_cast<const PPP_ContentDecryptor_Private*>( - module_->GetPluginInterface( - PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE)); - } - return !!plugin_decryption_interface_; -} - bool PluginInstance::LoadFindInterface() { if (!plugin_find_interface_) { plugin_find_interface_ = @@ -1623,336 +1375,6 @@ void PluginInstance::RotateView(WebPlugin::RotationType type) { // NOTE: plugin instance may have been deleted. } -void PluginInstance::set_decrypt_client( - media::DecryptorClient* decryptor_client) { - decryptor_client_ = decryptor_client; -} - -bool PluginInstance::GenerateKeyRequest(const std::string& key_system, - const std::string& type, - const std::string& init_data) { - if (!LoadContentDecryptorInterface()) - return false; - if (key_system.empty()) - return false; - - PP_Var init_data_array = - PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( - init_data.size(), init_data.data()); - - plugin_decryption_interface_->GenerateKeyRequest( - pp_instance(), - StringVar::StringToPPVar(key_system), - StringVar::StringToPPVar(type), - init_data_array); - return true; -} - -bool PluginInstance::AddKey(const std::string& session_id, - const std::string& key, - const std::string& init_data) { - if (!LoadContentDecryptorInterface()) - return false; - PP_Var key_array = - PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(key.size(), - key.data()); - PP_Var init_data_array = - PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( - init_data.size(), - init_data.data()); - - plugin_decryption_interface_->AddKey( - pp_instance(), - StringVar::StringToPPVar(session_id), - key_array, - init_data_array); - return true; -} - -bool PluginInstance::CancelKeyRequest(const std::string& session_id) { - if (!LoadContentDecryptorInterface()) - return false; - plugin_decryption_interface_->CancelKeyRequest( - pp_instance(), - StringVar::StringToPPVar(session_id)); - return true; -} - -// TODO(xhwang): Remove duplication of code in Decrypt(), -// DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). -bool PluginInstance::Decrypt( - media::Decryptor::StreamType stream_type, - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::DecryptCB& decrypt_cb) { - DVLOG(3) << "Decrypt() - stream_type: " << stream_type; - if (!LoadContentDecryptorInterface()) - return false; - - ScopedPPResource encrypted_resource( - ScopedPPResource::PassRef(), - MakeBufferResource(pp_instance(), - encrypted_buffer->GetData(), - encrypted_buffer->GetDataSize())); - if (!encrypted_resource.get()) - return false; - - const uint32_t request_id = next_decryption_request_id_++; - DVLOG(2) << "Decrypt() - request_id " << request_id; - - PP_EncryptedBlockInfo block_info; - DCHECK(encrypted_buffer->GetDecryptConfig()); - if (!MakeEncryptedBlockInfo(encrypted_buffer->GetDecryptConfig(), - encrypted_buffer->GetTimestamp().InMicroseconds(), - request_id, - &block_info)) { - return false; - } - - // There is only one pending decrypt request at any time per stream. This is - // enforced by the media pipeline. - switch (stream_type) { - case media::Decryptor::kAudio: - DCHECK_EQ(pending_audio_decrypt_request_id_, 0u); - DCHECK(pending_audio_decrypt_cb_.is_null()); - pending_audio_decrypt_request_id_ = request_id; - pending_audio_decrypt_cb_ = decrypt_cb; - break; - case media::Decryptor::kVideo: - DCHECK_EQ(pending_video_decrypt_request_id_, 0u); - DCHECK(pending_video_decrypt_cb_.is_null()); - pending_video_decrypt_request_id_ = request_id; - pending_video_decrypt_cb_ = decrypt_cb; - break; - default: - NOTREACHED(); - return false; - } - - plugin_decryption_interface_->Decrypt(pp_instance(), - encrypted_resource, - &block_info); - return true; -} - -bool PluginInstance::CancelDecrypt(media::Decryptor::StreamType stream_type) { - DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type; - - media::Decryptor::DecryptCB decrypt_cb; - switch (stream_type) { - case media::Decryptor::kAudio: - pending_audio_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); - break; - case media::Decryptor::kVideo: - pending_video_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); - break; - default: - NOTREACHED(); - return false; - } - - if (!decrypt_cb.is_null()) - decrypt_cb.Run(media::Decryptor::kSuccess, NULL); - - return true; -} - -bool PluginInstance::InitializeAudioDecoder( - const media::AudioDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& init_cb) { - PP_AudioDecoderConfig pp_decoder_config; - pp_decoder_config.codec = - MediaAudioCodecToPpAudioCodec(decoder_config.codec()); - pp_decoder_config.channel_count = - media::ChannelLayoutToChannelCount(decoder_config.channel_layout()); - pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel(); - pp_decoder_config.samples_per_second = decoder_config.samples_per_second(); - pp_decoder_config.request_id = next_decryption_request_id_++; - - ScopedPPResource extra_data_resource( - ScopedPPResource::PassRef(), - MakeBufferResource(pp_instance(), - decoder_config.extra_data(), - decoder_config.extra_data_size())); - - DCHECK_EQ(pending_audio_decoder_init_request_id_, 0u); - DCHECK(pending_audio_decoder_init_cb_.is_null()); - pending_audio_decoder_init_request_id_ = pp_decoder_config.request_id; - pending_audio_decoder_init_cb_ = init_cb; - - plugin_decryption_interface_->InitializeAudioDecoder(pp_instance(), - &pp_decoder_config, - extra_data_resource); - return true; -} - -bool PluginInstance::InitializeVideoDecoder( - const media::VideoDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& init_cb) { - PP_VideoDecoderConfig pp_decoder_config; - pp_decoder_config.codec = - MediaVideoCodecToPpVideoCodec(decoder_config.codec()); - pp_decoder_config.profile = - MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile()); - pp_decoder_config.format = - MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format()); - pp_decoder_config.width = decoder_config.coded_size().width(); - pp_decoder_config.height = decoder_config.coded_size().height(); - pp_decoder_config.request_id = next_decryption_request_id_++; - - ScopedPPResource extra_data_resource( - ScopedPPResource::PassRef(), - MakeBufferResource(pp_instance(), - decoder_config.extra_data(), - decoder_config.extra_data_size())); - - DCHECK_EQ(pending_video_decoder_init_request_id_, 0u); - DCHECK(pending_video_decoder_init_cb_.is_null()); - pending_video_decoder_init_request_id_ = pp_decoder_config.request_id; - pending_video_decoder_init_cb_ = init_cb; - - plugin_decryption_interface_->InitializeVideoDecoder(pp_instance(), - &pp_decoder_config, - extra_data_resource); - return true; -} - -// TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt(). -void PluginInstance::CancelDecode(media::Decryptor::StreamType stream_type) { - switch (stream_type) { - case media::Decryptor::kAudio: - pending_audio_decode_request_id_ = 0; - if (!pending_audio_decode_cb_.is_null()) - base::ResetAndReturn(&pending_audio_decode_cb_).Run( - media::Decryptor::kSuccess, media::Decryptor::AudioBuffers()); - break; - case media::Decryptor::kVideo: - pending_video_decode_request_id_ = 0; - if (!pending_video_decode_cb_.is_null()) - base::ResetAndReturn(&pending_video_decode_cb_).Run( - media::Decryptor::kSuccess, NULL); - break; - default: - NOTREACHED(); - } -} - -bool PluginInstance::DeinitializeDecoder( - media::Decryptor::StreamType stream_type) { - if (!LoadContentDecryptorInterface()) - return false; - - CancelDecode(stream_type); - - // TODO(tomfinegan): Add decoder deinitialize request tracking, and get - // stream type from media stack. - plugin_decryption_interface_->DeinitializeDecoder( - pp_instance(), MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); - return true; -} - -bool PluginInstance::ResetDecoder(media::Decryptor::StreamType stream_type) { - if (!LoadContentDecryptorInterface()) - return false; - - CancelDecode(stream_type); - - // TODO(tomfinegan): Add decoder reset request tracking. - plugin_decryption_interface_->ResetDecoder( - pp_instance(), MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); - return true; -} - -bool PluginInstance::DecryptAndDecodeAudio( - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::AudioDecodeCB& audio_decode_cb) { - if (!LoadContentDecryptorInterface()) - return false; - - // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() - // return NULL and 0 respectively. In that case, we'll just create a 0 - // resource. - ScopedPPResource encrypted_resource( - ScopedPPResource::PassRef(), - MakeBufferResource(pp_instance(), - encrypted_buffer->GetData(), - encrypted_buffer->GetDataSize())); - if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) - return false; - - const uint32_t request_id = next_decryption_request_id_++; - DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id; - - PP_EncryptedBlockInfo block_info; - if (!MakeEncryptedBlockInfo( - encrypted_buffer->GetDecryptConfig(), - encrypted_buffer->GetTimestamp().InMicroseconds(), - request_id, - &block_info)) { - return false; - } - - // There is only one pending audio decode request at any time. This is - // enforced by the media pipeline. - DCHECK_EQ(pending_audio_decode_request_id_, 0u); - DCHECK(pending_audio_decode_cb_.is_null()); - pending_audio_decode_request_id_ = request_id; - pending_audio_decode_cb_ = audio_decode_cb; - - plugin_decryption_interface_->DecryptAndDecode(pp_instance(), - PP_DECRYPTORSTREAMTYPE_AUDIO, - encrypted_resource, - &block_info); - return true; -} - -bool PluginInstance::DecryptAndDecodeVideo( - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::VideoDecodeCB& video_decode_cb) { - if (!LoadContentDecryptorInterface()) - return false; - - // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() - // return NULL and 0 respectively. In that case, we'll just create a 0 - // resource. - ScopedPPResource encrypted_resource( - ScopedPPResource::PassRef(), - MakeBufferResource(pp_instance(), - encrypted_buffer->GetData(), - encrypted_buffer->GetDataSize())); - if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) - return false; - - const uint32_t request_id = next_decryption_request_id_++; - DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; - TRACE_EVENT_ASYNC_BEGIN0( - "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); - - PP_EncryptedBlockInfo block_info; - if (!MakeEncryptedBlockInfo( - encrypted_buffer->GetDecryptConfig(), - encrypted_buffer->GetTimestamp().InMicroseconds(), - request_id, - &block_info)) { - return false; - } - - // Only one pending video decode request at any time. This is enforced by the - // media pipeline. - DCHECK_EQ(pending_video_decode_request_id_, 0u); - DCHECK(pending_video_decode_cb_.is_null()); - pending_video_decode_request_id_ = request_id; - pending_video_decode_cb_ = video_decode_cb; - - // TODO(tomfinegan): Need to get stream type from media stack. - plugin_decryption_interface_->DecryptAndDecode(pp_instance(), - PP_DECRYPTORSTREAMTYPE_VIDEO, - encrypted_resource, - &block_info); - return true; -} - bool PluginInstance::FlashIsFullscreenOrPending() { return fullscreen_container_ != NULL; } @@ -2400,6 +1822,22 @@ void PluginInstance::SimulateImeSetCompositionEvent( utf16_text, underlines, offsets[0], offsets[1]); } +ContentDecryptorDelegate* PluginInstance::GetContentDecryptorDelegate() { + if (content_decryptor_delegate_) + return content_decryptor_delegate_.get(); + + const PPP_ContentDecryptor_Private* plugin_decryption_interface = + static_cast<const PPP_ContentDecryptor_Private*>( + module_->GetPluginInterface( + PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE)); + if (!plugin_decryption_interface) + return NULL; + + content_decryptor_delegate_.reset( + new ContentDecryptorDelegate(pp_instance_, plugin_decryption_interface)); + return content_decryptor_delegate_.get(); +} + void PluginInstance::ClosePendingUserGesture(PP_Instance instance, PP_TimeTicks timestamp) { // Do nothing so that the pending user gesture will stay open for @@ -2566,28 +2004,22 @@ PP_Var PluginInstance::GetFontFamilies(PP_Instance instance) { return PP_MakeUndefined(); } +// These PPB_ContentDecryptor_Private calls are responses to +// PPP_ContentDecryptor_Private calls made on |content_decryptor_delegate_|. +// Therefore, |content_decryptor_delegate_| must have been initialized when +// the following methods are called. void PluginInstance::NeedKey(PP_Instance instance, PP_Var key_system_var, PP_Var session_id_var, PP_Var init_data_var) { - // TODO(tomfinegan): send the data to media stack. + content_decryptor_delegate_->NeedKey( + key_system_var, session_id_var, init_data_var); } void PluginInstance::KeyAdded(PP_Instance instance, PP_Var key_system_var, PP_Var session_id_var) { - if (!decryptor_client_) - return; - - StringVar* key_system_string = StringVar::FromPPVar(key_system_var); - StringVar* session_id_string = StringVar::FromPPVar(session_id_var); - if (!key_system_string || !session_id_string) { - decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); - return; - } - - decryptor_client_->KeyAdded(key_system_string->value(), - session_id_string->value()); + content_decryptor_delegate_->KeyAdded(key_system_var, session_id_var); } void PluginInstance::KeyMessage(PP_Instance instance, @@ -2595,37 +2027,8 @@ void PluginInstance::KeyMessage(PP_Instance instance, PP_Var session_id_var, PP_Resource message_resource, PP_Var default_url_var) { - if (!decryptor_client_) - return; - - StringVar* key_system_string = StringVar::FromPPVar(key_system_var); - StringVar* session_id_string = StringVar::FromPPVar(session_id_var); - StringVar* default_url_string = StringVar::FromPPVar(default_url_var); - - if (!key_system_string || !session_id_string || !default_url_string) { - decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); - return; - } - - EnterResourceNoLock<PPB_Buffer_API> enter(message_resource, true); - if (!enter.succeeded()) { - decryptor_client_->KeyError(key_system_string->value(), - session_id_string->value(), - media::Decryptor::kUnknownError, - 0); - return; - } - - BufferAutoMapper mapper(enter.object()); - scoped_array<uint8> message_array(new uint8[mapper.size()]); - if (mapper.data() && mapper.size()) - memcpy(message_array.get(), mapper.data(), mapper.size()); - - decryptor_client_->KeyMessage(key_system_string->value(), - session_id_string->value(), - message_array.Pass(), - mapper.size(), - default_url_string->value()); + content_decryptor_delegate_->KeyMessage( + key_system_var, session_id_var, message_resource, default_url_var); } void PluginInstance::KeyError(PP_Instance instance, @@ -2633,227 +2036,49 @@ void PluginInstance::KeyError(PP_Instance instance, PP_Var session_id_var, int32_t media_error, int32_t system_code) { - if (!decryptor_client_) - return; - - StringVar* key_system_string = StringVar::FromPPVar(key_system_var); - StringVar* session_id_string = StringVar::FromPPVar(session_id_var); - if (!key_system_string || !session_id_string) { - decryptor_client_->KeyError("", "", media::Decryptor::kUnknownError, 0); - return; - } + content_decryptor_delegate_->KeyError( + key_system_var, session_id_var, media_error, system_code); +} - decryptor_client_->KeyError( - key_system_string->value(), - session_id_string->value(), - static_cast<media::Decryptor::KeyError>(media_error), - system_code); +void PluginInstance::DeliverBlock(PP_Instance instance, + PP_Resource decrypted_block, + const PP_DecryptedBlockInfo* block_info) { + content_decryptor_delegate_->DeliverBlock(decrypted_block, block_info); } void PluginInstance::DecoderInitializeDone(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id, PP_Bool success) { - if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) { - // If the request ID is not valid or does not match what's saved, do - // nothing. - if (request_id == 0 || - request_id != pending_audio_decoder_init_request_id_) - return; - - DCHECK(!pending_audio_decoder_init_cb_.is_null()); - pending_audio_decoder_init_request_id_ = 0; - base::ResetAndReturn( - &pending_audio_decoder_init_cb_).Run(PP_ToBool(success)); - } else { - if (request_id == 0 || - request_id != pending_video_decoder_init_request_id_) - return; - - DCHECK(!pending_video_decoder_init_cb_.is_null()); - pending_video_decoder_init_request_id_ = 0; - base::ResetAndReturn( - &pending_video_decoder_init_cb_).Run(PP_ToBool(success)); - } + content_decryptor_delegate_->DecoderInitializeDone( + decoder_type, request_id, success); } void PluginInstance::DecoderDeinitializeDone( PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id) { - // TODO(tomfinegan): Add decoder stop completion handling. + content_decryptor_delegate_->DecoderDeinitializeDone(decoder_type, + request_id); } void PluginInstance::DecoderResetDone(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id) { - // TODO(tomfinegan): Add decoder reset completion handling. + content_decryptor_delegate_->DecoderResetDone(decoder_type, request_id); } -void PluginInstance::DeliverBlock(PP_Instance instance, - PP_Resource decrypted_block, - const PP_DecryptedBlockInfo* block_info) { - DCHECK(block_info); - const uint32_t request_id = block_info->tracking_info.request_id; - DVLOG(2) << "DeliverBlock() - request_id: " << request_id; - - // If the request ID is not valid or does not match what's saved, do nothing. - if (request_id == 0) { - DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id; - return; - } - - media::Decryptor::DecryptCB decrypt_cb; - if (request_id == pending_audio_decrypt_request_id_) { - DCHECK(!pending_audio_decrypt_cb_.is_null()); - pending_audio_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); - } else if (request_id == pending_video_decrypt_request_id_) { - DCHECK(!pending_video_decrypt_cb_.is_null()); - pending_video_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); - } else { - DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found"; - return; - } - - media::Decryptor::Status status = - PpDecryptResultToMediaDecryptorStatus(block_info->result); - if (status != media::Decryptor::kSuccess) { - decrypt_cb.Run(status, NULL); - return; - } - - EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true); - if (!enter.succeeded()) { - decrypt_cb.Run(media::Decryptor::kError, NULL); - return; - } - BufferAutoMapper mapper(enter.object()); - if (!mapper.data() || !mapper.size()) { - decrypt_cb.Run(media::Decryptor::kError, NULL); - return; - } - - // TODO(tomfinegan): Find a way to take ownership of the shared memory - // managed by the PPB_Buffer_Dev, and avoid the extra copy. - scoped_refptr<media::DecoderBuffer> decrypted_buffer( - media::DecoderBuffer::CopyFrom( - static_cast<uint8*>(mapper.data()), mapper.size())); - decrypted_buffer->SetTimestamp(base::TimeDelta::FromMicroseconds( - block_info->tracking_info.timestamp)); - decrypt_cb.Run(media::Decryptor::kSuccess, decrypted_buffer); -} void PluginInstance::DeliverFrame(PP_Instance instance, PP_Resource decrypted_frame, const PP_DecryptedFrameInfo* frame_info) { - DCHECK(frame_info); - const uint32_t request_id = frame_info->tracking_info.request_id; - DVLOG(2) << "DeliverFrame() - request_id: " << request_id; - - // If the request ID is not valid or does not match what's saved, do nothing. - if (request_id == 0 || request_id != pending_video_decode_request_id_) { - DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; - return; - } - - TRACE_EVENT_ASYNC_END0( - "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); - - DCHECK(!pending_video_decode_cb_.is_null()); - pending_video_decode_request_id_ = 0; - media::Decryptor::VideoDecodeCB video_decode_cb = - base::ResetAndReturn(&pending_video_decode_cb_); - - media::Decryptor::Status status = - PpDecryptResultToMediaDecryptorStatus(frame_info->result); - if (status != media::Decryptor::kSuccess) { - video_decode_cb.Run(status, NULL); - return; - } - - EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_frame, true); - if (!enter.succeeded()) { - video_decode_cb.Run(media::Decryptor::kError, NULL); - return; - } - BufferAutoMapper mapper(enter.object()); - if (!mapper.data() || !mapper.size()) { - video_decode_cb.Run(media::Decryptor::kError, NULL); - return; - } - - const uint8* frame_data = static_cast<uint8*>(mapper.data()); - gfx::Size frame_size(frame_info->width, frame_info->height); - - DCHECK(frame_info->format == PP_DECRYPTEDFRAMEFORMAT_YV12); - const media::VideoFrame::Format format = media::VideoFrame::YV12; - - // TODO(tomfinegan): Find a way to take ownership of the shared memory - // managed by the PPB_Buffer_Dev, and avoid the extra copy. - scoped_refptr<media::VideoFrame> decoded_frame( - media::VideoFrame::CreateFrame( - format, frame_size, frame_size, - base::TimeDelta::FromMicroseconds( - frame_info->tracking_info.timestamp))); - - media::CopyYPlane( - frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y], - frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y], - frame_info->height, - decoded_frame.get()); - - media::CopyUPlane( - frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U], - frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U], - frame_info->height, - decoded_frame.get()); - - media::CopyVPlane( - frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V], - frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V], - frame_info->height, - decoded_frame.get()); - - video_decode_cb.Run(media::Decryptor::kSuccess, decoded_frame); + content_decryptor_delegate_->DeliverFrame(decrypted_frame, frame_info); } void PluginInstance::DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const PP_DecryptedBlockInfo* block_info) { - DCHECK(block_info); - const uint32_t request_id = block_info->tracking_info.request_id; - DVLOG(2) << "DeliverSamples() - request_id: " << request_id; - - // If the request ID is not valid or does not match what's saved, do nothing. - if (request_id == 0 || request_id != pending_audio_decode_request_id_) { - DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found"; - return; - } - - DCHECK(!pending_audio_decode_cb_.is_null()); - pending_audio_decode_request_id_ = 0; - media::Decryptor::AudioDecodeCB audio_decode_cb = - base::ResetAndReturn(&pending_audio_decode_cb_); - - const media::Decryptor::AudioBuffers empty_frames; - - media::Decryptor::Status status = - PpDecryptResultToMediaDecryptorStatus(block_info->result); - if (status != media::Decryptor::kSuccess) { - audio_decode_cb.Run(status, empty_frames); - return; - } - - media::Decryptor::AudioBuffers audio_frame_list; - if (!DeserializeAudioFrames(audio_frames, &audio_frame_list)) { - NOTREACHED() << "CDM did not serialize the buffer correctly."; - audio_decode_cb.Run(media::Decryptor::kError, empty_frames); - return; - } - - audio_decode_cb.Run(media::Decryptor::kSuccess, audio_frame_list); + content_decryptor_delegate_->DeliverSamples(audio_frames, block_info); } void PluginInstance::NumberOfFindResultsChanged(PP_Instance instance, diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h index 426106e..762510a 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.h +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -5,20 +5,17 @@ #ifndef WEBKIT_PLUGINS_PPAPI_PPAPI_PLUGIN_INSTANCE_H_ #define WEBKIT_PLUGINS_PPAPI_PPAPI_PLUGIN_INSTANCE_H_ -#include <map> #include <set> #include <string> #include <vector> #include "base/basictypes.h" -#include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/string16.h" #include "googleurl/src/gurl.h" -#include "media/base/decryptor.h" #include "ppapi/c/dev/pp_cursor_type_dev.h" #include "ppapi/c/dev/ppp_printing_dev.h" #include "ppapi/c/dev/ppp_find_dev.h" @@ -38,7 +35,6 @@ #include "ppapi/c/ppp_messaging.h" #include "ppapi/c/ppp_mouse_lock.h" #include "ppapi/c/private/ppb_content_decryptor_private.h" -#include "ppapi/c/private/ppp_content_decryptor_private.h" #include "ppapi/c/private/ppp_instance_private.h" #include "ppapi/shared_impl/ppb_instance_shared.h" #include "ppapi/shared_impl/ppb_view_shared.h" @@ -58,7 +54,6 @@ #include "webkit/plugins/ppapi/ppp_pdf.h" #include "webkit/plugins/webkit_plugins_export.h" -struct PP_DecryptedBlockInfo; struct PP_Point; class SkBitmap; @@ -73,13 +68,6 @@ struct WebCursorInfo; struct WebPrintParams; } -namespace media { -class AudioDecoderConfig; -class DecoderBuffer; -class DecryptorClient; -class VideoDecoderConfig; -} - namespace ppapi { struct InputEventData; struct PPP_Instance_Combined; @@ -94,6 +82,7 @@ class Range; namespace webkit { namespace ppapi { +class ContentDecryptorDelegate; class FullscreenContainer; class MessageChannel; class PluginDelegate; @@ -254,38 +243,6 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : void Graphics3DContextLost(); - // Provides access to PPP_ContentDecryptor_Private. - // TODO(tomfinegan): Move decryptor methods to delegate class. - void set_decrypt_client(media::DecryptorClient* client); - bool GenerateKeyRequest(const std::string& key_system, - const std::string& type, - const std::string& init_data); - bool AddKey(const std::string& session_id, - const std::string& key, - const std::string& init_data); - bool CancelKeyRequest(const std::string& session_id); - bool Decrypt(media::Decryptor::StreamType stream_type, - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::DecryptCB& decrypt_cb); - bool CancelDecrypt(media::Decryptor::StreamType stream_type); - bool InitializeAudioDecoder( - const media::AudioDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& decoder_init_cb); - bool InitializeVideoDecoder( - const media::VideoDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& decoder_init_cb); - // TODO(tomfinegan): Add callback args for DeinitializeDecoder() and - // ResetDecoder() - bool DeinitializeDecoder(media::Decryptor::StreamType stream_type); - bool ResetDecoder(media::Decryptor::StreamType stream_type); - // Note: These methods can be used with unencrypted data. - bool DecryptAndDecodeAudio( - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::AudioDecodeCB& audio_decode_cb); - bool DecryptAndDecodeVideo( - const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::VideoDecodeCB& video_decode_cb); - // There are 2 implementations of the fullscreen interface // PPB_FlashFullscreen is used by Pepper Flash. // PPB_Fullscreen is intended for other applications including NaCl. @@ -381,6 +338,8 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : void SimulateImeSetCompositionEvent( const ::ppapi::InputEventData& input_event); + ContentDecryptorDelegate* GetContentDecryptorDelegate(); + // PPB_Instance_API implementation. virtual PP_Bool BindGraphics(PP_Instance instance, PP_Resource device) OVERRIDE; @@ -458,9 +417,7 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : PP_Instance instance, PP_URLComponents_Dev* components) OVERRIDE; - // PPB_ContentDecryptor_Private - // TODO(tomfinegan): Move the PPB_ContentDecryptor_Private methods to a - // delegate class. + // PPB_ContentDecryptor_Private implementation. virtual void NeedKey(PP_Instance instance, PP_Var key_system, PP_Var session_id, @@ -525,7 +482,6 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : PluginModule* module, ::ppapi::PPP_Instance_Combined* instance_interface); - bool LoadContentDecryptorInterface(); bool LoadFindInterface(); bool LoadInputEventInterface(); bool LoadMessagingInterface(); @@ -605,9 +561,6 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : void SetSizeAttributesForFullscreen(); void ResetSizeAttributesAfterFullscreen(); - // Cancels the pending decrypt-and-decode callback for |stream_type|. - void CancelDecode(media::Decryptor::StreamType stream_type); - PluginDelegate* delegate_; scoped_refptr<PluginModule> module_; scoped_ptr< ::ppapi::PPP_Instance_Combined> instance_interface_; @@ -662,7 +615,6 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // The plugin-provided interfaces. // When adding PPP interfaces, make sure to reset them in ResetAsProxied. - const PPP_ContentDecryptor_Private* plugin_decryption_interface_; const PPP_Find_Dev* plugin_find_interface_; const PPP_InputEvent* plugin_input_event_interface_; const PPP_Messaging* plugin_messaging_interface_; @@ -796,31 +748,9 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // the pointer so we can re-send it later if we are reset to talk to NaCl. scoped_refptr<PPB_URLLoader_Impl> document_loader_; - media::DecryptorClient* decryptor_client_; - - // Request ID for tracking pending content decryption callbacks. - // Note that zero indicates an invalid request ID. - // TODO(xhwang): Add completion callbacks for Reset/Stop and remove the use - // of request IDs. - uint32_t next_decryption_request_id_; - - uint32_t pending_audio_decrypt_request_id_; - media::Decryptor::DecryptCB pending_audio_decrypt_cb_; - - uint32_t pending_video_decrypt_request_id_; - media::Decryptor::DecryptCB pending_video_decrypt_cb_; - - uint32_t pending_audio_decoder_init_request_id_; - media::Decryptor::DecoderInitCB pending_audio_decoder_init_cb_; - - uint32_t pending_video_decoder_init_request_id_; - media::Decryptor::DecoderInitCB pending_video_decoder_init_cb_; - - uint32_t pending_audio_decode_request_id_; - media::Decryptor::AudioDecodeCB pending_audio_decode_cb_; - - uint32_t pending_video_decode_request_id_; - media::Decryptor::VideoDecodeCB pending_video_decode_cb_; + // The ContentDecryptorDelegate forwards PPP_ContentDecryptor_Private + // calls and handles PPB_ContentDecryptor_Private calls. + scoped_ptr<ContentDecryptorDelegate> content_decryptor_delegate_; DISALLOW_COPY_AND_ASSIGN(PluginInstance); }; |