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
;
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
,
60 scoped_refptr
<PPB_Buffer_Impl
>* resource
) {
61 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
65 DCHECK(!data
&& !size
);
70 scoped_refptr
<PPB_Buffer_Impl
> buffer(
71 PPB_Buffer_Impl::CreateResource(instance
, size
));
75 BufferAutoMapper
mapper(buffer
.get());
76 if (!mapper
.data() || mapper
.size() < size
)
78 memcpy(mapper
.data(), data
, size
);
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())
92 memcpy(array
, str
.data(), str
.size());
96 // Fills the |block_info| with information from |encrypted_buffer|.
98 // Returns true if |block_info| is successfully filled. Returns false
100 bool MakeEncryptedBlockInfo(
101 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
103 PP_EncryptedBlockInfo
* block_info
) {
104 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
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())
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
))
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
))
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
;
144 PP_AudioCodec
MediaAudioCodecToPpAudioCodec(media::AudioCodec codec
) {
146 case media::kCodecVorbis
:
147 return PP_AUDIOCODEC_VORBIS
;
148 case media::kCodecAAC
:
149 return PP_AUDIOCODEC_AAC
;
151 return PP_AUDIOCODEC_UNKNOWN
;
155 PP_VideoCodec
MediaVideoCodecToPpVideoCodec(media::VideoCodec 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
;
164 return PP_VIDEOCODEC_UNKNOWN
;
168 PP_VideoCodecProfile
MediaVideoCodecProfileToPpVideoCodecProfile(
169 media::VideoCodecProfile 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
;
189 return PP_VIDEOCODECPROFILE_UNKNOWN
;
193 PP_DecryptedFrameFormat
MediaVideoFormatToPpDecryptedFrameFormat(
194 media::VideoFrame::Format format
) {
196 case media::VideoFrame::YV12
:
197 return PP_DECRYPTEDFRAMEFORMAT_YV12
;
198 case media::VideoFrame::I420
:
199 return PP_DECRYPTEDFRAMEFORMAT_I420
;
201 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN
;
205 Decryptor::Status
PpDecryptResultToMediaDecryptorStatus(
206 PP_DecryptResult 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
;
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
;
233 return PP_DECRYPTORSTREAMTYPE_VIDEO
;
237 media::SampleFormat
PpDecryptedSampleFormatToMediaSampleFormat(
238 PP_DecryptedSampleFormat 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
;
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
;
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
;
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",
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
),
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
) {
359 certificate_length
< media::limits::kMinCertificateLength
||
360 certificate_length
> media::limits::kMaxCertificateLength
) {
362 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect certificate.");
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(
387 StringVar::StringToPPVar(init_data_type
),
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
,
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(
412 StringVar::StringToPPVar(web_session_id
),
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
) {
421 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect session.");
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
) {
435 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect session.");
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
) {
449 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect session.");
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()) {
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
)) {
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
);
492 case Decryptor::kVideo
:
493 video_decrypt_cb_
.Set(request_id
, decrypt_cb
);
500 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
502 plugin_decryption_interface_
->Decrypt(pp_instance_
, pp_resource
, &block_info
);
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
516 audio_input_resource_
= NULL
;
517 decrypt_cb
= audio_decrypt_cb_
.ResetAndReturn();
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
523 video_input_resource_
= NULL
;
524 decrypt_cb
= video_decrypt_cb_
.ResetAndReturn();
531 if (!decrypt_cb
.is_null())
532 decrypt_cb
.Run(Decryptor::kSuccess
, NULL
);
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
)) {
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
);
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
)) {
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
);
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);
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);
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
)) {
634 // The resource should not be NULL for non-EOS buffer.
635 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
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
)) {
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
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
);
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
)) {
672 // The resource should not be 0 for non-EOS buffer.
673 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
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
)) {
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
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
);
701 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id
) {
702 scoped_ptr
<CdmPromise
> promise
= TakePromise(promise_id
);
704 promise
->GetResolveParameterType() != media::CdmPromise::VOID_TYPE
) {
709 SimpleCdmPromise
* simple_promise
=
710 static_cast<SimpleCdmPromise
*>(promise
.get());
711 simple_promise
->resolve();
714 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
716 PP_Var web_session_id
) {
717 scoped_ptr
<CdmPromise
> promise
= TakePromise(promise_id
);
719 promise
->GetResolveParameterType() != media::CdmPromise::STRING_TYPE
) {
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(
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
));
745 array_buffer
->ByteLength() < media::limits::kMinKeyIdLength
||
746 array_buffer
->ByteLength() > media::limits::kMaxKeyIdLength
) {
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
);
759 promise
->GetResolveParameterType() !=
760 media::CdmPromise::KEY_IDS_VECTOR_TYPE
) {
765 KeyIdsPromise
* key_ids_promise(static_cast<KeyIdsPromise
*>(promise
.get()));
766 key_ids_promise
->resolve(key_ids_vector
);
769 void ContentDecryptorDelegate::OnPromiseRejected(
771 PP_CdmExceptionCode exception_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
);
782 promise
->reject(PpExceptionTypeToMediaException(exception_code
),
784 error_description_string
->value());
788 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id
,
790 PP_Var destination_url
) {
791 if (session_message_cb_
.is_null())
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())
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())
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())
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())
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
,
868 PP_Var error_description
) {
869 ReportSystemCodeUMA(key_system_
, system_code
);
871 if (session_error_cb_
.is_null())
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
),
883 error_description_string
->value());
886 void ContentDecryptorDelegate::DecoderInitializeDone(
887 PP_DecryptorStreamType decoder_type
,
890 if (decoder_type
== PP_DECRYPTORSTREAMTYPE_AUDIO
) {
891 // If the request ID is not valid or does not match what's saved, do
893 if (request_id
== 0 || !audio_decoder_init_cb_
.Matches(request_id
))
896 audio_decoder_init_cb_
.ResetAndReturn().Run(PP_ToBool(success
));
898 if (request_id
== 0 || !video_decoder_init_cb_
.Matches(request_id
))
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
) {
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
;
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();
942 DVLOG(1) << "DeliverBlock() - request_id " << request_id
<< " not found";
946 Decryptor::Status status
=
947 PpDecryptResultToMediaDecryptorStatus(block_info
->result
);
948 if (status
!= Decryptor::kSuccess
) {
949 decrypt_cb
.Run(status
, NULL
);
953 EnterResourceNoLock
<PPB_Buffer_API
> enter(decrypted_block
, true);
954 if (!enter
.succeeded()) {
955 decrypt_cb
.Run(Decryptor::kError
, NULL
);
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
);
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
) {
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())
993 uint8
* mapped_data
= static_cast<uint8
*>(enter
.object()->Map());
994 if (!enter
.object()->IsMapped() || !mapped_data
)
997 uint32_t mapped_size
= 0;
998 if (!enter
.object()->Describe(&mapped_size
) || !mapped_size
) {
999 enter
.object()->Unmap();
1003 *ppb_buffer
= static_cast<PPB_Buffer_Impl
*>(enter
.object());
1008 void ContentDecryptorDelegate::DeliverFrame(
1009 PP_Resource decrypted_frame
,
1010 const PP_DecryptedFrameInfo
* 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
);
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
);
1036 scoped_refptr
<PPB_Buffer_Impl
> ppb_buffer
;
1037 uint8
* frame_data
= GetMappedBuffer(decrypted_frame
, &ppb_buffer
);
1039 FreeBuffer(frame_info
->tracking_info
.buffer_id
);
1040 video_decode_cb
.Run(Decryptor::kError
, NULL
);
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
,
1051 gfx::Rect(frame_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
,
1064 base::Bind(&ContentDecryptorDelegate::FreeBuffer
,
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";
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
);
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
,
1105 &audio_frame_list
)) {
1106 NOTREACHED() << "CDM did not serialize the buffer correctly.";
1107 audio_decode_cb
.Run(Decryptor::kError
, empty_frames
);
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
1121 audio_input_resource_
= NULL
;
1122 if (!audio_decode_cb_
.is_null())
1123 audio_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
,
1124 Decryptor::AudioBuffers());
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
1130 video_input_resource_
= NULL
;
1131 if (!video_decode_cb_
.is_null())
1132 video_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
, NULL
);
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()) {
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.";
1177 PPB_Buffer_Impl::CreateResource(pp_instance_
, media_resource_size
);
1178 if (!media_resource
.get())
1182 BufferAutoMapper
mapper(media_resource
.get());
1183 if (!mapper
.data() || mapper
.size() < data_size
) {
1184 media_resource
= NULL
;
1187 memcpy(mapper
.data(), encrypted_buffer
->data(), data_size
);
1189 *resource
= media_resource
;
1193 void ContentDecryptorDelegate::FreeBuffer(uint32_t 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())
1205 tracking_info
->buffer_id
= free_buffers_
.front();
1206 free_buffers_
.pop();
1209 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1210 PP_Resource audio_frames
,
1212 media::SampleFormat sample_format
,
1213 Decryptor::AudioBuffers
* frames
) {
1215 EnterResourceNoLock
<PPB_Buffer_API
> enter(audio_frames
, true);
1216 if (!enter
.succeeded())
1219 BufferAutoMapper
mapper(enter
.object());
1220 if (!mapper
.data() || !mapper
.size() ||
1221 mapper
.size() < static_cast<uint32_t>(data_size
))
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)
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
));
1240 int64 timestamp
= 0;
1241 int64 frame_size
= -1;
1242 const size_t kHeaderSize
= sizeof(timestamp
) + sizeof(frame_size
);
1244 if (bytes_left
< kHeaderSize
)
1247 memcpy(×tamp
, 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
)) {
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(
1270 audio_channel_layout_
,
1271 audio_channel_count_
,
1272 audio_samples_per_second_
,
1275 base::TimeDelta::FromMicroseconds(timestamp
));
1276 frames
->push_back(frame
);
1279 bytes_left
-= frame_size
;
1280 } while (bytes_left
> 0);
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
,
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();
1314 media::MediaKeys::UNKNOWN_ERROR
, 0, "Failure calling plugin.");
1319 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr
<CdmPromise
> promise
) {
1320 uint32_t promise_id
= next_promise_id_
++;
1321 promises_
.add(promise_id
, promise
.Pass());
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