Chromium Code Reviews| Index: webkit/plugins/ppapi/ppapi_plugin_instance.cc |
| diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc |
| index d630a722704e18eaef7304645ffb1b787d2cc0ae..7f23b56858331611ec9a4eb384c93726ceb555b1 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_)); |
| @@ -1559,7 +1569,7 @@ bool PluginInstance::Decrypt( |
| 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)) { |
| @@ -1577,7 +1587,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()); |
| @@ -1589,17 +1599,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); |
| @@ -1633,30 +1643,36 @@ 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()) |
| - return false; |
| - |
| + ScopedPPResource encrypted_resource; |
| + PP_EncryptedBlockInfo block_info; |
| const uint32_t request_id = next_decryption_request_id_++; |
| - PP_EncryptedBlockInfo block_info; |
| - DCHECK(encrypted_buffer->GetDecryptConfig()); |
| - if (!MakeEncryptedBlockInfo(*encrypted_buffer->GetDecryptConfig(), |
| - encrypted_buffer->GetTimestamp().InMicroseconds(), |
| - request_id, |
| - &block_info)) { |
| + if (!encrypted_buffer->IsEndOfStream()) { |
| + encrypted_resource = MakeBufferResource(pp_instance(), |
| + encrypted_buffer->GetData(), |
| + encrypted_buffer->GetDataSize()); |
| + if (!encrypted_resource.get()) |
| + return false; |
| + } |
| + |
| + 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(), |
| @@ -2362,17 +2378,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( |
| @@ -2403,6 +2415,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; |
| @@ -2432,8 +2445,77 @@ void PluginInstance::DeliverBlock(PP_Instance instance, |
| void PluginInstance::DeliverFrame(PP_Instance instance, |
| PP_Resource decrypted_frame, |
| const PP_DecryptedFrameInfo* frame_info) { |
| - // TODO(tomfinegan): To be implemented after completion of v0.1 of the |
| - // EME/CDM work. |
| + DCHECK(frame_info); |
| + uint32_t request_id = frame_info->tracking_info.request_id; |
|
ddorwin
2012/10/13 01:40:28
nit: Since this is just an alias, I think it shoul
xhwang
2012/10/15 19:53:01
Done.
|
| + |
| + // 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_) |
|
ddorwin
2012/10/13 01:40:28
DCHECK?
xhwang
2012/10/15 19:53:01
My whole point is that I treat CDM as a third part
ddorwin
2012/10/15 23:31:38
Well, we want to catch bugs in these third-party m
|
| + 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 = reinterpret_cast<uint8*>(mapper.data()); |
| + |
| + // TODO(tomfinegan): Find a way to take ownership of the shared memory |
|
ddorwin
2012/10/13 01:40:28
Should this be before 2494 instead?
xhwang
2012/10/15 19:53:01
Done.
|
| + // managed by the PPB_Buffer_Dev, and avoid the extra copy. |
| + DCHECK(frame_info->format == PP_DECRYPTEDFRAMEFORMAT_YV12); |
|
ddorwin
2012/10/13 01:40:28
This should be closer to the use of the YV12 enum.
xhwang
2012/10/15 19:53:01
Done.
|
| + gfx::Size frame_size(frame_info->width, frame_info->height); |
| + |
| + scoped_refptr<media::VideoFrame> decoded_frame( |
| + media::VideoFrame::CreateFrame( |
| + media::VideoFrame::YV12, 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, |