chrome.bluetoothSocket: clean-up Listen functions
[chromium-blink-merge.git] / content / renderer / pepper / content_decryptor_delegate.cc
blob8692c1ce643083c62c82c86f1eb47dafc616054a
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 // TODO(xhwang): VP8 and VP9 do not have profiles. Clean up
165 // media::VideoCodecProfile and remove these two cases.
166 case media::VP8PROFILE_MAIN:
167 case media::VP9PROFILE_MAIN:
168 return PP_VIDEOCODECPROFILE_NOT_NEEDED;
169 case media::H264PROFILE_BASELINE:
170 return PP_VIDEOCODECPROFILE_H264_BASELINE;
171 case media::H264PROFILE_MAIN:
172 return PP_VIDEOCODECPROFILE_H264_MAIN;
173 case media::H264PROFILE_EXTENDED:
174 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
175 case media::H264PROFILE_HIGH:
176 return PP_VIDEOCODECPROFILE_H264_HIGH;
177 case media::H264PROFILE_HIGH10PROFILE:
178 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
179 case media::H264PROFILE_HIGH422PROFILE:
180 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
181 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
182 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
183 default:
184 return PP_VIDEOCODECPROFILE_UNKNOWN;
188 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
189 media::VideoFrame::Format format) {
190 switch (format) {
191 case media::VideoFrame::YV12:
192 return PP_DECRYPTEDFRAMEFORMAT_YV12;
193 case media::VideoFrame::I420:
194 return PP_DECRYPTEDFRAMEFORMAT_I420;
195 default:
196 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
200 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
201 PP_DecryptResult result) {
202 switch (result) {
203 case PP_DECRYPTRESULT_SUCCESS:
204 return Decryptor::kSuccess;
205 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
206 return Decryptor::kNoKey;
207 case PP_DECRYPTRESULT_NEEDMOREDATA:
208 return Decryptor::kNeedMoreData;
209 case PP_DECRYPTRESULT_DECRYPT_ERROR:
210 return Decryptor::kError;
211 case PP_DECRYPTRESULT_DECODE_ERROR:
212 return Decryptor::kError;
213 default:
214 NOTREACHED();
215 return Decryptor::kError;
219 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
220 Decryptor::StreamType stream_type) {
221 switch (stream_type) {
222 case Decryptor::kAudio:
223 return PP_DECRYPTORSTREAMTYPE_AUDIO;
224 case Decryptor::kVideo:
225 return PP_DECRYPTORSTREAMTYPE_VIDEO;
226 default:
227 NOTREACHED();
228 return PP_DECRYPTORSTREAMTYPE_VIDEO;
232 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
233 PP_DecryptedSampleFormat result) {
234 switch (result) {
235 case PP_DECRYPTEDSAMPLEFORMAT_U8:
236 return media::kSampleFormatU8;
237 case PP_DECRYPTEDSAMPLEFORMAT_S16:
238 return media::kSampleFormatS16;
239 case PP_DECRYPTEDSAMPLEFORMAT_S32:
240 return media::kSampleFormatS32;
241 case PP_DECRYPTEDSAMPLEFORMAT_F32:
242 return media::kSampleFormatF32;
243 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
244 return media::kSampleFormatPlanarS16;
245 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
246 return media::kSampleFormatPlanarF32;
247 default:
248 NOTREACHED();
249 return media::kUnknownSampleFormat;
253 PP_SessionType MediaSessionTypeToPpSessionType(
254 MediaKeys::SessionType session_type) {
255 switch (session_type) {
256 case MediaKeys::TEMPORARY_SESSION:
257 return PP_SESSIONTYPE_TEMPORARY;
258 case MediaKeys::PERSISTENT_SESSION:
259 return PP_SESSIONTYPE_PERSISTENT;
260 default:
261 NOTREACHED();
262 return PP_SESSIONTYPE_TEMPORARY;
266 MediaKeys::Exception PpExceptionTypeToMediaException(
267 PP_CdmExceptionCode exception_code) {
268 switch (exception_code) {
269 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
270 return MediaKeys::NOT_SUPPORTED_ERROR;
271 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
272 return MediaKeys::INVALID_STATE_ERROR;
273 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
274 return MediaKeys::INVALID_ACCESS_ERROR;
275 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
276 return MediaKeys::QUOTA_EXCEEDED_ERROR;
277 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
278 return MediaKeys::UNKNOWN_ERROR;
279 case PP_CDMEXCEPTIONCODE_CLIENTERROR:
280 return MediaKeys::CLIENT_ERROR;
281 case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
282 return MediaKeys::OUTPUT_ERROR;
283 default:
284 NOTREACHED();
285 return MediaKeys::UNKNOWN_ERROR;
289 } // namespace
291 ContentDecryptorDelegate::ContentDecryptorDelegate(
292 PP_Instance pp_instance,
293 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
294 : pp_instance_(pp_instance),
295 plugin_decryption_interface_(plugin_decryption_interface),
296 next_decryption_request_id_(1),
297 audio_samples_per_second_(0),
298 audio_channel_count_(0),
299 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
300 next_promise_id_(1),
301 weak_ptr_factory_(this) {
302 weak_this_ = weak_ptr_factory_.GetWeakPtr();
305 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
306 SatisfyAllPendingCallbacksOnError();
309 void ContentDecryptorDelegate::Initialize(
310 const std::string& key_system,
311 const media::SessionMessageCB& session_message_cb,
312 const media::SessionReadyCB& session_ready_cb,
313 const media::SessionClosedCB& session_closed_cb,
314 const media::SessionErrorCB& session_error_cb,
315 const base::Closure& fatal_plugin_error_cb) {
316 DCHECK(!key_system.empty());
317 DCHECK(key_system_.empty());
318 key_system_ = key_system;
320 session_message_cb_ = session_message_cb;
321 session_ready_cb_ = session_ready_cb;
322 session_closed_cb_ = session_closed_cb;
323 session_error_cb_ = session_error_cb;
324 fatal_plugin_error_cb_ = fatal_plugin_error_cb;
326 plugin_decryption_interface_->Initialize(
327 pp_instance_, StringVar::StringToPPVar(key_system_));
330 void ContentDecryptorDelegate::InstanceCrashed() {
331 fatal_plugin_error_cb_.Run();
332 SatisfyAllPendingCallbacksOnError();
335 void ContentDecryptorDelegate::CreateSession(
336 const std::string& init_data_type,
337 const uint8* init_data,
338 int init_data_length,
339 MediaKeys::SessionType session_type,
340 scoped_ptr<NewSessionCdmPromise> promise) {
341 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
342 PP_Var init_data_array =
343 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
344 init_data_length, init_data);
345 plugin_decryption_interface_->CreateSession(
346 pp_instance_,
347 promise_id,
348 StringVar::StringToPPVar(init_data_type),
349 init_data_array,
350 MediaSessionTypeToPpSessionType(session_type));
353 void ContentDecryptorDelegate::LoadSession(
354 const std::string& web_session_id,
355 scoped_ptr<NewSessionCdmPromise> promise) {
356 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
357 plugin_decryption_interface_->LoadSession(
358 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
361 void ContentDecryptorDelegate::UpdateSession(
362 const std::string& web_session_id,
363 const uint8* response,
364 int response_length,
365 scoped_ptr<SimpleCdmPromise> promise) {
366 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
367 PP_Var response_array =
368 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
369 response_length, response);
370 plugin_decryption_interface_->UpdateSession(
371 pp_instance_,
372 promise_id,
373 StringVar::StringToPPVar(web_session_id),
374 response_array);
377 void ContentDecryptorDelegate::ReleaseSession(
378 const std::string& web_session_id,
379 scoped_ptr<SimpleCdmPromise> promise) {
380 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
381 plugin_decryption_interface_->ReleaseSession(
382 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
385 // TODO(xhwang): Remove duplication of code in Decrypt(),
386 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
387 bool ContentDecryptorDelegate::Decrypt(
388 Decryptor::StreamType stream_type,
389 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
390 const Decryptor::DecryptCB& decrypt_cb) {
391 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
393 // |{audio|video}_input_resource_| is not being used by the plugin
394 // now because there is only one pending audio/video decrypt request at any
395 // time. This is enforced by the media pipeline.
396 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
397 if (!MakeMediaBufferResource(
398 stream_type, encrypted_buffer, &encrypted_resource) ||
399 !encrypted_resource.get()) {
400 return false;
402 ScopedPPResource pp_resource(encrypted_resource.get());
404 const uint32_t request_id = next_decryption_request_id_++;
405 DVLOG(2) << "Decrypt() - request_id " << request_id;
407 PP_EncryptedBlockInfo block_info = {};
408 DCHECK(encrypted_buffer->decrypt_config());
409 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
410 return false;
413 // There is only one pending decrypt request at any time per stream. This is
414 // enforced by the media pipeline.
415 switch (stream_type) {
416 case Decryptor::kAudio:
417 audio_decrypt_cb_.Set(request_id, decrypt_cb);
418 break;
419 case Decryptor::kVideo:
420 video_decrypt_cb_.Set(request_id, decrypt_cb);
421 break;
422 default:
423 NOTREACHED();
424 return false;
427 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
429 plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
430 return true;
433 bool ContentDecryptorDelegate::CancelDecrypt(
434 Decryptor::StreamType stream_type) {
435 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
437 Decryptor::DecryptCB decrypt_cb;
438 switch (stream_type) {
439 case Decryptor::kAudio:
440 // Release the shared memory as it can still be in use by the plugin.
441 // The next Decrypt() call will need to allocate a new shared memory
442 // buffer.
443 audio_input_resource_ = NULL;
444 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
445 break;
446 case Decryptor::kVideo:
447 // Release the shared memory as it can still be in use by the plugin.
448 // The next Decrypt() call will need to allocate a new shared memory
449 // buffer.
450 video_input_resource_ = NULL;
451 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
452 break;
453 default:
454 NOTREACHED();
455 return false;
458 if (!decrypt_cb.is_null())
459 decrypt_cb.Run(Decryptor::kSuccess, NULL);
461 return true;
464 bool ContentDecryptorDelegate::InitializeAudioDecoder(
465 const media::AudioDecoderConfig& decoder_config,
466 const Decryptor::DecoderInitCB& init_cb) {
467 PP_AudioDecoderConfig pp_decoder_config;
468 pp_decoder_config.codec =
469 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
470 pp_decoder_config.channel_count =
471 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
472 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
473 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
474 pp_decoder_config.request_id = next_decryption_request_id_++;
476 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
477 audio_channel_count_ = pp_decoder_config.channel_count;
478 audio_channel_layout_ = decoder_config.channel_layout();
480 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
481 if (!MakeBufferResource(pp_instance_,
482 decoder_config.extra_data(),
483 decoder_config.extra_data_size(),
484 &extra_data_resource)) {
485 return false;
487 ScopedPPResource pp_resource(extra_data_resource.get());
489 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
490 plugin_decryption_interface_->InitializeAudioDecoder(
491 pp_instance_, &pp_decoder_config, pp_resource);
492 return true;
495 bool ContentDecryptorDelegate::InitializeVideoDecoder(
496 const media::VideoDecoderConfig& decoder_config,
497 const Decryptor::DecoderInitCB& init_cb) {
498 PP_VideoDecoderConfig pp_decoder_config;
499 pp_decoder_config.codec =
500 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
501 pp_decoder_config.profile =
502 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
503 pp_decoder_config.format =
504 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
505 pp_decoder_config.width = decoder_config.coded_size().width();
506 pp_decoder_config.height = decoder_config.coded_size().height();
507 pp_decoder_config.request_id = next_decryption_request_id_++;
509 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
510 if (!MakeBufferResource(pp_instance_,
511 decoder_config.extra_data(),
512 decoder_config.extra_data_size(),
513 &extra_data_resource)) {
514 return false;
516 ScopedPPResource pp_resource(extra_data_resource.get());
518 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
519 natural_size_ = decoder_config.natural_size();
521 plugin_decryption_interface_->InitializeVideoDecoder(
522 pp_instance_, &pp_decoder_config, pp_resource);
523 return true;
526 bool ContentDecryptorDelegate::DeinitializeDecoder(
527 Decryptor::StreamType stream_type) {
528 CancelDecode(stream_type);
530 if (stream_type == Decryptor::kVideo)
531 natural_size_ = gfx::Size();
533 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
534 // stream type from media stack.
535 plugin_decryption_interface_->DeinitializeDecoder(
536 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
537 return true;
540 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
541 CancelDecode(stream_type);
543 // TODO(tomfinegan): Add decoder reset request tracking.
544 plugin_decryption_interface_->ResetDecoder(
545 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
546 return true;
549 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
550 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
551 const Decryptor::AudioDecodeCB& audio_decode_cb) {
552 // |audio_input_resource_| is not being used by the plugin now
553 // because there is only one pending audio decode request at any time.
554 // This is enforced by the media pipeline.
555 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
556 if (!MakeMediaBufferResource(
557 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
558 return false;
561 // The resource should not be NULL for non-EOS buffer.
562 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
563 return false;
565 const uint32_t request_id = next_decryption_request_id_++;
566 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
568 PP_EncryptedBlockInfo block_info = {};
569 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
570 return false;
573 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
575 // There is only one pending audio decode request at any time. This is
576 // enforced by the media pipeline. If this DCHECK is violated, our buffer
577 // reuse policy is not valid, and we may have race problems for the shared
578 // buffer.
579 audio_decode_cb_.Set(request_id, audio_decode_cb);
581 ScopedPPResource pp_resource(encrypted_resource.get());
582 plugin_decryption_interface_->DecryptAndDecode(
583 pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
584 return true;
587 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
588 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
589 const Decryptor::VideoDecodeCB& video_decode_cb) {
590 // |video_input_resource_| is not being used by the plugin now
591 // because there is only one pending video decode request at any time.
592 // This is enforced by the media pipeline.
593 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
594 if (!MakeMediaBufferResource(
595 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
596 return false;
599 // The resource should not be 0 for non-EOS buffer.
600 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
601 return false;
603 const uint32_t request_id = next_decryption_request_id_++;
604 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
605 TRACE_EVENT_ASYNC_BEGIN0(
606 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
608 PP_EncryptedBlockInfo block_info = {};
609 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
610 return false;
613 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
615 // Only one pending video decode request at any time. This is enforced by the
616 // media pipeline. If this DCHECK is violated, our buffer
617 // reuse policy is not valid, and we may have race problems for the shared
618 // buffer.
619 video_decode_cb_.Set(request_id, video_decode_cb);
621 // TODO(tomfinegan): Need to get stream type from media stack.
622 ScopedPPResource pp_resource(encrypted_resource.get());
623 plugin_decryption_interface_->DecryptAndDecode(
624 pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
625 return true;
628 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
629 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
630 if (promise) {
631 SimpleCdmPromise* simple_promise(
632 static_cast<SimpleCdmPromise*>(promise.get()));
633 simple_promise->resolve();
637 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
638 uint32 promise_id,
639 PP_Var web_session_id) {
640 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
642 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
643 DCHECK(web_session_id_string);
645 if (promise) {
646 NewSessionCdmPromise* session_promise(
647 static_cast<NewSessionCdmPromise*>(promise.get()));
648 session_promise->resolve(web_session_id_string->value());
652 void ContentDecryptorDelegate::OnPromiseRejected(
653 uint32 promise_id,
654 PP_CdmExceptionCode exception_code,
655 uint32 system_code,
656 PP_Var error_description) {
657 StringVar* error_description_string = StringVar::FromPPVar(error_description);
658 DCHECK(error_description_string);
660 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
661 if (promise) {
662 promise->reject(PpExceptionTypeToMediaException(exception_code),
663 system_code,
664 error_description_string->value());
668 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
669 PP_Var message,
670 PP_Var destination_url) {
671 if (session_message_cb_.is_null())
672 return;
674 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
675 DCHECK(web_session_id_string);
677 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
678 std::vector<uint8> message_vector;
679 if (message_array_buffer) {
680 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
681 message_vector.assign(data, data + message_array_buffer->ByteLength());
684 StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
685 DCHECK(destination_url_string);
687 GURL verified_gurl = GURL(destination_url_string->value());
688 if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
689 DLOG(WARNING) << "SessionMessage default_url is invalid : "
690 << verified_gurl.possibly_invalid_spec();
691 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
694 session_message_cb_.Run(
695 web_session_id_string->value(), message_vector, verified_gurl);
698 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
699 if (session_ready_cb_.is_null())
700 return;
702 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
703 DCHECK(web_session_id_string);
705 session_ready_cb_.Run(web_session_id_string->value());
708 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
709 if (session_closed_cb_.is_null())
710 return;
712 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
713 DCHECK(web_session_id_string);
715 session_closed_cb_.Run(web_session_id_string->value());
718 void ContentDecryptorDelegate::OnSessionError(
719 PP_Var web_session_id,
720 PP_CdmExceptionCode exception_code,
721 uint32 system_code,
722 PP_Var error_description) {
723 if (session_error_cb_.is_null())
724 return;
726 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
727 DCHECK(web_session_id_string);
729 StringVar* error_description_string = StringVar::FromPPVar(error_description);
730 DCHECK(error_description_string);
732 session_error_cb_.Run(web_session_id_string->value(),
733 PpExceptionTypeToMediaException(exception_code),
734 system_code,
735 error_description_string->value());
738 void ContentDecryptorDelegate::DecoderInitializeDone(
739 PP_DecryptorStreamType decoder_type,
740 uint32_t request_id,
741 PP_Bool success) {
742 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
743 // If the request ID is not valid or does not match what's saved, do
744 // nothing.
745 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
746 return;
748 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
749 } else {
750 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
751 return;
753 if (!success)
754 natural_size_ = gfx::Size();
756 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
760 void ContentDecryptorDelegate::DecoderDeinitializeDone(
761 PP_DecryptorStreamType decoder_type,
762 uint32_t request_id) {
763 // TODO(tomfinegan): Add decoder stop completion handling.
766 void ContentDecryptorDelegate::DecoderResetDone(
767 PP_DecryptorStreamType decoder_type,
768 uint32_t request_id) {
769 // TODO(tomfinegan): Add decoder reset completion handling.
772 void ContentDecryptorDelegate::DeliverBlock(
773 PP_Resource decrypted_block,
774 const PP_DecryptedBlockInfo* block_info) {
775 DCHECK(block_info);
777 FreeBuffer(block_info->tracking_info.buffer_id);
779 const uint32_t request_id = block_info->tracking_info.request_id;
780 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
782 // If the request ID is not valid or does not match what's saved, do nothing.
783 if (request_id == 0) {
784 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
785 return;
788 Decryptor::DecryptCB decrypt_cb;
789 if (audio_decrypt_cb_.Matches(request_id)) {
790 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
791 } else if (video_decrypt_cb_.Matches(request_id)) {
792 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
793 } else {
794 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
795 return;
798 Decryptor::Status status =
799 PpDecryptResultToMediaDecryptorStatus(block_info->result);
800 if (status != Decryptor::kSuccess) {
801 decrypt_cb.Run(status, NULL);
802 return;
805 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
806 if (!enter.succeeded()) {
807 decrypt_cb.Run(Decryptor::kError, NULL);
808 return;
810 BufferAutoMapper mapper(enter.object());
811 if (!mapper.data() || !mapper.size() ||
812 mapper.size() < block_info->data_size) {
813 decrypt_cb.Run(Decryptor::kError, NULL);
814 return;
817 // TODO(tomfinegan): Find a way to take ownership of the shared memory
818 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
819 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
820 media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
821 block_info->data_size));
822 decrypted_buffer->set_timestamp(
823 base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
824 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
827 // Use a non-class-member function here so that if for some reason
828 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
829 // we can still get the shared memory unmapped.
830 static void BufferNoLongerNeeded(
831 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
832 base::Closure buffer_no_longer_needed_cb) {
833 ppb_buffer->Unmap();
834 buffer_no_longer_needed_cb.Run();
837 // Enters |resource|, maps shared memory and returns pointer of mapped data.
838 // Returns NULL if any error occurs.
839 static uint8* GetMappedBuffer(PP_Resource resource,
840 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
841 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
842 if (!enter.succeeded())
843 return NULL;
845 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
846 if (!enter.object()->IsMapped() || !mapped_data)
847 return NULL;
849 uint32_t mapped_size = 0;
850 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
851 enter.object()->Unmap();
852 return NULL;
855 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
857 return mapped_data;
860 void ContentDecryptorDelegate::DeliverFrame(
861 PP_Resource decrypted_frame,
862 const PP_DecryptedFrameInfo* frame_info) {
863 DCHECK(frame_info);
865 const uint32_t request_id = frame_info->tracking_info.request_id;
866 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
868 // If the request ID is not valid or does not match what's saved, do nothing.
869 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
870 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
871 FreeBuffer(frame_info->tracking_info.buffer_id);
872 return;
875 TRACE_EVENT_ASYNC_END0(
876 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
878 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
880 Decryptor::Status status =
881 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
882 if (status != Decryptor::kSuccess) {
883 DCHECK(!frame_info->tracking_info.buffer_id);
884 video_decode_cb.Run(status, NULL);
885 return;
888 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
889 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
890 if (!frame_data) {
891 FreeBuffer(frame_info->tracking_info.buffer_id);
892 video_decode_cb.Run(Decryptor::kError, NULL);
893 return;
896 gfx::Size frame_size(frame_info->width, frame_info->height);
897 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
899 scoped_refptr<media::VideoFrame> decoded_frame =
900 media::VideoFrame::WrapExternalYuvData(
901 media::VideoFrame::YV12,
902 frame_size,
903 gfx::Rect(frame_size),
904 natural_size_,
905 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
906 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
907 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
908 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
909 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
910 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
911 base::TimeDelta::FromMicroseconds(
912 frame_info->tracking_info.timestamp),
913 media::BindToCurrentLoop(
914 base::Bind(&BufferNoLongerNeeded,
915 ppb_buffer,
916 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
917 weak_this_,
918 frame_info->tracking_info.buffer_id))));
920 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
923 void ContentDecryptorDelegate::DeliverSamples(
924 PP_Resource audio_frames,
925 const PP_DecryptedSampleInfo* sample_info) {
926 DCHECK(sample_info);
928 FreeBuffer(sample_info->tracking_info.buffer_id);
930 const uint32_t request_id = sample_info->tracking_info.request_id;
931 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
933 // If the request ID is not valid or does not match what's saved, do nothing.
934 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
935 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
936 return;
939 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
941 const Decryptor::AudioBuffers empty_frames;
943 Decryptor::Status status =
944 PpDecryptResultToMediaDecryptorStatus(sample_info->result);
945 if (status != Decryptor::kSuccess) {
946 audio_decode_cb.Run(status, empty_frames);
947 return;
950 media::SampleFormat sample_format =
951 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
953 Decryptor::AudioBuffers audio_frame_list;
954 if (!DeserializeAudioFrames(audio_frames,
955 sample_info->data_size,
956 sample_format,
957 &audio_frame_list)) {
958 NOTREACHED() << "CDM did not serialize the buffer correctly.";
959 audio_decode_cb.Run(Decryptor::kError, empty_frames);
960 return;
963 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
966 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
967 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
968 switch (stream_type) {
969 case Decryptor::kAudio:
970 // Release the shared memory as it can still be in use by the plugin.
971 // The next DecryptAndDecode() call will need to allocate a new shared
972 // memory buffer.
973 audio_input_resource_ = NULL;
974 if (!audio_decode_cb_.is_null())
975 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
976 Decryptor::AudioBuffers());
977 break;
978 case Decryptor::kVideo:
979 // Release the shared memory as it can still be in use by the plugin.
980 // The next DecryptAndDecode() call will need to allocate a new shared
981 // memory buffer.
982 video_input_resource_ = NULL;
983 if (!video_decode_cb_.is_null())
984 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
985 break;
986 default:
987 NOTREACHED();
991 bool ContentDecryptorDelegate::MakeMediaBufferResource(
992 Decryptor::StreamType stream_type,
993 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
994 scoped_refptr<PPB_Buffer_Impl>* resource) {
995 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
997 // End of stream buffers are represented as null resources.
998 if (encrypted_buffer->end_of_stream()) {
999 *resource = NULL;
1000 return true;
1003 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1004 scoped_refptr<PPB_Buffer_Impl>& media_resource =
1005 (stream_type == Decryptor::kAudio) ? audio_input_resource_
1006 : video_input_resource_;
1008 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1009 if (!media_resource.get() || media_resource->size() < data_size) {
1010 // Either the buffer hasn't been created yet, or we have one that isn't big
1011 // enough to fit |size| bytes.
1013 // Media resource size starts from |kMinimumMediaBufferSize| and grows
1014 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1015 // which is usually expensive. Since input media buffers are compressed,
1016 // they are usually small (compared to outputs). The over-allocated memory
1017 // should be negligible.
1018 const uint32_t kMinimumMediaBufferSize = 1024;
1019 uint32_t media_resource_size =
1020 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1021 while (media_resource_size < data_size)
1022 media_resource_size *= 2;
1024 DVLOG(2) << "Size of media buffer for "
1025 << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1026 << " stream bumped to " << media_resource_size
1027 << " bytes to fit input.";
1028 media_resource =
1029 PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1030 if (!media_resource.get())
1031 return false;
1034 BufferAutoMapper mapper(media_resource.get());
1035 if (!mapper.data() || mapper.size() < data_size) {
1036 media_resource = NULL;
1037 return false;
1039 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1041 *resource = media_resource;
1042 return true;
1045 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1046 if (buffer_id)
1047 free_buffers_.push(buffer_id);
1050 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1051 PP_DecryptTrackingInfo* tracking_info) {
1052 DCHECK_EQ(tracking_info->buffer_id, 0u);
1054 if (free_buffers_.empty())
1055 return;
1057 tracking_info->buffer_id = free_buffers_.front();
1058 free_buffers_.pop();
1061 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1062 PP_Resource audio_frames,
1063 size_t data_size,
1064 media::SampleFormat sample_format,
1065 Decryptor::AudioBuffers* frames) {
1066 DCHECK(frames);
1067 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1068 if (!enter.succeeded())
1069 return false;
1071 BufferAutoMapper mapper(enter.object());
1072 if (!mapper.data() || !mapper.size() ||
1073 mapper.size() < static_cast<uint32_t>(data_size))
1074 return false;
1076 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1077 // the copy. Since it is possible to get multiple buffers, it would need to be
1078 // sliced and ref counted appropriately. http://crbug.com/255576.
1079 const uint8* cur = static_cast<uint8*>(mapper.data());
1080 size_t bytes_left = data_size;
1082 const int audio_bytes_per_frame =
1083 media::SampleFormatToBytesPerChannel(sample_format) *
1084 audio_channel_count_;
1085 if (audio_bytes_per_frame <= 0)
1086 return false;
1088 // Allocate space for the channel pointers given to AudioBuffer.
1089 std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1090 static_cast<const uint8*>(NULL));
1091 do {
1092 int64 timestamp = 0;
1093 int64 frame_size = -1;
1094 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1096 if (bytes_left < kHeaderSize)
1097 return false;
1099 memcpy(&timestamp, cur, sizeof(timestamp));
1100 cur += sizeof(timestamp);
1101 bytes_left -= sizeof(timestamp);
1103 memcpy(&frame_size, cur, sizeof(frame_size));
1104 cur += sizeof(frame_size);
1105 bytes_left -= sizeof(frame_size);
1107 // We should *not* have empty frames in the list.
1108 if (frame_size <= 0 ||
1109 bytes_left < base::checked_cast<size_t>(frame_size)) {
1110 return false;
1113 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1114 // one in the case of interleaved data.
1115 const int size_per_channel = frame_size / audio_channel_count_;
1116 for (int i = 0; i < audio_channel_count_; ++i)
1117 channel_ptrs[i] = cur + i * size_per_channel;
1119 const int frame_count = frame_size / audio_bytes_per_frame;
1120 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1121 sample_format,
1122 audio_channel_layout_,
1123 audio_channel_count_,
1124 audio_samples_per_second_,
1125 frame_count,
1126 &channel_ptrs[0],
1127 base::TimeDelta::FromMicroseconds(timestamp));
1128 frames->push_back(frame);
1130 cur += frame_size;
1131 bytes_left -= frame_size;
1132 } while (bytes_left > 0);
1134 return true;
1137 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1138 if (!audio_decoder_init_cb_.is_null())
1139 audio_decoder_init_cb_.ResetAndReturn().Run(false);
1141 if (!video_decoder_init_cb_.is_null())
1142 video_decoder_init_cb_.ResetAndReturn().Run(false);
1144 audio_input_resource_ = NULL;
1145 video_input_resource_ = NULL;
1147 if (!audio_decrypt_cb_.is_null())
1148 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1150 if (!video_decrypt_cb_.is_null())
1151 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1153 if (!audio_decode_cb_.is_null()) {
1154 const media::Decryptor::AudioBuffers empty_frames;
1155 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1156 empty_frames);
1159 if (!video_decode_cb_.is_null())
1160 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1162 // Reject all outstanding promises.
1163 for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
1164 ++it) {
1165 it->second->reject(
1166 media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
1168 promises_.clear();
1171 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
1172 uint32_t promise_id = next_promise_id_++;
1173 promises_.add(promise_id, promise.Pass());
1174 return promise_id;
1177 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
1178 uint32_t promise_id) {
1179 PromiseMap::iterator it = promises_.find(promise_id);
1180 if (it == promises_.end())
1181 return scoped_ptr<CdmPromise>();
1182 return promises_.take_and_erase(it);
1185 } // namespace content