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/metrics/sparse_histogram.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/stl_util.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
;
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
,
58 scoped_refptr
<PPB_Buffer_Impl
>* resource
) {
59 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
63 DCHECK(!data
&& !size
);
68 scoped_refptr
<PPB_Buffer_Impl
> buffer(
69 PPB_Buffer_Impl::CreateResource(instance
, size
));
73 BufferAutoMapper
mapper(buffer
.get());
74 if (!mapper
.data() || mapper
.size() < size
)
76 memcpy(mapper
.data(), data
, size
);
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_t(&array
)[array_size
]) {
87 if (array_size
< str
.size())
90 memcpy(array
, str
.data(), str
.size());
94 // Fills the |block_info| with information from |encrypted_buffer|.
96 // Returns true if |block_info| is successfully filled. Returns false
98 bool MakeEncryptedBlockInfo(
99 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
101 PP_EncryptedBlockInfo
* block_info
) {
102 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
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())
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
))
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
))
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
;
142 PP_AudioCodec
MediaAudioCodecToPpAudioCodec(media::AudioCodec codec
) {
144 case media::kCodecVorbis
:
145 return PP_AUDIOCODEC_VORBIS
;
146 case media::kCodecAAC
:
147 return PP_AUDIOCODEC_AAC
;
149 return PP_AUDIOCODEC_UNKNOWN
;
153 PP_VideoCodec
MediaVideoCodecToPpVideoCodec(media::VideoCodec 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
;
162 return PP_VIDEOCODEC_UNKNOWN
;
166 PP_VideoCodecProfile
MediaVideoCodecProfileToPpVideoCodecProfile(
167 media::VideoCodecProfile 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
;
187 return PP_VIDEOCODECPROFILE_UNKNOWN
;
191 PP_DecryptedFrameFormat
MediaVideoFormatToPpDecryptedFrameFormat(
192 media::VideoPixelFormat format
) {
194 case media::PIXEL_FORMAT_YV12
:
195 return PP_DECRYPTEDFRAMEFORMAT_YV12
;
196 case media::PIXEL_FORMAT_I420
:
197 return PP_DECRYPTEDFRAMEFORMAT_I420
;
199 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN
;
203 Decryptor::Status
PpDecryptResultToMediaDecryptorStatus(
204 PP_DecryptResult 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
;
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
;
231 return PP_DECRYPTORSTREAMTYPE_VIDEO
;
235 media::SampleFormat
PpDecryptedSampleFormatToMediaSampleFormat(
236 PP_DecryptedSampleFormat 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
;
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
;
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
:
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
;
306 return MediaKeys::UNKNOWN_ERROR
;
310 media::CdmKeyInformation::KeyStatus
PpCdmKeyStatusToCdmKeyInformationKeyStatus(
311 PP_CdmKeyStatus 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_OUTPUTRESTRICTED
:
320 return media::CdmKeyInformation::OUTPUT_RESTRICTED
;
321 case PP_CDMKEYSTATUS_OUTPUTDOWNSCALED
:
322 return media::CdmKeyInformation::OUTPUT_DOWNSCALED
;
323 case PP_CDMKEYSTATUS_STATUSPENDING
:
324 return media::CdmKeyInformation::KEY_STATUS_PENDING
;
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
;
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_t 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",
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 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
386 DCHECK(!key_system
.empty());
387 DCHECK(key_system_
.empty());
388 key_system_
= key_system
;
390 session_message_cb_
= session_message_cb
;
391 session_closed_cb_
= session_closed_cb
;
392 legacy_session_error_cb_
= legacy_session_error_cb
;
393 session_keys_change_cb_
= session_keys_change_cb
;
394 session_expiration_update_cb_
= session_expiration_update_cb
;
395 fatal_plugin_error_cb_
= fatal_plugin_error_cb
;
397 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
398 plugin_decryption_interface_
->Initialize(
399 pp_instance_
, promise_id
, StringVar::StringToPPVar(key_system_
),
400 PP_FromBool(allow_distinctive_identifier
),
401 PP_FromBool(allow_persistent_state
));
404 void ContentDecryptorDelegate::InstanceCrashed() {
405 fatal_plugin_error_cb_
.Run();
406 SatisfyAllPendingCallbacksOnError();
409 void ContentDecryptorDelegate::SetServerCertificate(
410 const std::vector
<uint8_t>& certificate
,
411 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
412 if (certificate
.size() < media::limits::kMinCertificateLength
||
413 certificate
.size() > media::limits::kMaxCertificateLength
) {
415 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect certificate.");
419 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
420 PP_Var certificate_array
=
421 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
422 base::checked_cast
<uint32
>(certificate
.size()),
423 vector_as_array(&certificate
));
424 plugin_decryption_interface_
->SetServerCertificate(
425 pp_instance_
, promise_id
, certificate_array
);
428 void ContentDecryptorDelegate::CreateSessionAndGenerateRequest(
429 MediaKeys::SessionType session_type
,
430 media::EmeInitDataType init_data_type
,
431 const std::vector
<uint8_t>& init_data
,
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 base::checked_cast
<uint32
>(init_data
.size()),
437 vector_as_array(&init_data
));
438 plugin_decryption_interface_
->CreateSessionAndGenerateRequest(
439 pp_instance_
, promise_id
, MediaSessionTypeToPpSessionType(session_type
),
440 MediaInitDataTypeToPpInitDataType(init_data_type
), init_data_array
);
443 void ContentDecryptorDelegate::LoadSession(
444 media::MediaKeys::SessionType session_type
,
445 const std::string
& session_id
,
446 scoped_ptr
<NewSessionCdmPromise
> promise
) {
447 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
448 plugin_decryption_interface_
->LoadSession(
449 pp_instance_
, promise_id
, MediaSessionTypeToPpSessionType(session_type
),
450 StringVar::StringToPPVar(session_id
));
453 void ContentDecryptorDelegate::UpdateSession(
454 const std::string
& session_id
,
455 const std::vector
<uint8_t>& response
,
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 base::checked_cast
<uint32
>(response
.size()),
461 vector_as_array(&response
));
462 plugin_decryption_interface_
->UpdateSession(
463 pp_instance_
, promise_id
, StringVar::StringToPPVar(session_id
),
467 void ContentDecryptorDelegate::CloseSession(
468 const std::string
& session_id
,
469 scoped_ptr
<SimpleCdmPromise
> promise
) {
470 if (session_id
.length() > media::limits::kMaxSessionIdLength
) {
472 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect session.");
476 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
477 plugin_decryption_interface_
->CloseSession(
478 pp_instance_
, promise_id
, StringVar::StringToPPVar(session_id
));
481 void ContentDecryptorDelegate::RemoveSession(
482 const std::string
& session_id
,
483 scoped_ptr
<SimpleCdmPromise
> promise
) {
484 if (session_id
.length() > media::limits::kMaxSessionIdLength
) {
486 media::MediaKeys::INVALID_ACCESS_ERROR
, 0, "Incorrect session.");
490 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
491 plugin_decryption_interface_
->RemoveSession(
492 pp_instance_
, promise_id
, StringVar::StringToPPVar(session_id
));
495 // TODO(xhwang): Remove duplication of code in Decrypt(),
496 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
497 bool ContentDecryptorDelegate::Decrypt(
498 Decryptor::StreamType stream_type
,
499 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
500 const Decryptor::DecryptCB
& decrypt_cb
) {
501 DVLOG(3) << "Decrypt() - stream_type: " << stream_type
;
503 // |{audio|video}_input_resource_| is not being used by the plugin
504 // now because there is only one pending audio/video decrypt request at any
505 // time. This is enforced by the media pipeline.
506 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
507 if (!MakeMediaBufferResource(
508 stream_type
, encrypted_buffer
, &encrypted_resource
) ||
509 !encrypted_resource
.get()) {
512 ScopedPPResource
pp_resource(encrypted_resource
.get());
514 const uint32_t request_id
= next_decryption_request_id_
++;
515 DVLOG(2) << "Decrypt() - request_id " << request_id
;
517 PP_EncryptedBlockInfo block_info
= {};
518 DCHECK(encrypted_buffer
->decrypt_config());
519 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
523 // There is only one pending decrypt request at any time per stream. This is
524 // enforced by the media pipeline.
525 switch (stream_type
) {
526 case Decryptor::kAudio
:
527 audio_decrypt_cb_
.Set(request_id
, decrypt_cb
);
529 case Decryptor::kVideo
:
530 video_decrypt_cb_
.Set(request_id
, decrypt_cb
);
537 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
539 plugin_decryption_interface_
->Decrypt(pp_instance_
, pp_resource
, &block_info
);
543 bool ContentDecryptorDelegate::CancelDecrypt(
544 Decryptor::StreamType stream_type
) {
545 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type
;
547 Decryptor::DecryptCB decrypt_cb
;
548 switch (stream_type
) {
549 case Decryptor::kAudio
:
550 // Release the shared memory as it can still be in use by the plugin.
551 // The next Decrypt() call will need to allocate a new shared memory
553 audio_input_resource_
= NULL
;
554 decrypt_cb
= audio_decrypt_cb_
.ResetAndReturn();
556 case Decryptor::kVideo
:
557 // Release the shared memory as it can still be in use by the plugin.
558 // The next Decrypt() call will need to allocate a new shared memory
560 video_input_resource_
= NULL
;
561 decrypt_cb
= video_decrypt_cb_
.ResetAndReturn();
568 if (!decrypt_cb
.is_null())
569 decrypt_cb
.Run(Decryptor::kSuccess
, NULL
);
574 bool ContentDecryptorDelegate::InitializeAudioDecoder(
575 const media::AudioDecoderConfig
& decoder_config
,
576 const Decryptor::DecoderInitCB
& init_cb
) {
577 PP_AudioDecoderConfig pp_decoder_config
;
578 pp_decoder_config
.codec
=
579 MediaAudioCodecToPpAudioCodec(decoder_config
.codec());
580 pp_decoder_config
.channel_count
=
581 media::ChannelLayoutToChannelCount(decoder_config
.channel_layout());
582 pp_decoder_config
.bits_per_channel
= decoder_config
.bits_per_channel();
583 pp_decoder_config
.samples_per_second
= decoder_config
.samples_per_second();
584 pp_decoder_config
.request_id
= next_decryption_request_id_
++;
586 audio_samples_per_second_
= pp_decoder_config
.samples_per_second
;
587 audio_channel_count_
= pp_decoder_config
.channel_count
;
588 audio_channel_layout_
= decoder_config
.channel_layout();
590 scoped_refptr
<PPB_Buffer_Impl
> extra_data_resource
;
591 if (!MakeBufferResource(pp_instance_
,
592 decoder_config
.extra_data(),
593 decoder_config
.extra_data_size(),
594 &extra_data_resource
)) {
597 ScopedPPResource
pp_resource(extra_data_resource
.get());
599 audio_decoder_init_cb_
.Set(pp_decoder_config
.request_id
, init_cb
);
600 plugin_decryption_interface_
->InitializeAudioDecoder(
601 pp_instance_
, &pp_decoder_config
, pp_resource
);
605 bool ContentDecryptorDelegate::InitializeVideoDecoder(
606 const media::VideoDecoderConfig
& decoder_config
,
607 const Decryptor::DecoderInitCB
& init_cb
) {
608 PP_VideoDecoderConfig pp_decoder_config
;
609 pp_decoder_config
.codec
=
610 MediaVideoCodecToPpVideoCodec(decoder_config
.codec());
611 pp_decoder_config
.profile
=
612 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config
.profile());
613 pp_decoder_config
.format
=
614 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config
.format());
615 pp_decoder_config
.width
= decoder_config
.coded_size().width();
616 pp_decoder_config
.height
= decoder_config
.coded_size().height();
617 pp_decoder_config
.request_id
= next_decryption_request_id_
++;
619 scoped_refptr
<PPB_Buffer_Impl
> extra_data_resource
;
620 if (!MakeBufferResource(pp_instance_
,
621 decoder_config
.extra_data(),
622 decoder_config
.extra_data_size(),
623 &extra_data_resource
)) {
626 ScopedPPResource
pp_resource(extra_data_resource
.get());
628 video_decoder_init_cb_
.Set(pp_decoder_config
.request_id
, init_cb
);
629 natural_size_
= decoder_config
.natural_size();
631 plugin_decryption_interface_
->InitializeVideoDecoder(
632 pp_instance_
, &pp_decoder_config
, pp_resource
);
636 bool ContentDecryptorDelegate::DeinitializeDecoder(
637 Decryptor::StreamType stream_type
) {
638 CancelDecode(stream_type
);
640 if (stream_type
== Decryptor::kVideo
)
641 natural_size_
= gfx::Size();
643 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
644 // stream type from media stack.
645 plugin_decryption_interface_
->DeinitializeDecoder(
646 pp_instance_
, MediaDecryptorStreamTypeToPpStreamType(stream_type
), 0);
650 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type
) {
651 CancelDecode(stream_type
);
653 // TODO(tomfinegan): Add decoder reset request tracking.
654 plugin_decryption_interface_
->ResetDecoder(
655 pp_instance_
, MediaDecryptorStreamTypeToPpStreamType(stream_type
), 0);
659 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
660 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
661 const Decryptor::AudioDecodeCB
& audio_decode_cb
) {
662 // |audio_input_resource_| is not being used by the plugin now
663 // because there is only one pending audio decode request at any time.
664 // This is enforced by the media pipeline.
665 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
666 if (!MakeMediaBufferResource(
667 Decryptor::kAudio
, encrypted_buffer
, &encrypted_resource
)) {
671 // The resource should not be NULL for non-EOS buffer.
672 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
675 const uint32_t request_id
= next_decryption_request_id_
++;
676 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id
;
678 PP_EncryptedBlockInfo block_info
= {};
679 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
683 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
685 // There is only one pending audio decode request at any time. This is
686 // enforced by the media pipeline. If this DCHECK is violated, our buffer
687 // reuse policy is not valid, and we may have race problems for the shared
689 audio_decode_cb_
.Set(request_id
, audio_decode_cb
);
691 ScopedPPResource
pp_resource(encrypted_resource
.get());
692 plugin_decryption_interface_
->DecryptAndDecode(
693 pp_instance_
, PP_DECRYPTORSTREAMTYPE_AUDIO
, pp_resource
, &block_info
);
697 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
698 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
699 const Decryptor::VideoDecodeCB
& video_decode_cb
) {
700 // |video_input_resource_| is not being used by the plugin now
701 // because there is only one pending video decode request at any time.
702 // This is enforced by the media pipeline.
703 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
704 if (!MakeMediaBufferResource(
705 Decryptor::kVideo
, encrypted_buffer
, &encrypted_resource
)) {
709 // The resource should not be 0 for non-EOS buffer.
710 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
713 const uint32_t request_id
= next_decryption_request_id_
++;
714 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id
;
715 TRACE_EVENT_ASYNC_BEGIN0(
716 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id
);
718 PP_EncryptedBlockInfo block_info
= {};
719 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
723 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
725 // Only one pending video decode request at any time. This is enforced by the
726 // media pipeline. If this DCHECK is violated, our buffer
727 // reuse policy is not valid, and we may have race problems for the shared
729 video_decode_cb_
.Set(request_id
, video_decode_cb
);
731 // TODO(tomfinegan): Need to get stream type from media stack.
732 ScopedPPResource
pp_resource(encrypted_resource
.get());
733 plugin_decryption_interface_
->DecryptAndDecode(
734 pp_instance_
, PP_DECRYPTORSTREAMTYPE_VIDEO
, pp_resource
, &block_info
);
738 void ContentDecryptorDelegate::OnPromiseResolved(uint32_t promise_id
) {
739 cdm_promise_adapter_
.ResolvePromise(promise_id
);
742 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(uint32_t promise_id
,
744 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
745 DCHECK(session_id_string
);
746 cdm_promise_adapter_
.ResolvePromise(promise_id
, session_id_string
->value());
749 void ContentDecryptorDelegate::OnPromiseRejected(
751 PP_CdmExceptionCode exception_code
,
752 uint32_t system_code
,
753 PP_Var error_description
) {
754 ReportSystemCodeUMA(key_system_
, system_code
);
756 StringVar
* error_description_string
= StringVar::FromPPVar(error_description
);
757 DCHECK(error_description_string
);
758 cdm_promise_adapter_
.RejectPromise(
759 promise_id
, PpExceptionTypeToMediaException(exception_code
), system_code
,
760 error_description_string
->value());
763 void ContentDecryptorDelegate::OnSessionMessage(PP_Var session_id
,
764 PP_CdmMessageType message_type
,
766 PP_Var legacy_destination_url
) {
767 if (session_message_cb_
.is_null())
770 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
771 DCHECK(session_id_string
);
773 ArrayBufferVar
* message_array_buffer
= ArrayBufferVar::FromPPVar(message
);
774 std::vector
<uint8_t> message_vector
;
775 if (message_array_buffer
) {
776 const uint8_t* data
=
777 static_cast<const uint8_t*>(message_array_buffer
->Map());
778 message_vector
.assign(data
, data
+ message_array_buffer
->ByteLength());
781 StringVar
* destination_url_string
=
782 StringVar::FromPPVar(legacy_destination_url
);
783 if (!destination_url_string
) {
788 GURL verified_gurl
= GURL(destination_url_string
->value());
789 if (!verified_gurl
.is_valid()) {
790 DLOG(WARNING
) << "SessionMessage legacy_destination_url is invalid : "
791 << verified_gurl
.possibly_invalid_spec();
792 verified_gurl
= GURL::EmptyGURL(); // Replace invalid destination_url.
795 session_message_cb_
.Run(session_id_string
->value(),
796 PpCdmMessageTypeToMediaMessageType(message_type
),
797 message_vector
, verified_gurl
);
800 void ContentDecryptorDelegate::OnSessionKeysChange(
802 PP_Bool has_additional_usable_key
,
804 const struct PP_KeyInformation key_information
[]) {
805 if (session_keys_change_cb_
.is_null())
808 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
809 DCHECK(session_id_string
);
811 media::CdmKeysInfo keys_info
;
812 keys_info
.reserve(key_count
);
813 for (uint32_t i
= 0; i
< key_count
; ++i
) {
814 scoped_ptr
<media::CdmKeyInformation
> key_info(new media::CdmKeyInformation
);
815 const auto& info
= key_information
[i
];
816 key_info
->key_id
.assign(info
.key_id
, info
.key_id
+ info
.key_id_size
);
818 PpCdmKeyStatusToCdmKeyInformationKeyStatus(info
.key_status
);
819 key_info
->system_code
= info
.system_code
;
820 keys_info
.push_back(key_info
.release());
823 session_keys_change_cb_
.Run(session_id_string
->value(),
824 PP_ToBool(has_additional_usable_key
),
828 void ContentDecryptorDelegate::OnSessionExpirationChange(
830 PP_Time new_expiry_time
) {
831 if (session_expiration_update_cb_
.is_null())
834 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
835 DCHECK(session_id_string
);
837 session_expiration_update_cb_
.Run(session_id_string
->value(),
838 ppapi::PPTimeToTime(new_expiry_time
));
841 void ContentDecryptorDelegate::OnSessionClosed(PP_Var session_id
) {
842 if (session_closed_cb_
.is_null())
845 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
846 DCHECK(session_id_string
);
848 session_closed_cb_
.Run(session_id_string
->value());
851 void ContentDecryptorDelegate::OnLegacySessionError(
853 PP_CdmExceptionCode exception_code
,
854 uint32_t system_code
,
855 PP_Var error_description
) {
856 ReportSystemCodeUMA(key_system_
, system_code
);
858 if (legacy_session_error_cb_
.is_null())
861 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
862 DCHECK(session_id_string
);
864 StringVar
* error_description_string
= StringVar::FromPPVar(error_description
);
865 DCHECK(error_description_string
);
867 legacy_session_error_cb_
.Run(session_id_string
->value(),
868 PpExceptionTypeToMediaException(exception_code
),
869 system_code
, error_description_string
->value());
872 void ContentDecryptorDelegate::DecoderInitializeDone(
873 PP_DecryptorStreamType decoder_type
,
876 if (decoder_type
== PP_DECRYPTORSTREAMTYPE_AUDIO
) {
877 // If the request ID is not valid or does not match what's saved, do
879 if (request_id
== 0 || !audio_decoder_init_cb_
.Matches(request_id
))
882 audio_decoder_init_cb_
.ResetAndReturn().Run(PP_ToBool(success
));
884 if (request_id
== 0 || !video_decoder_init_cb_
.Matches(request_id
))
888 natural_size_
= gfx::Size();
890 video_decoder_init_cb_
.ResetAndReturn().Run(PP_ToBool(success
));
894 void ContentDecryptorDelegate::DecoderDeinitializeDone(
895 PP_DecryptorStreamType decoder_type
,
896 uint32_t request_id
) {
897 // TODO(tomfinegan): Add decoder stop completion handling.
900 void ContentDecryptorDelegate::DecoderResetDone(
901 PP_DecryptorStreamType decoder_type
,
902 uint32_t request_id
) {
903 // TODO(tomfinegan): Add decoder reset completion handling.
906 void ContentDecryptorDelegate::DeliverBlock(
907 PP_Resource decrypted_block
,
908 const PP_DecryptedBlockInfo
* block_info
) {
911 FreeBuffer(block_info
->tracking_info
.buffer_id
);
913 const uint32_t request_id
= block_info
->tracking_info
.request_id
;
914 DVLOG(2) << "DeliverBlock() - request_id: " << request_id
;
916 // If the request ID is not valid or does not match what's saved, do nothing.
917 if (request_id
== 0) {
918 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id
;
922 Decryptor::DecryptCB decrypt_cb
;
923 if (audio_decrypt_cb_
.Matches(request_id
)) {
924 decrypt_cb
= audio_decrypt_cb_
.ResetAndReturn();
925 } else if (video_decrypt_cb_
.Matches(request_id
)) {
926 decrypt_cb
= video_decrypt_cb_
.ResetAndReturn();
928 DVLOG(1) << "DeliverBlock() - request_id " << request_id
<< " not found";
932 Decryptor::Status status
=
933 PpDecryptResultToMediaDecryptorStatus(block_info
->result
);
934 if (status
!= Decryptor::kSuccess
) {
935 decrypt_cb
.Run(status
, NULL
);
939 EnterResourceNoLock
<PPB_Buffer_API
> enter(decrypted_block
, true);
940 if (!enter
.succeeded()) {
941 decrypt_cb
.Run(Decryptor::kError
, NULL
);
944 BufferAutoMapper
mapper(enter
.object());
945 if (!mapper
.data() || !mapper
.size() ||
946 mapper
.size() < block_info
->data_size
) {
947 decrypt_cb
.Run(Decryptor::kError
, NULL
);
951 // TODO(tomfinegan): Find a way to take ownership of the shared memory
952 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
953 scoped_refptr
<media::DecoderBuffer
> decrypted_buffer(
954 media::DecoderBuffer::CopyFrom(static_cast<uint8_t*>(mapper
.data()),
955 block_info
->data_size
));
956 decrypted_buffer
->set_timestamp(
957 base::TimeDelta::FromMicroseconds(block_info
->tracking_info
.timestamp
));
958 decrypt_cb
.Run(Decryptor::kSuccess
, decrypted_buffer
);
961 // Use a non-class-member function here so that if for some reason
962 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
963 // we can still get the shared memory unmapped.
964 static void BufferNoLongerNeeded(
965 const scoped_refptr
<PPB_Buffer_Impl
>& ppb_buffer
,
966 base::Closure buffer_no_longer_needed_cb
) {
968 buffer_no_longer_needed_cb
.Run();
971 // Enters |resource|, maps shared memory and returns pointer of mapped data.
972 // Returns NULL if any error occurs.
973 static uint8_t* GetMappedBuffer(PP_Resource resource
,
974 scoped_refptr
<PPB_Buffer_Impl
>* ppb_buffer
) {
975 EnterResourceNoLock
<PPB_Buffer_API
> enter(resource
, true);
976 if (!enter
.succeeded())
979 uint8_t* mapped_data
= static_cast<uint8_t*>(enter
.object()->Map());
980 if (!enter
.object()->IsMapped() || !mapped_data
)
983 uint32_t mapped_size
= 0;
984 if (!enter
.object()->Describe(&mapped_size
) || !mapped_size
) {
985 enter
.object()->Unmap();
989 *ppb_buffer
= static_cast<PPB_Buffer_Impl
*>(enter
.object());
994 void ContentDecryptorDelegate::DeliverFrame(
995 PP_Resource decrypted_frame
,
996 const PP_DecryptedFrameInfo
* frame_info
) {
999 const uint32_t request_id
= frame_info
->tracking_info
.request_id
;
1000 DVLOG(2) << "DeliverFrame() - request_id: " << request_id
;
1002 // If the request ID is not valid or does not match what's saved, do nothing.
1003 if (request_id
== 0 || !video_decode_cb_
.Matches(request_id
)) {
1004 DVLOG(1) << "DeliverFrame() - request_id " << request_id
<< " not found";
1005 FreeBuffer(frame_info
->tracking_info
.buffer_id
);
1009 TRACE_EVENT_ASYNC_END0(
1010 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id
);
1012 Decryptor::VideoDecodeCB video_decode_cb
= video_decode_cb_
.ResetAndReturn();
1014 Decryptor::Status status
=
1015 PpDecryptResultToMediaDecryptorStatus(frame_info
->result
);
1016 if (status
!= Decryptor::kSuccess
) {
1017 DCHECK(!frame_info
->tracking_info
.buffer_id
);
1018 video_decode_cb
.Run(status
, NULL
);
1022 scoped_refptr
<PPB_Buffer_Impl
> ppb_buffer
;
1023 uint8_t* frame_data
= GetMappedBuffer(decrypted_frame
, &ppb_buffer
);
1025 FreeBuffer(frame_info
->tracking_info
.buffer_id
);
1026 video_decode_cb
.Run(Decryptor::kError
, NULL
);
1030 gfx::Size
frame_size(frame_info
->width
, frame_info
->height
);
1031 DCHECK_EQ(frame_info
->format
, PP_DECRYPTEDFRAMEFORMAT_YV12
);
1033 scoped_refptr
<media::VideoFrame
> decoded_frame
=
1034 media::VideoFrame::WrapExternalYuvData(
1035 media::PIXEL_FORMAT_YV12
, frame_size
, gfx::Rect(frame_size
),
1036 natural_size_
, frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_Y
],
1037 frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_U
],
1038 frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_V
],
1039 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_Y
],
1040 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_U
],
1041 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_V
],
1042 base::TimeDelta::FromMicroseconds(
1043 frame_info
->tracking_info
.timestamp
));
1044 decoded_frame
->AddDestructionObserver(
1045 media::BindToCurrentLoop(
1046 base::Bind(&BufferNoLongerNeeded
,
1048 base::Bind(&ContentDecryptorDelegate::FreeBuffer
,
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";
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
);
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
,
1089 &audio_frame_list
)) {
1090 NOTREACHED() << "CDM did not serialize the buffer correctly.";
1091 audio_decode_cb
.Run(Decryptor::kError
, empty_frames
);
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
1105 audio_input_resource_
= NULL
;
1106 if (!audio_decode_cb_
.is_null())
1107 audio_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
,
1108 Decryptor::AudioFrames());
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
1114 video_input_resource_
= NULL
;
1115 if (!video_decode_cb_
.is_null())
1116 video_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
, NULL
);
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()) {
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.";
1161 PPB_Buffer_Impl::CreateResource(pp_instance_
, media_resource_size
);
1162 if (!media_resource
.get())
1166 BufferAutoMapper
mapper(media_resource
.get());
1167 if (!mapper
.data() || mapper
.size() < data_size
) {
1168 media_resource
= NULL
;
1171 memcpy(mapper
.data(), encrypted_buffer
->data(), data_size
);
1173 *resource
= media_resource
;
1177 void ContentDecryptorDelegate::FreeBuffer(uint32_t 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())
1189 tracking_info
->buffer_id
= free_buffers_
.front();
1190 free_buffers_
.pop();
1193 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1194 PP_Resource audio_frames
,
1196 media::SampleFormat sample_format
,
1197 Decryptor::AudioFrames
* frames
) {
1199 EnterResourceNoLock
<PPB_Buffer_API
> enter(audio_frames
, true);
1200 if (!enter
.succeeded())
1203 BufferAutoMapper
mapper(enter
.object());
1204 if (!mapper
.data() || !mapper
.size() ||
1205 mapper
.size() < static_cast<uint32_t>(data_size
))
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_t* cur
= static_cast<uint8_t*>(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)
1220 // Allocate space for the channel pointers given to AudioBuffer.
1221 std::vector
<const uint8_t*> channel_ptrs(audio_channel_count_
, nullptr);
1223 int64 timestamp
= 0;
1224 int64 frame_size
= -1;
1225 const size_t kHeaderSize
= sizeof(timestamp
) + sizeof(frame_size
);
1227 if (bytes_left
< kHeaderSize
)
1230 memcpy(×tamp
, cur
, sizeof(timestamp
));
1231 cur
+= sizeof(timestamp
);
1232 bytes_left
-= sizeof(timestamp
);
1234 memcpy(&frame_size
, cur
, sizeof(frame_size
));
1235 cur
+= sizeof(frame_size
);
1236 bytes_left
-= sizeof(frame_size
);
1238 // We should *not* have empty frames in the list.
1239 if (frame_size
<= 0 ||
1240 bytes_left
< base::checked_cast
<size_t>(frame_size
)) {
1244 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1245 // one in the case of interleaved data.
1246 const int size_per_channel
= frame_size
/ audio_channel_count_
;
1247 for (int i
= 0; i
< audio_channel_count_
; ++i
)
1248 channel_ptrs
[i
] = cur
+ i
* size_per_channel
;
1250 const int frame_count
= frame_size
/ audio_bytes_per_frame
;
1251 scoped_refptr
<media::AudioBuffer
> frame
= media::AudioBuffer::CopyFrom(
1253 audio_channel_layout_
,
1254 audio_channel_count_
,
1255 audio_samples_per_second_
,
1258 base::TimeDelta::FromMicroseconds(timestamp
));
1259 frames
->push_back(frame
);
1262 bytes_left
-= frame_size
;
1263 } while (bytes_left
> 0);
1268 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1269 if (!audio_decoder_init_cb_
.is_null())
1270 audio_decoder_init_cb_
.ResetAndReturn().Run(false);
1272 if (!video_decoder_init_cb_
.is_null())
1273 video_decoder_init_cb_
.ResetAndReturn().Run(false);
1275 audio_input_resource_
= NULL
;
1276 video_input_resource_
= NULL
;
1278 if (!audio_decrypt_cb_
.is_null())
1279 audio_decrypt_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1281 if (!video_decrypt_cb_
.is_null())
1282 video_decrypt_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1284 if (!audio_decode_cb_
.is_null()) {
1285 const media::Decryptor::AudioFrames empty_frames
;
1286 audio_decode_cb_
.ResetAndReturn().Run(media::Decryptor::kError
,
1290 if (!video_decode_cb_
.is_null())
1291 video_decode_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1293 cdm_promise_adapter_
.Clear();
1296 } // namespace content