Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Unified Diff: webkit/plugins/ppapi/ppapi_plugin_instance.cc

Issue 11189082: Update PluginInstance for audio support for content decryption. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 0452e855e57f948a43de77a8b90572e671ad27a5..dcee8a66350e685dc7adbf86d5389577d622cbba 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,47 @@ bool MakeEncryptedBlockInfo(
return true;
}
+bool MakeAudioFrames(PP_Resource audio_frames,
xhwang 2012/10/19 17:07:33 probably need comments here.
Tom Finegan 2012/10/19 22:53:52 Agreed, but I don't think it needs anything too bi
ddorwin 2012/10/20 00:14:36 Especially since the out parameter type is "buffer
xhwang 2012/10/21 19:05:06 Done.
xhwang 2012/10/21 19:05:06 Hmm, maybe we should rename media::Decryptor::Audi
ddorwin 2012/10/22 17:47:11 SGTM (in another CL).
+ 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 {
+ if (bytes_left < 16)
ddorwin 2012/10/20 00:14:36 why? 16 is a magic number here and below. 8 too. s
xhwang 2012/10/21 19:05:06 Done.
+ return false;
+
+ int64 timestamp = *(reinterpret_cast<const int64*>(cur));
+ cur += 8;
+ int64 frame_size = *(reinterpret_cast<const int64*>(cur));
+ cur += 8;
+ bytes_left -= 16;
ddorwin 2012/10/20 00:14:36 (8 + 8) would be clearer, esp. when using sizeof()
xhwang 2012/10/21 19:05:06 Done.
+
+ if (frame_size < 0 || bytes_left < frame_size)
ddorwin 2012/10/20 00:14:36 DCHECK? Is this a bug if we see it?
xhwang 2012/10/21 19:05:06 As I said, I don't trust CDMs. The renderer should
ddorwin 2012/10/22 17:47:11 A DCHECK just tells us something is wrong in a deb
+ return false;
+
+ scoped_refptr<media::DataBuffer> frame(new media::DataBuffer(frame_size));
+ if (frame_size > 0) {
+ memcpy(frame->GetWritableData(), cur, frame_size);
+ frame->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp));
+ cur += frame_size;
+ bytes_left -= frame_size;
+ }
+ frames->push_back(frame);
+ }
+ while (bytes_left > 0);
Tom Finegan 2012/10/19 22:53:52 Move the while up on the same line with the closin
xhwang 2012/10/21 19:05:06 Done.
+
+ return true;
+}
+
PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
if (codec == media::kCodecVorbis)
return PP_AUDIOCODEC_VORBIS;
@@ -500,8 +543,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);
@@ -1508,7 +1554,6 @@ void PluginInstance::RotateView(WebPlugin::RotationType type) {
void PluginInstance::set_decrypt_client(
media::DecryptorClient* decryptor_client) {
- DCHECK(decryptor_client);
decryptor_client_ = decryptor_client;
}
@@ -1560,10 +1605,13 @@ bool PluginInstance::CancelKeyRequest(const std::string& session_id) {
return true;
}
+// TODO(xhwang): Remove duplication of code in Decrypt(),
+// DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
Tom Finegan 2012/10/19 22:53:52 We should do this when we refactor and add the del
xhwang 2012/10/21 19:05:06 Agreed.
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;
@@ -1587,8 +1635,19 @@ bool PluginInstance::Decrypt(
return false;
}
- DCHECK(!ContainsKey(pending_decryption_cbs_, request_id));
- pending_decryption_cbs_.insert(std::make_pair(request_id, decrypt_cb));
+ uint32_t& pending_decrypt_request_id =
ddorwin 2012/10/20 00:14:36 DCHECK stream_type, Would a switch statement be eq
xhwang 2012/10/21 19:05:06 Done.
+ (stream_type == media::Decryptor::kAudio) ?
+ pending_audio_decrypt_request_id_ : pending_video_decrypt_request_id_;
+ media::Decryptor::DecryptCB& pending_decrypt_cb =
+ (stream_type == media::Decryptor::kAudio) ?
+ pending_audio_decrypt_cb_ : pending_video_decrypt_cb_;
+
+ // There is only one pending decrypt request at any time per stream. This is
+ // enforced by the media pipeline.
+ DCHECK_EQ(pending_decrypt_request_id, 0u);
+ DCHECK(pending_decrypt_cb.is_null());
+ pending_decrypt_request_id = request_id;
+ pending_decrypt_cb = decrypt_cb;
plugin_decryption_interface_->Decrypt(pp_instance(),
encrypted_resource,
@@ -1596,6 +1655,30 @@ bool PluginInstance::Decrypt(
return true;
}
+bool PluginInstance::CancelDecrypt(media::Decryptor::StreamType stream_type) {
ddorwin 2012/10/20 00:14:36 Is it easy for the client to know whether to call
xhwang 2012/10/21 19:05:06 I agree it's confusing. For decoder, we have Rese
+ 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_);
ddorwin 2012/10/20 00:14:36 Does this work if pending_audio_decrypt_cb_ is nul
xhwang 2012/10/21 19:05:06 Yes. Line 1676 checks this condition.
+ 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) {
@@ -1654,10 +1737,32 @@ bool PluginInstance::InitializeVideoDecoder(
return true;
}
-bool PluginInstance::DeinitializeDecoder() {
+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());
ddorwin 2012/10/20 00:14:36 odd that video passes NULL but this doesn't. I ass
xhwang 2012/10/21 19:05:06 VideoDecodeCB takes scoped_refptr<VideoFrame>, so
+ 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(
@@ -1667,10 +1772,12 @@ bool PluginInstance::DeinitializeDecoder() {
return true;
}
-bool PluginInstance::ResetDecoder() {
+bool PluginInstance::ResetDecoder(media::Decryptor::StreamType stream_type) {
ddorwin 2012/10/20 00:14:36 Does just a Reset() for decrypt & D&D make sense?
xhwang 2012/10/21 19:05:06 We can discuss about this. See above comment.
if (!LoadContentDecryptorInterface())
return false;
+ CancelDecode(stream_type);
+
// TODO(tomfinegan): Add decoder reset request tracking, and get
// stream type from media stack.
plugin_decryption_interface_->ResetDecoder(pp_instance(),
@@ -1679,7 +1786,50 @@ bool PluginInstance::ResetDecoder() {
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) << "DecryptAndDecode() - request_id " << request_id;
Tom Finegan 2012/10/19 22:53:52 s/DecryptAndDecode/DecryptAndDecodeAudio/ (Here a
xhwang 2012/10/21 19:05:06 Done.
+
+ 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())
@@ -2348,6 +2498,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) {
@@ -2355,7 +2508,6 @@ void PluginInstance::KeyAdded(PP_Instance instance,
return;
}
- DCHECK(decryptor_client_);
decryptor_client_->KeyAdded(key_system_string->value(),
session_id_string->value());
}
@@ -2365,6 +2517,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);
@@ -2388,7 +2543,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(),
@@ -2401,6 +2555,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) {
@@ -2408,7 +2565,6 @@ void PluginInstance::KeyError(PP_Instance instance,
return;
}
- DCHECK(decryptor_client_);
decryptor_client_->KeyError(
key_system_string->value(),
session_id_string->value(),
@@ -2462,12 +2618,26 @@ void PluginInstance::DeliverBlock(PP_Instance instance,
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())
+
+ // If the request ID is not valid or does not match what's saved, do nothing.
+ const uint32_t request_id = block_info->tracking_info.request_id;
+ if (request_id == 0)
return;
- media::Decryptor::DecryptCB decrypt_cb = found->second;
- pending_decryption_cbs_.erase(found);
+
+ 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 "
+ << block_info->tracking_info.request_id << " no found";
ddorwin 2012/10/20 00:14:36 s/no/not/
ddorwin 2012/10/20 00:14:36 you already have request_id local var you can use.
xhwang 2012/10/21 19:05:06 Done.
+ return;
+ }
if (block_info->result == PP_DECRYPTRESULT_DECRYPT_NOKEY) {
decrypt_cb.Run(media::Decryptor::kNoKey, NULL);
@@ -2587,8 +2757,45 @@ void PluginInstance::DeliverSamples(PP_Instance instance,
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(audio_frames);
ddorwin 2012/10/20 00:14:36 decrypted_block can be null above but this can't?
xhwang 2012/10/21 19:05:06 Done.
+
+ // If the request ID is not valid or does not match what's saved, do nothing.
+ if (block_info->tracking_info.request_id == 0 ||
+ block_info->tracking_info.request_id !=
+ pending_audio_decode_request_id_) {
+ DCHECK(pending_audio_decode_cb_.is_null());
+ 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;
+
+ if (block_info->result == PP_DECRYPTRESULT_DECRYPT_NOKEY) {
+ audio_decode_cb.Run(media::Decryptor::kNoKey, empty_frames);
+ return;
+ }
+
+ if (block_info->result != PP_DECRYPTRESULT_SUCCESS) {
+ audio_decode_cb.Run(media::Decryptor::kError, empty_frames);
+ return;
+ }
+
+ if (audio_frames == 0) { // End-of-stream frame.
xhwang 2012/10/19 17:07:33 We can remove this check if we all agree that EOS
Tom Finegan 2012/10/19 22:53:52 This isn't necessarily and end of stream frame. Th
xhwang 2012/10/21 19:05:06 Yeah, done in another CL: 11234019
+ audio_decode_cb.Run(media::Decryptor::kSuccess, empty_frames);
+ return;
+ }
+
+ media::Decryptor::AudioBuffers audio_frame_list;
+ if (!MakeAudioFrames(audio_frames, &audio_frame_list)) {
+ 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,
« webkit/plugins/ppapi/ppapi_plugin_instance.h ('K') | « webkit/plugins/ppapi/ppapi_plugin_instance.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698