mesa gn build: suppress -Wstring-conversion warnings
[chromium-blink-merge.git] / content / renderer / pepper / content_decryptor_delegate.cc
blob039f040465ce4c64b75eab20a83e97b0fb6f9901
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/metrics/sparse_histogram.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "content/renderer/pepper/ppb_buffer_impl.h"
13 #include "media/base/audio_buffer.h"
14 #include "media/base/audio_decoder_config.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/cdm_promise.h"
17 #include "media/base/channel_layout.h"
18 #include "media/base/data_buffer.h"
19 #include "media/base/decoder_buffer.h"
20 #include "media/base/decrypt_config.h"
21 #include "media/base/key_systems.h"
22 #include "media/base/limits.h"
23 #include "media/base/video_decoder_config.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/video_util.h"
26 #include "ppapi/shared_impl/array_var.h"
27 #include "ppapi/shared_impl/scoped_pp_resource.h"
28 #include "ppapi/shared_impl/time_conversion.h"
29 #include "ppapi/shared_impl/var.h"
30 #include "ppapi/shared_impl/var_tracker.h"
31 #include "ppapi/thunk/enter.h"
32 #include "ppapi/thunk/ppb_buffer_api.h"
33 #include "ui/gfx/rect.h"
35 using media::CdmPromise;
36 using media::Decryptor;
37 using media::KeyIdsPromise;
38 using media::MediaKeys;
39 using media::NewSessionCdmPromise;
40 using media::SimpleCdmPromise;
41 using ppapi::ArrayBufferVar;
42 using ppapi::ArrayVar;
43 using ppapi::PpapiGlobals;
44 using ppapi::ScopedPPResource;
45 using ppapi::StringVar;
46 using ppapi::thunk::EnterResourceNoLock;
47 using ppapi::thunk::PPB_Buffer_API;
49 namespace content {
51 namespace {
53 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
54 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
55 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
56 // true upon success and false if any error happened.
57 bool MakeBufferResource(PP_Instance instance,
58 const uint8* data,
59 uint32_t size,
60 scoped_refptr<PPB_Buffer_Impl>* resource) {
61 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
62 DCHECK(resource);
64 if (!data || !size) {
65 DCHECK(!data && !size);
66 resource = NULL;
67 return true;
70 scoped_refptr<PPB_Buffer_Impl> buffer(
71 PPB_Buffer_Impl::CreateResource(instance, size));
72 if (!buffer.get())
73 return false;
75 BufferAutoMapper mapper(buffer.get());
76 if (!mapper.data() || mapper.size() < size)
77 return false;
78 memcpy(mapper.data(), data, size);
80 *resource = buffer;
81 return true;
84 // Copies the content of |str| into |array|.
85 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
86 // |array_size| is smaller than the |str| length.
87 template <uint32_t array_size>
88 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
89 if (array_size < str.size())
90 return false;
92 memcpy(array, str.data(), str.size());
93 return true;
96 // Fills the |block_info| with information from |encrypted_buffer|.
98 // Returns true if |block_info| is successfully filled. Returns false
99 // otherwise.
100 bool MakeEncryptedBlockInfo(
101 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
102 uint32_t request_id,
103 PP_EncryptedBlockInfo* block_info) {
104 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
105 // anywhere else.
106 memset(block_info, 0, sizeof(*block_info));
107 block_info->tracking_info.request_id = request_id;
109 // EOS buffers need a request ID and nothing more.
110 if (encrypted_buffer->end_of_stream())
111 return true;
113 DCHECK(encrypted_buffer->data_size())
114 << "DecryptConfig is set on an empty buffer";
116 block_info->tracking_info.timestamp =
117 encrypted_buffer->timestamp().InMicroseconds();
118 block_info->data_size = encrypted_buffer->data_size();
120 const media::DecryptConfig* decrypt_config =
121 encrypted_buffer->decrypt_config();
123 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
124 !CopyStringToArray(decrypt_config->iv(), block_info->iv))
125 return false;
127 block_info->key_id_size = decrypt_config->key_id().size();
128 block_info->iv_size = decrypt_config->iv().size();
130 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
131 return false;
133 block_info->num_subsamples = decrypt_config->subsamples().size();
134 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
135 block_info->subsamples[i].clear_bytes =
136 decrypt_config->subsamples()[i].clear_bytes;
137 block_info->subsamples[i].cipher_bytes =
138 decrypt_config->subsamples()[i].cypher_bytes;
141 return true;
144 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
145 switch (codec) {
146 case media::kCodecVorbis:
147 return PP_AUDIOCODEC_VORBIS;
148 case media::kCodecAAC:
149 return PP_AUDIOCODEC_AAC;
150 default:
151 return PP_AUDIOCODEC_UNKNOWN;
155 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
156 switch (codec) {
157 case media::kCodecVP8:
158 return PP_VIDEOCODEC_VP8;
159 case media::kCodecH264:
160 return PP_VIDEOCODEC_H264;
161 case media::kCodecVP9:
162 return PP_VIDEOCODEC_VP9;
163 default:
164 return PP_VIDEOCODEC_UNKNOWN;
168 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
169 media::VideoCodecProfile profile) {
170 switch (profile) {
171 case media::VP8PROFILE_ANY:
172 case media::VP9PROFILE_ANY:
173 return PP_VIDEOCODECPROFILE_NOT_NEEDED;
174 case media::H264PROFILE_BASELINE:
175 return PP_VIDEOCODECPROFILE_H264_BASELINE;
176 case media::H264PROFILE_MAIN:
177 return PP_VIDEOCODECPROFILE_H264_MAIN;
178 case media::H264PROFILE_EXTENDED:
179 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
180 case media::H264PROFILE_HIGH:
181 return PP_VIDEOCODECPROFILE_H264_HIGH;
182 case media::H264PROFILE_HIGH10PROFILE:
183 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
184 case media::H264PROFILE_HIGH422PROFILE:
185 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
186 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
187 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
188 default:
189 return PP_VIDEOCODECPROFILE_UNKNOWN;
193 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
194 media::VideoFrame::Format format) {
195 switch (format) {
196 case media::VideoFrame::YV12:
197 return PP_DECRYPTEDFRAMEFORMAT_YV12;
198 case media::VideoFrame::I420:
199 return PP_DECRYPTEDFRAMEFORMAT_I420;
200 default:
201 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
205 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
206 PP_DecryptResult result) {
207 switch (result) {
208 case PP_DECRYPTRESULT_SUCCESS:
209 return Decryptor::kSuccess;
210 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
211 return Decryptor::kNoKey;
212 case PP_DECRYPTRESULT_NEEDMOREDATA:
213 return Decryptor::kNeedMoreData;
214 case PP_DECRYPTRESULT_DECRYPT_ERROR:
215 return Decryptor::kError;
216 case PP_DECRYPTRESULT_DECODE_ERROR:
217 return Decryptor::kError;
218 default:
219 NOTREACHED();
220 return Decryptor::kError;
224 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
225 Decryptor::StreamType stream_type) {
226 switch (stream_type) {
227 case Decryptor::kAudio:
228 return PP_DECRYPTORSTREAMTYPE_AUDIO;
229 case Decryptor::kVideo:
230 return PP_DECRYPTORSTREAMTYPE_VIDEO;
231 default:
232 NOTREACHED();
233 return PP_DECRYPTORSTREAMTYPE_VIDEO;
237 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
238 PP_DecryptedSampleFormat result) {
239 switch (result) {
240 case PP_DECRYPTEDSAMPLEFORMAT_U8:
241 return media::kSampleFormatU8;
242 case PP_DECRYPTEDSAMPLEFORMAT_S16:
243 return media::kSampleFormatS16;
244 case PP_DECRYPTEDSAMPLEFORMAT_S32:
245 return media::kSampleFormatS32;
246 case PP_DECRYPTEDSAMPLEFORMAT_F32:
247 return media::kSampleFormatF32;
248 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
249 return media::kSampleFormatPlanarS16;
250 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
251 return media::kSampleFormatPlanarF32;
252 default:
253 NOTREACHED();
254 return media::kUnknownSampleFormat;
258 PP_SessionType MediaSessionTypeToPpSessionType(
259 MediaKeys::SessionType session_type) {
260 switch (session_type) {
261 case MediaKeys::TEMPORARY_SESSION:
262 return PP_SESSIONTYPE_TEMPORARY;
263 case MediaKeys::PERSISTENT_SESSION:
264 return PP_SESSIONTYPE_PERSISTENT;
265 default:
266 NOTREACHED();
267 return PP_SESSIONTYPE_TEMPORARY;
271 MediaKeys::Exception PpExceptionTypeToMediaException(
272 PP_CdmExceptionCode exception_code) {
273 switch (exception_code) {
274 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
275 return MediaKeys::NOT_SUPPORTED_ERROR;
276 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
277 return MediaKeys::INVALID_STATE_ERROR;
278 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
279 return MediaKeys::INVALID_ACCESS_ERROR;
280 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
281 return MediaKeys::QUOTA_EXCEEDED_ERROR;
282 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
283 return MediaKeys::UNKNOWN_ERROR;
284 case PP_CDMEXCEPTIONCODE_CLIENTERROR:
285 return MediaKeys::CLIENT_ERROR;
286 case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
287 return MediaKeys::OUTPUT_ERROR;
288 default:
289 NOTREACHED();
290 return MediaKeys::UNKNOWN_ERROR;
294 // TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated.
295 // See http://crbug.com/412987 for details.
296 void ReportSystemCodeUMA(const std::string& key_system, uint32 system_code) {
297 // Sparse histogram macro does not cache the histogram, so it's safe to use
298 // macro with non-static histogram name here.
299 UMA_HISTOGRAM_SPARSE_SLOWLY(
300 "Media.EME." + media::GetKeySystemNameForUMA(key_system) + ".SystemCode",
301 system_code);
304 } // namespace
306 ContentDecryptorDelegate::ContentDecryptorDelegate(
307 PP_Instance pp_instance,
308 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
309 : pp_instance_(pp_instance),
310 plugin_decryption_interface_(plugin_decryption_interface),
311 next_decryption_request_id_(1),
312 audio_samples_per_second_(0),
313 audio_channel_count_(0),
314 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
315 next_promise_id_(1),
316 weak_ptr_factory_(this) {
317 weak_this_ = weak_ptr_factory_.GetWeakPtr();
320 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
321 SatisfyAllPendingCallbacksOnError();
324 void ContentDecryptorDelegate::Initialize(
325 const std::string& key_system,
326 const media::SessionMessageCB& session_message_cb,
327 const media::SessionReadyCB& session_ready_cb,
328 const media::SessionClosedCB& session_closed_cb,
329 const media::SessionErrorCB& session_error_cb,
330 const media::SessionKeysChangeCB& session_keys_change_cb,
331 const media::SessionExpirationUpdateCB& session_expiration_update_cb,
332 const base::Closure& fatal_plugin_error_cb) {
333 DCHECK(!key_system.empty());
334 DCHECK(key_system_.empty());
335 key_system_ = key_system;
337 session_message_cb_ = session_message_cb;
338 session_ready_cb_ = session_ready_cb;
339 session_closed_cb_ = session_closed_cb;
340 session_error_cb_ = session_error_cb;
341 session_keys_change_cb_ = session_keys_change_cb;
342 session_expiration_update_cb_ = session_expiration_update_cb;
343 fatal_plugin_error_cb_ = fatal_plugin_error_cb;
345 plugin_decryption_interface_->Initialize(
346 pp_instance_, StringVar::StringToPPVar(key_system_));
349 void ContentDecryptorDelegate::InstanceCrashed() {
350 fatal_plugin_error_cb_.Run();
351 SatisfyAllPendingCallbacksOnError();
354 void ContentDecryptorDelegate::SetServerCertificate(
355 const uint8_t* certificate,
356 uint32_t certificate_length,
357 scoped_ptr<media::SimpleCdmPromise> promise) {
358 if (!certificate ||
359 certificate_length < media::limits::kMinCertificateLength ||
360 certificate_length > media::limits::kMaxCertificateLength) {
361 promise->reject(
362 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
363 return;
366 uint32_t promise_id = SavePromise(promise.Pass());
367 PP_Var certificate_array =
368 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
369 certificate_length, certificate);
370 plugin_decryption_interface_->SetServerCertificate(
371 pp_instance_, promise_id, certificate_array);
374 void ContentDecryptorDelegate::CreateSession(
375 const std::string& init_data_type,
376 const uint8* init_data,
377 int init_data_length,
378 MediaKeys::SessionType session_type,
379 scoped_ptr<NewSessionCdmPromise> promise) {
380 uint32_t promise_id = SavePromise(promise.Pass());
381 PP_Var init_data_array =
382 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
383 init_data_length, init_data);
384 plugin_decryption_interface_->CreateSession(
385 pp_instance_,
386 promise_id,
387 StringVar::StringToPPVar(init_data_type),
388 init_data_array,
389 MediaSessionTypeToPpSessionType(session_type));
392 void ContentDecryptorDelegate::LoadSession(
393 const std::string& web_session_id,
394 scoped_ptr<NewSessionCdmPromise> promise) {
395 uint32_t promise_id = SavePromise(promise.Pass());
396 plugin_decryption_interface_->LoadSession(
397 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
400 void ContentDecryptorDelegate::UpdateSession(
401 const std::string& web_session_id,
402 const uint8* response,
403 int response_length,
404 scoped_ptr<SimpleCdmPromise> promise) {
405 uint32_t promise_id = SavePromise(promise.Pass());
406 PP_Var response_array =
407 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
408 response_length, response);
409 plugin_decryption_interface_->UpdateSession(
410 pp_instance_,
411 promise_id,
412 StringVar::StringToPPVar(web_session_id),
413 response_array);
416 void ContentDecryptorDelegate::CloseSession(
417 const std::string& web_session_id,
418 scoped_ptr<SimpleCdmPromise> promise) {
419 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
420 promise->reject(
421 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
422 return;
425 uint32_t promise_id = SavePromise(promise.Pass());
426 plugin_decryption_interface_->CloseSession(
427 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
430 void ContentDecryptorDelegate::RemoveSession(
431 const std::string& web_session_id,
432 scoped_ptr<SimpleCdmPromise> promise) {
433 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
434 promise->reject(
435 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
436 return;
439 uint32_t promise_id = SavePromise(promise.Pass());
440 plugin_decryption_interface_->RemoveSession(
441 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
444 void ContentDecryptorDelegate::GetUsableKeyIds(
445 const std::string& web_session_id,
446 scoped_ptr<media::KeyIdsPromise> promise) {
447 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
448 promise->reject(
449 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
450 return;
453 uint32_t promise_id = SavePromise(promise.Pass());
454 plugin_decryption_interface_->GetUsableKeyIds(
455 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
458 // TODO(xhwang): Remove duplication of code in Decrypt(),
459 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
460 bool ContentDecryptorDelegate::Decrypt(
461 Decryptor::StreamType stream_type,
462 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
463 const Decryptor::DecryptCB& decrypt_cb) {
464 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
466 // |{audio|video}_input_resource_| is not being used by the plugin
467 // now because there is only one pending audio/video decrypt request at any
468 // time. This is enforced by the media pipeline.
469 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
470 if (!MakeMediaBufferResource(
471 stream_type, encrypted_buffer, &encrypted_resource) ||
472 !encrypted_resource.get()) {
473 return false;
475 ScopedPPResource pp_resource(encrypted_resource.get());
477 const uint32_t request_id = next_decryption_request_id_++;
478 DVLOG(2) << "Decrypt() - request_id " << request_id;
480 PP_EncryptedBlockInfo block_info = {};
481 DCHECK(encrypted_buffer->decrypt_config());
482 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
483 return false;
486 // There is only one pending decrypt request at any time per stream. This is
487 // enforced by the media pipeline.
488 switch (stream_type) {
489 case Decryptor::kAudio:
490 audio_decrypt_cb_.Set(request_id, decrypt_cb);
491 break;
492 case Decryptor::kVideo:
493 video_decrypt_cb_.Set(request_id, decrypt_cb);
494 break;
495 default:
496 NOTREACHED();
497 return false;
500 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
502 plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
503 return true;
506 bool ContentDecryptorDelegate::CancelDecrypt(
507 Decryptor::StreamType stream_type) {
508 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
510 Decryptor::DecryptCB decrypt_cb;
511 switch (stream_type) {
512 case Decryptor::kAudio:
513 // Release the shared memory as it can still be in use by the plugin.
514 // The next Decrypt() call will need to allocate a new shared memory
515 // buffer.
516 audio_input_resource_ = NULL;
517 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
518 break;
519 case Decryptor::kVideo:
520 // Release the shared memory as it can still be in use by the plugin.
521 // The next Decrypt() call will need to allocate a new shared memory
522 // buffer.
523 video_input_resource_ = NULL;
524 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
525 break;
526 default:
527 NOTREACHED();
528 return false;
531 if (!decrypt_cb.is_null())
532 decrypt_cb.Run(Decryptor::kSuccess, NULL);
534 return true;
537 bool ContentDecryptorDelegate::InitializeAudioDecoder(
538 const media::AudioDecoderConfig& decoder_config,
539 const Decryptor::DecoderInitCB& init_cb) {
540 PP_AudioDecoderConfig pp_decoder_config;
541 pp_decoder_config.codec =
542 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
543 pp_decoder_config.channel_count =
544 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
545 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
546 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
547 pp_decoder_config.request_id = next_decryption_request_id_++;
549 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
550 audio_channel_count_ = pp_decoder_config.channel_count;
551 audio_channel_layout_ = decoder_config.channel_layout();
553 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
554 if (!MakeBufferResource(pp_instance_,
555 decoder_config.extra_data(),
556 decoder_config.extra_data_size(),
557 &extra_data_resource)) {
558 return false;
560 ScopedPPResource pp_resource(extra_data_resource.get());
562 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
563 plugin_decryption_interface_->InitializeAudioDecoder(
564 pp_instance_, &pp_decoder_config, pp_resource);
565 return true;
568 bool ContentDecryptorDelegate::InitializeVideoDecoder(
569 const media::VideoDecoderConfig& decoder_config,
570 const Decryptor::DecoderInitCB& init_cb) {
571 PP_VideoDecoderConfig pp_decoder_config;
572 pp_decoder_config.codec =
573 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
574 pp_decoder_config.profile =
575 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
576 pp_decoder_config.format =
577 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
578 pp_decoder_config.width = decoder_config.coded_size().width();
579 pp_decoder_config.height = decoder_config.coded_size().height();
580 pp_decoder_config.request_id = next_decryption_request_id_++;
582 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
583 if (!MakeBufferResource(pp_instance_,
584 decoder_config.extra_data(),
585 decoder_config.extra_data_size(),
586 &extra_data_resource)) {
587 return false;
589 ScopedPPResource pp_resource(extra_data_resource.get());
591 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
592 natural_size_ = decoder_config.natural_size();
594 plugin_decryption_interface_->InitializeVideoDecoder(
595 pp_instance_, &pp_decoder_config, pp_resource);
596 return true;
599 bool ContentDecryptorDelegate::DeinitializeDecoder(
600 Decryptor::StreamType stream_type) {
601 CancelDecode(stream_type);
603 if (stream_type == Decryptor::kVideo)
604 natural_size_ = gfx::Size();
606 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
607 // stream type from media stack.
608 plugin_decryption_interface_->DeinitializeDecoder(
609 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
610 return true;
613 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
614 CancelDecode(stream_type);
616 // TODO(tomfinegan): Add decoder reset request tracking.
617 plugin_decryption_interface_->ResetDecoder(
618 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
619 return true;
622 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
623 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
624 const Decryptor::AudioDecodeCB& audio_decode_cb) {
625 // |audio_input_resource_| is not being used by the plugin now
626 // because there is only one pending audio decode request at any time.
627 // This is enforced by the media pipeline.
628 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
629 if (!MakeMediaBufferResource(
630 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
631 return false;
634 // The resource should not be NULL for non-EOS buffer.
635 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
636 return false;
638 const uint32_t request_id = next_decryption_request_id_++;
639 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
641 PP_EncryptedBlockInfo block_info = {};
642 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
643 return false;
646 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
648 // There is only one pending audio decode request at any time. This is
649 // enforced by the media pipeline. If this DCHECK is violated, our buffer
650 // reuse policy is not valid, and we may have race problems for the shared
651 // buffer.
652 audio_decode_cb_.Set(request_id, audio_decode_cb);
654 ScopedPPResource pp_resource(encrypted_resource.get());
655 plugin_decryption_interface_->DecryptAndDecode(
656 pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
657 return true;
660 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
661 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
662 const Decryptor::VideoDecodeCB& video_decode_cb) {
663 // |video_input_resource_| is not being used by the plugin now
664 // because there is only one pending video decode request at any time.
665 // This is enforced by the media pipeline.
666 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
667 if (!MakeMediaBufferResource(
668 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
669 return false;
672 // The resource should not be 0 for non-EOS buffer.
673 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
674 return false;
676 const uint32_t request_id = next_decryption_request_id_++;
677 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
678 TRACE_EVENT_ASYNC_BEGIN0(
679 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
681 PP_EncryptedBlockInfo block_info = {};
682 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
683 return false;
686 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
688 // Only one pending video decode request at any time. This is enforced by the
689 // media pipeline. If this DCHECK is violated, our buffer
690 // reuse policy is not valid, and we may have race problems for the shared
691 // buffer.
692 video_decode_cb_.Set(request_id, video_decode_cb);
694 // TODO(tomfinegan): Need to get stream type from media stack.
695 ScopedPPResource pp_resource(encrypted_resource.get());
696 plugin_decryption_interface_->DecryptAndDecode(
697 pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
698 return true;
701 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
702 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
703 if (!promise ||
704 promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
705 NOTREACHED();
706 return;
709 SimpleCdmPromise* simple_promise =
710 static_cast<SimpleCdmPromise*>(promise.get());
711 simple_promise->resolve();
714 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
715 uint32 promise_id,
716 PP_Var web_session_id) {
717 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
718 if (!promise ||
719 promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) {
720 NOTREACHED();
721 return;
724 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
725 DCHECK(web_session_id_string);
727 NewSessionCdmPromise* session_promise =
728 static_cast<NewSessionCdmPromise*>(promise.get());
729 session_promise->resolve(web_session_id_string->value());
732 void ContentDecryptorDelegate::OnPromiseResolvedWithKeyIds(
733 uint32 promise_id,
734 PP_Var key_ids_array) {
735 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
737 ArrayVar* key_ids = ArrayVar::FromPPVar(key_ids_array);
738 DCHECK(key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds);
739 media::KeyIdsVector key_ids_vector;
740 if (key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds) {
741 for (size_t i = 0; i < key_ids->GetLength(); ++i) {
742 ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(key_ids->Get(i));
744 if (!array_buffer ||
745 array_buffer->ByteLength() < media::limits::kMinKeyIdLength ||
746 array_buffer->ByteLength() > media::limits::kMaxKeyIdLength) {
747 NOTREACHED();
748 continue;
751 std::vector<uint8> key_id;
752 const uint8* data = static_cast<const uint8*>(array_buffer->Map());
753 key_id.assign(data, data + array_buffer->ByteLength());
754 key_ids_vector.push_back(key_id);
758 if (!promise ||
759 promise->GetResolveParameterType() !=
760 media::CdmPromise::KEY_IDS_VECTOR_TYPE) {
761 NOTREACHED();
762 return;
765 KeyIdsPromise* key_ids_promise(static_cast<KeyIdsPromise*>(promise.get()));
766 key_ids_promise->resolve(key_ids_vector);
769 void ContentDecryptorDelegate::OnPromiseRejected(
770 uint32 promise_id,
771 PP_CdmExceptionCode exception_code,
772 uint32 system_code,
773 PP_Var error_description) {
774 ReportSystemCodeUMA(key_system_, system_code);
776 StringVar* error_description_string = StringVar::FromPPVar(error_description);
777 DCHECK(error_description_string);
779 scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
780 DCHECK(promise);
781 if (promise) {
782 promise->reject(PpExceptionTypeToMediaException(exception_code),
783 system_code,
784 error_description_string->value());
788 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
789 PP_Var message,
790 PP_Var destination_url) {
791 if (session_message_cb_.is_null())
792 return;
794 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
795 DCHECK(web_session_id_string);
797 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
798 std::vector<uint8> message_vector;
799 if (message_array_buffer) {
800 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
801 message_vector.assign(data, data + message_array_buffer->ByteLength());
804 StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
805 DCHECK(destination_url_string);
807 GURL verified_gurl = GURL(destination_url_string->value());
808 if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
809 DLOG(WARNING) << "SessionMessage default_url is invalid : "
810 << verified_gurl.possibly_invalid_spec();
811 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
814 session_message_cb_.Run(
815 web_session_id_string->value(), message_vector, verified_gurl);
818 void ContentDecryptorDelegate::OnSessionKeysChange(
819 PP_Var web_session_id,
820 PP_Bool has_additional_usable_key) {
821 if (session_keys_change_cb_.is_null())
822 return;
824 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
825 DCHECK(web_session_id_string);
827 session_keys_change_cb_.Run(web_session_id_string->value(),
828 PP_ToBool(has_additional_usable_key));
831 void ContentDecryptorDelegate::OnSessionExpirationChange(
832 PP_Var web_session_id,
833 PP_Time new_expiry_time) {
834 if (session_expiration_update_cb_.is_null())
835 return;
837 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
838 DCHECK(web_session_id_string);
840 session_expiration_update_cb_.Run(web_session_id_string->value(),
841 ppapi::PPTimeToTime(new_expiry_time));
844 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
845 if (session_ready_cb_.is_null())
846 return;
848 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
849 DCHECK(web_session_id_string);
851 session_ready_cb_.Run(web_session_id_string->value());
854 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
855 if (session_closed_cb_.is_null())
856 return;
858 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
859 DCHECK(web_session_id_string);
861 session_closed_cb_.Run(web_session_id_string->value());
864 void ContentDecryptorDelegate::OnSessionError(
865 PP_Var web_session_id,
866 PP_CdmExceptionCode exception_code,
867 uint32 system_code,
868 PP_Var error_description) {
869 ReportSystemCodeUMA(key_system_, system_code);
871 if (session_error_cb_.is_null())
872 return;
874 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
875 DCHECK(web_session_id_string);
877 StringVar* error_description_string = StringVar::FromPPVar(error_description);
878 DCHECK(error_description_string);
880 session_error_cb_.Run(web_session_id_string->value(),
881 PpExceptionTypeToMediaException(exception_code),
882 system_code,
883 error_description_string->value());
886 void ContentDecryptorDelegate::DecoderInitializeDone(
887 PP_DecryptorStreamType decoder_type,
888 uint32_t request_id,
889 PP_Bool success) {
890 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
891 // If the request ID is not valid or does not match what's saved, do
892 // nothing.
893 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
894 return;
896 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
897 } else {
898 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
899 return;
901 if (!success)
902 natural_size_ = gfx::Size();
904 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
908 void ContentDecryptorDelegate::DecoderDeinitializeDone(
909 PP_DecryptorStreamType decoder_type,
910 uint32_t request_id) {
911 // TODO(tomfinegan): Add decoder stop completion handling.
914 void ContentDecryptorDelegate::DecoderResetDone(
915 PP_DecryptorStreamType decoder_type,
916 uint32_t request_id) {
917 // TODO(tomfinegan): Add decoder reset completion handling.
920 void ContentDecryptorDelegate::DeliverBlock(
921 PP_Resource decrypted_block,
922 const PP_DecryptedBlockInfo* block_info) {
923 DCHECK(block_info);
925 FreeBuffer(block_info->tracking_info.buffer_id);
927 const uint32_t request_id = block_info->tracking_info.request_id;
928 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
930 // If the request ID is not valid or does not match what's saved, do nothing.
931 if (request_id == 0) {
932 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
933 return;
936 Decryptor::DecryptCB decrypt_cb;
937 if (audio_decrypt_cb_.Matches(request_id)) {
938 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
939 } else if (video_decrypt_cb_.Matches(request_id)) {
940 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
941 } else {
942 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
943 return;
946 Decryptor::Status status =
947 PpDecryptResultToMediaDecryptorStatus(block_info->result);
948 if (status != Decryptor::kSuccess) {
949 decrypt_cb.Run(status, NULL);
950 return;
953 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
954 if (!enter.succeeded()) {
955 decrypt_cb.Run(Decryptor::kError, NULL);
956 return;
958 BufferAutoMapper mapper(enter.object());
959 if (!mapper.data() || !mapper.size() ||
960 mapper.size() < block_info->data_size) {
961 decrypt_cb.Run(Decryptor::kError, NULL);
962 return;
965 // TODO(tomfinegan): Find a way to take ownership of the shared memory
966 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
967 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
968 media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
969 block_info->data_size));
970 decrypted_buffer->set_timestamp(
971 base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
972 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
975 // Use a non-class-member function here so that if for some reason
976 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
977 // we can still get the shared memory unmapped.
978 static void BufferNoLongerNeeded(
979 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
980 base::Closure buffer_no_longer_needed_cb) {
981 ppb_buffer->Unmap();
982 buffer_no_longer_needed_cb.Run();
985 // Enters |resource|, maps shared memory and returns pointer of mapped data.
986 // Returns NULL if any error occurs.
987 static uint8* GetMappedBuffer(PP_Resource resource,
988 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
989 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
990 if (!enter.succeeded())
991 return NULL;
993 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
994 if (!enter.object()->IsMapped() || !mapped_data)
995 return NULL;
997 uint32_t mapped_size = 0;
998 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
999 enter.object()->Unmap();
1000 return NULL;
1003 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
1005 return mapped_data;
1008 void ContentDecryptorDelegate::DeliverFrame(
1009 PP_Resource decrypted_frame,
1010 const PP_DecryptedFrameInfo* frame_info) {
1011 DCHECK(frame_info);
1013 const uint32_t request_id = frame_info->tracking_info.request_id;
1014 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
1016 // If the request ID is not valid or does not match what's saved, do nothing.
1017 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
1018 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
1019 FreeBuffer(frame_info->tracking_info.buffer_id);
1020 return;
1023 TRACE_EVENT_ASYNC_END0(
1024 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
1026 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
1028 Decryptor::Status status =
1029 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
1030 if (status != Decryptor::kSuccess) {
1031 DCHECK(!frame_info->tracking_info.buffer_id);
1032 video_decode_cb.Run(status, NULL);
1033 return;
1036 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
1037 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
1038 if (!frame_data) {
1039 FreeBuffer(frame_info->tracking_info.buffer_id);
1040 video_decode_cb.Run(Decryptor::kError, NULL);
1041 return;
1044 gfx::Size frame_size(frame_info->width, frame_info->height);
1045 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
1047 scoped_refptr<media::VideoFrame> decoded_frame =
1048 media::VideoFrame::WrapExternalYuvData(
1049 media::VideoFrame::YV12,
1050 frame_size,
1051 gfx::Rect(frame_size),
1052 natural_size_,
1053 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
1054 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
1055 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
1056 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
1057 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
1058 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
1059 base::TimeDelta::FromMicroseconds(
1060 frame_info->tracking_info.timestamp),
1061 media::BindToCurrentLoop(
1062 base::Bind(&BufferNoLongerNeeded,
1063 ppb_buffer,
1064 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
1065 weak_this_,
1066 frame_info->tracking_info.buffer_id))));
1068 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
1071 void ContentDecryptorDelegate::DeliverSamples(
1072 PP_Resource audio_frames,
1073 const PP_DecryptedSampleInfo* sample_info) {
1074 DCHECK(sample_info);
1076 FreeBuffer(sample_info->tracking_info.buffer_id);
1078 const uint32_t request_id = sample_info->tracking_info.request_id;
1079 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
1081 // If the request ID is not valid or does not match what's saved, do nothing.
1082 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
1083 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
1084 return;
1087 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
1089 const Decryptor::AudioBuffers empty_frames;
1091 Decryptor::Status status =
1092 PpDecryptResultToMediaDecryptorStatus(sample_info->result);
1093 if (status != Decryptor::kSuccess) {
1094 audio_decode_cb.Run(status, empty_frames);
1095 return;
1098 media::SampleFormat sample_format =
1099 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
1101 Decryptor::AudioBuffers audio_frame_list;
1102 if (!DeserializeAudioFrames(audio_frames,
1103 sample_info->data_size,
1104 sample_format,
1105 &audio_frame_list)) {
1106 NOTREACHED() << "CDM did not serialize the buffer correctly.";
1107 audio_decode_cb.Run(Decryptor::kError, empty_frames);
1108 return;
1111 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
1114 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
1115 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
1116 switch (stream_type) {
1117 case Decryptor::kAudio:
1118 // Release the shared memory as it can still be in use by the plugin.
1119 // The next DecryptAndDecode() call will need to allocate a new shared
1120 // memory buffer.
1121 audio_input_resource_ = NULL;
1122 if (!audio_decode_cb_.is_null())
1123 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
1124 Decryptor::AudioBuffers());
1125 break;
1126 case Decryptor::kVideo:
1127 // Release the shared memory as it can still be in use by the plugin.
1128 // The next DecryptAndDecode() call will need to allocate a new shared
1129 // memory buffer.
1130 video_input_resource_ = NULL;
1131 if (!video_decode_cb_.is_null())
1132 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
1133 break;
1134 default:
1135 NOTREACHED();
1139 bool ContentDecryptorDelegate::MakeMediaBufferResource(
1140 Decryptor::StreamType stream_type,
1141 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
1142 scoped_refptr<PPB_Buffer_Impl>* resource) {
1143 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
1145 // End of stream buffers are represented as null resources.
1146 if (encrypted_buffer->end_of_stream()) {
1147 *resource = NULL;
1148 return true;
1151 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1152 scoped_refptr<PPB_Buffer_Impl>& media_resource =
1153 (stream_type == Decryptor::kAudio) ? audio_input_resource_
1154 : video_input_resource_;
1156 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1157 if (!media_resource.get() || media_resource->size() < data_size) {
1158 // Either the buffer hasn't been created yet, or we have one that isn't big
1159 // enough to fit |size| bytes.
1161 // Media resource size starts from |kMinimumMediaBufferSize| and grows
1162 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1163 // which is usually expensive. Since input media buffers are compressed,
1164 // they are usually small (compared to outputs). The over-allocated memory
1165 // should be negligible.
1166 const uint32_t kMinimumMediaBufferSize = 1024;
1167 uint32_t media_resource_size =
1168 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1169 while (media_resource_size < data_size)
1170 media_resource_size *= 2;
1172 DVLOG(2) << "Size of media buffer for "
1173 << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1174 << " stream bumped to " << media_resource_size
1175 << " bytes to fit input.";
1176 media_resource =
1177 PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1178 if (!media_resource.get())
1179 return false;
1182 BufferAutoMapper mapper(media_resource.get());
1183 if (!mapper.data() || mapper.size() < data_size) {
1184 media_resource = NULL;
1185 return false;
1187 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1189 *resource = media_resource;
1190 return true;
1193 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1194 if (buffer_id)
1195 free_buffers_.push(buffer_id);
1198 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1199 PP_DecryptTrackingInfo* tracking_info) {
1200 DCHECK_EQ(tracking_info->buffer_id, 0u);
1202 if (free_buffers_.empty())
1203 return;
1205 tracking_info->buffer_id = free_buffers_.front();
1206 free_buffers_.pop();
1209 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1210 PP_Resource audio_frames,
1211 size_t data_size,
1212 media::SampleFormat sample_format,
1213 Decryptor::AudioBuffers* frames) {
1214 DCHECK(frames);
1215 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1216 if (!enter.succeeded())
1217 return false;
1219 BufferAutoMapper mapper(enter.object());
1220 if (!mapper.data() || !mapper.size() ||
1221 mapper.size() < static_cast<uint32_t>(data_size))
1222 return false;
1224 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1225 // the copy. Since it is possible to get multiple buffers, it would need to be
1226 // sliced and ref counted appropriately. http://crbug.com/255576.
1227 const uint8* cur = static_cast<uint8*>(mapper.data());
1228 size_t bytes_left = data_size;
1230 const int audio_bytes_per_frame =
1231 media::SampleFormatToBytesPerChannel(sample_format) *
1232 audio_channel_count_;
1233 if (audio_bytes_per_frame <= 0)
1234 return false;
1236 // Allocate space for the channel pointers given to AudioBuffer.
1237 std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1238 static_cast<const uint8*>(NULL));
1239 do {
1240 int64 timestamp = 0;
1241 int64 frame_size = -1;
1242 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1244 if (bytes_left < kHeaderSize)
1245 return false;
1247 memcpy(&timestamp, cur, sizeof(timestamp));
1248 cur += sizeof(timestamp);
1249 bytes_left -= sizeof(timestamp);
1251 memcpy(&frame_size, cur, sizeof(frame_size));
1252 cur += sizeof(frame_size);
1253 bytes_left -= sizeof(frame_size);
1255 // We should *not* have empty frames in the list.
1256 if (frame_size <= 0 ||
1257 bytes_left < base::checked_cast<size_t>(frame_size)) {
1258 return false;
1261 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1262 // one in the case of interleaved data.
1263 const int size_per_channel = frame_size / audio_channel_count_;
1264 for (int i = 0; i < audio_channel_count_; ++i)
1265 channel_ptrs[i] = cur + i * size_per_channel;
1267 const int frame_count = frame_size / audio_bytes_per_frame;
1268 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1269 sample_format,
1270 audio_channel_layout_,
1271 audio_channel_count_,
1272 audio_samples_per_second_,
1273 frame_count,
1274 &channel_ptrs[0],
1275 base::TimeDelta::FromMicroseconds(timestamp));
1276 frames->push_back(frame);
1278 cur += frame_size;
1279 bytes_left -= frame_size;
1280 } while (bytes_left > 0);
1282 return true;
1285 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1286 if (!audio_decoder_init_cb_.is_null())
1287 audio_decoder_init_cb_.ResetAndReturn().Run(false);
1289 if (!video_decoder_init_cb_.is_null())
1290 video_decoder_init_cb_.ResetAndReturn().Run(false);
1292 audio_input_resource_ = NULL;
1293 video_input_resource_ = NULL;
1295 if (!audio_decrypt_cb_.is_null())
1296 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1298 if (!video_decrypt_cb_.is_null())
1299 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1301 if (!audio_decode_cb_.is_null()) {
1302 const media::Decryptor::AudioBuffers empty_frames;
1303 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1304 empty_frames);
1307 if (!video_decode_cb_.is_null())
1308 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1310 // Reject all outstanding promises.
1311 for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
1312 ++it) {
1313 it->second->reject(
1314 media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
1316 promises_.clear();
1319 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
1320 uint32_t promise_id = next_promise_id_++;
1321 promises_.add(promise_id, promise.Pass());
1322 return promise_id;
1325 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
1326 uint32_t promise_id) {
1327 PromiseMap::iterator it = promises_.find(promise_id);
1328 if (it == promises_.end())
1329 return scoped_ptr<CdmPromise>();
1330 return promises_.take_and_erase(it);
1333 } // namespace content