1 // Copyright 2013 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 "media/cdm/ppapi/cdm_adapter.h"
7 #include "media/cdm/ppapi/cdm_helpers.h"
9 #if defined(CHECK_DOCUMENT_URL)
10 #include "ppapi/cpp/dev/url_util_dev.h"
11 #include "ppapi/cpp/instance_handle.h"
12 #endif // defined(CHECK_DOCUMENT_URL)
17 return pp::Module::Get()->core()->IsMainThread();
20 // Posts a task to run |cb| on the main thread. The task is posted even if the
21 // current thread is the main thread.
22 void PostOnMain(pp::CompletionCallback cb
) {
23 pp::Module::Get()->core()->CallOnMainThread(0, cb
, PP_OK
);
26 // Ensures |cb| is called on the main thread, either because the current thread
27 // is the main thread or by posting it to the main thread.
28 void CallOnMain(pp::CompletionCallback cb
) {
29 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
30 // off the main thread yet. Remove this once the change lands.
37 // Configures a cdm::InputBuffer. |subsamples| must exist as long as
38 // |input_buffer| is in use.
39 void ConfigureInputBuffer(
40 const pp::Buffer_Dev
& encrypted_buffer
,
41 const PP_EncryptedBlockInfo
& encrypted_block_info
,
42 std::vector
<cdm::SubsampleEntry
>* subsamples
,
43 cdm::InputBuffer
* input_buffer
) {
44 PP_DCHECK(subsamples
);
45 PP_DCHECK(!encrypted_buffer
.is_null());
47 input_buffer
->data
= static_cast<uint8_t*>(encrypted_buffer
.data());
48 input_buffer
->data_size
= encrypted_block_info
.data_size
;
49 PP_DCHECK(encrypted_buffer
.size() >= input_buffer
->data_size
);
50 input_buffer
->data_offset
= encrypted_block_info
.data_offset
;
52 PP_DCHECK(encrypted_block_info
.key_id_size
<=
53 arraysize(encrypted_block_info
.key_id
));
54 input_buffer
->key_id_size
= encrypted_block_info
.key_id_size
;
55 input_buffer
->key_id
= input_buffer
->key_id_size
> 0 ?
56 encrypted_block_info
.key_id
: NULL
;
58 PP_DCHECK(encrypted_block_info
.iv_size
<= arraysize(encrypted_block_info
.iv
));
59 input_buffer
->iv_size
= encrypted_block_info
.iv_size
;
60 input_buffer
->iv
= encrypted_block_info
.iv_size
> 0 ?
61 encrypted_block_info
.iv
: NULL
;
63 input_buffer
->num_subsamples
= encrypted_block_info
.num_subsamples
;
64 if (encrypted_block_info
.num_subsamples
> 0) {
65 subsamples
->reserve(encrypted_block_info
.num_subsamples
);
67 for (uint32_t i
= 0; i
< encrypted_block_info
.num_subsamples
; ++i
) {
68 subsamples
->push_back(cdm::SubsampleEntry(
69 encrypted_block_info
.subsamples
[i
].clear_bytes
,
70 encrypted_block_info
.subsamples
[i
].cipher_bytes
));
73 input_buffer
->subsamples
= &(*subsamples
)[0];
76 input_buffer
->timestamp
= encrypted_block_info
.tracking_info
.timestamp
;
79 PP_DecryptResult
CdmStatusToPpDecryptResult(cdm::Status status
) {
82 return PP_DECRYPTRESULT_SUCCESS
;
84 return PP_DECRYPTRESULT_DECRYPT_NOKEY
;
85 case cdm::kNeedMoreData
:
86 return PP_DECRYPTRESULT_NEEDMOREDATA
;
87 case cdm::kDecryptError
:
88 return PP_DECRYPTRESULT_DECRYPT_ERROR
;
89 case cdm::kDecodeError
:
90 return PP_DECRYPTRESULT_DECODE_ERROR
;
93 return PP_DECRYPTRESULT_DECODE_ERROR
;
97 PP_DecryptedFrameFormat
CdmVideoFormatToPpDecryptedFrameFormat(
98 cdm::VideoFormat format
) {
101 return PP_DECRYPTEDFRAMEFORMAT_YV12
;
103 return PP_DECRYPTEDFRAMEFORMAT_I420
;
105 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN
;
109 PP_DecryptedSampleFormat
CdmAudioFormatToPpDecryptedSampleFormat(
110 cdm::AudioFormat format
) {
112 case cdm::kAudioFormatU8
:
113 return PP_DECRYPTEDSAMPLEFORMAT_U8
;
114 case cdm::kAudioFormatS16
:
115 return PP_DECRYPTEDSAMPLEFORMAT_S16
;
116 case cdm::kAudioFormatS32
:
117 return PP_DECRYPTEDSAMPLEFORMAT_S32
;
118 case cdm::kAudioFormatF32
:
119 return PP_DECRYPTEDSAMPLEFORMAT_F32
;
120 case cdm::kAudioFormatPlanarS16
:
121 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16
;
122 case cdm::kAudioFormatPlanarF32
:
123 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32
;
125 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN
;
129 cdm::AudioDecoderConfig::AudioCodec
PpAudioCodecToCdmAudioCodec(
130 PP_AudioCodec codec
) {
132 case PP_AUDIOCODEC_VORBIS
:
133 return cdm::AudioDecoderConfig::kCodecVorbis
;
134 case PP_AUDIOCODEC_AAC
:
135 return cdm::AudioDecoderConfig::kCodecAac
;
137 return cdm::AudioDecoderConfig::kUnknownAudioCodec
;
141 cdm::VideoDecoderConfig::VideoCodec
PpVideoCodecToCdmVideoCodec(
142 PP_VideoCodec codec
) {
144 case PP_VIDEOCODEC_VP8
:
145 return cdm::VideoDecoderConfig::kCodecVp8
;
146 case PP_VIDEOCODEC_H264
:
147 return cdm::VideoDecoderConfig::kCodecH264
;
149 return cdm::VideoDecoderConfig::kUnknownVideoCodec
;
153 cdm::VideoDecoderConfig::VideoCodecProfile
PpVCProfileToCdmVCProfile(
154 PP_VideoCodecProfile profile
) {
156 case PP_VIDEOCODECPROFILE_VP8_MAIN
:
157 return cdm::VideoDecoderConfig::kVp8ProfileMain
;
158 case PP_VIDEOCODECPROFILE_H264_BASELINE
:
159 return cdm::VideoDecoderConfig::kH264ProfileBaseline
;
160 case PP_VIDEOCODECPROFILE_H264_MAIN
:
161 return cdm::VideoDecoderConfig::kH264ProfileMain
;
162 case PP_VIDEOCODECPROFILE_H264_EXTENDED
:
163 return cdm::VideoDecoderConfig::kH264ProfileExtended
;
164 case PP_VIDEOCODECPROFILE_H264_HIGH
:
165 return cdm::VideoDecoderConfig::kH264ProfileHigh
;
166 case PP_VIDEOCODECPROFILE_H264_HIGH_10
:
167 return cdm::VideoDecoderConfig::kH264ProfileHigh10
;
168 case PP_VIDEOCODECPROFILE_H264_HIGH_422
:
169 return cdm::VideoDecoderConfig::kH264ProfileHigh422
;
170 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE
:
171 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive
;
173 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile
;
177 cdm::VideoFormat
PpDecryptedFrameFormatToCdmVideoFormat(
178 PP_DecryptedFrameFormat format
) {
180 case PP_DECRYPTEDFRAMEFORMAT_YV12
:
182 case PP_DECRYPTEDFRAMEFORMAT_I420
:
185 return cdm::kUnknownVideoFormat
;
189 cdm::StreamType
PpDecryptorStreamTypeToCdmStreamType(
190 PP_DecryptorStreamType stream_type
) {
191 switch (stream_type
) {
192 case PP_DECRYPTORSTREAMTYPE_AUDIO
:
193 return cdm::kStreamTypeAudio
;
194 case PP_DECRYPTORSTREAMTYPE_VIDEO
:
195 return cdm::kStreamTypeVideo
;
199 return cdm::kStreamTypeVideo
;
206 CdmAdapter::CdmAdapter(PP_Instance instance
, pp::Module
* module
)
207 : pp::Instance(instance
),
208 pp::ContentDecryptor_Private(this),
209 #if defined(OS_CHROMEOS)
210 output_protection_(this),
211 platform_verification_(this),
212 challenge_in_progress_(false),
213 output_link_mask_(0),
214 output_protection_mask_(0),
215 query_output_protection_in_progress_(false),
219 deferred_initialize_audio_decoder_(false),
220 deferred_audio_decoder_config_id_(0),
221 deferred_initialize_video_decoder_(false),
222 deferred_video_decoder_config_id_(0) {
223 callback_factory_
.Initialize(this);
226 CdmAdapter::~CdmAdapter() {}
228 bool CdmAdapter::CreateCdmInstance(const std::string
& key_system
) {
230 cdm_
= make_linked_ptr(CdmWrapper::Create(
231 key_system
.data(), key_system
.size(), GetCdmHost
, this));
232 return (cdm_
!= NULL
);
235 // No KeyErrors should be reported in this function because they cannot be
236 // bubbled up in the WD EME API. Those errors will be reported during session
237 // creation (aka GenerateKeyRequest).
238 void CdmAdapter::Initialize(const std::string
& key_system
,
239 bool can_challenge_platform
) {
240 PP_DCHECK(!key_system
.empty());
241 PP_DCHECK(key_system_
.empty() || (key_system_
== key_system
&& cdm_
));
243 if (!cdm_
&& !CreateCdmInstance(key_system
))
247 key_system_
= key_system
;
250 void CdmAdapter::GenerateKeyRequest(const std::string
& type
,
251 pp::VarArrayBuffer init_data
) {
252 // Initialize() doesn't report an error, so GenerateKeyRequest() can be called
253 // even if Initialize() failed.
255 SendUnknownKeyError(key_system_
, std::string());
259 #if defined(CHECK_DOCUMENT_URL)
260 PP_URLComponents_Dev url_components
= {};
261 pp::Var href
= pp::URLUtil_Dev::Get()->GetDocumentURL(
262 pp::InstanceHandle(pp_instance()), &url_components
);
263 PP_DCHECK(href
.is_string());
264 PP_DCHECK(!href
.AsString().empty());
265 PP_DCHECK(url_components
.host
.begin
);
266 PP_DCHECK(0 < url_components
.host
.len
);
267 #endif // defined(CHECK_DOCUMENT_URL)
269 cdm::Status status
= cdm_
->GenerateKeyRequest(
270 type
.data(), type
.size(),
271 static_cast<const uint8_t*>(init_data
.Map()),
272 init_data
.ByteLength());
273 PP_DCHECK(status
== cdm::kSuccess
|| status
== cdm::kSessionError
);
274 if (status
!= cdm::kSuccess
)
275 SendUnknownKeyError(key_system_
, std::string());
278 void CdmAdapter::AddKey(const std::string
& session_id
,
279 pp::VarArrayBuffer key
,
280 pp::VarArrayBuffer init_data
) {
281 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions.
282 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976.
284 SendUnknownKeyError(key_system_
, session_id
);
288 const uint8_t* key_ptr
= static_cast<const uint8_t*>(key
.Map());
289 const uint32_t key_size
= key
.ByteLength();
290 const uint8_t* init_data_ptr
= static_cast<const uint8_t*>(init_data
.Map());
291 const uint32_t init_data_size
= init_data
.ByteLength();
292 PP_DCHECK(!init_data_ptr
== !init_data_size
);
294 if (!key_ptr
|| !key_size
) {
295 SendUnknownKeyError(key_system_
, session_id
);
299 cdm::Status status
= cdm_
->AddKey(session_id
.data(), session_id
.size(),
301 init_data_ptr
, init_data_size
);
302 PP_DCHECK(status
== cdm::kSuccess
|| status
== cdm::kSessionError
);
303 if (status
!= cdm::kSuccess
) {
304 SendUnknownKeyError(key_system_
, session_id
);
308 SendKeyAdded(key_system_
, session_id
);
311 void CdmAdapter::CancelKeyRequest(const std::string
& session_id
) {
312 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions.
313 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976.
315 SendUnknownKeyError(key_system_
, session_id
);
319 cdm::Status status
= cdm_
->CancelKeyRequest(session_id
.data(),
321 PP_DCHECK(status
== cdm::kSuccess
|| status
== cdm::kSessionError
);
322 if (status
!= cdm::kSuccess
)
323 SendUnknownKeyError(key_system_
, session_id
);
326 // Note: In the following decryption/decoding related functions, errors are NOT
327 // reported via KeyError, but are reported via corresponding PPB calls.
329 void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer
,
330 const PP_EncryptedBlockInfo
& encrypted_block_info
) {
331 PP_DCHECK(!encrypted_buffer
.is_null());
333 // Release a buffer that the caller indicated it is finished with.
334 allocator_
.Release(encrypted_block_info
.tracking_info
.buffer_id
);
336 cdm::Status status
= cdm::kDecryptError
;
337 LinkedDecryptedBlock
decrypted_block(new DecryptedBlockImpl());
340 cdm::InputBuffer input_buffer
;
341 std::vector
<cdm::SubsampleEntry
> subsamples
;
342 ConfigureInputBuffer(encrypted_buffer
, encrypted_block_info
, &subsamples
,
344 status
= cdm_
->Decrypt(input_buffer
, decrypted_block
.get());
345 PP_DCHECK(status
!= cdm::kSuccess
||
346 (decrypted_block
->DecryptedBuffer() &&
347 decrypted_block
->DecryptedBuffer()->Size()));
350 CallOnMain(callback_factory_
.NewCallback(
351 &CdmAdapter::DeliverBlock
,
354 encrypted_block_info
.tracking_info
));
357 void CdmAdapter::InitializeAudioDecoder(
358 const PP_AudioDecoderConfig
& decoder_config
,
359 pp::Buffer_Dev extra_data_buffer
) {
360 PP_DCHECK(!deferred_initialize_audio_decoder_
);
361 PP_DCHECK(deferred_audio_decoder_config_id_
== 0);
362 cdm::Status status
= cdm::kSessionError
;
364 cdm::AudioDecoderConfig cdm_decoder_config
;
365 cdm_decoder_config
.codec
=
366 PpAudioCodecToCdmAudioCodec(decoder_config
.codec
);
367 cdm_decoder_config
.channel_count
= decoder_config
.channel_count
;
368 cdm_decoder_config
.bits_per_channel
= decoder_config
.bits_per_channel
;
369 cdm_decoder_config
.samples_per_second
= decoder_config
.samples_per_second
;
370 cdm_decoder_config
.extra_data
=
371 static_cast<uint8_t*>(extra_data_buffer
.data());
372 cdm_decoder_config
.extra_data_size
= extra_data_buffer
.size();
373 status
= cdm_
->InitializeAudioDecoder(cdm_decoder_config
);
376 if (status
== cdm::kDeferredInitialization
) {
377 deferred_initialize_audio_decoder_
= true;
378 deferred_audio_decoder_config_id_
= decoder_config
.request_id
;
382 CallOnMain(callback_factory_
.NewCallback(
383 &CdmAdapter::DecoderInitializeDone
,
384 PP_DECRYPTORSTREAMTYPE_AUDIO
,
385 decoder_config
.request_id
,
386 status
== cdm::kSuccess
));
389 void CdmAdapter::InitializeVideoDecoder(
390 const PP_VideoDecoderConfig
& decoder_config
,
391 pp::Buffer_Dev extra_data_buffer
) {
392 PP_DCHECK(!deferred_initialize_video_decoder_
);
393 PP_DCHECK(deferred_video_decoder_config_id_
== 0);
394 cdm::Status status
= cdm::kSessionError
;
396 cdm::VideoDecoderConfig cdm_decoder_config
;
397 cdm_decoder_config
.codec
=
398 PpVideoCodecToCdmVideoCodec(decoder_config
.codec
);
399 cdm_decoder_config
.profile
=
400 PpVCProfileToCdmVCProfile(decoder_config
.profile
);
401 cdm_decoder_config
.format
=
402 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config
.format
);
403 cdm_decoder_config
.coded_size
.width
= decoder_config
.width
;
404 cdm_decoder_config
.coded_size
.height
= decoder_config
.height
;
405 cdm_decoder_config
.extra_data
=
406 static_cast<uint8_t*>(extra_data_buffer
.data());
407 cdm_decoder_config
.extra_data_size
= extra_data_buffer
.size();
408 status
= cdm_
->InitializeVideoDecoder(cdm_decoder_config
);
411 if (status
== cdm::kDeferredInitialization
) {
412 deferred_initialize_video_decoder_
= true;
413 deferred_video_decoder_config_id_
= decoder_config
.request_id
;
417 CallOnMain(callback_factory_
.NewCallback(
418 &CdmAdapter::DecoderInitializeDone
,
419 PP_DECRYPTORSTREAMTYPE_VIDEO
,
420 decoder_config
.request_id
,
421 status
== cdm::kSuccess
));
424 void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type
,
425 uint32_t request_id
) {
426 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
428 cdm_
->DeinitializeDecoder(
429 PpDecryptorStreamTypeToCdmStreamType(decoder_type
));
432 CallOnMain(callback_factory_
.NewCallback(
433 &CdmAdapter::DecoderDeinitializeDone
,
438 void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type
,
439 uint32_t request_id
) {
440 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
442 cdm_
->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type
));
444 CallOnMain(callback_factory_
.NewCallback(&CdmAdapter::DecoderResetDone
,
449 void CdmAdapter::DecryptAndDecode(
450 PP_DecryptorStreamType decoder_type
,
451 pp::Buffer_Dev encrypted_buffer
,
452 const PP_EncryptedBlockInfo
& encrypted_block_info
) {
453 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
454 // Release a buffer that the caller indicated it is finished with.
455 allocator_
.Release(encrypted_block_info
.tracking_info
.buffer_id
);
457 cdm::InputBuffer input_buffer
;
458 std::vector
<cdm::SubsampleEntry
> subsamples
;
459 if (cdm_
&& !encrypted_buffer
.is_null()) {
460 ConfigureInputBuffer(encrypted_buffer
,
461 encrypted_block_info
,
466 cdm::Status status
= cdm::kDecodeError
;
468 switch (decoder_type
) {
469 case PP_DECRYPTORSTREAMTYPE_VIDEO
: {
470 LinkedVideoFrame
video_frame(new VideoFrameImpl());
472 status
= cdm_
->DecryptAndDecodeFrame(input_buffer
, video_frame
.get());
473 CallOnMain(callback_factory_
.NewCallback(
474 &CdmAdapter::DeliverFrame
,
477 encrypted_block_info
.tracking_info
));
481 case PP_DECRYPTORSTREAMTYPE_AUDIO
: {
482 LinkedAudioFrames
audio_frames(new AudioFramesImpl());
484 status
= cdm_
->DecryptAndDecodeSamples(input_buffer
,
487 CallOnMain(callback_factory_
.NewCallback(
488 &CdmAdapter::DeliverSamples
,
491 encrypted_block_info
.tracking_info
));
501 cdm::Buffer
* CdmAdapter::Allocate(uint32_t capacity
) {
502 return allocator_
.Allocate(capacity
);
505 void CdmAdapter::SetTimer(int64_t delay_ms
, void* context
) {
506 // NOTE: doesn't really need to run on the main thread; could just as well run
507 // on a helper thread if |cdm_| were thread-friendly and care was taken. We
508 // only use CallOnMainThread() here to get delayed-execution behavior.
509 pp::Module::Get()->core()->CallOnMainThread(
511 callback_factory_
.NewCallback(&CdmAdapter::TimerExpired
, context
),
515 void CdmAdapter::TimerExpired(int32_t result
, void* context
) {
516 PP_DCHECK(result
== PP_OK
);
517 cdm_
->TimerExpired(context
);
520 double CdmAdapter::GetCurrentWallTimeInSeconds() {
521 return pp::Module::Get()->core()->GetTime();
524 void CdmAdapter::SendKeyMessage(
525 const char* session_id
, uint32_t session_id_length
,
526 const char* message
, uint32_t message_length
,
527 const char* default_url
, uint32_t default_url_length
) {
528 PP_DCHECK(!key_system_
.empty());
529 PostOnMain(callback_factory_
.NewCallback(
530 &CdmAdapter::KeyMessage
,
531 SessionInfo(key_system_
,
532 std::string(session_id
, session_id_length
)),
533 std::vector
<uint8
>(message
, message
+ message_length
),
534 std::string(default_url
, default_url_length
)));
537 void CdmAdapter::SendKeyError(const char* session_id
,
538 uint32_t session_id_length
,
539 cdm::MediaKeyError error_code
,
540 uint32_t system_code
) {
541 SendKeyErrorInternal(key_system_
,
542 std::string(session_id
, session_id_length
),
547 void CdmAdapter::GetPrivateData(int32_t* instance
,
548 GetPrivateInterface
* get_interface
) {
549 *instance
= pp_instance();
550 *get_interface
= pp::Module::Get()->get_browser_interface();
553 void CdmAdapter::SendUnknownKeyError(const std::string
& key_system
,
554 const std::string
& session_id
) {
555 SendKeyErrorInternal(key_system
, session_id
, cdm::kUnknownError
, 0);
558 void CdmAdapter::SendKeyAdded(const std::string
& key_system
,
559 const std::string
& session_id
) {
560 PostOnMain(callback_factory_
.NewCallback(
561 &CdmAdapter::KeyAdded
,
562 SessionInfo(key_system_
, session_id
)));
565 void CdmAdapter::SendKeyErrorInternal(const std::string
& key_system
,
566 const std::string
& session_id
,
567 cdm::MediaKeyError error_code
,
568 uint32_t system_code
) {
569 PostOnMain(callback_factory_
.NewCallback(&CdmAdapter::KeyError
,
570 SessionInfo(key_system_
, session_id
),
575 void CdmAdapter::KeyAdded(int32_t result
, const SessionInfo
& session_info
) {
576 PP_DCHECK(result
== PP_OK
);
577 PP_DCHECK(!session_info
.key_system
.empty());
578 pp::ContentDecryptor_Private::KeyAdded(session_info
.key_system
,
579 session_info
.session_id
);
582 void CdmAdapter::KeyMessage(int32_t result
,
583 const SessionInfo
& session_info
,
584 const std::vector
<uint8
>& message
,
585 const std::string
& default_url
) {
586 PP_DCHECK(result
== PP_OK
);
587 PP_DCHECK(!session_info
.key_system
.empty());
589 pp::VarArrayBuffer
message_array_buffer(message
.size());
590 if (message
.size() > 0) {
591 memcpy(message_array_buffer
.Map(), message
.data(), message
.size());
594 pp::ContentDecryptor_Private::KeyMessage(
595 session_info
.key_system
, session_info
.session_id
,
596 message_array_buffer
, default_url
);
599 void CdmAdapter::KeyError(int32_t result
,
600 const SessionInfo
& session_info
,
601 cdm::MediaKeyError error_code
,
602 uint32_t system_code
) {
603 PP_DCHECK(result
== PP_OK
);
604 pp::ContentDecryptor_Private::KeyError(
605 session_info
.key_system
, session_info
.session_id
,
606 error_code
, system_code
);
609 void CdmAdapter::DeliverBlock(int32_t result
,
610 const cdm::Status
& status
,
611 const LinkedDecryptedBlock
& decrypted_block
,
612 const PP_DecryptTrackingInfo
& tracking_info
) {
613 PP_DCHECK(result
== PP_OK
);
614 PP_DecryptedBlockInfo decrypted_block_info
;
615 decrypted_block_info
.tracking_info
= tracking_info
;
616 decrypted_block_info
.tracking_info
.timestamp
= decrypted_block
->Timestamp();
617 decrypted_block_info
.tracking_info
.buffer_id
= 0;
618 decrypted_block_info
.data_size
= 0;
619 decrypted_block_info
.result
= CdmStatusToPpDecryptResult(status
);
621 pp::Buffer_Dev buffer
;
623 if (decrypted_block_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
624 PP_DCHECK(decrypted_block
.get() && decrypted_block
->DecryptedBuffer());
625 if (!decrypted_block
.get() || !decrypted_block
->DecryptedBuffer()) {
627 decrypted_block_info
.result
= PP_DECRYPTRESULT_DECRYPT_ERROR
;
629 PpbBuffer
* ppb_buffer
=
630 static_cast<PpbBuffer
*>(decrypted_block
->DecryptedBuffer());
631 buffer
= ppb_buffer
->buffer_dev();
632 decrypted_block_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
633 decrypted_block_info
.data_size
= ppb_buffer
->Size();
637 pp::ContentDecryptor_Private::DeliverBlock(buffer
, decrypted_block_info
);
640 void CdmAdapter::DecoderInitializeDone(int32_t result
,
641 PP_DecryptorStreamType decoder_type
,
644 PP_DCHECK(result
== PP_OK
);
645 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type
,
650 void CdmAdapter::DecoderDeinitializeDone(int32_t result
,
651 PP_DecryptorStreamType decoder_type
,
652 uint32_t request_id
) {
653 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type
,
657 void CdmAdapter::DecoderResetDone(int32_t result
,
658 PP_DecryptorStreamType decoder_type
,
659 uint32_t request_id
) {
660 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type
, request_id
);
663 void CdmAdapter::DeliverFrame(
665 const cdm::Status
& status
,
666 const LinkedVideoFrame
& video_frame
,
667 const PP_DecryptTrackingInfo
& tracking_info
) {
668 PP_DCHECK(result
== PP_OK
);
669 PP_DecryptedFrameInfo decrypted_frame_info
;
670 decrypted_frame_info
.tracking_info
.request_id
= tracking_info
.request_id
;
671 decrypted_frame_info
.tracking_info
.buffer_id
= 0;
672 decrypted_frame_info
.result
= CdmStatusToPpDecryptResult(status
);
674 pp::Buffer_Dev buffer
;
676 if (decrypted_frame_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
677 if (!IsValidVideoFrame(video_frame
)) {
679 decrypted_frame_info
.result
= PP_DECRYPTRESULT_DECODE_ERROR
;
681 PpbBuffer
* ppb_buffer
=
682 static_cast<PpbBuffer
*>(video_frame
->FrameBuffer());
684 buffer
= ppb_buffer
->buffer_dev();
686 decrypted_frame_info
.tracking_info
.timestamp
= video_frame
->Timestamp();
687 decrypted_frame_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
688 decrypted_frame_info
.format
=
689 CdmVideoFormatToPpDecryptedFrameFormat(video_frame
->Format());
690 decrypted_frame_info
.width
= video_frame
->Size().width
;
691 decrypted_frame_info
.height
= video_frame
->Size().height
;
692 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_Y
] =
693 video_frame
->PlaneOffset(cdm::VideoFrame::kYPlane
);
694 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_U
] =
695 video_frame
->PlaneOffset(cdm::VideoFrame::kUPlane
);
696 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_V
] =
697 video_frame
->PlaneOffset(cdm::VideoFrame::kVPlane
);
698 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_Y
] =
699 video_frame
->Stride(cdm::VideoFrame::kYPlane
);
700 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_U
] =
701 video_frame
->Stride(cdm::VideoFrame::kUPlane
);
702 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_V
] =
703 video_frame
->Stride(cdm::VideoFrame::kVPlane
);
706 pp::ContentDecryptor_Private::DeliverFrame(buffer
, decrypted_frame_info
);
709 void CdmAdapter::DeliverSamples(int32_t result
,
710 const cdm::Status
& status
,
711 const LinkedAudioFrames
& audio_frames
,
712 const PP_DecryptTrackingInfo
& tracking_info
) {
713 PP_DCHECK(result
== PP_OK
);
715 PP_DecryptedSampleInfo decrypted_sample_info
;
716 decrypted_sample_info
.tracking_info
= tracking_info
;
717 decrypted_sample_info
.tracking_info
.timestamp
= 0;
718 decrypted_sample_info
.tracking_info
.buffer_id
= 0;
719 decrypted_sample_info
.data_size
= 0;
720 decrypted_sample_info
.result
= CdmStatusToPpDecryptResult(status
);
722 pp::Buffer_Dev buffer
;
724 if (decrypted_sample_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
725 PP_DCHECK(audio_frames
.get() && audio_frames
->FrameBuffer());
726 if (!audio_frames
.get() || !audio_frames
->FrameBuffer()) {
728 decrypted_sample_info
.result
= PP_DECRYPTRESULT_DECRYPT_ERROR
;
730 PpbBuffer
* ppb_buffer
=
731 static_cast<PpbBuffer
*>(audio_frames
->FrameBuffer());
732 buffer
= ppb_buffer
->buffer_dev();
733 decrypted_sample_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
734 decrypted_sample_info
.data_size
= ppb_buffer
->Size();
735 decrypted_sample_info
.format
=
736 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames
->Format());
740 pp::ContentDecryptor_Private::DeliverSamples(buffer
, decrypted_sample_info
);
743 bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame
& video_frame
) {
744 if (!video_frame
.get() ||
745 !video_frame
->FrameBuffer() ||
746 (video_frame
->Format() != cdm::kI420
&&
747 video_frame
->Format() != cdm::kYv12
)) {
751 PpbBuffer
* ppb_buffer
= static_cast<PpbBuffer
*>(video_frame
->FrameBuffer());
753 for (uint32_t i
= 0; i
< cdm::VideoFrame::kMaxPlanes
; ++i
) {
754 int plane_height
= (i
== cdm::VideoFrame::kYPlane
) ?
755 video_frame
->Size().height
: (video_frame
->Size().height
+ 1) / 2;
756 cdm::VideoFrame::VideoPlane plane
=
757 static_cast<cdm::VideoFrame::VideoPlane
>(i
);
758 if (ppb_buffer
->Size() < video_frame
->PlaneOffset(plane
) +
759 plane_height
* video_frame
->Stride(plane
)) {
767 void CdmAdapter::SendPlatformChallenge(
768 const char* service_id
, uint32_t service_id_length
,
769 const char* challenge
, uint32_t challenge_length
) {
770 #if defined(OS_CHROMEOS)
771 PP_DCHECK(!challenge_in_progress_
);
773 // Ensure member variables set by the callback are in a clean state.
774 signed_data_output_
= pp::Var();
775 signed_data_signature_output_
= pp::Var();
776 platform_key_certificate_output_
= pp::Var();
778 pp::VarArrayBuffer
challenge_var(challenge_length
);
779 uint8_t* var_data
= static_cast<uint8_t*>(challenge_var
.Map());
780 memcpy(var_data
, challenge
, challenge_length
);
782 std::string
service_id_str(service_id
, service_id_length
);
783 int32_t result
= platform_verification_
.ChallengePlatform(
784 pp::Var(service_id_str
), challenge_var
, &signed_data_output_
,
785 &signed_data_signature_output_
, &platform_key_certificate_output_
,
786 callback_factory_
.NewCallback(&CdmAdapter::SendPlatformChallengeDone
));
787 challenge_var
.Unmap();
788 if (result
== PP_OK_COMPLETIONPENDING
) {
789 challenge_in_progress_
= true;
793 // Fall through on error and issue an empty OnPlatformChallengeResponse().
794 PP_DCHECK(result
!= PP_OK
);
797 cdm::PlatformChallengeResponse response
= {};
798 cdm_
->OnPlatformChallengeResponse(response
);
801 void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask
) {
802 #if defined(OS_CHROMEOS)
803 output_protection_
.EnableProtection(
804 desired_protection_mask
, callback_factory_
.NewCallback(
805 &CdmAdapter::EnableProtectionDone
));
807 // Errors are ignored since clients must call QueryOutputProtectionStatus() to
808 // inspect the protection status on a regular basis.
809 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here...
813 void CdmAdapter::QueryOutputProtectionStatus() {
814 #if defined(OS_CHROMEOS)
815 PP_DCHECK(!query_output_protection_in_progress_
);
817 output_link_mask_
= output_protection_mask_
= 0;
818 const int32_t result
= output_protection_
.QueryStatus(
820 &output_protection_mask_
,
821 callback_factory_
.NewCallback(
822 &CdmAdapter::QueryOutputProtectionStatusDone
));
823 if (result
== PP_OK_COMPLETIONPENDING
) {
824 query_output_protection_in_progress_
= true;
828 // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
829 PP_DCHECK(result
!= PP_OK
);
832 cdm_
->OnQueryOutputProtectionStatus(0, 0);
835 void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type
,
836 cdm::Status decoder_status
) {
837 switch (stream_type
) {
838 case cdm::kStreamTypeAudio
:
839 PP_DCHECK(deferred_initialize_audio_decoder_
);
841 callback_factory_
.NewCallback(&CdmAdapter::DecoderInitializeDone
,
842 PP_DECRYPTORSTREAMTYPE_AUDIO
,
843 deferred_audio_decoder_config_id_
,
844 decoder_status
== cdm::kSuccess
));
845 deferred_initialize_audio_decoder_
= false;
846 deferred_audio_decoder_config_id_
= 0;
848 case cdm::kStreamTypeVideo
:
849 PP_DCHECK(deferred_initialize_video_decoder_
);
851 callback_factory_
.NewCallback(&CdmAdapter::DecoderInitializeDone
,
852 PP_DECRYPTORSTREAMTYPE_VIDEO
,
853 deferred_video_decoder_config_id_
,
854 decoder_status
== cdm::kSuccess
));
855 deferred_initialize_video_decoder_
= false;
856 deferred_video_decoder_config_id_
= 0;
861 #if defined(OS_CHROMEOS)
862 void CdmAdapter::SendPlatformChallengeDone(int32_t result
) {
863 challenge_in_progress_
= false;
865 if (result
!= PP_OK
) {
866 cdm::PlatformChallengeResponse response
= {};
867 cdm_
->OnPlatformChallengeResponse(response
);
871 pp::VarArrayBuffer
signed_data_var(signed_data_output_
);
872 pp::VarArrayBuffer
signed_data_signature_var(signed_data_signature_output_
);
873 std::string platform_key_certificate_string
=
874 platform_key_certificate_output_
.AsString();
876 cdm::PlatformChallengeResponse response
= {
877 static_cast<uint8_t*>(signed_data_var
.Map()),
878 signed_data_var
.ByteLength(),
880 static_cast<uint8_t*>(signed_data_signature_var
.Map()),
881 signed_data_signature_var
.ByteLength(),
883 reinterpret_cast<const uint8_t*>(platform_key_certificate_string
.c_str()),
884 static_cast<uint32_t>(platform_key_certificate_string
.length())
886 cdm_
->OnPlatformChallengeResponse(response
);
888 signed_data_var
.Unmap();
889 signed_data_signature_var
.Unmap();
892 void CdmAdapter::EnableProtectionDone(int32_t result
) {
893 // Does nothing since clients must call QueryOutputProtectionStatus() to
894 // inspect the protection status on a regular basis.
895 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here...
898 void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result
) {
899 PP_DCHECK(query_output_protection_in_progress_
);
900 query_output_protection_in_progress_
= false;
902 // Return a protection status of none on error.
904 output_link_mask_
= output_protection_mask_
= 0;
906 cdm_
->OnQueryOutputProtectionStatus(output_link_mask_
,
907 output_protection_mask_
);
911 void* GetCdmHost(int host_interface_version
, void* user_data
) {
912 if (!host_interface_version
|| !user_data
)
915 CdmAdapter
* cdm_adapter
= static_cast<CdmAdapter
*>(user_data
);
916 switch (host_interface_version
) {
917 case cdm::kHostInterfaceVersion_1
:
918 return static_cast<cdm::Host_1
*>(cdm_adapter
);
919 case cdm::kHostInterfaceVersion_2
:
920 return static_cast<cdm::Host_2
*>(cdm_adapter
);
927 // This object is the global object representing this plugin library as long
929 class CdmAdapterModule
: public pp::Module
{
931 CdmAdapterModule() : pp::Module() {
932 // This function blocks the renderer thread (PluginInstance::Initialize()).
933 // Move this call to other places if this may be a concern in the future.
934 INITIALIZE_CDM_MODULE();
936 virtual ~CdmAdapterModule() {
937 DeinitializeCdmModule();
940 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
941 return new CdmAdapter(instance
, this);
949 // Factory function for your specialization of the Module object.
950 Module
* CreateModule() {
951 return new media::CdmAdapterModule();