Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / pepper / content_decryptor_delegate.cc
blobe1b0b1ba3e5d1100275908abf15dd578ec1b86a9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/content_decryptor_delegate.h"
7 #include "base/callback_helpers.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "content/renderer/pepper/ppb_buffer_impl.h"
12 #include "media/base/audio_buffer.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/cdm_promise.h"
16 #include "media/base/channel_layout.h"
17 #include "media/base/data_buffer.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/decrypt_config.h"
20 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h"
22 #include "media/base/video_util.h"
23 #include "ppapi/shared_impl/scoped_pp_resource.h"
24 #include "ppapi/shared_impl/var.h"
25 #include "ppapi/shared_impl/var_tracker.h"
26 #include "ppapi/thunk/enter.h"
27 #include "ppapi/thunk/ppb_buffer_api.h"
28 #include "ui/gfx/rect.h"
30 using media::CdmPromise;
31 using media::Decryptor;
32 using media::MediaKeys;
33 using media::NewSessionCdmPromise;
34 using media::SimpleCdmPromise;
35 using ppapi::ArrayBufferVar;
36 using ppapi::PpapiGlobals;
37 using ppapi::ScopedPPResource;
38 using ppapi::StringVar;
39 using ppapi::thunk::EnterResourceNoLock;
40 using ppapi::thunk::PPB_Buffer_API;
42 namespace content {
44 namespace {
46 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
47 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
48 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
49 // true upon success and false if any error happened.
50 bool MakeBufferResource(PP_Instance instance,
51 const uint8* data,
52 uint32_t size,
53 scoped_refptr<PPB_Buffer_Impl>* resource) {
54 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
55 DCHECK(resource);
57 if (!data || !size) {
58 DCHECK(!data && !size);
59 resource = NULL;
60 return true;
63 scoped_refptr<PPB_Buffer_Impl> buffer(
64 PPB_Buffer_Impl::CreateResource(instance, size));
65 if (!buffer.get())
66 return false;
68 BufferAutoMapper mapper(buffer.get());
69 if (!mapper.data() || mapper.size() < size)
70 return false;
71 memcpy(mapper.data(), data, size);
73 *resource = buffer;
74 return true;
77 // Copies the content of |str| into |array|.
78 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
79 // |array_size| is smaller than the |str| length.
80 template <uint32_t array_size>
81 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
82 if (array_size < str.size())
83 return false;
85 memcpy(array, str.data(), str.size());
86 return true;
89 // Fills the |block_info| with information from |encrypted_buffer|.
91 // Returns true if |block_info| is successfully filled. Returns false
92 // otherwise.
93 static bool MakeEncryptedBlockInfo(
94 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
95 uint32_t request_id,
96 PP_EncryptedBlockInfo* block_info) {
97 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
98 // anywhere else.
99 memset(block_info, 0, sizeof(*block_info));
100 block_info->tracking_info.request_id = request_id;
102 // EOS buffers need a request ID and nothing more.
103 if (encrypted_buffer->end_of_stream())
104 return true;
106 DCHECK(encrypted_buffer->data_size())
107 << "DecryptConfig is set on an empty buffer";
109 block_info->tracking_info.timestamp =
110 encrypted_buffer->timestamp().InMicroseconds();
111 block_info->data_size = encrypted_buffer->data_size();
113 const media::DecryptConfig* decrypt_config =
114 encrypted_buffer->decrypt_config();
116 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
117 !CopyStringToArray(decrypt_config->iv(), block_info->iv))
118 return false;
120 block_info->key_id_size = decrypt_config->key_id().size();
121 block_info->iv_size = decrypt_config->iv().size();
123 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
124 return false;
126 block_info->num_subsamples = decrypt_config->subsamples().size();
127 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
128 block_info->subsamples[i].clear_bytes =
129 decrypt_config->subsamples()[i].clear_bytes;
130 block_info->subsamples[i].cipher_bytes =
131 decrypt_config->subsamples()[i].cypher_bytes;
134 return true;
137 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
138 switch (codec) {
139 case media::kCodecVorbis:
140 return PP_AUDIOCODEC_VORBIS;
141 case media::kCodecAAC:
142 return PP_AUDIOCODEC_AAC;
143 default:
144 return PP_AUDIOCODEC_UNKNOWN;
148 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
149 switch (codec) {
150 case media::kCodecVP8:
151 return PP_VIDEOCODEC_VP8;
152 case media::kCodecH264:
153 return PP_VIDEOCODEC_H264;
154 case media::kCodecVP9:
155 return PP_VIDEOCODEC_VP9;
156 default:
157 return PP_VIDEOCODEC_UNKNOWN;
161 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
162 media::VideoCodecProfile profile) {
163 switch (profile) {
164 case media::VP8PROFILE_ANY:
165 case media::VP9PROFILE_ANY:
166 return PP_VIDEOCODECPROFILE_NOT_NEEDED;
167 case media::H264PROFILE_BASELINE:
168 return PP_VIDEOCODECPROFILE_H264_BASELINE;
169 case media::H264PROFILE_MAIN:
170 return PP_VIDEOCODECPROFILE_H264_MAIN;
171 case media::H264PROFILE_EXTENDED:
172 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
173 case media::H264PROFILE_HIGH:
174 return PP_VIDEOCODECPROFILE_H264_HIGH;
175 case media::H264PROFILE_HIGH10PROFILE:
176 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
177 case media::H264PROFILE_HIGH422PROFILE:
178 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
179 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
180 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
181 default:
182 return PP_VIDEOCODECPROFILE_UNKNOWN;
186 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
187 media::VideoFrame::Format format) {
188 switch (format) {
189 case media::VideoFrame::YV12:
190 return PP_DECRYPTEDFRAMEFORMAT_YV12;
191 case media::VideoFrame::I420:
192 return PP_DECRYPTEDFRAMEFORMAT_I420;
193 default:
194 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
198 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
199 PP_DecryptResult result) {
200 switch (result) {
201 case PP_DECRYPTRESULT_SUCCESS:
202 return Decryptor::kSuccess;
203 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
204 return Decryptor::kNoKey;
205 case PP_DECRYPTRESULT_NEEDMOREDATA:
206 return Decryptor::kNeedMoreData;
207 case PP_DECRYPTRESULT_DECRYPT_ERROR:
208 return Decryptor::kError;
209 case PP_DECRYPTRESULT_DECODE_ERROR:
210 return Decryptor::kError;
211 default:
212 NOTREACHED();
213 return Decryptor::kError;
217 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
218 Decryptor::StreamType stream_type) {
219 switch (stream_type) {
220 case Decryptor::kAudio:
221 return PP_DECRYPTORSTREAMTYPE_AUDIO;
222 case Decryptor::kVideo:
223 return PP_DECRYPTORSTREAMTYPE_VIDEO;
224 default:
225 NOTREACHED();
226 return PP_DECRYPTORSTREAMTYPE_VIDEO;
230 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
231 PP_DecryptedSampleFormat result) {
232 switch (result) {
233 case PP_DECRYPTEDSAMPLEFORMAT_U8:
234 return media::kSampleFormatU8;
235 case PP_DECRYPTEDSAMPLEFORMAT_S16:
236 return media::kSampleFormatS16;
237 case PP_DECRYPTEDSAMPLEFORMAT_S32:
238 return media::kSampleFormatS32;
239 case PP_DECRYPTEDSAMPLEFORMAT_F32:
240 return media::kSampleFormatF32;
241 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
242 return media::kSampleFormatPlanarS16;
243 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
244 return media::kSampleFormatPlanarF32;
245 default:
246 NOTREACHED();
247 return media::kUnknownSampleFormat;
251 PP_SessionType MediaSessionTypeToPpSessionType(
252 MediaKeys::SessionType session_type) {
253 switch (session_type) {
254 case MediaKeys::TEMPORARY_SESSION:
255 return PP_SESSIONTYPE_TEMPORARY;
256 case MediaKeys::PERSISTENT_SESSION:
257 return PP_SESSIONTYPE_PERSISTENT;
258 default:
259 NOTREACHED();
260 return PP_SESSIONTYPE_TEMPORARY;
264 MediaKeys::Exception PpExceptionTypeToMediaException(
265 PP_CdmExceptionCode exception_code) {
266 switch (exception_code) {
267 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
268 return MediaKeys::NOT_SUPPORTED_ERROR;
269 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
270 return MediaKeys::INVALID_STATE_ERROR;
271 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
272 return MediaKeys::INVALID_ACCESS_ERROR;
273 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
274 return MediaKeys::QUOTA_EXCEEDED_ERROR;
275 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
276 return MediaKeys::UNKNOWN_ERROR;
277 case PP_CDMEXCEPTIONCODE_CLIENTERROR:
278 return MediaKeys::CLIENT_ERROR;
279 case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
280 return MediaKeys::OUTPUT_ERROR;
281 default:
282 NOTREACHED();
283 return MediaKeys::UNKNOWN_ERROR;
287 } // namespace
289 ContentDecryptorDelegate::ContentDecryptorDelegate(
290 PP_Instance pp_instance,
291 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
292 : pp_instance_(pp_instance),
293 plugin_decryption_interface_(plugin_decryption_interface),
294 next_decryption_request_id_(1),
295 audio_samples_per_second_(0),
296 audio_channel_count_(0),
297 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
298 next_promise_id_(1),
299 weak_ptr_factory_(this) {
300 weak_this_ = weak_ptr_factory_.GetWeakPtr();
303 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
304 SatisfyAllPendingCallbacksOnError();
307 void ContentDecryptorDelegate::Initialize(
308 const std::string& key_system,
309 const media::SessionMessageCB& session_message_cb,
310 const media::SessionReadyCB& session_ready_cb,
311 const media::SessionClosedCB& session_closed_cb,
312 const media::SessionErrorCB& session_error_cb,
313 const base::Closure& fatal_plugin_error_cb) {
314 DCHECK(!key_system.empty());
315 DCHECK(key_system_.empty());
316 key_system_ = key_system;
318 session_message_cb_ = session_message_cb;
319 session_ready_cb_ = session_ready_cb;
320 session_closed_cb_ = session_closed_cb;
321 session_error_cb_ = session_error_cb;
322 fatal_plugin_error_cb_ = fatal_plugin_error_cb;
324 plugin_decryption_interface_->Initialize(
325 pp_instance_, StringVar::StringToPPVar(key_system_));
328 void ContentDecryptorDelegate::InstanceCrashed() {
329 fatal_plugin_error_cb_.Run();
330 SatisfyAllPendingCallbacksOnError();
333 void ContentDecryptorDelegate::CreateSession(
334 const std::string& init_data_type,
335 const uint8* init_data,
336 int init_data_length,
337 MediaKeys::SessionType session_type,
338 scoped_ptr<NewSessionCdmPromise> promise) {
339 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
340 PP_Var init_data_array =
341 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
342 init_data_length, init_data);
343 plugin_decryption_interface_->CreateSession(
344 pp_instance_,
345 promise_id,
346 StringVar::StringToPPVar(init_data_type),
347 init_data_array,
348 MediaSessionTypeToPpSessionType(session_type));
351 void ContentDecryptorDelegate::LoadSession(
352 const std::string& web_session_id,
353 scoped_ptr<NewSessionCdmPromise> promise) {
354 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
355 plugin_decryption_interface_->LoadSession(
356 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
359 void ContentDecryptorDelegate::UpdateSession(
360 const std::string& web_session_id,
361 const uint8* response,
362 int response_length,
363 scoped_ptr<SimpleCdmPromise> promise) {
364 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
365 PP_Var response_array =
366 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
367 response_length, response);
368 plugin_decryption_interface_->UpdateSession(
369 pp_instance_,
370 promise_id,
371 StringVar::StringToPPVar(web_session_id),
372 response_array);
375 void ContentDecryptorDelegate::ReleaseSession(
376 const std::string& web_session_id,
377 scoped_ptr<SimpleCdmPromise> promise) {
378 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
379 plugin_decryption_interface_->ReleaseSession(
380 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
383 // TODO(xhwang): Remove duplication of code in Decrypt(),
384 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
385 bool ContentDecryptorDelegate::Decrypt(
386 Decryptor::StreamType stream_type,
387 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
388 const Decryptor::DecryptCB& decrypt_cb) {
389 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
391 // |{audio|video}_input_resource_| is not being used by the plugin
392 // now because there is only one pending audio/video decrypt request at any
393 // time. This is enforced by the media pipeline.
394 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
395 if (!MakeMediaBufferResource(
396 stream_type, encrypted_buffer, &encrypted_resource) ||
397 !encrypted_resource.get()) {
398 return false;
400 ScopedPPResource pp_resource(encrypted_resource.get());
402 const uint32_t request_id = next_decryption_request_id_++;
403 DVLOG(2) << "Decrypt() - request_id " << request_id;
405 PP_EncryptedBlockInfo block_info = {};
406 DCHECK(encrypted_buffer->decrypt_config());
407 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
408 return false;
411 // There is only one pending decrypt request at any time per stream. This is
412 // enforced by the media pipeline.
413 switch (stream_type) {
414 case Decryptor::kAudio:
415 audio_decrypt_cb_.Set(request_id, decrypt_cb);
416 break;
417 case Decryptor::kVideo:
418 video_decrypt_cb_.Set(request_id, decrypt_cb);
419 break;
420 default:
421 NOTREACHED();
422 return false;
425 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
427 plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
428 return true;
431 bool ContentDecryptorDelegate::CancelDecrypt(
432 Decryptor::StreamType stream_type) {
433 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
435 Decryptor::DecryptCB decrypt_cb;
436 switch (stream_type) {
437 case Decryptor::kAudio:
438 // Release the shared memory as it can still be in use by the plugin.
439 // The next Decrypt() call will need to allocate a new shared memory
440 // buffer.
441 audio_input_resource_ = NULL;
442 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
443 break;
444 case Decryptor::kVideo:
445 // Release the shared memory as it can still be in use by the plugin.
446 // The next Decrypt() call will need to allocate a new shared memory
447 // buffer.
448 video_input_resource_ = NULL;
449 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
450 break;
451 default:
452 NOTREACHED();
453 return false;
456 if (!decrypt_cb.is_null())
457 decrypt_cb.Run(Decryptor::kSuccess, NULL);
459 return true;
462 bool ContentDecryptorDelegate::InitializeAudioDecoder(
463 const media::AudioDecoderConfig& decoder_config,
464 const Decryptor::DecoderInitCB& init_cb) {
465 PP_AudioDecoderConfig pp_decoder_config;
466 pp_decoder_config.codec =
467 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
468 pp_decoder_config.channel_count =
469 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
470 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
471 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
472 pp_decoder_config.request_id = next_decryption_request_id_++;
474 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
475 audio_channel_count_ = pp_decoder_config.channel_count;
476 audio_channel_layout_ = decoder_config.channel_layout();
478 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
479 if (!MakeBufferResource(pp_instance_,
480 decoder_config.extra_data(),
481 decoder_config.extra_data_size(),
482 &extra_data_resource)) {
483 return false;
485 ScopedPPResource pp_resource(extra_data_resource.get());
487 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
488 plugin_decryption_interface_->InitializeAudioDecoder(
489 pp_instance_, &pp_decoder_config, pp_resource);
490 return true;
493 bool ContentDecryptorDelegate::InitializeVideoDecoder(
494 const media::VideoDecoderConfig& decoder_config,
495 const Decryptor::DecoderInitCB& init_cb) {
496 PP_VideoDecoderConfig pp_decoder_config;
497 pp_decoder_config.codec =
498 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
499 pp_decoder_config.profile =
500 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
501 pp_decoder_config.format =
502 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
503 pp_decoder_config.width = decoder_config.coded_size().width();
504 pp_decoder_config.height = decoder_config.coded_size().height();
505 pp_decoder_config.request_id = next_decryption_request_id_++;
507 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
508 if (!MakeBufferResource(pp_instance_,
509 decoder_config.extra_data(),
510 decoder_config.extra_data_size(),
511 &extra_data_resource)) {
512 return false;
514 ScopedPPResource pp_resource(extra_data_resource.get());
516 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
517 natural_size_ = decoder_config.natural_size();
519 plugin_decryption_interface_->InitializeVideoDecoder(
520 pp_instance_, &pp_decoder_config, pp_resource);
521 return true;
524 bool ContentDecryptorDelegate::DeinitializeDecoder(
525 Decryptor::StreamType stream_type) {
526 CancelDecode(stream_type);
528 if (stream_type == Decryptor::kVideo)
529 natural_size_ = gfx::Size();
531 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
532 // stream type from media stack.
533 plugin_decryption_interface_->DeinitializeDecoder(
534 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
535 return true;
538 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
539 CancelDecode(stream_type);
541 // TODO(tomfinegan): Add decoder reset request tracking.
542 plugin_decryption_interface_->ResetDecoder(
543 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
544 return true;
547 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
548 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
549 const Decryptor::AudioDecodeCB& audio_decode_cb) {
550 // |audio_input_resource_| is not being used by the plugin now
551 // because there is only one pending audio decode request at any time.
552 // This is enforced by the media pipeline.
553 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
554 if (!MakeMediaBufferResource(
555 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
556 return false;
559 // The resource should not be NULL for non-EOS buffer.
560 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
561 return false;
563 const uint32_t request_id = next_decryption_request_id_++;
564 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
566 PP_EncryptedBlockInfo block_info = {};
567 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
568 return false;
571 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
573 // There is only one pending audio decode request at any time. This is
574 // enforced by the media pipeline. If this DCHECK is violated, our buffer
575 // reuse policy is not valid, and we may have race problems for the shared
576 // buffer.
577 audio_decode_cb_.Set(request_id, audio_decode_cb);
579 ScopedPPResource pp_resource(encrypted_resource.get());
580 plugin_decryption_interface_->DecryptAndDecode(
581 pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
582 return true;
585 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
586 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
587 const Decryptor::VideoDecodeCB& video_decode_cb) {
588 // |video_input_resource_| is not being used by the plugin now
589 // because there is only one pending video decode request at any time.
590 // This is enforced by the media pipeline.
591 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
592 if (!MakeMediaBufferResource(
593 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
594 return false;
597 // The resource should not be 0 for non-EOS buffer.
598 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
599 return false;
601 const uint32_t request_id = next_decryption_request_id_++;
602 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
603 TRACE_EVENT_ASYNC_BEGIN0(
604 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
606 PP_EncryptedBlockInfo block_info = {};
607 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
608 return false;
611 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
613 // Only one pending video decode request at any time. This is enforced by the
614 // media pipeline. If this DCHECK is violated, our buffer
615 // reuse policy is not valid, and we may have race problems for the shared
616 // buffer.
617 video_decode_cb_.Set(request_id, video_decode_cb);
619 // TODO(tomfinegan): Need to get stream type from media stack.
620 ScopedPPResource pp_resource(encrypted_resource.get());
621 plugin_decryption_interface_->DecryptAndDecode(
622 pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
623 return true;
626 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
627 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
628 if (promise) {
629 SimpleCdmPromise* simple_promise(
630 static_cast<SimpleCdmPromise*>(promise.get()));
631 simple_promise->resolve();
635 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
636 uint32 promise_id,
637 PP_Var web_session_id) {
638 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
640 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
641 DCHECK(web_session_id_string);
643 if (promise) {
644 NewSessionCdmPromise* session_promise(
645 static_cast<NewSessionCdmPromise*>(promise.get()));
646 session_promise->resolve(web_session_id_string->value());
650 void ContentDecryptorDelegate::OnPromiseRejected(
651 uint32 promise_id,
652 PP_CdmExceptionCode exception_code,
653 uint32 system_code,
654 PP_Var error_description) {
655 StringVar* error_description_string = StringVar::FromPPVar(error_description);
656 DCHECK(error_description_string);
658 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
659 if (promise) {
660 promise->reject(PpExceptionTypeToMediaException(exception_code),
661 system_code,
662 error_description_string->value());
666 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
667 PP_Var message,
668 PP_Var destination_url) {
669 if (session_message_cb_.is_null())
670 return;
672 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
673 DCHECK(web_session_id_string);
675 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
676 std::vector<uint8> message_vector;
677 if (message_array_buffer) {
678 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
679 message_vector.assign(data, data + message_array_buffer->ByteLength());
682 StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
683 DCHECK(destination_url_string);
685 GURL verified_gurl = GURL(destination_url_string->value());
686 if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
687 DLOG(WARNING) << "SessionMessage default_url is invalid : "
688 << verified_gurl.possibly_invalid_spec();
689 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
692 session_message_cb_.Run(
693 web_session_id_string->value(), message_vector, verified_gurl);
696 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
697 if (session_ready_cb_.is_null())
698 return;
700 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
701 DCHECK(web_session_id_string);
703 session_ready_cb_.Run(web_session_id_string->value());
706 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
707 if (session_closed_cb_.is_null())
708 return;
710 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
711 DCHECK(web_session_id_string);
713 session_closed_cb_.Run(web_session_id_string->value());
716 void ContentDecryptorDelegate::OnSessionError(
717 PP_Var web_session_id,
718 PP_CdmExceptionCode exception_code,
719 uint32 system_code,
720 PP_Var error_description) {
721 if (session_error_cb_.is_null())
722 return;
724 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
725 DCHECK(web_session_id_string);
727 StringVar* error_description_string = StringVar::FromPPVar(error_description);
728 DCHECK(error_description_string);
730 session_error_cb_.Run(web_session_id_string->value(),
731 PpExceptionTypeToMediaException(exception_code),
732 system_code,
733 error_description_string->value());
736 void ContentDecryptorDelegate::DecoderInitializeDone(
737 PP_DecryptorStreamType decoder_type,
738 uint32_t request_id,
739 PP_Bool success) {
740 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
741 // If the request ID is not valid or does not match what's saved, do
742 // nothing.
743 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
744 return;
746 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
747 } else {
748 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
749 return;
751 if (!success)
752 natural_size_ = gfx::Size();
754 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
758 void ContentDecryptorDelegate::DecoderDeinitializeDone(
759 PP_DecryptorStreamType decoder_type,
760 uint32_t request_id) {
761 // TODO(tomfinegan): Add decoder stop completion handling.
764 void ContentDecryptorDelegate::DecoderResetDone(
765 PP_DecryptorStreamType decoder_type,
766 uint32_t request_id) {
767 // TODO(tomfinegan): Add decoder reset completion handling.
770 void ContentDecryptorDelegate::DeliverBlock(
771 PP_Resource decrypted_block,
772 const PP_DecryptedBlockInfo* block_info) {
773 DCHECK(block_info);
775 FreeBuffer(block_info->tracking_info.buffer_id);
777 const uint32_t request_id = block_info->tracking_info.request_id;
778 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
780 // If the request ID is not valid or does not match what's saved, do nothing.
781 if (request_id == 0) {
782 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
783 return;
786 Decryptor::DecryptCB decrypt_cb;
787 if (audio_decrypt_cb_.Matches(request_id)) {
788 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
789 } else if (video_decrypt_cb_.Matches(request_id)) {
790 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
791 } else {
792 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
793 return;
796 Decryptor::Status status =
797 PpDecryptResultToMediaDecryptorStatus(block_info->result);
798 if (status != Decryptor::kSuccess) {
799 decrypt_cb.Run(status, NULL);
800 return;
803 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
804 if (!enter.succeeded()) {
805 decrypt_cb.Run(Decryptor::kError, NULL);
806 return;
808 BufferAutoMapper mapper(enter.object());
809 if (!mapper.data() || !mapper.size() ||
810 mapper.size() < block_info->data_size) {
811 decrypt_cb.Run(Decryptor::kError, NULL);
812 return;
815 // TODO(tomfinegan): Find a way to take ownership of the shared memory
816 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
817 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
818 media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
819 block_info->data_size));
820 decrypted_buffer->set_timestamp(
821 base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
822 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
825 // Use a non-class-member function here so that if for some reason
826 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
827 // we can still get the shared memory unmapped.
828 static void BufferNoLongerNeeded(
829 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
830 base::Closure buffer_no_longer_needed_cb) {
831 ppb_buffer->Unmap();
832 buffer_no_longer_needed_cb.Run();
835 // Enters |resource|, maps shared memory and returns pointer of mapped data.
836 // Returns NULL if any error occurs.
837 static uint8* GetMappedBuffer(PP_Resource resource,
838 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
839 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
840 if (!enter.succeeded())
841 return NULL;
843 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
844 if (!enter.object()->IsMapped() || !mapped_data)
845 return NULL;
847 uint32_t mapped_size = 0;
848 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
849 enter.object()->Unmap();
850 return NULL;
853 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
855 return mapped_data;
858 void ContentDecryptorDelegate::DeliverFrame(
859 PP_Resource decrypted_frame,
860 const PP_DecryptedFrameInfo* frame_info) {
861 DCHECK(frame_info);
863 const uint32_t request_id = frame_info->tracking_info.request_id;
864 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
866 // If the request ID is not valid or does not match what's saved, do nothing.
867 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
868 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
869 FreeBuffer(frame_info->tracking_info.buffer_id);
870 return;
873 TRACE_EVENT_ASYNC_END0(
874 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
876 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
878 Decryptor::Status status =
879 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
880 if (status != Decryptor::kSuccess) {
881 DCHECK(!frame_info->tracking_info.buffer_id);
882 video_decode_cb.Run(status, NULL);
883 return;
886 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
887 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
888 if (!frame_data) {
889 FreeBuffer(frame_info->tracking_info.buffer_id);
890 video_decode_cb.Run(Decryptor::kError, NULL);
891 return;
894 gfx::Size frame_size(frame_info->width, frame_info->height);
895 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
897 scoped_refptr<media::VideoFrame> decoded_frame =
898 media::VideoFrame::WrapExternalYuvData(
899 media::VideoFrame::YV12,
900 frame_size,
901 gfx::Rect(frame_size),
902 natural_size_,
903 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
904 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
905 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
906 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
907 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
908 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
909 base::TimeDelta::FromMicroseconds(
910 frame_info->tracking_info.timestamp),
911 media::BindToCurrentLoop(
912 base::Bind(&BufferNoLongerNeeded,
913 ppb_buffer,
914 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
915 weak_this_,
916 frame_info->tracking_info.buffer_id))));
918 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
921 void ContentDecryptorDelegate::DeliverSamples(
922 PP_Resource audio_frames,
923 const PP_DecryptedSampleInfo* sample_info) {
924 DCHECK(sample_info);
926 FreeBuffer(sample_info->tracking_info.buffer_id);
928 const uint32_t request_id = sample_info->tracking_info.request_id;
929 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
931 // If the request ID is not valid or does not match what's saved, do nothing.
932 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
933 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
934 return;
937 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
939 const Decryptor::AudioBuffers empty_frames;
941 Decryptor::Status status =
942 PpDecryptResultToMediaDecryptorStatus(sample_info->result);
943 if (status != Decryptor::kSuccess) {
944 audio_decode_cb.Run(status, empty_frames);
945 return;
948 media::SampleFormat sample_format =
949 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
951 Decryptor::AudioBuffers audio_frame_list;
952 if (!DeserializeAudioFrames(audio_frames,
953 sample_info->data_size,
954 sample_format,
955 &audio_frame_list)) {
956 NOTREACHED() << "CDM did not serialize the buffer correctly.";
957 audio_decode_cb.Run(Decryptor::kError, empty_frames);
958 return;
961 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
964 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
965 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
966 switch (stream_type) {
967 case Decryptor::kAudio:
968 // Release the shared memory as it can still be in use by the plugin.
969 // The next DecryptAndDecode() call will need to allocate a new shared
970 // memory buffer.
971 audio_input_resource_ = NULL;
972 if (!audio_decode_cb_.is_null())
973 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
974 Decryptor::AudioBuffers());
975 break;
976 case Decryptor::kVideo:
977 // Release the shared memory as it can still be in use by the plugin.
978 // The next DecryptAndDecode() call will need to allocate a new shared
979 // memory buffer.
980 video_input_resource_ = NULL;
981 if (!video_decode_cb_.is_null())
982 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
983 break;
984 default:
985 NOTREACHED();
989 bool ContentDecryptorDelegate::MakeMediaBufferResource(
990 Decryptor::StreamType stream_type,
991 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
992 scoped_refptr<PPB_Buffer_Impl>* resource) {
993 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
995 // End of stream buffers are represented as null resources.
996 if (encrypted_buffer->end_of_stream()) {
997 *resource = NULL;
998 return true;
1001 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1002 scoped_refptr<PPB_Buffer_Impl>& media_resource =
1003 (stream_type == Decryptor::kAudio) ? audio_input_resource_
1004 : video_input_resource_;
1006 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1007 if (!media_resource.get() || media_resource->size() < data_size) {
1008 // Either the buffer hasn't been created yet, or we have one that isn't big
1009 // enough to fit |size| bytes.
1011 // Media resource size starts from |kMinimumMediaBufferSize| and grows
1012 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1013 // which is usually expensive. Since input media buffers are compressed,
1014 // they are usually small (compared to outputs). The over-allocated memory
1015 // should be negligible.
1016 const uint32_t kMinimumMediaBufferSize = 1024;
1017 uint32_t media_resource_size =
1018 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1019 while (media_resource_size < data_size)
1020 media_resource_size *= 2;
1022 DVLOG(2) << "Size of media buffer for "
1023 << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1024 << " stream bumped to " << media_resource_size
1025 << " bytes to fit input.";
1026 media_resource =
1027 PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1028 if (!media_resource.get())
1029 return false;
1032 BufferAutoMapper mapper(media_resource.get());
1033 if (!mapper.data() || mapper.size() < data_size) {
1034 media_resource = NULL;
1035 return false;
1037 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1039 *resource = media_resource;
1040 return true;
1043 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1044 if (buffer_id)
1045 free_buffers_.push(buffer_id);
1048 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1049 PP_DecryptTrackingInfo* tracking_info) {
1050 DCHECK_EQ(tracking_info->buffer_id, 0u);
1052 if (free_buffers_.empty())
1053 return;
1055 tracking_info->buffer_id = free_buffers_.front();
1056 free_buffers_.pop();
1059 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1060 PP_Resource audio_frames,
1061 size_t data_size,
1062 media::SampleFormat sample_format,
1063 Decryptor::AudioBuffers* frames) {
1064 DCHECK(frames);
1065 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1066 if (!enter.succeeded())
1067 return false;
1069 BufferAutoMapper mapper(enter.object());
1070 if (!mapper.data() || !mapper.size() ||
1071 mapper.size() < static_cast<uint32_t>(data_size))
1072 return false;
1074 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1075 // the copy. Since it is possible to get multiple buffers, it would need to be
1076 // sliced and ref counted appropriately. http://crbug.com/255576.
1077 const uint8* cur = static_cast<uint8*>(mapper.data());
1078 size_t bytes_left = data_size;
1080 const int audio_bytes_per_frame =
1081 media::SampleFormatToBytesPerChannel(sample_format) *
1082 audio_channel_count_;
1083 if (audio_bytes_per_frame <= 0)
1084 return false;
1086 // Allocate space for the channel pointers given to AudioBuffer.
1087 std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1088 static_cast<const uint8*>(NULL));
1089 do {
1090 int64 timestamp = 0;
1091 int64 frame_size = -1;
1092 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1094 if (bytes_left < kHeaderSize)
1095 return false;
1097 memcpy(&timestamp, cur, sizeof(timestamp));
1098 cur += sizeof(timestamp);
1099 bytes_left -= sizeof(timestamp);
1101 memcpy(&frame_size, cur, sizeof(frame_size));
1102 cur += sizeof(frame_size);
1103 bytes_left -= sizeof(frame_size);
1105 // We should *not* have empty frames in the list.
1106 if (frame_size <= 0 ||
1107 bytes_left < base::checked_cast<size_t>(frame_size)) {
1108 return false;
1111 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1112 // one in the case of interleaved data.
1113 const int size_per_channel = frame_size / audio_channel_count_;
1114 for (int i = 0; i < audio_channel_count_; ++i)
1115 channel_ptrs[i] = cur + i * size_per_channel;
1117 const int frame_count = frame_size / audio_bytes_per_frame;
1118 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1119 sample_format,
1120 audio_channel_layout_,
1121 audio_channel_count_,
1122 audio_samples_per_second_,
1123 frame_count,
1124 &channel_ptrs[0],
1125 base::TimeDelta::FromMicroseconds(timestamp));
1126 frames->push_back(frame);
1128 cur += frame_size;
1129 bytes_left -= frame_size;
1130 } while (bytes_left > 0);
1132 return true;
1135 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1136 if (!audio_decoder_init_cb_.is_null())
1137 audio_decoder_init_cb_.ResetAndReturn().Run(false);
1139 if (!video_decoder_init_cb_.is_null())
1140 video_decoder_init_cb_.ResetAndReturn().Run(false);
1142 audio_input_resource_ = NULL;
1143 video_input_resource_ = NULL;
1145 if (!audio_decrypt_cb_.is_null())
1146 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1148 if (!video_decrypt_cb_.is_null())
1149 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1151 if (!audio_decode_cb_.is_null()) {
1152 const media::Decryptor::AudioBuffers empty_frames;
1153 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1154 empty_frames);
1157 if (!video_decode_cb_.is_null())
1158 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1160 // Reject all outstanding promises.
1161 for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
1162 ++it) {
1163 it->second->reject(
1164 media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
1166 promises_.clear();
1169 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
1170 uint32_t promise_id = next_promise_id_++;
1171 promises_.add(promise_id, promise.Pass());
1172 return promise_id;
1175 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
1176 uint32_t promise_id) {
1177 PromiseMap::iterator it = promises_.find(promise_id);
1178 if (it == promises_.end())
1179 return scoped_ptr<CdmPromise>();
1180 return promises_.take_and_erase(it);
1183 } // namespace content