Removed unused VideoCaptureCapability parameters.
[chromium-blink-merge.git] / media / cdm / ppapi / cdm_adapter.cc
blobd9419977f38a2120db1a696ca7f71da037634c8d
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)
14 namespace {
16 bool IsMainThread() {
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.
31 if (IsMainThread())
32 cb.Run(PP_OK);
33 else
34 PostOnMain(cb);
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) {
80 switch (status) {
81 case cdm::kSuccess:
82 return PP_DECRYPTRESULT_SUCCESS;
83 case cdm::kNoKey:
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;
91 default:
92 PP_NOTREACHED();
93 return PP_DECRYPTRESULT_DECODE_ERROR;
97 PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
98 cdm::VideoFormat format) {
99 switch (format) {
100 case cdm::kYv12:
101 return PP_DECRYPTEDFRAMEFORMAT_YV12;
102 case cdm::kI420:
103 return PP_DECRYPTEDFRAMEFORMAT_I420;
104 default:
105 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
109 PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
110 cdm::AudioFormat format) {
111 switch (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;
124 default:
125 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
129 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
130 PP_AudioCodec codec) {
131 switch (codec) {
132 case PP_AUDIOCODEC_VORBIS:
133 return cdm::AudioDecoderConfig::kCodecVorbis;
134 case PP_AUDIOCODEC_AAC:
135 return cdm::AudioDecoderConfig::kCodecAac;
136 default:
137 return cdm::AudioDecoderConfig::kUnknownAudioCodec;
141 cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec(
142 PP_VideoCodec codec) {
143 switch (codec) {
144 case PP_VIDEOCODEC_VP8:
145 return cdm::VideoDecoderConfig::kCodecVp8;
146 case PP_VIDEOCODEC_H264:
147 return cdm::VideoDecoderConfig::kCodecH264;
148 default:
149 return cdm::VideoDecoderConfig::kUnknownVideoCodec;
153 cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile(
154 PP_VideoCodecProfile profile) {
155 switch (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;
172 default:
173 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
177 cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
178 PP_DecryptedFrameFormat format) {
179 switch (format) {
180 case PP_DECRYPTEDFRAMEFORMAT_YV12:
181 return cdm::kYv12;
182 case PP_DECRYPTEDFRAMEFORMAT_I420:
183 return cdm::kI420;
184 default:
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;
198 PP_NOTREACHED();
199 return cdm::kStreamTypeVideo;
202 } // namespace
204 namespace media {
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),
216 #endif
217 allocator_(this),
218 cdm_(NULL),
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) {
229 PP_DCHECK(!cdm_);
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))
244 return;
246 PP_DCHECK(cdm_);
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.
254 if (!cdm_) {
255 SendUnknownKeyError(key_system_, std::string());
256 return;
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.
283 if (!cdm_) {
284 SendUnknownKeyError(key_system_, session_id);
285 return;
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);
296 return;
299 cdm::Status status = cdm_->AddKey(session_id.data(), session_id.size(),
300 key_ptr, key_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);
305 return;
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.
314 if (!cdm_) {
315 SendUnknownKeyError(key_system_, session_id);
316 return;
319 cdm::Status status = cdm_->CancelKeyRequest(session_id.data(),
320 session_id.size());
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());
339 if (cdm_) {
340 cdm::InputBuffer input_buffer;
341 std::vector<cdm::SubsampleEntry> subsamples;
342 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
343 &input_buffer);
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,
352 status,
353 decrypted_block,
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;
363 if (cdm_) {
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;
379 return;
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;
395 if (cdm_) {
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;
414 return;
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.
427 if (cdm_) {
428 cdm_->DeinitializeDecoder(
429 PpDecryptorStreamTypeToCdmStreamType(decoder_type));
432 CallOnMain(callback_factory_.NewCallback(
433 &CdmAdapter::DecoderDeinitializeDone,
434 decoder_type,
435 request_id));
438 void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
439 uint32_t request_id) {
440 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded.
441 if (cdm_)
442 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
444 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone,
445 decoder_type,
446 request_id));
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,
462 &subsamples,
463 &input_buffer);
466 cdm::Status status = cdm::kDecodeError;
468 switch (decoder_type) {
469 case PP_DECRYPTORSTREAMTYPE_VIDEO: {
470 LinkedVideoFrame video_frame(new VideoFrameImpl());
471 if (cdm_)
472 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
473 CallOnMain(callback_factory_.NewCallback(
474 &CdmAdapter::DeliverFrame,
475 status,
476 video_frame,
477 encrypted_block_info.tracking_info));
478 return;
481 case PP_DECRYPTORSTREAMTYPE_AUDIO: {
482 LinkedAudioFrames audio_frames(new AudioFramesImpl());
483 if (cdm_) {
484 status = cdm_->DecryptAndDecodeSamples(input_buffer,
485 audio_frames.get());
487 CallOnMain(callback_factory_.NewCallback(
488 &CdmAdapter::DeliverSamples,
489 status,
490 audio_frames,
491 encrypted_block_info.tracking_info));
492 return;
495 default:
496 PP_NOTREACHED();
497 return;
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(
510 delay_ms,
511 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context),
512 PP_OK);
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),
543 error_code,
544 system_code);
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),
571 error_code,
572 system_code));
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()) {
626 PP_NOTREACHED();
627 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
628 } else {
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,
642 uint32_t request_id,
643 bool success) {
644 PP_DCHECK(result == PP_OK);
645 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
646 request_id,
647 success);
650 void CdmAdapter::DecoderDeinitializeDone(int32_t result,
651 PP_DecryptorStreamType decoder_type,
652 uint32_t request_id) {
653 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
654 request_id);
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(
664 int32_t result,
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)) {
678 PP_NOTREACHED();
679 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
680 } else {
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()) {
727 PP_NOTREACHED();
728 decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
729 } else {
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)) {
748 return false;
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)) {
760 return false;
764 return true;
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;
790 return;
793 // Fall through on error and issue an empty OnPlatformChallengeResponse().
794 PP_DCHECK(result != PP_OK);
795 #endif
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...
810 #endif
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(
819 &output_link_mask_,
820 &output_protection_mask_,
821 callback_factory_.NewCallback(
822 &CdmAdapter::QueryOutputProtectionStatusDone));
823 if (result == PP_OK_COMPLETIONPENDING) {
824 query_output_protection_in_progress_ = true;
825 return;
828 // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
829 PP_DCHECK(result != PP_OK);
830 #endif
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_);
840 CallOnMain(
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;
847 break;
848 case cdm::kStreamTypeVideo:
849 PP_DCHECK(deferred_initialize_video_decoder_);
850 CallOnMain(
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;
857 break;
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);
868 return;
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.
903 if (result != PP_OK)
904 output_link_mask_ = output_protection_mask_ = 0;
906 cdm_->OnQueryOutputProtectionStatus(output_link_mask_,
907 output_protection_mask_);
909 #endif
911 void* GetCdmHost(int host_interface_version, void* user_data) {
912 if (!host_interface_version || !user_data)
913 return NULL;
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);
921 default:
922 PP_NOTREACHED();
923 return NULL;
927 // This object is the global object representing this plugin library as long
928 // as it is loaded.
929 class CdmAdapterModule : public pp::Module {
930 public:
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);
945 } // namespace media
947 namespace pp {
949 // Factory function for your specialization of the Module object.
950 Module* CreateModule() {
951 return new media::CdmAdapterModule();
954 } // namespace pp