diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 07:02:25 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 07:02:25 +0000 |
commit | 741c28f9db1521cb02c6b89fe2966f67f4329dff (patch) | |
tree | f2374aebedd9c46a28d513b4b713a55d44f4a4e2 /webkit/plugins | |
parent | 4eb2f2630d82f0ebd859092a99c7e900dc9360f5 (diff) | |
download | chromium_src-741c28f9db1521cb02c6b89fe2966f67f4329dff.zip chromium_src-741c28f9db1521cb02c6b89fe2966f67f4329dff.tar.gz chromium_src-741c28f9db1521cb02c6b89fe2966f67f4329dff.tar.bz2 |
Update PluginInstance for decrypt-and-decode video.
- Hook up PpapiDecryptor and PluginInstance in terms of decrypt-and-decode calls.
- Enable empty input buffer and empty video frame to be passed to/from the plugin. This is used for end-of-stream buffer/frames.
- Add logs in DecryptingVideoDecoder.
BUG=141780,141784
TEST=Decrypt-and-decode of video is working with a fake video decoder in clearkey CDM.
Review URL: https://chromiumcodereview.appspot.com/11091005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162657 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins')
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.cc | 179 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.h | 20 |
2 files changed, 150 insertions, 49 deletions
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index 5206617..2a14faf 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -5,6 +5,7 @@ #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/memory/linked_ptr.h" @@ -14,10 +15,12 @@ #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/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" @@ -344,11 +347,12 @@ bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) { } // Fills the |block_info| with information from |decrypt_config|, |timestamp| -// and |request_id|. +// 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, + const media::DecryptConfig* decrypt_config, int64_t timestamp, uint32_t request_id, PP_EncryptedBlockInfo* block_info) { @@ -360,24 +364,28 @@ bool MakeEncryptedBlockInfo( block_info->tracking_info.request_id = request_id; block_info->tracking_info.timestamp = timestamp; - 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)) + 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(); + 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)) + if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples)) return false; - block_info->num_subsamples = decrypt_config.subsamples().size(); + 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; + decrypt_config->subsamples()[i].clear_bytes; block_info->subsamples[i].cipher_bytes = - decrypt_config.subsamples()[i].cypher_bytes; + decrypt_config->subsamples()[i].cypher_bytes; } return true; @@ -483,7 +491,9 @@ PluginInstance::PluginInstance( pending_user_gesture_(0.0), flash_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), decryptor_client_(NULL), - next_decryption_request_id_(1) { + next_decryption_request_id_(1), + pending_video_decoder_init_request_id_(0), + pending_video_decode_request_id_(0) { pp_instance_ = HostGlobals::Get()->AddInstance(this); memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); @@ -1556,12 +1566,12 @@ bool PluginInstance::Decrypt( if (!encrypted_resource.get()) return false; - uint32_t request_id = next_decryption_request_id_++; + 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(), + if (!MakeEncryptedBlockInfo(encrypted_buffer->GetDecryptConfig(), encrypted_buffer->GetTimestamp().InMicroseconds(), request_id, &block_info)) { @@ -1579,7 +1589,7 @@ bool PluginInstance::Decrypt( bool PluginInstance::InitializeVideoDecoder( const media::VideoDecoderConfig& decoder_config, - const media::Decryptor::DecryptCB& decrypt_cb) { + const media::Decryptor::DecoderInitCB& init_cb) { PP_VideoDecoderConfig pp_decoder_config; pp_decoder_config.codec = MediaVideoCodecToPpVideoCodec(decoder_config.codec()); @@ -1591,17 +1601,17 @@ bool PluginInstance::InitializeVideoDecoder( pp_decoder_config.height = decoder_config.coded_size().height(); pp_decoder_config.request_id = next_decryption_request_id_++; - // TODO(xhwang): Use individual variables for decoder init request tracking. - DCHECK(!ContainsKey(pending_decryption_cbs_, pp_decoder_config.request_id)); - pending_decryption_cbs_.insert(std::make_pair(pp_decoder_config.request_id, - decrypt_cb)); - 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); @@ -1635,30 +1645,39 @@ bool PluginInstance::ResetDecoder() { bool PluginInstance::DecryptAndDecode( const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::DecryptCB& decrypt_cb) { + const media::Decryptor::VideoDecodeCB& video_decode_cb) { if (!LoadContentDecryptorInterface()) return false; - ScopedPPResource encrypted_resource(MakeBufferResource( - pp_instance(), - encrypted_buffer->GetData(), - encrypted_buffer->GetDataSize())); - if (!encrypted_resource.get()) + // 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) << "DecryptAndDecode() - 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)) { + if (!MakeEncryptedBlockInfo( + encrypted_buffer->GetDecryptConfig(), + encrypted_buffer->GetTimestamp().InMicroseconds(), + request_id, + &block_info)) { return false; } - DCHECK(!ContainsKey(pending_decryption_cbs_, request_id)); - pending_decryption_cbs_.insert(std::make_pair(request_id, decrypt_cb)); + // 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(), @@ -2364,17 +2383,13 @@ void PluginInstance::KeyError(PP_Instance instance, void PluginInstance::DecoderInitialized(PP_Instance instance, PP_Bool success, uint32_t request_id) { - // TODO(xhwang): Use individual variables for decoder init request tracking. - DecryptionCBMap::iterator found = pending_decryption_cbs_.find(request_id); - if (found == pending_decryption_cbs_.end()) + // If the request ID is not valid or does not match what's saved, do nothing. + if (request_id == 0 || request_id != pending_video_decoder_init_request_id_) return; - media::Decryptor::DecryptCB decrypt_cb = found->second; - pending_decryption_cbs_.erase(found); - media::Decryptor::Status status = - success == PP_TRUE ? media::Decryptor::kSuccess : - media::Decryptor::kError; - decrypt_cb.Run(status, NULL); + 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 PluginInstance::DecoderDeinitializeDone( @@ -2407,6 +2422,7 @@ void PluginInstance::DeliverBlock(PP_Instance instance, decrypt_cb.Run(media::Decryptor::kNoKey, NULL); return; } + if (block_info->result != PP_DECRYPTRESULT_SUCCESS) { decrypt_cb.Run(media::Decryptor::kError, NULL); return; @@ -2427,7 +2443,7 @@ void PluginInstance::DeliverBlock(PP_Instance instance, // managed by the PPB_Buffer_Dev, and avoid the extra copy. scoped_refptr<media::DecoderBuffer> decrypted_buffer( media::DecoderBuffer::CopyFrom( - reinterpret_cast<const uint8*>(mapper.data()), mapper.size())); + 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); @@ -2438,8 +2454,81 @@ void PluginInstance::DeliverFrame(PP_Instance instance, const PP_DecryptedFrameInfo* frame_info) { DVLOG(2) << "DeliverFrame() - request_id: " << frame_info->tracking_info.request_id; - // TODO(tomfinegan): To be implemented after completion of v0.1 of the - // EME/CDM work. + DCHECK(frame_info); + + // If the request ID is not valid or does not match what's saved, do nothing. + if (frame_info->tracking_info.request_id == 0 || + frame_info->tracking_info.request_id != + pending_video_decode_request_id_) { + DCHECK(pending_video_decode_cb_.is_null()); + return; + } + + 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_); + + if (frame_info->result == PP_DECRYPTRESULT_DECRYPT_NOKEY) { + video_decode_cb.Run(media::Decryptor::kNoKey, NULL); + return; + } + + if (frame_info->result != PP_DECRYPTRESULT_SUCCESS) { + video_decode_cb.Run(media::Decryptor::kError, NULL); + return; + } + + if (frame_info->format == PP_DECRYPTEDFRAMEFORMAT_EMPTY) { + video_decode_cb.Run(media::Decryptor::kSuccess, + media::VideoFrame::CreateEmptyFrame()); + 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 PluginInstance::DeliverSamples(PP_Instance instance, diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h index d14e7b2..29d6869 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.h +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -263,19 +263,17 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : bool CancelKeyRequest(const std::string& session_id); bool Decrypt(const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, const media::Decryptor::DecryptCB& decrypt_cb); - // TODO(xhwang): Change DecryptCB to a DecoderInitCB. bool InitializeVideoDecoder( const media::VideoDecoderConfig& decoder_config, - const media::Decryptor::DecryptCB& decrypt_cb); + const media::Decryptor::DecoderInitCB& decoder_init_cb); // TODO(tomfinegan): Add callback args for DeinitializeDecoder() and // ResetDecoder() bool DeinitializeDecoder(); bool ResetDecoder(); - // TODO(xhwang): Update this when we need to support decrypt and decode. // Note: This method can be used with an unencrypted frame. bool DecryptAndDecode( const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::DecryptCB& decrypt_cb); + const media::Decryptor::VideoDecodeCB& video_decode_cb); // There are 2 implementations of the fullscreen interface // PPB_FlashFullscreen is used by Pepper Flash. @@ -782,10 +780,24 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : 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_; + + // TODO(xhwang): Use two separate callbacks for video and audio instead using + // a map here. typedef std::map<uint32_t, media::Decryptor::DecryptCB> DecryptionCBMap; DecryptionCBMap pending_decryption_cbs_; + uint32_t pending_video_decoder_init_request_id_; + media::Decryptor::DecoderInitCB pending_video_decoder_init_cb_; + + uint32_t pending_video_decode_request_id_; + media::Decryptor::VideoDecodeCB pending_video_decode_cb_; + DISALLOW_COPY_AND_ASSIGN(PluginInstance); }; |