Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / content_decryptor_delegate.cc
blobe8dc612953d2b1ae9ff368e67c5098775faed1f9
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/message_loop/message_loop_proxy.h"
9 #include "base/metrics/sparse_histogram.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/trace_event/trace_event.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_key_information.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/geometry/rect.h"
35 using media::Decryptor;
36 using media::MediaKeys;
37 using media::NewSessionCdmPromise;
38 using media::SimpleCdmPromise;
39 using ppapi::ArrayBufferVar;
40 using ppapi::ArrayVar;
41 using ppapi::PpapiGlobals;
42 using ppapi::ScopedPPResource;
43 using ppapi::StringVar;
44 using ppapi::thunk::EnterResourceNoLock;
45 using ppapi::thunk::PPB_Buffer_API;
47 namespace content {
49 namespace {
51 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
52 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
53 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
54 // true upon success and false if any error happened.
55 bool MakeBufferResource(PP_Instance instance,
56 const uint8* data,
57 uint32_t size,
58 scoped_refptr<PPB_Buffer_Impl>* resource) {
59 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
60 DCHECK(resource);
62 if (!data || !size) {
63 DCHECK(!data && !size);
64 resource = NULL;
65 return true;
68 scoped_refptr<PPB_Buffer_Impl> buffer(
69 PPB_Buffer_Impl::CreateResource(instance, size));
70 if (!buffer.get())
71 return false;
73 BufferAutoMapper mapper(buffer.get());
74 if (!mapper.data() || mapper.size() < size)
75 return false;
76 memcpy(mapper.data(), data, size);
78 *resource = buffer;
79 return true;
82 // Copies the content of |str| into |array|.
83 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
84 // |array_size| is smaller than the |str| length.
85 template <uint32_t array_size>
86 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
87 if (array_size < str.size())
88 return false;
90 memcpy(array, str.data(), str.size());
91 return true;
94 // Fills the |block_info| with information from |encrypted_buffer|.
96 // Returns true if |block_info| is successfully filled. Returns false
97 // otherwise.
98 bool MakeEncryptedBlockInfo(
99 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
100 uint32_t request_id,
101 PP_EncryptedBlockInfo* block_info) {
102 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
103 // anywhere else.
104 memset(block_info, 0, sizeof(*block_info));
105 block_info->tracking_info.request_id = request_id;
107 // EOS buffers need a request ID and nothing more.
108 if (encrypted_buffer->end_of_stream())
109 return true;
111 DCHECK(encrypted_buffer->data_size())
112 << "DecryptConfig is set on an empty buffer";
114 block_info->tracking_info.timestamp =
115 encrypted_buffer->timestamp().InMicroseconds();
116 block_info->data_size = encrypted_buffer->data_size();
118 const media::DecryptConfig* decrypt_config =
119 encrypted_buffer->decrypt_config();
121 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
122 !CopyStringToArray(decrypt_config->iv(), block_info->iv))
123 return false;
125 block_info->key_id_size = decrypt_config->key_id().size();
126 block_info->iv_size = decrypt_config->iv().size();
128 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
129 return false;
131 block_info->num_subsamples = decrypt_config->subsamples().size();
132 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
133 block_info->subsamples[i].clear_bytes =
134 decrypt_config->subsamples()[i].clear_bytes;
135 block_info->subsamples[i].cipher_bytes =
136 decrypt_config->subsamples()[i].cypher_bytes;
139 return true;
142 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
143 switch (codec) {
144 case media::kCodecVorbis:
145 return PP_AUDIOCODEC_VORBIS;
146 case media::kCodecAAC:
147 return PP_AUDIOCODEC_AAC;
148 default:
149 return PP_AUDIOCODEC_UNKNOWN;
153 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
154 switch (codec) {
155 case media::kCodecVP8:
156 return PP_VIDEOCODEC_VP8;
157 case media::kCodecH264:
158 return PP_VIDEOCODEC_H264;
159 case media::kCodecVP9:
160 return PP_VIDEOCODEC_VP9;
161 default:
162 return PP_VIDEOCODEC_UNKNOWN;
166 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
167 media::VideoCodecProfile profile) {
168 switch (profile) {
169 case media::VP8PROFILE_ANY:
170 case media::VP9PROFILE_ANY:
171 return PP_VIDEOCODECPROFILE_NOT_NEEDED;
172 case media::H264PROFILE_BASELINE:
173 return PP_VIDEOCODECPROFILE_H264_BASELINE;
174 case media::H264PROFILE_MAIN:
175 return PP_VIDEOCODECPROFILE_H264_MAIN;
176 case media::H264PROFILE_EXTENDED:
177 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
178 case media::H264PROFILE_HIGH:
179 return PP_VIDEOCODECPROFILE_H264_HIGH;
180 case media::H264PROFILE_HIGH10PROFILE:
181 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
182 case media::H264PROFILE_HIGH422PROFILE:
183 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
184 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
185 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
186 default:
187 return PP_VIDEOCODECPROFILE_UNKNOWN;
191 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
192 media::VideoFrame::Format format) {
193 switch (format) {
194 case media::VideoFrame::YV12:
195 return PP_DECRYPTEDFRAMEFORMAT_YV12;
196 case media::VideoFrame::I420:
197 return PP_DECRYPTEDFRAMEFORMAT_I420;
198 default:
199 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
203 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
204 PP_DecryptResult result) {
205 switch (result) {
206 case PP_DECRYPTRESULT_SUCCESS:
207 return Decryptor::kSuccess;
208 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
209 return Decryptor::kNoKey;
210 case PP_DECRYPTRESULT_NEEDMOREDATA:
211 return Decryptor::kNeedMoreData;
212 case PP_DECRYPTRESULT_DECRYPT_ERROR:
213 return Decryptor::kError;
214 case PP_DECRYPTRESULT_DECODE_ERROR:
215 return Decryptor::kError;
216 default:
217 NOTREACHED();
218 return Decryptor::kError;
222 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
223 Decryptor::StreamType stream_type) {
224 switch (stream_type) {
225 case Decryptor::kAudio:
226 return PP_DECRYPTORSTREAMTYPE_AUDIO;
227 case Decryptor::kVideo:
228 return PP_DECRYPTORSTREAMTYPE_VIDEO;
229 default:
230 NOTREACHED();
231 return PP_DECRYPTORSTREAMTYPE_VIDEO;
235 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
236 PP_DecryptedSampleFormat result) {
237 switch (result) {
238 case PP_DECRYPTEDSAMPLEFORMAT_U8:
239 return media::kSampleFormatU8;
240 case PP_DECRYPTEDSAMPLEFORMAT_S16:
241 return media::kSampleFormatS16;
242 case PP_DECRYPTEDSAMPLEFORMAT_S32:
243 return media::kSampleFormatS32;
244 case PP_DECRYPTEDSAMPLEFORMAT_F32:
245 return media::kSampleFormatF32;
246 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
247 return media::kSampleFormatPlanarS16;
248 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
249 return media::kSampleFormatPlanarF32;
250 default:
251 NOTREACHED();
252 return media::kUnknownSampleFormat;
256 PP_SessionType MediaSessionTypeToPpSessionType(
257 MediaKeys::SessionType session_type) {
258 switch (session_type) {
259 case MediaKeys::TEMPORARY_SESSION:
260 return PP_SESSIONTYPE_TEMPORARY;
261 case MediaKeys::PERSISTENT_LICENSE_SESSION:
262 return PP_SESSIONTYPE_PERSISTENT_LICENSE;
263 case MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION:
264 return PP_SESSIONTYPE_PERSISTENT_RELEASE;
265 default:
266 NOTREACHED();
267 return PP_SESSIONTYPE_TEMPORARY;
271 PP_InitDataType MediaInitDataTypeToPpInitDataType(
272 media::EmeInitDataType init_data_type) {
273 switch (init_data_type) {
274 case media::EmeInitDataType::CENC:
275 return PP_INITDATATYPE_CENC;
276 case media::EmeInitDataType::KEYIDS:
277 return PP_INITDATATYPE_KEYIDS;
278 case media::EmeInitDataType::WEBM:
279 return PP_INITDATATYPE_WEBM;
280 case media::EmeInitDataType::UNKNOWN:
281 break;
283 NOTREACHED();
284 return PP_INITDATATYPE_KEYIDS;
287 MediaKeys::Exception PpExceptionTypeToMediaException(
288 PP_CdmExceptionCode exception_code) {
289 switch (exception_code) {
290 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
291 return MediaKeys::NOT_SUPPORTED_ERROR;
292 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
293 return MediaKeys::INVALID_STATE_ERROR;
294 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
295 return MediaKeys::INVALID_ACCESS_ERROR;
296 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
297 return MediaKeys::QUOTA_EXCEEDED_ERROR;
298 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
299 return MediaKeys::UNKNOWN_ERROR;
300 case PP_CDMEXCEPTIONCODE_CLIENTERROR:
301 return MediaKeys::CLIENT_ERROR;
302 case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
303 return MediaKeys::OUTPUT_ERROR;
304 default:
305 NOTREACHED();
306 return MediaKeys::UNKNOWN_ERROR;
310 media::CdmKeyInformation::KeyStatus PpCdmKeyStatusToCdmKeyInformationKeyStatus(
311 PP_CdmKeyStatus status) {
312 switch (status) {
313 case PP_CDMKEYSTATUS_USABLE:
314 return media::CdmKeyInformation::USABLE;
315 case PP_CDMKEYSTATUS_INVALID:
316 return media::CdmKeyInformation::INTERNAL_ERROR;
317 case PP_CDMKEYSTATUS_EXPIRED:
318 return media::CdmKeyInformation::EXPIRED;
319 case PP_CDMKEYSTATUS_OUTPUTNOTALLOWED:
320 return media::CdmKeyInformation::OUTPUT_NOT_ALLOWED;
321 case PP_CDMKEYSTATUS_OUTPUTDOWNSCALED:
322 return media::CdmKeyInformation::OUTPUT_DOWNSCALED;
323 case PP_CDMKEYSTATUS_STATUSPENDING:
324 return media::CdmKeyInformation::KEY_STATUS_PENDING;
325 default:
326 NOTREACHED();
327 return media::CdmKeyInformation::INTERNAL_ERROR;
331 MediaKeys::MessageType PpCdmMessageTypeToMediaMessageType(
332 PP_CdmMessageType message_type) {
333 switch (message_type) {
334 case PP_CDMMESSAGETYPE_LICENSE_REQUEST:
335 return MediaKeys::LICENSE_REQUEST;
336 case PP_CDMMESSAGETYPE_LICENSE_RENEWAL:
337 return MediaKeys::LICENSE_RENEWAL;
338 case PP_CDMMESSAGETYPE_LICENSE_RELEASE:
339 return MediaKeys::LICENSE_RELEASE;
340 default:
341 NOTREACHED();
342 return MediaKeys::LICENSE_REQUEST;
346 // TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated.
347 // See http://crbug.com/412987 for details.
348 void ReportSystemCodeUMA(const std::string& key_system, uint32 system_code) {
349 // Sparse histogram macro does not cache the histogram, so it's safe to use
350 // macro with non-static histogram name here.
351 UMA_HISTOGRAM_SPARSE_SLOWLY(
352 "Media.EME." + media::GetKeySystemNameForUMA(key_system) + ".SystemCode",
353 system_code);
356 } // namespace
358 ContentDecryptorDelegate::ContentDecryptorDelegate(
359 PP_Instance pp_instance,
360 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
361 : pp_instance_(pp_instance),
362 plugin_decryption_interface_(plugin_decryption_interface),
363 next_decryption_request_id_(1),
364 audio_samples_per_second_(0),
365 audio_channel_count_(0),
366 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
367 weak_ptr_factory_(this) {
368 weak_this_ = weak_ptr_factory_.GetWeakPtr();
371 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
372 SatisfyAllPendingCallbacksOnError();
375 void ContentDecryptorDelegate::Initialize(
376 const std::string& key_system,
377 bool allow_distinctive_identifier,
378 bool allow_persistent_state,
379 const media::SessionMessageCB& session_message_cb,
380 const media::SessionClosedCB& session_closed_cb,
381 const media::LegacySessionErrorCB& legacy_session_error_cb,
382 const media::SessionKeysChangeCB& session_keys_change_cb,
383 const media::SessionExpirationUpdateCB& session_expiration_update_cb,
384 const base::Closure& fatal_plugin_error_cb) {
385 DCHECK(!key_system.empty());
386 DCHECK(key_system_.empty());
387 key_system_ = key_system;
389 session_message_cb_ = session_message_cb;
390 session_closed_cb_ = session_closed_cb;
391 legacy_session_error_cb_ = legacy_session_error_cb;
392 session_keys_change_cb_ = session_keys_change_cb;
393 session_expiration_update_cb_ = session_expiration_update_cb;
394 fatal_plugin_error_cb_ = fatal_plugin_error_cb;
396 plugin_decryption_interface_->Initialize(
397 pp_instance_, StringVar::StringToPPVar(key_system_),
398 PP_FromBool(allow_distinctive_identifier),
399 PP_FromBool(allow_persistent_state));
402 void ContentDecryptorDelegate::InstanceCrashed() {
403 fatal_plugin_error_cb_.Run();
404 SatisfyAllPendingCallbacksOnError();
407 void ContentDecryptorDelegate::SetServerCertificate(
408 const uint8_t* certificate,
409 uint32_t certificate_length,
410 scoped_ptr<media::SimpleCdmPromise> promise) {
411 if (!certificate ||
412 certificate_length < media::limits::kMinCertificateLength ||
413 certificate_length > media::limits::kMaxCertificateLength) {
414 promise->reject(
415 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
416 return;
419 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
420 PP_Var certificate_array =
421 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
422 certificate_length, certificate);
423 plugin_decryption_interface_->SetServerCertificate(
424 pp_instance_, promise_id, certificate_array);
427 void ContentDecryptorDelegate::CreateSessionAndGenerateRequest(
428 MediaKeys::SessionType session_type,
429 media::EmeInitDataType init_data_type,
430 const uint8* init_data,
431 int init_data_length,
432 scoped_ptr<NewSessionCdmPromise> promise) {
433 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
434 PP_Var init_data_array =
435 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
436 init_data_length, init_data);
437 plugin_decryption_interface_->CreateSessionAndGenerateRequest(
438 pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
439 MediaInitDataTypeToPpInitDataType(init_data_type), init_data_array);
442 void ContentDecryptorDelegate::LoadSession(
443 media::MediaKeys::SessionType session_type,
444 const std::string& session_id,
445 scoped_ptr<NewSessionCdmPromise> promise) {
446 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
447 plugin_decryption_interface_->LoadSession(
448 pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
449 StringVar::StringToPPVar(session_id));
452 void ContentDecryptorDelegate::UpdateSession(
453 const std::string& session_id,
454 const uint8* response,
455 int response_length,
456 scoped_ptr<SimpleCdmPromise> promise) {
457 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
458 PP_Var response_array =
459 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
460 response_length, response);
461 plugin_decryption_interface_->UpdateSession(
462 pp_instance_, promise_id, StringVar::StringToPPVar(session_id),
463 response_array);
466 void ContentDecryptorDelegate::CloseSession(
467 const std::string& session_id,
468 scoped_ptr<SimpleCdmPromise> promise) {
469 if (session_id.length() > media::limits::kMaxSessionIdLength) {
470 promise->reject(
471 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
472 return;
475 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
476 plugin_decryption_interface_->CloseSession(
477 pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
480 void ContentDecryptorDelegate::RemoveSession(
481 const std::string& session_id,
482 scoped_ptr<SimpleCdmPromise> promise) {
483 if (session_id.length() > media::limits::kMaxSessionIdLength) {
484 promise->reject(
485 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
486 return;
489 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
490 plugin_decryption_interface_->RemoveSession(
491 pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
494 // TODO(xhwang): Remove duplication of code in Decrypt(),
495 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
496 bool ContentDecryptorDelegate::Decrypt(
497 Decryptor::StreamType stream_type,
498 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
499 const Decryptor::DecryptCB& decrypt_cb) {
500 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
502 // |{audio|video}_input_resource_| is not being used by the plugin
503 // now because there is only one pending audio/video decrypt request at any
504 // time. This is enforced by the media pipeline.
505 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
506 if (!MakeMediaBufferResource(
507 stream_type, encrypted_buffer, &encrypted_resource) ||
508 !encrypted_resource.get()) {
509 return false;
511 ScopedPPResource pp_resource(encrypted_resource.get());
513 const uint32_t request_id = next_decryption_request_id_++;
514 DVLOG(2) << "Decrypt() - request_id " << request_id;
516 PP_EncryptedBlockInfo block_info = {};
517 DCHECK(encrypted_buffer->decrypt_config());
518 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
519 return false;
522 // There is only one pending decrypt request at any time per stream. This is
523 // enforced by the media pipeline.
524 switch (stream_type) {
525 case Decryptor::kAudio:
526 audio_decrypt_cb_.Set(request_id, decrypt_cb);
527 break;
528 case Decryptor::kVideo:
529 video_decrypt_cb_.Set(request_id, decrypt_cb);
530 break;
531 default:
532 NOTREACHED();
533 return false;
536 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
538 plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
539 return true;
542 bool ContentDecryptorDelegate::CancelDecrypt(
543 Decryptor::StreamType stream_type) {
544 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
546 Decryptor::DecryptCB decrypt_cb;
547 switch (stream_type) {
548 case Decryptor::kAudio:
549 // Release the shared memory as it can still be in use by the plugin.
550 // The next Decrypt() call will need to allocate a new shared memory
551 // buffer.
552 audio_input_resource_ = NULL;
553 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
554 break;
555 case Decryptor::kVideo:
556 // Release the shared memory as it can still be in use by the plugin.
557 // The next Decrypt() call will need to allocate a new shared memory
558 // buffer.
559 video_input_resource_ = NULL;
560 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
561 break;
562 default:
563 NOTREACHED();
564 return false;
567 if (!decrypt_cb.is_null())
568 decrypt_cb.Run(Decryptor::kSuccess, NULL);
570 return true;
573 bool ContentDecryptorDelegate::InitializeAudioDecoder(
574 const media::AudioDecoderConfig& decoder_config,
575 const Decryptor::DecoderInitCB& init_cb) {
576 PP_AudioDecoderConfig pp_decoder_config;
577 pp_decoder_config.codec =
578 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
579 pp_decoder_config.channel_count =
580 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
581 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
582 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
583 pp_decoder_config.request_id = next_decryption_request_id_++;
585 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
586 audio_channel_count_ = pp_decoder_config.channel_count;
587 audio_channel_layout_ = decoder_config.channel_layout();
589 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
590 if (!MakeBufferResource(pp_instance_,
591 decoder_config.extra_data(),
592 decoder_config.extra_data_size(),
593 &extra_data_resource)) {
594 return false;
596 ScopedPPResource pp_resource(extra_data_resource.get());
598 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
599 plugin_decryption_interface_->InitializeAudioDecoder(
600 pp_instance_, &pp_decoder_config, pp_resource);
601 return true;
604 bool ContentDecryptorDelegate::InitializeVideoDecoder(
605 const media::VideoDecoderConfig& decoder_config,
606 const Decryptor::DecoderInitCB& init_cb) {
607 PP_VideoDecoderConfig pp_decoder_config;
608 pp_decoder_config.codec =
609 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
610 pp_decoder_config.profile =
611 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
612 pp_decoder_config.format =
613 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
614 pp_decoder_config.width = decoder_config.coded_size().width();
615 pp_decoder_config.height = decoder_config.coded_size().height();
616 pp_decoder_config.request_id = next_decryption_request_id_++;
618 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
619 if (!MakeBufferResource(pp_instance_,
620 decoder_config.extra_data(),
621 decoder_config.extra_data_size(),
622 &extra_data_resource)) {
623 return false;
625 ScopedPPResource pp_resource(extra_data_resource.get());
627 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
628 natural_size_ = decoder_config.natural_size();
630 plugin_decryption_interface_->InitializeVideoDecoder(
631 pp_instance_, &pp_decoder_config, pp_resource);
632 return true;
635 bool ContentDecryptorDelegate::DeinitializeDecoder(
636 Decryptor::StreamType stream_type) {
637 CancelDecode(stream_type);
639 if (stream_type == Decryptor::kVideo)
640 natural_size_ = gfx::Size();
642 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
643 // stream type from media stack.
644 plugin_decryption_interface_->DeinitializeDecoder(
645 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
646 return true;
649 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
650 CancelDecode(stream_type);
652 // TODO(tomfinegan): Add decoder reset request tracking.
653 plugin_decryption_interface_->ResetDecoder(
654 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
655 return true;
658 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
659 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
660 const Decryptor::AudioDecodeCB& audio_decode_cb) {
661 // |audio_input_resource_| is not being used by the plugin now
662 // because there is only one pending audio decode request at any time.
663 // This is enforced by the media pipeline.
664 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
665 if (!MakeMediaBufferResource(
666 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
667 return false;
670 // The resource should not be NULL for non-EOS buffer.
671 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
672 return false;
674 const uint32_t request_id = next_decryption_request_id_++;
675 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
677 PP_EncryptedBlockInfo block_info = {};
678 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
679 return false;
682 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
684 // There is only one pending audio decode request at any time. This is
685 // enforced by the media pipeline. If this DCHECK is violated, our buffer
686 // reuse policy is not valid, and we may have race problems for the shared
687 // buffer.
688 audio_decode_cb_.Set(request_id, audio_decode_cb);
690 ScopedPPResource pp_resource(encrypted_resource.get());
691 plugin_decryption_interface_->DecryptAndDecode(
692 pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
693 return true;
696 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
697 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
698 const Decryptor::VideoDecodeCB& video_decode_cb) {
699 // |video_input_resource_| is not being used by the plugin now
700 // because there is only one pending video decode request at any time.
701 // This is enforced by the media pipeline.
702 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
703 if (!MakeMediaBufferResource(
704 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
705 return false;
708 // The resource should not be 0 for non-EOS buffer.
709 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
710 return false;
712 const uint32_t request_id = next_decryption_request_id_++;
713 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
714 TRACE_EVENT_ASYNC_BEGIN0(
715 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
717 PP_EncryptedBlockInfo block_info = {};
718 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
719 return false;
722 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
724 // Only one pending video decode request at any time. This is enforced by the
725 // media pipeline. If this DCHECK is violated, our buffer
726 // reuse policy is not valid, and we may have race problems for the shared
727 // buffer.
728 video_decode_cb_.Set(request_id, video_decode_cb);
730 // TODO(tomfinegan): Need to get stream type from media stack.
731 ScopedPPResource pp_resource(encrypted_resource.get());
732 plugin_decryption_interface_->DecryptAndDecode(
733 pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
734 return true;
737 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
738 cdm_promise_adapter_.ResolvePromise(promise_id);
741 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(uint32 promise_id,
742 PP_Var session_id) {
743 StringVar* session_id_string = StringVar::FromPPVar(session_id);
744 DCHECK(session_id_string);
745 cdm_promise_adapter_.ResolvePromise(promise_id, session_id_string->value());
748 void ContentDecryptorDelegate::OnPromiseRejected(
749 uint32 promise_id,
750 PP_CdmExceptionCode exception_code,
751 uint32 system_code,
752 PP_Var error_description) {
753 ReportSystemCodeUMA(key_system_, system_code);
755 StringVar* error_description_string = StringVar::FromPPVar(error_description);
756 DCHECK(error_description_string);
757 cdm_promise_adapter_.RejectPromise(
758 promise_id, PpExceptionTypeToMediaException(exception_code), system_code,
759 error_description_string->value());
762 void ContentDecryptorDelegate::OnSessionMessage(PP_Var session_id,
763 PP_CdmMessageType message_type,
764 PP_Var message,
765 PP_Var legacy_destination_url) {
766 if (session_message_cb_.is_null())
767 return;
769 StringVar* session_id_string = StringVar::FromPPVar(session_id);
770 DCHECK(session_id_string);
772 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
773 std::vector<uint8> message_vector;
774 if (message_array_buffer) {
775 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
776 message_vector.assign(data, data + message_array_buffer->ByteLength());
779 StringVar* destination_url_string =
780 StringVar::FromPPVar(legacy_destination_url);
781 if (!destination_url_string) {
782 NOTREACHED();
783 return;
786 GURL verified_gurl = GURL(destination_url_string->value());
787 if (!verified_gurl.is_valid()) {
788 DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
789 << verified_gurl.possibly_invalid_spec();
790 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
793 session_message_cb_.Run(session_id_string->value(),
794 PpCdmMessageTypeToMediaMessageType(message_type),
795 message_vector, verified_gurl);
798 void ContentDecryptorDelegate::OnSessionKeysChange(
799 PP_Var session_id,
800 PP_Bool has_additional_usable_key,
801 uint32_t key_count,
802 const struct PP_KeyInformation key_information[]) {
803 if (session_keys_change_cb_.is_null())
804 return;
806 StringVar* session_id_string = StringVar::FromPPVar(session_id);
807 DCHECK(session_id_string);
809 media::CdmKeysInfo keys_info;
810 keys_info.reserve(key_count);
811 for (uint32_t i = 0; i < key_count; ++i) {
812 scoped_ptr<media::CdmKeyInformation> key_info(new media::CdmKeyInformation);
813 const auto& info = key_information[i];
814 key_info->key_id.assign(info.key_id, info.key_id + info.key_id_size);
815 key_info->status =
816 PpCdmKeyStatusToCdmKeyInformationKeyStatus(info.key_status);
817 key_info->system_code = info.system_code;
818 keys_info.push_back(key_info.release());
821 session_keys_change_cb_.Run(session_id_string->value(),
822 PP_ToBool(has_additional_usable_key),
823 keys_info.Pass());
826 void ContentDecryptorDelegate::OnSessionExpirationChange(
827 PP_Var session_id,
828 PP_Time new_expiry_time) {
829 if (session_expiration_update_cb_.is_null())
830 return;
832 StringVar* session_id_string = StringVar::FromPPVar(session_id);
833 DCHECK(session_id_string);
835 session_expiration_update_cb_.Run(session_id_string->value(),
836 ppapi::PPTimeToTime(new_expiry_time));
839 void ContentDecryptorDelegate::OnSessionClosed(PP_Var session_id) {
840 if (session_closed_cb_.is_null())
841 return;
843 StringVar* session_id_string = StringVar::FromPPVar(session_id);
844 DCHECK(session_id_string);
846 session_closed_cb_.Run(session_id_string->value());
849 void ContentDecryptorDelegate::OnLegacySessionError(
850 PP_Var session_id,
851 PP_CdmExceptionCode exception_code,
852 uint32 system_code,
853 PP_Var error_description) {
854 ReportSystemCodeUMA(key_system_, system_code);
856 if (legacy_session_error_cb_.is_null())
857 return;
859 StringVar* session_id_string = StringVar::FromPPVar(session_id);
860 DCHECK(session_id_string);
862 StringVar* error_description_string = StringVar::FromPPVar(error_description);
863 DCHECK(error_description_string);
865 legacy_session_error_cb_.Run(session_id_string->value(),
866 PpExceptionTypeToMediaException(exception_code),
867 system_code, error_description_string->value());
870 void ContentDecryptorDelegate::DecoderInitializeDone(
871 PP_DecryptorStreamType decoder_type,
872 uint32_t request_id,
873 PP_Bool success) {
874 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
875 // If the request ID is not valid or does not match what's saved, do
876 // nothing.
877 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
878 return;
880 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
881 } else {
882 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
883 return;
885 if (!success)
886 natural_size_ = gfx::Size();
888 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
892 void ContentDecryptorDelegate::DecoderDeinitializeDone(
893 PP_DecryptorStreamType decoder_type,
894 uint32_t request_id) {
895 // TODO(tomfinegan): Add decoder stop completion handling.
898 void ContentDecryptorDelegate::DecoderResetDone(
899 PP_DecryptorStreamType decoder_type,
900 uint32_t request_id) {
901 // TODO(tomfinegan): Add decoder reset completion handling.
904 void ContentDecryptorDelegate::DeliverBlock(
905 PP_Resource decrypted_block,
906 const PP_DecryptedBlockInfo* block_info) {
907 DCHECK(block_info);
909 FreeBuffer(block_info->tracking_info.buffer_id);
911 const uint32_t request_id = block_info->tracking_info.request_id;
912 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
914 // If the request ID is not valid or does not match what's saved, do nothing.
915 if (request_id == 0) {
916 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
917 return;
920 Decryptor::DecryptCB decrypt_cb;
921 if (audio_decrypt_cb_.Matches(request_id)) {
922 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
923 } else if (video_decrypt_cb_.Matches(request_id)) {
924 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
925 } else {
926 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
927 return;
930 Decryptor::Status status =
931 PpDecryptResultToMediaDecryptorStatus(block_info->result);
932 if (status != Decryptor::kSuccess) {
933 decrypt_cb.Run(status, NULL);
934 return;
937 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
938 if (!enter.succeeded()) {
939 decrypt_cb.Run(Decryptor::kError, NULL);
940 return;
942 BufferAutoMapper mapper(enter.object());
943 if (!mapper.data() || !mapper.size() ||
944 mapper.size() < block_info->data_size) {
945 decrypt_cb.Run(Decryptor::kError, NULL);
946 return;
949 // TODO(tomfinegan): Find a way to take ownership of the shared memory
950 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
951 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
952 media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
953 block_info->data_size));
954 decrypted_buffer->set_timestamp(
955 base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
956 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
959 // Use a non-class-member function here so that if for some reason
960 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
961 // we can still get the shared memory unmapped.
962 static void BufferNoLongerNeeded(
963 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
964 base::Closure buffer_no_longer_needed_cb) {
965 ppb_buffer->Unmap();
966 buffer_no_longer_needed_cb.Run();
969 // Enters |resource|, maps shared memory and returns pointer of mapped data.
970 // Returns NULL if any error occurs.
971 static uint8* GetMappedBuffer(PP_Resource resource,
972 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
973 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
974 if (!enter.succeeded())
975 return NULL;
977 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
978 if (!enter.object()->IsMapped() || !mapped_data)
979 return NULL;
981 uint32_t mapped_size = 0;
982 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
983 enter.object()->Unmap();
984 return NULL;
987 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
989 return mapped_data;
992 void ContentDecryptorDelegate::DeliverFrame(
993 PP_Resource decrypted_frame,
994 const PP_DecryptedFrameInfo* frame_info) {
995 DCHECK(frame_info);
997 const uint32_t request_id = frame_info->tracking_info.request_id;
998 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
1000 // If the request ID is not valid or does not match what's saved, do nothing.
1001 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
1002 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
1003 FreeBuffer(frame_info->tracking_info.buffer_id);
1004 return;
1007 TRACE_EVENT_ASYNC_END0(
1008 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
1010 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
1012 Decryptor::Status status =
1013 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
1014 if (status != Decryptor::kSuccess) {
1015 DCHECK(!frame_info->tracking_info.buffer_id);
1016 video_decode_cb.Run(status, NULL);
1017 return;
1020 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
1021 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
1022 if (!frame_data) {
1023 FreeBuffer(frame_info->tracking_info.buffer_id);
1024 video_decode_cb.Run(Decryptor::kError, NULL);
1025 return;
1028 gfx::Size frame_size(frame_info->width, frame_info->height);
1029 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
1031 scoped_refptr<media::VideoFrame> decoded_frame =
1032 media::VideoFrame::WrapExternalYuvData(
1033 media::VideoFrame::YV12,
1034 frame_size,
1035 gfx::Rect(frame_size),
1036 natural_size_,
1037 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
1038 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
1039 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
1040 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
1041 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
1042 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
1043 base::TimeDelta::FromMicroseconds(
1044 frame_info->tracking_info.timestamp),
1045 media::BindToCurrentLoop(
1046 base::Bind(&BufferNoLongerNeeded,
1047 ppb_buffer,
1048 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
1049 weak_this_,
1050 frame_info->tracking_info.buffer_id))));
1052 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
1055 void ContentDecryptorDelegate::DeliverSamples(
1056 PP_Resource audio_frames,
1057 const PP_DecryptedSampleInfo* sample_info) {
1058 DCHECK(sample_info);
1060 FreeBuffer(sample_info->tracking_info.buffer_id);
1062 const uint32_t request_id = sample_info->tracking_info.request_id;
1063 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
1065 // If the request ID is not valid or does not match what's saved, do nothing.
1066 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
1067 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
1068 return;
1071 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
1073 const Decryptor::AudioFrames empty_frames;
1075 Decryptor::Status status =
1076 PpDecryptResultToMediaDecryptorStatus(sample_info->result);
1077 if (status != Decryptor::kSuccess) {
1078 audio_decode_cb.Run(status, empty_frames);
1079 return;
1082 media::SampleFormat sample_format =
1083 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
1085 Decryptor::AudioFrames audio_frame_list;
1086 if (!DeserializeAudioFrames(audio_frames,
1087 sample_info->data_size,
1088 sample_format,
1089 &audio_frame_list)) {
1090 NOTREACHED() << "CDM did not serialize the buffer correctly.";
1091 audio_decode_cb.Run(Decryptor::kError, empty_frames);
1092 return;
1095 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
1098 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
1099 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
1100 switch (stream_type) {
1101 case Decryptor::kAudio:
1102 // Release the shared memory as it can still be in use by the plugin.
1103 // The next DecryptAndDecode() call will need to allocate a new shared
1104 // memory buffer.
1105 audio_input_resource_ = NULL;
1106 if (!audio_decode_cb_.is_null())
1107 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
1108 Decryptor::AudioFrames());
1109 break;
1110 case Decryptor::kVideo:
1111 // Release the shared memory as it can still be in use by the plugin.
1112 // The next DecryptAndDecode() call will need to allocate a new shared
1113 // memory buffer.
1114 video_input_resource_ = NULL;
1115 if (!video_decode_cb_.is_null())
1116 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
1117 break;
1118 default:
1119 NOTREACHED();
1123 bool ContentDecryptorDelegate::MakeMediaBufferResource(
1124 Decryptor::StreamType stream_type,
1125 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
1126 scoped_refptr<PPB_Buffer_Impl>* resource) {
1127 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
1129 // End of stream buffers are represented as null resources.
1130 if (encrypted_buffer->end_of_stream()) {
1131 *resource = NULL;
1132 return true;
1135 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1136 scoped_refptr<PPB_Buffer_Impl>& media_resource =
1137 (stream_type == Decryptor::kAudio) ? audio_input_resource_
1138 : video_input_resource_;
1140 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1141 if (!media_resource.get() || media_resource->size() < data_size) {
1142 // Either the buffer hasn't been created yet, or we have one that isn't big
1143 // enough to fit |size| bytes.
1145 // Media resource size starts from |kMinimumMediaBufferSize| and grows
1146 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1147 // which is usually expensive. Since input media buffers are compressed,
1148 // they are usually small (compared to outputs). The over-allocated memory
1149 // should be negligible.
1150 const uint32_t kMinimumMediaBufferSize = 1024;
1151 uint32_t media_resource_size =
1152 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1153 while (media_resource_size < data_size)
1154 media_resource_size *= 2;
1156 DVLOG(2) << "Size of media buffer for "
1157 << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1158 << " stream bumped to " << media_resource_size
1159 << " bytes to fit input.";
1160 media_resource =
1161 PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1162 if (!media_resource.get())
1163 return false;
1166 BufferAutoMapper mapper(media_resource.get());
1167 if (!mapper.data() || mapper.size() < data_size) {
1168 media_resource = NULL;
1169 return false;
1171 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1173 *resource = media_resource;
1174 return true;
1177 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1178 if (buffer_id)
1179 free_buffers_.push(buffer_id);
1182 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1183 PP_DecryptTrackingInfo* tracking_info) {
1184 DCHECK_EQ(tracking_info->buffer_id, 0u);
1186 if (free_buffers_.empty())
1187 return;
1189 tracking_info->buffer_id = free_buffers_.front();
1190 free_buffers_.pop();
1193 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1194 PP_Resource audio_frames,
1195 size_t data_size,
1196 media::SampleFormat sample_format,
1197 Decryptor::AudioFrames* frames) {
1198 DCHECK(frames);
1199 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1200 if (!enter.succeeded())
1201 return false;
1203 BufferAutoMapper mapper(enter.object());
1204 if (!mapper.data() || !mapper.size() ||
1205 mapper.size() < static_cast<uint32_t>(data_size))
1206 return false;
1208 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1209 // the copy. Since it is possible to get multiple buffers, it would need to be
1210 // sliced and ref counted appropriately. http://crbug.com/255576.
1211 const uint8* cur = static_cast<uint8*>(mapper.data());
1212 size_t bytes_left = data_size;
1214 const int audio_bytes_per_frame =
1215 media::SampleFormatToBytesPerChannel(sample_format) *
1216 audio_channel_count_;
1217 if (audio_bytes_per_frame <= 0)
1218 return false;
1220 // Allocate space for the channel pointers given to AudioBuffer.
1221 std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1222 static_cast<const uint8*>(NULL));
1223 do {
1224 int64 timestamp = 0;
1225 int64 frame_size = -1;
1226 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1228 if (bytes_left < kHeaderSize)
1229 return false;
1231 memcpy(&timestamp, cur, sizeof(timestamp));
1232 cur += sizeof(timestamp);
1233 bytes_left -= sizeof(timestamp);
1235 memcpy(&frame_size, cur, sizeof(frame_size));
1236 cur += sizeof(frame_size);
1237 bytes_left -= sizeof(frame_size);
1239 // We should *not* have empty frames in the list.
1240 if (frame_size <= 0 ||
1241 bytes_left < base::checked_cast<size_t>(frame_size)) {
1242 return false;
1245 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1246 // one in the case of interleaved data.
1247 const int size_per_channel = frame_size / audio_channel_count_;
1248 for (int i = 0; i < audio_channel_count_; ++i)
1249 channel_ptrs[i] = cur + i * size_per_channel;
1251 const int frame_count = frame_size / audio_bytes_per_frame;
1252 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1253 sample_format,
1254 audio_channel_layout_,
1255 audio_channel_count_,
1256 audio_samples_per_second_,
1257 frame_count,
1258 &channel_ptrs[0],
1259 base::TimeDelta::FromMicroseconds(timestamp));
1260 frames->push_back(frame);
1262 cur += frame_size;
1263 bytes_left -= frame_size;
1264 } while (bytes_left > 0);
1266 return true;
1269 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1270 if (!audio_decoder_init_cb_.is_null())
1271 audio_decoder_init_cb_.ResetAndReturn().Run(false);
1273 if (!video_decoder_init_cb_.is_null())
1274 video_decoder_init_cb_.ResetAndReturn().Run(false);
1276 audio_input_resource_ = NULL;
1277 video_input_resource_ = NULL;
1279 if (!audio_decrypt_cb_.is_null())
1280 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1282 if (!video_decrypt_cb_.is_null())
1283 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1285 if (!audio_decode_cb_.is_null()) {
1286 const media::Decryptor::AudioFrames empty_frames;
1287 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1288 empty_frames);
1291 if (!video_decode_cb_.is_null())
1292 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1294 cdm_promise_adapter_.Clear();
1297 } // namespace content