1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/content_decryptor_delegate.h"
7 #include "base/callback_helpers.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "content/renderer/pepper/ppb_buffer_impl.h"
12 #include "media/base/audio_buffer.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/cdm_promise.h"
16 #include "media/base/channel_layout.h"
17 #include "media/base/data_buffer.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/decrypt_config.h"
20 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h"
22 #include "media/base/video_util.h"
23 #include "ppapi/shared_impl/scoped_pp_resource.h"
24 #include "ppapi/shared_impl/var.h"
25 #include "ppapi/shared_impl/var_tracker.h"
26 #include "ppapi/thunk/enter.h"
27 #include "ppapi/thunk/ppb_buffer_api.h"
28 #include "ui/gfx/rect.h"
30 using media::CdmPromise
;
31 using media::Decryptor
;
32 using media::MediaKeys
;
33 using media::NewSessionCdmPromise
;
34 using media::SimpleCdmPromise
;
35 using ppapi::ArrayBufferVar
;
36 using ppapi::PpapiGlobals
;
37 using ppapi::ScopedPPResource
;
38 using ppapi::StringVar
;
39 using ppapi::thunk::EnterResourceNoLock
;
40 using ppapi::thunk::PPB_Buffer_API
;
46 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
47 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
48 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
49 // true upon success and false if any error happened.
50 bool MakeBufferResource(PP_Instance instance
,
53 scoped_refptr
<PPB_Buffer_Impl
>* resource
) {
54 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
58 DCHECK(!data
&& !size
);
63 scoped_refptr
<PPB_Buffer_Impl
> buffer(
64 PPB_Buffer_Impl::CreateResource(instance
, size
));
68 BufferAutoMapper
mapper(buffer
.get());
69 if (!mapper
.data() || mapper
.size() < size
)
71 memcpy(mapper
.data(), data
, size
);
77 // Copies the content of |str| into |array|.
78 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
79 // |array_size| is smaller than the |str| length.
80 template <uint32_t array_size
>
81 bool CopyStringToArray(const std::string
& str
, uint8 (&array
)[array_size
]) {
82 if (array_size
< str
.size())
85 memcpy(array
, str
.data(), str
.size());
89 // Fills the |block_info| with information from |encrypted_buffer|.
91 // Returns true if |block_info| is successfully filled. Returns false
93 static bool MakeEncryptedBlockInfo(
94 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
96 PP_EncryptedBlockInfo
* block_info
) {
97 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
99 memset(block_info
, 0, sizeof(*block_info
));
100 block_info
->tracking_info
.request_id
= request_id
;
102 // EOS buffers need a request ID and nothing more.
103 if (encrypted_buffer
->end_of_stream())
106 DCHECK(encrypted_buffer
->data_size())
107 << "DecryptConfig is set on an empty buffer";
109 block_info
->tracking_info
.timestamp
=
110 encrypted_buffer
->timestamp().InMicroseconds();
111 block_info
->data_size
= encrypted_buffer
->data_size();
113 const media::DecryptConfig
* decrypt_config
=
114 encrypted_buffer
->decrypt_config();
116 if (!CopyStringToArray(decrypt_config
->key_id(), block_info
->key_id
) ||
117 !CopyStringToArray(decrypt_config
->iv(), block_info
->iv
))
120 block_info
->key_id_size
= decrypt_config
->key_id().size();
121 block_info
->iv_size
= decrypt_config
->iv().size();
123 if (decrypt_config
->subsamples().size() > arraysize(block_info
->subsamples
))
126 block_info
->num_subsamples
= decrypt_config
->subsamples().size();
127 for (uint32_t i
= 0; i
< block_info
->num_subsamples
; ++i
) {
128 block_info
->subsamples
[i
].clear_bytes
=
129 decrypt_config
->subsamples()[i
].clear_bytes
;
130 block_info
->subsamples
[i
].cipher_bytes
=
131 decrypt_config
->subsamples()[i
].cypher_bytes
;
137 PP_AudioCodec
MediaAudioCodecToPpAudioCodec(media::AudioCodec codec
) {
139 case media::kCodecVorbis
:
140 return PP_AUDIOCODEC_VORBIS
;
141 case media::kCodecAAC
:
142 return PP_AUDIOCODEC_AAC
;
144 return PP_AUDIOCODEC_UNKNOWN
;
148 PP_VideoCodec
MediaVideoCodecToPpVideoCodec(media::VideoCodec codec
) {
150 case media::kCodecVP8
:
151 return PP_VIDEOCODEC_VP8
;
152 case media::kCodecH264
:
153 return PP_VIDEOCODEC_H264
;
154 case media::kCodecVP9
:
155 return PP_VIDEOCODEC_VP9
;
157 return PP_VIDEOCODEC_UNKNOWN
;
161 PP_VideoCodecProfile
MediaVideoCodecProfileToPpVideoCodecProfile(
162 media::VideoCodecProfile profile
) {
164 // TODO(xhwang): VP8 and VP9 do not have profiles. Clean up
165 // media::VideoCodecProfile and remove these two cases.
166 case media::VP8PROFILE_MAIN
:
167 case media::VP9PROFILE_MAIN
:
168 return PP_VIDEOCODECPROFILE_NOT_NEEDED
;
169 case media::H264PROFILE_BASELINE
:
170 return PP_VIDEOCODECPROFILE_H264_BASELINE
;
171 case media::H264PROFILE_MAIN
:
172 return PP_VIDEOCODECPROFILE_H264_MAIN
;
173 case media::H264PROFILE_EXTENDED
:
174 return PP_VIDEOCODECPROFILE_H264_EXTENDED
;
175 case media::H264PROFILE_HIGH
:
176 return PP_VIDEOCODECPROFILE_H264_HIGH
;
177 case media::H264PROFILE_HIGH10PROFILE
:
178 return PP_VIDEOCODECPROFILE_H264_HIGH_10
;
179 case media::H264PROFILE_HIGH422PROFILE
:
180 return PP_VIDEOCODECPROFILE_H264_HIGH_422
;
181 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE
:
182 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE
;
184 return PP_VIDEOCODECPROFILE_UNKNOWN
;
188 PP_DecryptedFrameFormat
MediaVideoFormatToPpDecryptedFrameFormat(
189 media::VideoFrame::Format format
) {
191 case media::VideoFrame::YV12
:
192 return PP_DECRYPTEDFRAMEFORMAT_YV12
;
193 case media::VideoFrame::I420
:
194 return PP_DECRYPTEDFRAMEFORMAT_I420
;
196 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN
;
200 Decryptor::Status
PpDecryptResultToMediaDecryptorStatus(
201 PP_DecryptResult result
) {
203 case PP_DECRYPTRESULT_SUCCESS
:
204 return Decryptor::kSuccess
;
205 case PP_DECRYPTRESULT_DECRYPT_NOKEY
:
206 return Decryptor::kNoKey
;
207 case PP_DECRYPTRESULT_NEEDMOREDATA
:
208 return Decryptor::kNeedMoreData
;
209 case PP_DECRYPTRESULT_DECRYPT_ERROR
:
210 return Decryptor::kError
;
211 case PP_DECRYPTRESULT_DECODE_ERROR
:
212 return Decryptor::kError
;
215 return Decryptor::kError
;
219 PP_DecryptorStreamType
MediaDecryptorStreamTypeToPpStreamType(
220 Decryptor::StreamType stream_type
) {
221 switch (stream_type
) {
222 case Decryptor::kAudio
:
223 return PP_DECRYPTORSTREAMTYPE_AUDIO
;
224 case Decryptor::kVideo
:
225 return PP_DECRYPTORSTREAMTYPE_VIDEO
;
228 return PP_DECRYPTORSTREAMTYPE_VIDEO
;
232 media::SampleFormat
PpDecryptedSampleFormatToMediaSampleFormat(
233 PP_DecryptedSampleFormat result
) {
235 case PP_DECRYPTEDSAMPLEFORMAT_U8
:
236 return media::kSampleFormatU8
;
237 case PP_DECRYPTEDSAMPLEFORMAT_S16
:
238 return media::kSampleFormatS16
;
239 case PP_DECRYPTEDSAMPLEFORMAT_S32
:
240 return media::kSampleFormatS32
;
241 case PP_DECRYPTEDSAMPLEFORMAT_F32
:
242 return media::kSampleFormatF32
;
243 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16
:
244 return media::kSampleFormatPlanarS16
;
245 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32
:
246 return media::kSampleFormatPlanarF32
;
249 return media::kUnknownSampleFormat
;
253 PP_SessionType
MediaSessionTypeToPpSessionType(
254 MediaKeys::SessionType session_type
) {
255 switch (session_type
) {
256 case MediaKeys::TEMPORARY_SESSION
:
257 return PP_SESSIONTYPE_TEMPORARY
;
258 case MediaKeys::PERSISTENT_SESSION
:
259 return PP_SESSIONTYPE_PERSISTENT
;
262 return PP_SESSIONTYPE_TEMPORARY
;
266 MediaKeys::Exception
PpExceptionTypeToMediaException(
267 PP_CdmExceptionCode exception_code
) {
268 switch (exception_code
) {
269 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR
:
270 return MediaKeys::NOT_SUPPORTED_ERROR
;
271 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR
:
272 return MediaKeys::INVALID_STATE_ERROR
;
273 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR
:
274 return MediaKeys::INVALID_ACCESS_ERROR
;
275 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR
:
276 return MediaKeys::QUOTA_EXCEEDED_ERROR
;
277 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR
:
278 return MediaKeys::UNKNOWN_ERROR
;
279 case PP_CDMEXCEPTIONCODE_CLIENTERROR
:
280 return MediaKeys::CLIENT_ERROR
;
281 case PP_CDMEXCEPTIONCODE_OUTPUTERROR
:
282 return MediaKeys::OUTPUT_ERROR
;
285 return MediaKeys::UNKNOWN_ERROR
;
291 ContentDecryptorDelegate::ContentDecryptorDelegate(
292 PP_Instance pp_instance
,
293 const PPP_ContentDecryptor_Private
* plugin_decryption_interface
)
294 : pp_instance_(pp_instance
),
295 plugin_decryption_interface_(plugin_decryption_interface
),
296 next_decryption_request_id_(1),
297 audio_samples_per_second_(0),
298 audio_channel_count_(0),
299 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE
),
301 weak_ptr_factory_(this) {
302 weak_this_
= weak_ptr_factory_
.GetWeakPtr();
305 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
306 SatisfyAllPendingCallbacksOnError();
309 void ContentDecryptorDelegate::Initialize(
310 const std::string
& key_system
,
311 const media::SessionMessageCB
& session_message_cb
,
312 const media::SessionReadyCB
& session_ready_cb
,
313 const media::SessionClosedCB
& session_closed_cb
,
314 const media::SessionErrorCB
& session_error_cb
,
315 const base::Closure
& fatal_plugin_error_cb
) {
316 DCHECK(!key_system
.empty());
317 DCHECK(key_system_
.empty());
318 key_system_
= key_system
;
320 session_message_cb_
= session_message_cb
;
321 session_ready_cb_
= session_ready_cb
;
322 session_closed_cb_
= session_closed_cb
;
323 session_error_cb_
= session_error_cb
;
324 fatal_plugin_error_cb_
= fatal_plugin_error_cb
;
326 plugin_decryption_interface_
->Initialize(
327 pp_instance_
, StringVar::StringToPPVar(key_system_
));
330 void ContentDecryptorDelegate::InstanceCrashed() {
331 fatal_plugin_error_cb_
.Run();
332 SatisfyAllPendingCallbacksOnError();
335 void ContentDecryptorDelegate::CreateSession(
336 const std::string
& init_data_type
,
337 const uint8
* init_data
,
338 int init_data_length
,
339 MediaKeys::SessionType session_type
,
340 scoped_ptr
<NewSessionCdmPromise
> promise
) {
341 uint32_t promise_id
= SavePromise(promise
.PassAs
<CdmPromise
>());
342 PP_Var init_data_array
=
343 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
344 init_data_length
, init_data
);
345 plugin_decryption_interface_
->CreateSession(
348 StringVar::StringToPPVar(init_data_type
),
350 MediaSessionTypeToPpSessionType(session_type
));
353 void ContentDecryptorDelegate::LoadSession(
354 const std::string
& web_session_id
,
355 scoped_ptr
<NewSessionCdmPromise
> promise
) {
356 uint32_t promise_id
= SavePromise(promise
.PassAs
<CdmPromise
>());
357 plugin_decryption_interface_
->LoadSession(
358 pp_instance_
, promise_id
, StringVar::StringToPPVar(web_session_id
));
361 void ContentDecryptorDelegate::UpdateSession(
362 const std::string
& web_session_id
,
363 const uint8
* response
,
365 scoped_ptr
<SimpleCdmPromise
> promise
) {
366 uint32_t promise_id
= SavePromise(promise
.PassAs
<CdmPromise
>());
367 PP_Var response_array
=
368 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
369 response_length
, response
);
370 plugin_decryption_interface_
->UpdateSession(
373 StringVar::StringToPPVar(web_session_id
),
377 void ContentDecryptorDelegate::ReleaseSession(
378 const std::string
& web_session_id
,
379 scoped_ptr
<SimpleCdmPromise
> promise
) {
380 uint32_t promise_id
= SavePromise(promise
.PassAs
<CdmPromise
>());
381 plugin_decryption_interface_
->ReleaseSession(
382 pp_instance_
, promise_id
, StringVar::StringToPPVar(web_session_id
));
385 // TODO(xhwang): Remove duplication of code in Decrypt(),
386 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
387 bool ContentDecryptorDelegate::Decrypt(
388 Decryptor::StreamType stream_type
,
389 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
390 const Decryptor::DecryptCB
& decrypt_cb
) {
391 DVLOG(3) << "Decrypt() - stream_type: " << stream_type
;
393 // |{audio|video}_input_resource_| is not being used by the plugin
394 // now because there is only one pending audio/video decrypt request at any
395 // time. This is enforced by the media pipeline.
396 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
397 if (!MakeMediaBufferResource(
398 stream_type
, encrypted_buffer
, &encrypted_resource
) ||
399 !encrypted_resource
.get()) {
402 ScopedPPResource
pp_resource(encrypted_resource
.get());
404 const uint32_t request_id
= next_decryption_request_id_
++;
405 DVLOG(2) << "Decrypt() - request_id " << request_id
;
407 PP_EncryptedBlockInfo block_info
= {};
408 DCHECK(encrypted_buffer
->decrypt_config());
409 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
413 // There is only one pending decrypt request at any time per stream. This is
414 // enforced by the media pipeline.
415 switch (stream_type
) {
416 case Decryptor::kAudio
:
417 audio_decrypt_cb_
.Set(request_id
, decrypt_cb
);
419 case Decryptor::kVideo
:
420 video_decrypt_cb_
.Set(request_id
, decrypt_cb
);
427 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
429 plugin_decryption_interface_
->Decrypt(pp_instance_
, pp_resource
, &block_info
);
433 bool ContentDecryptorDelegate::CancelDecrypt(
434 Decryptor::StreamType stream_type
) {
435 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type
;
437 Decryptor::DecryptCB decrypt_cb
;
438 switch (stream_type
) {
439 case Decryptor::kAudio
:
440 // Release the shared memory as it can still be in use by the plugin.
441 // The next Decrypt() call will need to allocate a new shared memory
443 audio_input_resource_
= NULL
;
444 decrypt_cb
= audio_decrypt_cb_
.ResetAndReturn();
446 case Decryptor::kVideo
:
447 // Release the shared memory as it can still be in use by the plugin.
448 // The next Decrypt() call will need to allocate a new shared memory
450 video_input_resource_
= NULL
;
451 decrypt_cb
= video_decrypt_cb_
.ResetAndReturn();
458 if (!decrypt_cb
.is_null())
459 decrypt_cb
.Run(Decryptor::kSuccess
, NULL
);
464 bool ContentDecryptorDelegate::InitializeAudioDecoder(
465 const media::AudioDecoderConfig
& decoder_config
,
466 const Decryptor::DecoderInitCB
& init_cb
) {
467 PP_AudioDecoderConfig pp_decoder_config
;
468 pp_decoder_config
.codec
=
469 MediaAudioCodecToPpAudioCodec(decoder_config
.codec());
470 pp_decoder_config
.channel_count
=
471 media::ChannelLayoutToChannelCount(decoder_config
.channel_layout());
472 pp_decoder_config
.bits_per_channel
= decoder_config
.bits_per_channel();
473 pp_decoder_config
.samples_per_second
= decoder_config
.samples_per_second();
474 pp_decoder_config
.request_id
= next_decryption_request_id_
++;
476 audio_samples_per_second_
= pp_decoder_config
.samples_per_second
;
477 audio_channel_count_
= pp_decoder_config
.channel_count
;
478 audio_channel_layout_
= decoder_config
.channel_layout();
480 scoped_refptr
<PPB_Buffer_Impl
> extra_data_resource
;
481 if (!MakeBufferResource(pp_instance_
,
482 decoder_config
.extra_data(),
483 decoder_config
.extra_data_size(),
484 &extra_data_resource
)) {
487 ScopedPPResource
pp_resource(extra_data_resource
.get());
489 audio_decoder_init_cb_
.Set(pp_decoder_config
.request_id
, init_cb
);
490 plugin_decryption_interface_
->InitializeAudioDecoder(
491 pp_instance_
, &pp_decoder_config
, pp_resource
);
495 bool ContentDecryptorDelegate::InitializeVideoDecoder(
496 const media::VideoDecoderConfig
& decoder_config
,
497 const Decryptor::DecoderInitCB
& init_cb
) {
498 PP_VideoDecoderConfig pp_decoder_config
;
499 pp_decoder_config
.codec
=
500 MediaVideoCodecToPpVideoCodec(decoder_config
.codec());
501 pp_decoder_config
.profile
=
502 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config
.profile());
503 pp_decoder_config
.format
=
504 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config
.format());
505 pp_decoder_config
.width
= decoder_config
.coded_size().width();
506 pp_decoder_config
.height
= decoder_config
.coded_size().height();
507 pp_decoder_config
.request_id
= next_decryption_request_id_
++;
509 scoped_refptr
<PPB_Buffer_Impl
> extra_data_resource
;
510 if (!MakeBufferResource(pp_instance_
,
511 decoder_config
.extra_data(),
512 decoder_config
.extra_data_size(),
513 &extra_data_resource
)) {
516 ScopedPPResource
pp_resource(extra_data_resource
.get());
518 video_decoder_init_cb_
.Set(pp_decoder_config
.request_id
, init_cb
);
519 natural_size_
= decoder_config
.natural_size();
521 plugin_decryption_interface_
->InitializeVideoDecoder(
522 pp_instance_
, &pp_decoder_config
, pp_resource
);
526 bool ContentDecryptorDelegate::DeinitializeDecoder(
527 Decryptor::StreamType stream_type
) {
528 CancelDecode(stream_type
);
530 if (stream_type
== Decryptor::kVideo
)
531 natural_size_
= gfx::Size();
533 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
534 // stream type from media stack.
535 plugin_decryption_interface_
->DeinitializeDecoder(
536 pp_instance_
, MediaDecryptorStreamTypeToPpStreamType(stream_type
), 0);
540 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type
) {
541 CancelDecode(stream_type
);
543 // TODO(tomfinegan): Add decoder reset request tracking.
544 plugin_decryption_interface_
->ResetDecoder(
545 pp_instance_
, MediaDecryptorStreamTypeToPpStreamType(stream_type
), 0);
549 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
550 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
551 const Decryptor::AudioDecodeCB
& audio_decode_cb
) {
552 // |audio_input_resource_| is not being used by the plugin now
553 // because there is only one pending audio decode request at any time.
554 // This is enforced by the media pipeline.
555 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
556 if (!MakeMediaBufferResource(
557 Decryptor::kAudio
, encrypted_buffer
, &encrypted_resource
)) {
561 // The resource should not be NULL for non-EOS buffer.
562 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
565 const uint32_t request_id
= next_decryption_request_id_
++;
566 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id
;
568 PP_EncryptedBlockInfo block_info
= {};
569 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
573 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
575 // There is only one pending audio decode request at any time. This is
576 // enforced by the media pipeline. If this DCHECK is violated, our buffer
577 // reuse policy is not valid, and we may have race problems for the shared
579 audio_decode_cb_
.Set(request_id
, audio_decode_cb
);
581 ScopedPPResource
pp_resource(encrypted_resource
.get());
582 plugin_decryption_interface_
->DecryptAndDecode(
583 pp_instance_
, PP_DECRYPTORSTREAMTYPE_AUDIO
, pp_resource
, &block_info
);
587 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
588 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
589 const Decryptor::VideoDecodeCB
& video_decode_cb
) {
590 // |video_input_resource_| is not being used by the plugin now
591 // because there is only one pending video decode request at any time.
592 // This is enforced by the media pipeline.
593 scoped_refptr
<PPB_Buffer_Impl
> encrypted_resource
;
594 if (!MakeMediaBufferResource(
595 Decryptor::kVideo
, encrypted_buffer
, &encrypted_resource
)) {
599 // The resource should not be 0 for non-EOS buffer.
600 if (!encrypted_buffer
->end_of_stream() && !encrypted_resource
.get())
603 const uint32_t request_id
= next_decryption_request_id_
++;
604 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id
;
605 TRACE_EVENT_ASYNC_BEGIN0(
606 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id
);
608 PP_EncryptedBlockInfo block_info
= {};
609 if (!MakeEncryptedBlockInfo(encrypted_buffer
, request_id
, &block_info
)) {
613 SetBufferToFreeInTrackingInfo(&block_info
.tracking_info
);
615 // Only one pending video decode request at any time. This is enforced by the
616 // media pipeline. If this DCHECK is violated, our buffer
617 // reuse policy is not valid, and we may have race problems for the shared
619 video_decode_cb_
.Set(request_id
, video_decode_cb
);
621 // TODO(tomfinegan): Need to get stream type from media stack.
622 ScopedPPResource
pp_resource(encrypted_resource
.get());
623 plugin_decryption_interface_
->DecryptAndDecode(
624 pp_instance_
, PP_DECRYPTORSTREAMTYPE_VIDEO
, pp_resource
, &block_info
);
628 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id
) {
629 scoped_ptr
<CdmPromise
> promise
= TakePromise(promise_id
);
631 SimpleCdmPromise
* simple_promise(
632 static_cast<SimpleCdmPromise
*>(promise
.get()));
633 simple_promise
->resolve();
637 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
639 PP_Var web_session_id
) {
640 scoped_ptr
<CdmPromise
> promise
= TakePromise(promise_id
);
642 StringVar
* web_session_id_string
= StringVar::FromPPVar(web_session_id
);
643 DCHECK(web_session_id_string
);
646 NewSessionCdmPromise
* session_promise(
647 static_cast<NewSessionCdmPromise
*>(promise
.get()));
648 session_promise
->resolve(web_session_id_string
->value());
652 void ContentDecryptorDelegate::OnPromiseRejected(
654 PP_CdmExceptionCode exception_code
,
656 PP_Var error_description
) {
657 StringVar
* error_description_string
= StringVar::FromPPVar(error_description
);
658 DCHECK(error_description_string
);
660 scoped_ptr
<CdmPromise
> promise
= TakePromise(promise_id
);
662 promise
->reject(PpExceptionTypeToMediaException(exception_code
),
664 error_description_string
->value());
668 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id
,
670 PP_Var destination_url
) {
671 if (session_message_cb_
.is_null())
674 StringVar
* web_session_id_string
= StringVar::FromPPVar(web_session_id
);
675 DCHECK(web_session_id_string
);
677 ArrayBufferVar
* message_array_buffer
= ArrayBufferVar::FromPPVar(message
);
678 std::vector
<uint8
> message_vector
;
679 if (message_array_buffer
) {
680 const uint8
* data
= static_cast<const uint8
*>(message_array_buffer
->Map());
681 message_vector
.assign(data
, data
+ message_array_buffer
->ByteLength());
684 StringVar
* destination_url_string
= StringVar::FromPPVar(destination_url
);
685 DCHECK(destination_url_string
);
687 GURL verified_gurl
= GURL(destination_url_string
->value());
688 if (!verified_gurl
.is_valid() && !verified_gurl
.is_empty()) {
689 DLOG(WARNING
) << "SessionMessage default_url is invalid : "
690 << verified_gurl
.possibly_invalid_spec();
691 verified_gurl
= GURL::EmptyGURL(); // Replace invalid destination_url.
694 session_message_cb_
.Run(
695 web_session_id_string
->value(), message_vector
, verified_gurl
);
698 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id
) {
699 if (session_ready_cb_
.is_null())
702 StringVar
* web_session_id_string
= StringVar::FromPPVar(web_session_id
);
703 DCHECK(web_session_id_string
);
705 session_ready_cb_
.Run(web_session_id_string
->value());
708 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id
) {
709 if (session_closed_cb_
.is_null())
712 StringVar
* web_session_id_string
= StringVar::FromPPVar(web_session_id
);
713 DCHECK(web_session_id_string
);
715 session_closed_cb_
.Run(web_session_id_string
->value());
718 void ContentDecryptorDelegate::OnSessionError(
719 PP_Var web_session_id
,
720 PP_CdmExceptionCode exception_code
,
722 PP_Var error_description
) {
723 if (session_error_cb_
.is_null())
726 StringVar
* web_session_id_string
= StringVar::FromPPVar(web_session_id
);
727 DCHECK(web_session_id_string
);
729 StringVar
* error_description_string
= StringVar::FromPPVar(error_description
);
730 DCHECK(error_description_string
);
732 session_error_cb_
.Run(web_session_id_string
->value(),
733 PpExceptionTypeToMediaException(exception_code
),
735 error_description_string
->value());
738 void ContentDecryptorDelegate::DecoderInitializeDone(
739 PP_DecryptorStreamType decoder_type
,
742 if (decoder_type
== PP_DECRYPTORSTREAMTYPE_AUDIO
) {
743 // If the request ID is not valid or does not match what's saved, do
745 if (request_id
== 0 || !audio_decoder_init_cb_
.Matches(request_id
))
748 audio_decoder_init_cb_
.ResetAndReturn().Run(PP_ToBool(success
));
750 if (request_id
== 0 || !video_decoder_init_cb_
.Matches(request_id
))
754 natural_size_
= gfx::Size();
756 video_decoder_init_cb_
.ResetAndReturn().Run(PP_ToBool(success
));
760 void ContentDecryptorDelegate::DecoderDeinitializeDone(
761 PP_DecryptorStreamType decoder_type
,
762 uint32_t request_id
) {
763 // TODO(tomfinegan): Add decoder stop completion handling.
766 void ContentDecryptorDelegate::DecoderResetDone(
767 PP_DecryptorStreamType decoder_type
,
768 uint32_t request_id
) {
769 // TODO(tomfinegan): Add decoder reset completion handling.
772 void ContentDecryptorDelegate::DeliverBlock(
773 PP_Resource decrypted_block
,
774 const PP_DecryptedBlockInfo
* block_info
) {
777 FreeBuffer(block_info
->tracking_info
.buffer_id
);
779 const uint32_t request_id
= block_info
->tracking_info
.request_id
;
780 DVLOG(2) << "DeliverBlock() - request_id: " << request_id
;
782 // If the request ID is not valid or does not match what's saved, do nothing.
783 if (request_id
== 0) {
784 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id
;
788 Decryptor::DecryptCB decrypt_cb
;
789 if (audio_decrypt_cb_
.Matches(request_id
)) {
790 decrypt_cb
= audio_decrypt_cb_
.ResetAndReturn();
791 } else if (video_decrypt_cb_
.Matches(request_id
)) {
792 decrypt_cb
= video_decrypt_cb_
.ResetAndReturn();
794 DVLOG(1) << "DeliverBlock() - request_id " << request_id
<< " not found";
798 Decryptor::Status status
=
799 PpDecryptResultToMediaDecryptorStatus(block_info
->result
);
800 if (status
!= Decryptor::kSuccess
) {
801 decrypt_cb
.Run(status
, NULL
);
805 EnterResourceNoLock
<PPB_Buffer_API
> enter(decrypted_block
, true);
806 if (!enter
.succeeded()) {
807 decrypt_cb
.Run(Decryptor::kError
, NULL
);
810 BufferAutoMapper
mapper(enter
.object());
811 if (!mapper
.data() || !mapper
.size() ||
812 mapper
.size() < block_info
->data_size
) {
813 decrypt_cb
.Run(Decryptor::kError
, NULL
);
817 // TODO(tomfinegan): Find a way to take ownership of the shared memory
818 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
819 scoped_refptr
<media::DecoderBuffer
> decrypted_buffer(
820 media::DecoderBuffer::CopyFrom(static_cast<uint8
*>(mapper
.data()),
821 block_info
->data_size
));
822 decrypted_buffer
->set_timestamp(
823 base::TimeDelta::FromMicroseconds(block_info
->tracking_info
.timestamp
));
824 decrypt_cb
.Run(Decryptor::kSuccess
, decrypted_buffer
);
827 // Use a non-class-member function here so that if for some reason
828 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
829 // we can still get the shared memory unmapped.
830 static void BufferNoLongerNeeded(
831 const scoped_refptr
<PPB_Buffer_Impl
>& ppb_buffer
,
832 base::Closure buffer_no_longer_needed_cb
) {
834 buffer_no_longer_needed_cb
.Run();
837 // Enters |resource|, maps shared memory and returns pointer of mapped data.
838 // Returns NULL if any error occurs.
839 static uint8
* GetMappedBuffer(PP_Resource resource
,
840 scoped_refptr
<PPB_Buffer_Impl
>* ppb_buffer
) {
841 EnterResourceNoLock
<PPB_Buffer_API
> enter(resource
, true);
842 if (!enter
.succeeded())
845 uint8
* mapped_data
= static_cast<uint8
*>(enter
.object()->Map());
846 if (!enter
.object()->IsMapped() || !mapped_data
)
849 uint32_t mapped_size
= 0;
850 if (!enter
.object()->Describe(&mapped_size
) || !mapped_size
) {
851 enter
.object()->Unmap();
855 *ppb_buffer
= static_cast<PPB_Buffer_Impl
*>(enter
.object());
860 void ContentDecryptorDelegate::DeliverFrame(
861 PP_Resource decrypted_frame
,
862 const PP_DecryptedFrameInfo
* frame_info
) {
865 const uint32_t request_id
= frame_info
->tracking_info
.request_id
;
866 DVLOG(2) << "DeliverFrame() - request_id: " << request_id
;
868 // If the request ID is not valid or does not match what's saved, do nothing.
869 if (request_id
== 0 || !video_decode_cb_
.Matches(request_id
)) {
870 DVLOG(1) << "DeliverFrame() - request_id " << request_id
<< " not found";
871 FreeBuffer(frame_info
->tracking_info
.buffer_id
);
875 TRACE_EVENT_ASYNC_END0(
876 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id
);
878 Decryptor::VideoDecodeCB video_decode_cb
= video_decode_cb_
.ResetAndReturn();
880 Decryptor::Status status
=
881 PpDecryptResultToMediaDecryptorStatus(frame_info
->result
);
882 if (status
!= Decryptor::kSuccess
) {
883 DCHECK(!frame_info
->tracking_info
.buffer_id
);
884 video_decode_cb
.Run(status
, NULL
);
888 scoped_refptr
<PPB_Buffer_Impl
> ppb_buffer
;
889 uint8
* frame_data
= GetMappedBuffer(decrypted_frame
, &ppb_buffer
);
891 FreeBuffer(frame_info
->tracking_info
.buffer_id
);
892 video_decode_cb
.Run(Decryptor::kError
, NULL
);
896 gfx::Size
frame_size(frame_info
->width
, frame_info
->height
);
897 DCHECK_EQ(frame_info
->format
, PP_DECRYPTEDFRAMEFORMAT_YV12
);
899 scoped_refptr
<media::VideoFrame
> decoded_frame
=
900 media::VideoFrame::WrapExternalYuvData(
901 media::VideoFrame::YV12
,
903 gfx::Rect(frame_size
),
905 frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_Y
],
906 frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_U
],
907 frame_info
->strides
[PP_DECRYPTEDFRAMEPLANES_V
],
908 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_Y
],
909 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_U
],
910 frame_data
+ frame_info
->plane_offsets
[PP_DECRYPTEDFRAMEPLANES_V
],
911 base::TimeDelta::FromMicroseconds(
912 frame_info
->tracking_info
.timestamp
),
913 media::BindToCurrentLoop(
914 base::Bind(&BufferNoLongerNeeded
,
916 base::Bind(&ContentDecryptorDelegate::FreeBuffer
,
918 frame_info
->tracking_info
.buffer_id
))));
920 video_decode_cb
.Run(Decryptor::kSuccess
, decoded_frame
);
923 void ContentDecryptorDelegate::DeliverSamples(
924 PP_Resource audio_frames
,
925 const PP_DecryptedSampleInfo
* sample_info
) {
928 FreeBuffer(sample_info
->tracking_info
.buffer_id
);
930 const uint32_t request_id
= sample_info
->tracking_info
.request_id
;
931 DVLOG(2) << "DeliverSamples() - request_id: " << request_id
;
933 // If the request ID is not valid or does not match what's saved, do nothing.
934 if (request_id
== 0 || !audio_decode_cb_
.Matches(request_id
)) {
935 DVLOG(1) << "DeliverSamples() - request_id " << request_id
<< " not found";
939 Decryptor::AudioDecodeCB audio_decode_cb
= audio_decode_cb_
.ResetAndReturn();
941 const Decryptor::AudioBuffers empty_frames
;
943 Decryptor::Status status
=
944 PpDecryptResultToMediaDecryptorStatus(sample_info
->result
);
945 if (status
!= Decryptor::kSuccess
) {
946 audio_decode_cb
.Run(status
, empty_frames
);
950 media::SampleFormat sample_format
=
951 PpDecryptedSampleFormatToMediaSampleFormat(sample_info
->format
);
953 Decryptor::AudioBuffers audio_frame_list
;
954 if (!DeserializeAudioFrames(audio_frames
,
955 sample_info
->data_size
,
957 &audio_frame_list
)) {
958 NOTREACHED() << "CDM did not serialize the buffer correctly.";
959 audio_decode_cb
.Run(Decryptor::kError
, empty_frames
);
963 audio_decode_cb
.Run(Decryptor::kSuccess
, audio_frame_list
);
966 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
967 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type
) {
968 switch (stream_type
) {
969 case Decryptor::kAudio
:
970 // Release the shared memory as it can still be in use by the plugin.
971 // The next DecryptAndDecode() call will need to allocate a new shared
973 audio_input_resource_
= NULL
;
974 if (!audio_decode_cb_
.is_null())
975 audio_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
,
976 Decryptor::AudioBuffers());
978 case Decryptor::kVideo
:
979 // Release the shared memory as it can still be in use by the plugin.
980 // The next DecryptAndDecode() call will need to allocate a new shared
982 video_input_resource_
= NULL
;
983 if (!video_decode_cb_
.is_null())
984 video_decode_cb_
.ResetAndReturn().Run(Decryptor::kSuccess
, NULL
);
991 bool ContentDecryptorDelegate::MakeMediaBufferResource(
992 Decryptor::StreamType stream_type
,
993 const scoped_refptr
<media::DecoderBuffer
>& encrypted_buffer
,
994 scoped_refptr
<PPB_Buffer_Impl
>* resource
) {
995 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
997 // End of stream buffers are represented as null resources.
998 if (encrypted_buffer
->end_of_stream()) {
1003 DCHECK(stream_type
== Decryptor::kAudio
|| stream_type
== Decryptor::kVideo
);
1004 scoped_refptr
<PPB_Buffer_Impl
>& media_resource
=
1005 (stream_type
== Decryptor::kAudio
) ? audio_input_resource_
1006 : video_input_resource_
;
1008 const size_t data_size
= static_cast<size_t>(encrypted_buffer
->data_size());
1009 if (!media_resource
.get() || media_resource
->size() < data_size
) {
1010 // Either the buffer hasn't been created yet, or we have one that isn't big
1011 // enough to fit |size| bytes.
1013 // Media resource size starts from |kMinimumMediaBufferSize| and grows
1014 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1015 // which is usually expensive. Since input media buffers are compressed,
1016 // they are usually small (compared to outputs). The over-allocated memory
1017 // should be negligible.
1018 const uint32_t kMinimumMediaBufferSize
= 1024;
1019 uint32_t media_resource_size
=
1020 media_resource
.get() ? media_resource
->size() : kMinimumMediaBufferSize
;
1021 while (media_resource_size
< data_size
)
1022 media_resource_size
*= 2;
1024 DVLOG(2) << "Size of media buffer for "
1025 << ((stream_type
== Decryptor::kAudio
) ? "audio" : "video")
1026 << " stream bumped to " << media_resource_size
1027 << " bytes to fit input.";
1029 PPB_Buffer_Impl::CreateResource(pp_instance_
, media_resource_size
);
1030 if (!media_resource
.get())
1034 BufferAutoMapper
mapper(media_resource
.get());
1035 if (!mapper
.data() || mapper
.size() < data_size
) {
1036 media_resource
= NULL
;
1039 memcpy(mapper
.data(), encrypted_buffer
->data(), data_size
);
1041 *resource
= media_resource
;
1045 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id
) {
1047 free_buffers_
.push(buffer_id
);
1050 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1051 PP_DecryptTrackingInfo
* tracking_info
) {
1052 DCHECK_EQ(tracking_info
->buffer_id
, 0u);
1054 if (free_buffers_
.empty())
1057 tracking_info
->buffer_id
= free_buffers_
.front();
1058 free_buffers_
.pop();
1061 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1062 PP_Resource audio_frames
,
1064 media::SampleFormat sample_format
,
1065 Decryptor::AudioBuffers
* frames
) {
1067 EnterResourceNoLock
<PPB_Buffer_API
> enter(audio_frames
, true);
1068 if (!enter
.succeeded())
1071 BufferAutoMapper
mapper(enter
.object());
1072 if (!mapper
.data() || !mapper
.size() ||
1073 mapper
.size() < static_cast<uint32_t>(data_size
))
1076 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1077 // the copy. Since it is possible to get multiple buffers, it would need to be
1078 // sliced and ref counted appropriately. http://crbug.com/255576.
1079 const uint8
* cur
= static_cast<uint8
*>(mapper
.data());
1080 size_t bytes_left
= data_size
;
1082 const int audio_bytes_per_frame
=
1083 media::SampleFormatToBytesPerChannel(sample_format
) *
1084 audio_channel_count_
;
1085 if (audio_bytes_per_frame
<= 0)
1088 // Allocate space for the channel pointers given to AudioBuffer.
1089 std::vector
<const uint8
*> channel_ptrs(audio_channel_count_
,
1090 static_cast<const uint8
*>(NULL
));
1092 int64 timestamp
= 0;
1093 int64 frame_size
= -1;
1094 const size_t kHeaderSize
= sizeof(timestamp
) + sizeof(frame_size
);
1096 if (bytes_left
< kHeaderSize
)
1099 memcpy(×tamp
, cur
, sizeof(timestamp
));
1100 cur
+= sizeof(timestamp
);
1101 bytes_left
-= sizeof(timestamp
);
1103 memcpy(&frame_size
, cur
, sizeof(frame_size
));
1104 cur
+= sizeof(frame_size
);
1105 bytes_left
-= sizeof(frame_size
);
1107 // We should *not* have empty frames in the list.
1108 if (frame_size
<= 0 ||
1109 bytes_left
< base::checked_cast
<size_t>(frame_size
)) {
1113 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1114 // one in the case of interleaved data.
1115 const int size_per_channel
= frame_size
/ audio_channel_count_
;
1116 for (int i
= 0; i
< audio_channel_count_
; ++i
)
1117 channel_ptrs
[i
] = cur
+ i
* size_per_channel
;
1119 const int frame_count
= frame_size
/ audio_bytes_per_frame
;
1120 scoped_refptr
<media::AudioBuffer
> frame
= media::AudioBuffer::CopyFrom(
1122 audio_channel_layout_
,
1123 audio_channel_count_
,
1124 audio_samples_per_second_
,
1127 base::TimeDelta::FromMicroseconds(timestamp
));
1128 frames
->push_back(frame
);
1131 bytes_left
-= frame_size
;
1132 } while (bytes_left
> 0);
1137 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1138 if (!audio_decoder_init_cb_
.is_null())
1139 audio_decoder_init_cb_
.ResetAndReturn().Run(false);
1141 if (!video_decoder_init_cb_
.is_null())
1142 video_decoder_init_cb_
.ResetAndReturn().Run(false);
1144 audio_input_resource_
= NULL
;
1145 video_input_resource_
= NULL
;
1147 if (!audio_decrypt_cb_
.is_null())
1148 audio_decrypt_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1150 if (!video_decrypt_cb_
.is_null())
1151 video_decrypt_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1153 if (!audio_decode_cb_
.is_null()) {
1154 const media::Decryptor::AudioBuffers empty_frames
;
1155 audio_decode_cb_
.ResetAndReturn().Run(media::Decryptor::kError
,
1159 if (!video_decode_cb_
.is_null())
1160 video_decode_cb_
.ResetAndReturn().Run(media::Decryptor::kError
, NULL
);
1162 // Reject all outstanding promises.
1163 for (PromiseMap::iterator it
= promises_
.begin(); it
!= promises_
.end();
1166 media::MediaKeys::UNKNOWN_ERROR
, 0, "Failure calling plugin.");
1171 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr
<CdmPromise
> promise
) {
1172 uint32_t promise_id
= next_promise_id_
++;
1173 promises_
.add(promise_id
, promise
.Pass());
1177 scoped_ptr
<CdmPromise
> ContentDecryptorDelegate::TakePromise(
1178 uint32_t promise_id
) {
1179 PromiseMap::iterator it
= promises_
.find(promise_id
);
1180 if (it
== promises_
.end())
1181 return scoped_ptr
<CdmPromise
>();
1182 return promises_
.take_and_erase(it
);
1185 } // namespace content