diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-24 22:33:54 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-24 22:33:54 +0000 |
commit | ecbb97687dd14622163c5ab5861fc6f8392e35c6 (patch) | |
tree | 3a08fb89e0da0801e006141f5740b5d0529930c6 /webkit | |
parent | 2bd7d9ec294434bc9819ee7cd553545c6eb765a3 (diff) | |
download | chromium_src-ecbb97687dd14622163c5ab5861fc6f8392e35c6.zip chromium_src-ecbb97687dd14622163c5ab5861fc6f8392e35c6.tar.gz chromium_src-ecbb97687dd14622163c5ab5861fc6f8392e35c6.tar.bz2 |
Update PluginInstance for audio support for content decryption.
BUG=123421
TEST=none
Review URL: https://chromiumcodereview.appspot.com/11189082
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163931 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/media/crypto/ppapi/cdm_wrapper.cc | 94 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/clear_key_cdm.cc | 11 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/clear_key_cdm.h | 2 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/content_decryption_module.h | 57 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi_decryptor.cc | 24 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.cc | 292 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.h | 30 |
7 files changed, 407 insertions, 103 deletions
diff --git a/webkit/media/crypto/ppapi/cdm_wrapper.cc b/webkit/media/crypto/ppapi/cdm_wrapper.cc index 77c2248..592ac1e 100644 --- a/webkit/media/crypto/ppapi/cdm_wrapper.cc +++ b/webkit/media/crypto/ppapi/cdm_wrapper.cc @@ -441,6 +441,28 @@ int64_t VideoFrameImpl::timestamp() const { return timestamp_; } +class AudioFramesImpl : public cdm::AudioFrames { + public: + AudioFramesImpl() : buffer_(NULL) {} + virtual ~AudioFramesImpl() { + if (buffer_) + buffer_->Destroy(); + } + + // AudioFrames implementation. + virtual void set_buffer(cdm::Buffer* buffer) OVERRIDE { + buffer_ = static_cast<PpbBuffer*>(buffer); + } + virtual cdm::Buffer* buffer() OVERRIDE { + return buffer_; + } + + private: + PpbBuffer* buffer_; + + DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl); +}; + // A wrapper class for abstracting away PPAPI interaction and threading for a // Content Decryption Module (CDM). class CdmWrapper : public pp::Instance, @@ -488,6 +510,7 @@ class CdmWrapper : public pp::Instance, typedef linked_ptr<DecryptedBlockImpl> LinkedDecryptedBlock; typedef linked_ptr<KeyMessageImpl> LinkedKeyMessage; typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame; + typedef linked_ptr<AudioFramesImpl> LinkedAudioFrames; // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to // <code>callback_factory_</code> to ensure that calls into @@ -513,6 +536,10 @@ class CdmWrapper : public pp::Instance, const cdm::Status& status, const LinkedVideoFrame& video_frame, const PP_DecryptTrackingInfo& tracking_info); + void DeliverSamples(int32_t result, + const cdm::Status& status, + const LinkedAudioFrames& audio_frames, + const PP_DecryptTrackingInfo& tracking_info); // Helper for SetTimer(). void TimerExpired(int32 result); @@ -714,8 +741,6 @@ void CdmWrapper::DecryptAndDecode( PP_DecryptorStreamType decoder_type, pp::Buffer_Dev encrypted_buffer, const PP_EncryptedBlockInfo& encrypted_block_info) { - // TODO(tomfinegan): Remove this check when audio decoding is added. - PP_DCHECK(decoder_type == PP_DECRYPTORSTREAMTYPE_VIDEO); PP_DCHECK(cdm_); cdm::InputBuffer input_buffer; @@ -727,14 +752,34 @@ void CdmWrapper::DecryptAndDecode( &input_buffer); } - LinkedVideoFrame video_frame(new VideoFrameImpl()); - cdm::Status status = cdm_->DecryptAndDecodeFrame(input_buffer, - video_frame.get()); - CallOnMain(callback_factory_.NewCallback( - &CdmWrapper::DeliverFrame, - status, - video_frame, - encrypted_block_info.tracking_info)); + cdm::Status status = cdm::kDecodeError; + switch (decoder_type) { + case PP_DECRYPTORSTREAMTYPE_VIDEO: { + LinkedVideoFrame video_frame(new VideoFrameImpl()); + status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); + CallOnMain(callback_factory_.NewCallback( + &CdmWrapper::DeliverFrame, + status, + video_frame, + encrypted_block_info.tracking_info)); + return; + } + + case PP_DECRYPTORSTREAMTYPE_AUDIO: { + LinkedAudioFrames audio_frames(new AudioFramesImpl()); + status = cdm_->DecryptAndDecodeSamples(input_buffer, audio_frames.get()); + CallOnMain(callback_factory_.NewCallback( + &CdmWrapper::DeliverSamples, + status, + audio_frames, + encrypted_block_info.tracking_info)); + return; + } + + default: + PP_NOTREACHED(); + return; + } } void CdmWrapper::SetTimer(int64 delay_ms) { @@ -808,6 +853,7 @@ void CdmWrapper::DeliverBlock(int32_t result, if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { PP_DCHECK(decrypted_block.get() && decrypted_block->buffer()); if (!decrypted_block.get() || !decrypted_block->buffer()) { + PP_NOTREACHED(); decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; } else { buffer = static_cast<PpbBuffer*>(decrypted_block->buffer())->buffer_dev(); @@ -864,6 +910,7 @@ void CdmWrapper::DeliverFrame( !video_frame->frame_buffer() || (decrypted_frame_info.format != PP_DECRYPTEDFRAMEFORMAT_YV12 && decrypted_frame_info.format != PP_DECRYPTEDFRAMEFORMAT_I420)) { + PP_NOTREACHED(); decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; } else { buffer = static_cast<PpbBuffer*>( @@ -888,6 +935,33 @@ void CdmWrapper::DeliverFrame( pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); } +void CdmWrapper::DeliverSamples(int32_t result, + const cdm::Status& status, + const LinkedAudioFrames& audio_frames, + const PP_DecryptTrackingInfo& tracking_info) { + PP_DCHECK(result == PP_OK); + // TODO(tomfinegan): Add PP_DecryptedSamplesInfo (or better name) for + // cdm::AudioFrames. + PP_DecryptedBlockInfo decrypted_block_info; + decrypted_block_info.tracking_info = tracking_info; + // TODO(tomfinegan): Remove this after PP_DecryptedSamplesInfo is added. + decrypted_block_info.tracking_info.timestamp = 0; + decrypted_block_info.result = CdmStatusToPpDecryptResult(status); + + pp::Buffer_Dev buffer; + + if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { + PP_DCHECK(audio_frames.get() && audio_frames->buffer()); + if (!audio_frames.get() || !audio_frames->buffer()) { + PP_NOTREACHED(); + decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; + } else { + buffer = static_cast<PpbBuffer*>(audio_frames->buffer())->buffer_dev(); + } + } + + pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info); +} // This object is the global object representing this plugin library as long // as it is loaded. diff --git a/webkit/media/crypto/ppapi/clear_key_cdm.cc b/webkit/media/crypto/ppapi/clear_key_cdm.cc index 00a11a3..390de92 100644 --- a/webkit/media/crypto/ppapi/clear_key_cdm.cc +++ b/webkit/media/crypto/ppapi/clear_key_cdm.cc @@ -283,20 +283,19 @@ cdm::Status ClearKeyCdm::InitializeVideoDecoder( NOTIMPLEMENTED(); return cdm::kSessionError; #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER - } void ClearKeyCdm::ResetDecoder(cdm::StreamType decoder_type) { #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) - DCHECK(decoder_type == cdm::kStreamTypeVideo); - video_decoder_->Reset(); + if (decoder_type == cdm::kStreamTypeVideo) + video_decoder_->Reset(); #endif } void ClearKeyCdm::DeinitializeDecoder(cdm::StreamType decoder_type) { #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) - DCHECK(decoder_type == cdm::kStreamTypeVideo); - video_decoder_->Deinitialize(); + if (decoder_type == cdm::kStreamTypeVideo) + video_decoder_->Deinitialize(); #endif } @@ -407,7 +406,7 @@ void ClearKeyCdm::GenerateFakeVideoFrame(base::TimeDelta timestamp, cdm::Status ClearKeyCdm::DecryptAndDecodeSamples( const cdm::InputBuffer& encrypted_buffer, - cdm::Buffer* sample_buffer) { + cdm::AudioFrames* audio_frames) { NOTIMPLEMENTED(); return cdm::kDecryptError; } diff --git a/webkit/media/crypto/ppapi/clear_key_cdm.h b/webkit/media/crypto/ppapi/clear_key_cdm.h index e490b95..09bc01b 100644 --- a/webkit/media/crypto/ppapi/clear_key_cdm.h +++ b/webkit/media/crypto/ppapi/clear_key_cdm.h @@ -64,7 +64,7 @@ class ClearKeyCdm : public cdm::ContentDecryptionModule { cdm::VideoFrame* video_frame) OVERRIDE; virtual cdm::Status DecryptAndDecodeSamples( const cdm::InputBuffer& encrypted_buffer, - cdm::Buffer* sample_buffer) OVERRIDE; + cdm::AudioFrames* audio_frames) OVERRIDE; private: class Client : public media::DecryptorClient { diff --git a/webkit/media/crypto/ppapi/content_decryption_module.h b/webkit/media/crypto/ppapi/content_decryption_module.h index 7d82d1b..aedf6d4 100644 --- a/webkit/media/crypto/ppapi/content_decryption_module.h +++ b/webkit/media/crypto/ppapi/content_decryption_module.h @@ -18,12 +18,8 @@ typedef __int64 int64_t; namespace cdm { class Allocator; -class Buffer; class CdmHost; class ContentDecryptionModule; -class DecryptedBlock; -class KeyMessage; -class VideoFrame; } extern "C" { @@ -37,6 +33,12 @@ CDM_EXPORT const char* GetCdmVersion(); namespace cdm { +class AudioFrames; +class Buffer; +class DecryptedBlock; +class KeyMessage; +class VideoFrame; + enum Status { kSuccess = 0, kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. @@ -315,20 +317,8 @@ class ContentDecryptionModule { // Returns kDecodeError if any decoding error happened. // If the return value is not kSuccess, |audio_frames| should be ignored by // the caller. - // - // |audio_frames| can contain multiple audio output buffers. Each buffer must - // be serialized in this format: - // - // |<------------------- serialized audio buffer ------------------->| - // | int64_t timestamp | int64_t length | length bytes of audio data | - // - // For example, with three audio output buffers, |audio_frames| will look - // like this: - // - // |<---------------- audio_frames ------------------>| - // | audio buffer 0 | audio buffer 1 | audio buffer 2 | virtual Status DecryptAndDecodeSamples(const InputBuffer& encrypted_buffer, - Buffer* audio_frames) = 0; + AudioFrames* audio_frames) = 0; virtual ~ContentDecryptionModule() {} }; @@ -415,10 +405,10 @@ class KeyMessage { class VideoFrame { public: enum VideoPlane { - kYPlane = 0, - kUPlane = 1, - kVPlane = 2, - kMaxPlanes = 3, + kYPlane = 0, + kUPlane = 1, + kVPlane = 2, + kMaxPlanes = 3, }; virtual void set_format(VideoFormat format) = 0; @@ -440,8 +430,29 @@ class VideoFrame { virtual int64_t timestamp() const = 0; protected: - VideoFrame() {} - virtual ~VideoFrame() {} + VideoFrame() {} + virtual ~VideoFrame() {} +}; + +// Represents decrypted and decoded audio frames. AudioFrames can contain +// multiple audio output buffers, which are serialized into this format: +// +// |<------------------- serialized audio buffer ------------------->| +// | int64_t timestamp | int64_t length | length bytes of audio data | +// +// For example, with three audio output buffers, the AudioFrames will look +// like this: +// +// |<----------------- AudioFrames ------------------>| +// | audio buffer 0 | audio buffer 1 | audio buffer 2 | +class AudioFrames { + public: + virtual void set_buffer(Buffer* buffer) = 0; + virtual Buffer* buffer() = 0; + + protected: + AudioFrames() {} + virtual ~AudioFrames() {} }; } // namespace cdm diff --git a/webkit/media/crypto/ppapi_decryptor.cc b/webkit/media/crypto/ppapi_decryptor.cc index 9fecb8b..8a2d7a1 100644 --- a/webkit/media/crypto/ppapi_decryptor.cc +++ b/webkit/media/crypto/ppapi_decryptor.cc @@ -36,6 +36,7 @@ PpapiDecryptor::PpapiDecryptor( } PpapiDecryptor::~PpapiDecryptor() { + cdm_plugin_->set_decrypt_client(NULL); } bool PpapiDecryptor::GenerateKeyRequest(const std::string& key_system, @@ -105,13 +106,13 @@ void PpapiDecryptor::Decrypt( } DVLOG(3) << "Decrypt() - stream_type: " << stream_type; - if (!cdm_plugin_->Decrypt(encrypted, decrypt_cb)) + if (!cdm_plugin_->Decrypt(stream_type, encrypted, decrypt_cb)) decrypt_cb.Run(kError, NULL); } void PpapiDecryptor::CancelDecrypt(StreamType stream_type) { DVLOG(1) << "CancelDecrypt() - stream_type: " << stream_type; - // TODO(xhwang): Implement CancelDecrypt() in PluginInstance and call it here. + cdm_plugin_->CancelDecrypt(stream_type); } void PpapiDecryptor::InitializeAudioDecoder( @@ -130,19 +131,12 @@ void PpapiDecryptor::InitializeAudioDecoder( DCHECK(config->IsValidConfig()); audio_decoder_init_cb_ = init_cb; - // TODO(xhwang): Implement InitializeAudioDecoder() in PluginInstance and call - // it here. - NOTIMPLEMENTED(); -#if 0 if (!cdm_plugin_->InitializeAudioDecoder(*config, base::Bind( &PpapiDecryptor::OnDecoderInitialized, weak_this_, kAudio, key_added_cb))) { -#endif base::ResetAndReturn(&audio_decoder_init_cb_).Run(false); -#if 0 return; } -#endif } void PpapiDecryptor::InitializeVideoDecoder( @@ -180,11 +174,7 @@ void PpapiDecryptor::DecryptAndDecodeAudio( } DVLOG(1) << "DecryptAndDecodeAudio()"; - NOTIMPLEMENTED(); - // TODO(xhwang): Enable this once PluginInstance is updated. -#if 0 if (!cdm_plugin_->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) -#endif audio_decode_cb.Run(kError, AudioBuffers()); } @@ -199,7 +189,7 @@ void PpapiDecryptor::DecryptAndDecodeVideo( } DVLOG(3) << "DecryptAndDecodeVideo()"; - if (!cdm_plugin_->DecryptAndDecode(encrypted, video_decode_cb)) + if (!cdm_plugin_->DecryptAndDecodeVideo(encrypted, video_decode_cb)) video_decode_cb.Run(kError, NULL); } @@ -211,8 +201,7 @@ void PpapiDecryptor::ResetDecoder(StreamType stream_type) { } DVLOG(2) << "ResetDecoder() - stream_type: " << stream_type; - // TODO(xhwang): Support stream type in PluginInstance. - cdm_plugin_->ResetDecoder(); + cdm_plugin_->ResetDecoder(stream_type); } void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) { @@ -222,8 +211,7 @@ void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) { return; } DVLOG(2) << "DeinitializeDecoder() - stream_type: " << stream_type; - // TODO(xhwang): Support stream type in PluginInstance. - cdm_plugin_->DeinitializeDecoder(); + cdm_plugin_->DeinitializeDecoder(stream_type); } void PpapiDecryptor::ReportFailureToCallPlugin(const std::string& key_system, diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index beb44d2..31bae32 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -17,6 +17,8 @@ #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" @@ -392,6 +394,55 @@ bool MakeEncryptedBlockInfo( 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; + + timestamp = *(reinterpret_cast<const int64*>(cur)); + cur += sizeof(timestamp); + bytes_left -= sizeof(timestamp); + + frame_size = *(reinterpret_cast<const int64*>(cur)); + 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(frame_size)); + frame->SetDataSize(frame_size); + memcpy(frame->GetWritableData(), 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: @@ -451,6 +502,19 @@ media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus( } } +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 @@ -525,8 +589,11 @@ PluginInstance::PluginInstance( 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) { pp_instance_ = HostGlobals::Get()->AddInstance(this); @@ -1536,7 +1603,6 @@ void PluginInstance::RotateView(WebPlugin::RotationType type) { void PluginInstance::set_decrypt_client( media::DecryptorClient* decryptor_client) { - DCHECK(decryptor_client); decryptor_client_ = decryptor_client; } @@ -1588,10 +1654,13 @@ bool PluginInstance::CancelKeyRequest(const std::string& 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()"; + DVLOG(3) << "Decrypt() - stream_type: " << stream_type; if (!LoadContentDecryptorInterface()) return false; @@ -1615,8 +1684,25 @@ bool PluginInstance::Decrypt( return false; } - DCHECK(!ContainsKey(pending_decryption_cbs_, request_id)); - pending_decryption_cbs_.insert(std::make_pair(request_id, decrypt_cb)); + // 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, @@ -1624,6 +1710,30 @@ bool PluginInstance::Decrypt( 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) { @@ -1684,32 +1794,96 @@ bool PluginInstance::InitializeVideoDecoder( return true; } -bool PluginInstance::DeinitializeDecoder() { +// 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(), - PP_DECRYPTORSTREAMTYPE_VIDEO, - 0); + pp_instance(), MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); return true; } -bool PluginInstance::ResetDecoder() { +bool PluginInstance::ResetDecoder(media::Decryptor::StreamType stream_type) { if (!LoadContentDecryptorInterface()) return false; - // TODO(tomfinegan): Add decoder reset request tracking, and get - // stream type from media stack. - plugin_decryption_interface_->ResetDecoder(pp_instance(), - PP_DECRYPTORSTREAMTYPE_VIDEO, - 0); + CancelDecode(stream_type); + + // TODO(tomfinegan): Add decoder reset request tracking. + plugin_decryption_interface_->ResetDecoder( + pp_instance(), MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); return true; } -bool PluginInstance::DecryptAndDecode( +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()) @@ -1727,7 +1901,7 @@ bool PluginInstance::DecryptAndDecode( return false; const uint32_t request_id = next_decryption_request_id_++; - DVLOG(2) << "DecryptAndDecode() - request_id " << request_id; + DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; PP_EncryptedBlockInfo block_info; if (!MakeEncryptedBlockInfo( @@ -2378,6 +2552,9 @@ void PluginInstance::NeedKey(PP_Instance instance, 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) { @@ -2385,7 +2562,6 @@ void PluginInstance::KeyAdded(PP_Instance instance, return; } - DCHECK(decryptor_client_); decryptor_client_->KeyAdded(key_system_string->value(), session_id_string->value()); } @@ -2395,6 +2571,9 @@ 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); @@ -2418,7 +2597,6 @@ void PluginInstance::KeyMessage(PP_Instance instance, if (mapper.data() && mapper.size()) memcpy(message_array.get(), mapper.data(), mapper.size()); - DCHECK(decryptor_client_); decryptor_client_->KeyMessage(key_system_string->value(), session_id_string->value(), message_array.Pass(), @@ -2431,6 +2609,9 @@ 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) { @@ -2438,7 +2619,6 @@ void PluginInstance::KeyError(PP_Instance instance, return; } - DCHECK(decryptor_client_); decryptor_client_->KeyError( key_system_string->value(), session_id_string->value(), @@ -2489,15 +2669,29 @@ void PluginInstance::DecoderResetDone(PP_Instance instance, void PluginInstance::DeliverBlock(PP_Instance instance, PP_Resource decrypted_block, const PP_DecryptedBlockInfo* block_info) { - DVLOG(2) << "DeliverBlock() - request_id: " - << block_info->tracking_info.request_id; DCHECK(block_info); - DecryptionCBMap::iterator found = pending_decryption_cbs_.find( - block_info->tracking_info.request_id); - if (found == pending_decryption_cbs_.end()) + 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::DecryptCB decrypt_cb = found->second; - pending_decryption_cbs_.erase(found); + } media::Decryptor::Status status = PpDecryptResultToMediaDecryptorStatus(block_info->result); @@ -2530,15 +2724,13 @@ void PluginInstance::DeliverBlock(PP_Instance instance, void PluginInstance::DeliverFrame(PP_Instance instance, PP_Resource decrypted_frame, const PP_DecryptedFrameInfo* frame_info) { - DVLOG(2) << "DeliverFrame() - request_id: " - << frame_info->tracking_info.request_id; 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 (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()); + if (request_id == 0 || request_id != pending_video_decode_request_id_) { + DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; return; } @@ -2603,10 +2795,38 @@ void PluginInstance::DeliverFrame(PP_Instance instance, void PluginInstance::DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const PP_DecryptedBlockInfo* block_info) { - DVLOG(2) << "DeliverSamples() - request_id: " - << block_info->tracking_info.request_id; - // TODO(tomfinegan): To be implemented after completion of v0.1 of the - // EME/CDM work. + 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); } 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 d7346f8..3bd03f4 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.h +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -262,8 +262,10 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : const std::string& key, const std::string& init_data); bool CancelKeyRequest(const std::string& session_id); - bool Decrypt(const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, + 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); @@ -272,10 +274,13 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : const media::Decryptor::DecoderInitCB& decoder_init_cb); // TODO(tomfinegan): Add callback args for DeinitializeDecoder() and // ResetDecoder() - bool DeinitializeDecoder(); - bool ResetDecoder(); - // Note: This method can be used with an unencrypted frame. - bool DecryptAndDecode( + 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); @@ -596,6 +601,9 @@ 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_; @@ -792,10 +800,11 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // 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_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_; @@ -803,6 +812,9 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : 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_; |