summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-24 22:33:54 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-24 22:33:54 +0000
commitecbb97687dd14622163c5ab5861fc6f8392e35c6 (patch)
tree3a08fb89e0da0801e006141f5740b5d0529930c6 /webkit
parent2bd7d9ec294434bc9819ee7cd553545c6eb765a3 (diff)
downloadchromium_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.cc94
-rw-r--r--webkit/media/crypto/ppapi/clear_key_cdm.cc11
-rw-r--r--webkit/media/crypto/ppapi/clear_key_cdm.h2
-rw-r--r--webkit/media/crypto/ppapi/content_decryption_module.h57
-rw-r--r--webkit/media/crypto/ppapi_decryptor.cc24
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.cc292
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.h30
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_;