cdm_adapter.cc revision f2477e01787aa58f445919b809d89e252beef54f
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. 4 5#include "media/cdm/ppapi/cdm_adapter.h" 6 7#include "media/cdm/ppapi/cdm_helpers.h" 8#include "media/cdm/ppapi/supported_cdm_versions.h" 9 10#if defined(CHECK_DOCUMENT_URL) 11#include "ppapi/cpp/dev/url_util_dev.h" 12#include "ppapi/cpp/instance_handle.h" 13#endif // defined(CHECK_DOCUMENT_URL) 14 15namespace { 16 17bool IsMainThread() { 18 return pp::Module::Get()->core()->IsMainThread(); 19} 20 21// Posts a task to run |cb| on the main thread. The task is posted even if the 22// current thread is the main thread. 23void PostOnMain(pp::CompletionCallback cb) { 24 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); 25} 26 27// Ensures |cb| is called on the main thread, either because the current thread 28// is the main thread or by posting it to the main thread. 29void CallOnMain(pp::CompletionCallback cb) { 30 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls 31 // off the main thread yet. Remove this once the change lands. 32 if (IsMainThread()) 33 cb.Run(PP_OK); 34 else 35 PostOnMain(cb); 36} 37 38// Configures a cdm::InputBuffer. |subsamples| must exist as long as 39// |input_buffer| is in use. 40void ConfigureInputBuffer( 41 const pp::Buffer_Dev& encrypted_buffer, 42 const PP_EncryptedBlockInfo& encrypted_block_info, 43 std::vector<cdm::SubsampleEntry>* subsamples, 44 cdm::InputBuffer* input_buffer) { 45 PP_DCHECK(subsamples); 46 PP_DCHECK(!encrypted_buffer.is_null()); 47 48 input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data()); 49 input_buffer->data_size = encrypted_block_info.data_size; 50 PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size); 51 input_buffer->data_offset = encrypted_block_info.data_offset; 52 53 PP_DCHECK(encrypted_block_info.key_id_size <= 54 arraysize(encrypted_block_info.key_id)); 55 input_buffer->key_id_size = encrypted_block_info.key_id_size; 56 input_buffer->key_id = input_buffer->key_id_size > 0 ? 57 encrypted_block_info.key_id : NULL; 58 59 PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv)); 60 input_buffer->iv_size = encrypted_block_info.iv_size; 61 input_buffer->iv = encrypted_block_info.iv_size > 0 ? 62 encrypted_block_info.iv : NULL; 63 64 input_buffer->num_subsamples = encrypted_block_info.num_subsamples; 65 if (encrypted_block_info.num_subsamples > 0) { 66 subsamples->reserve(encrypted_block_info.num_subsamples); 67 68 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) { 69 subsamples->push_back(cdm::SubsampleEntry( 70 encrypted_block_info.subsamples[i].clear_bytes, 71 encrypted_block_info.subsamples[i].cipher_bytes)); 72 } 73 74 input_buffer->subsamples = &(*subsamples)[0]; 75 } 76 77 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp; 78} 79 80PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) { 81 switch (status) { 82 case cdm::kSuccess: 83 return PP_DECRYPTRESULT_SUCCESS; 84 case cdm::kNoKey: 85 return PP_DECRYPTRESULT_DECRYPT_NOKEY; 86 case cdm::kNeedMoreData: 87 return PP_DECRYPTRESULT_NEEDMOREDATA; 88 case cdm::kDecryptError: 89 return PP_DECRYPTRESULT_DECRYPT_ERROR; 90 case cdm::kDecodeError: 91 return PP_DECRYPTRESULT_DECODE_ERROR; 92 default: 93 PP_NOTREACHED(); 94 return PP_DECRYPTRESULT_DECODE_ERROR; 95 } 96} 97 98PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat( 99 cdm::VideoFormat format) { 100 switch (format) { 101 case cdm::kYv12: 102 return PP_DECRYPTEDFRAMEFORMAT_YV12; 103 case cdm::kI420: 104 return PP_DECRYPTEDFRAMEFORMAT_I420; 105 default: 106 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; 107 } 108} 109 110PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat( 111 cdm::AudioFormat format) { 112 switch (format) { 113 case cdm::kAudioFormatU8: 114 return PP_DECRYPTEDSAMPLEFORMAT_U8; 115 case cdm::kAudioFormatS16: 116 return PP_DECRYPTEDSAMPLEFORMAT_S16; 117 case cdm::kAudioFormatS32: 118 return PP_DECRYPTEDSAMPLEFORMAT_S32; 119 case cdm::kAudioFormatF32: 120 return PP_DECRYPTEDSAMPLEFORMAT_F32; 121 case cdm::kAudioFormatPlanarS16: 122 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16; 123 case cdm::kAudioFormatPlanarF32: 124 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32; 125 default: 126 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN; 127 } 128} 129 130cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec( 131 PP_AudioCodec codec) { 132 switch (codec) { 133 case PP_AUDIOCODEC_VORBIS: 134 return cdm::AudioDecoderConfig::kCodecVorbis; 135 case PP_AUDIOCODEC_AAC: 136 return cdm::AudioDecoderConfig::kCodecAac; 137 default: 138 return cdm::AudioDecoderConfig::kUnknownAudioCodec; 139 } 140} 141 142cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec( 143 PP_VideoCodec codec) { 144 switch (codec) { 145 case PP_VIDEOCODEC_VP8: 146 return cdm::VideoDecoderConfig::kCodecVp8; 147 case PP_VIDEOCODEC_H264: 148 return cdm::VideoDecoderConfig::kCodecH264; 149 default: 150 return cdm::VideoDecoderConfig::kUnknownVideoCodec; 151 } 152} 153 154cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile( 155 PP_VideoCodecProfile profile) { 156 switch (profile) { 157 case PP_VIDEOCODECPROFILE_VP8_MAIN: 158 return cdm::VideoDecoderConfig::kVp8ProfileMain; 159 case PP_VIDEOCODECPROFILE_H264_BASELINE: 160 return cdm::VideoDecoderConfig::kH264ProfileBaseline; 161 case PP_VIDEOCODECPROFILE_H264_MAIN: 162 return cdm::VideoDecoderConfig::kH264ProfileMain; 163 case PP_VIDEOCODECPROFILE_H264_EXTENDED: 164 return cdm::VideoDecoderConfig::kH264ProfileExtended; 165 case PP_VIDEOCODECPROFILE_H264_HIGH: 166 return cdm::VideoDecoderConfig::kH264ProfileHigh; 167 case PP_VIDEOCODECPROFILE_H264_HIGH_10: 168 return cdm::VideoDecoderConfig::kH264ProfileHigh10; 169 case PP_VIDEOCODECPROFILE_H264_HIGH_422: 170 return cdm::VideoDecoderConfig::kH264ProfileHigh422; 171 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE: 172 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive; 173 default: 174 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile; 175 } 176} 177 178cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat( 179 PP_DecryptedFrameFormat format) { 180 switch (format) { 181 case PP_DECRYPTEDFRAMEFORMAT_YV12: 182 return cdm::kYv12; 183 case PP_DECRYPTEDFRAMEFORMAT_I420: 184 return cdm::kI420; 185 default: 186 return cdm::kUnknownVideoFormat; 187 } 188} 189 190cdm::StreamType PpDecryptorStreamTypeToCdmStreamType( 191 PP_DecryptorStreamType stream_type) { 192 switch (stream_type) { 193 case PP_DECRYPTORSTREAMTYPE_AUDIO: 194 return cdm::kStreamTypeAudio; 195 case PP_DECRYPTORSTREAMTYPE_VIDEO: 196 return cdm::kStreamTypeVideo; 197 } 198 199 PP_NOTREACHED(); 200 return cdm::kStreamTypeVideo; 201} 202 203} // namespace 204 205namespace media { 206 207CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module) 208 : pp::Instance(instance), 209 pp::ContentDecryptor_Private(this), 210#if defined(OS_CHROMEOS) 211 output_protection_(this), 212 platform_verification_(this), 213 challenge_in_progress_(false), 214 output_link_mask_(0), 215 output_protection_mask_(0), 216 query_output_protection_in_progress_(false), 217#endif 218 allocator_(this), 219 cdm_(NULL), 220 deferred_initialize_audio_decoder_(false), 221 deferred_audio_decoder_config_id_(0), 222 deferred_initialize_video_decoder_(false), 223 deferred_video_decoder_config_id_(0) { 224 callback_factory_.Initialize(this); 225} 226 227CdmAdapter::~CdmAdapter() {} 228 229bool CdmAdapter::CreateCdmInstance(const std::string& key_system) { 230 PP_DCHECK(!cdm_); 231 cdm_ = make_linked_ptr(CdmWrapper::Create( 232 key_system.data(), key_system.size(), GetCdmHost, this)); 233 return (cdm_ != NULL); 234} 235 236// No KeyErrors should be reported in this function because they cannot be 237// bubbled up in the WD EME API. Those errors will be reported during session 238// creation (aka GenerateKeyRequest). 239void CdmAdapter::Initialize(const std::string& key_system) { 240 PP_DCHECK(!key_system.empty()); 241 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); 242 243 if (!cdm_ && !CreateCdmInstance(key_system)) 244 return; 245 246 PP_DCHECK(cdm_); 247 key_system_ = key_system; 248} 249 250void CdmAdapter::GenerateKeyRequest(uint32_t reference_id, 251 const std::string& type, 252 pp::VarArrayBuffer init_data) { 253 // Initialize() doesn't report an error, so GenerateKeyRequest() can be called 254 // even if Initialize() failed. 255 if (!cdm_) { 256 SendUnknownKeyError(reference_id); 257 return; 258 } 259 260#if defined(CHECK_DOCUMENT_URL) 261 PP_URLComponents_Dev url_components = {}; 262 const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get(); 263 if (!url_util) { 264 SendUnknownKeyError(reference_id); 265 return; 266 } 267 pp::Var href = url_util->GetDocumentURL( 268 pp::InstanceHandle(pp_instance()), &url_components); 269 PP_DCHECK(href.is_string()); 270 PP_DCHECK(!href.AsString().empty()); 271 PP_DCHECK(url_components.host.begin); 272 PP_DCHECK(0 < url_components.host.len); 273#endif // defined(CHECK_DOCUMENT_URL) 274 275 cdm_->GenerateKeyRequest(reference_id, 276 type.data(), 277 type.size(), 278 static_cast<const uint8_t*>(init_data.Map()), 279 init_data.ByteLength()); 280} 281 282void CdmAdapter::AddKey(uint32_t reference_id, 283 pp::VarArrayBuffer key, 284 pp::VarArrayBuffer init_data) { 285 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 286 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 287 if (!cdm_) { 288 SendUnknownKeyError(reference_id); 289 return; 290 } 291 292 const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map()); 293 const uint32_t key_size = key.ByteLength(); 294 const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map()); 295 const uint32_t init_data_size = init_data.ByteLength(); 296 PP_DCHECK(!init_data_ptr == !init_data_size); 297 298 if (!key_ptr || key_size <= 0) { 299 SendUnknownKeyError(reference_id); 300 return; 301 } 302 CdmWrapper::Result result = cdm_->AddKey( 303 reference_id, key_ptr, key_size, init_data_ptr, init_data_size); 304 switch (result) { 305 case CdmWrapper::NO_ACTION: 306 break; 307 case CdmWrapper::CALL_KEY_ADDED: 308 SendKeyAdded(reference_id); 309 break; 310 case CdmWrapper::CALL_KEY_ERROR: 311 SendUnknownKeyError(reference_id); 312 break; 313 } 314} 315 316void CdmAdapter::CancelKeyRequest(uint32_t reference_id) { 317 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 318 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 319 if (!cdm_) { 320 SendUnknownKeyError(reference_id); 321 return; 322 } 323 324 CdmWrapper::Result result = cdm_->CancelKeyRequest(reference_id); 325 switch (result) { 326 case CdmWrapper::NO_ACTION: 327 break; 328 case CdmWrapper::CALL_KEY_ADDED: 329 PP_NOTREACHED(); 330 break; 331 case CdmWrapper::CALL_KEY_ERROR: 332 SendUnknownKeyError(reference_id); 333 break; 334 } 335} 336 337// Note: In the following decryption/decoding related functions, errors are NOT 338// reported via KeyError, but are reported via corresponding PPB calls. 339 340void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer, 341 const PP_EncryptedBlockInfo& encrypted_block_info) { 342 PP_DCHECK(!encrypted_buffer.is_null()); 343 344 // Release a buffer that the caller indicated it is finished with. 345 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 346 347 cdm::Status status = cdm::kDecryptError; 348 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); 349 350 if (cdm_) { 351 cdm::InputBuffer input_buffer; 352 std::vector<cdm::SubsampleEntry> subsamples; 353 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples, 354 &input_buffer); 355 status = cdm_->Decrypt(input_buffer, decrypted_block.get()); 356 PP_DCHECK(status != cdm::kSuccess || 357 (decrypted_block->DecryptedBuffer() && 358 decrypted_block->DecryptedBuffer()->Size())); 359 } 360 361 CallOnMain(callback_factory_.NewCallback( 362 &CdmAdapter::DeliverBlock, 363 status, 364 decrypted_block, 365 encrypted_block_info.tracking_info)); 366} 367 368void CdmAdapter::InitializeAudioDecoder( 369 const PP_AudioDecoderConfig& decoder_config, 370 pp::Buffer_Dev extra_data_buffer) { 371 PP_DCHECK(!deferred_initialize_audio_decoder_); 372 PP_DCHECK(deferred_audio_decoder_config_id_ == 0); 373 cdm::Status status = cdm::kSessionError; 374 if (cdm_) { 375 cdm::AudioDecoderConfig cdm_decoder_config; 376 cdm_decoder_config.codec = 377 PpAudioCodecToCdmAudioCodec(decoder_config.codec); 378 cdm_decoder_config.channel_count = decoder_config.channel_count; 379 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel; 380 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second; 381 cdm_decoder_config.extra_data = 382 static_cast<uint8_t*>(extra_data_buffer.data()); 383 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 384 status = cdm_->InitializeAudioDecoder(cdm_decoder_config); 385 } 386 387 if (status == cdm::kDeferredInitialization) { 388 deferred_initialize_audio_decoder_ = true; 389 deferred_audio_decoder_config_id_ = decoder_config.request_id; 390 return; 391 } 392 393 CallOnMain(callback_factory_.NewCallback( 394 &CdmAdapter::DecoderInitializeDone, 395 PP_DECRYPTORSTREAMTYPE_AUDIO, 396 decoder_config.request_id, 397 status == cdm::kSuccess)); 398} 399 400void CdmAdapter::InitializeVideoDecoder( 401 const PP_VideoDecoderConfig& decoder_config, 402 pp::Buffer_Dev extra_data_buffer) { 403 PP_DCHECK(!deferred_initialize_video_decoder_); 404 PP_DCHECK(deferred_video_decoder_config_id_ == 0); 405 cdm::Status status = cdm::kSessionError; 406 if (cdm_) { 407 cdm::VideoDecoderConfig cdm_decoder_config; 408 cdm_decoder_config.codec = 409 PpVideoCodecToCdmVideoCodec(decoder_config.codec); 410 cdm_decoder_config.profile = 411 PpVCProfileToCdmVCProfile(decoder_config.profile); 412 cdm_decoder_config.format = 413 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format); 414 cdm_decoder_config.coded_size.width = decoder_config.width; 415 cdm_decoder_config.coded_size.height = decoder_config.height; 416 cdm_decoder_config.extra_data = 417 static_cast<uint8_t*>(extra_data_buffer.data()); 418 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 419 status = cdm_->InitializeVideoDecoder(cdm_decoder_config); 420 } 421 422 if (status == cdm::kDeferredInitialization) { 423 deferred_initialize_video_decoder_ = true; 424 deferred_video_decoder_config_id_ = decoder_config.request_id; 425 return; 426 } 427 428 CallOnMain(callback_factory_.NewCallback( 429 &CdmAdapter::DecoderInitializeDone, 430 PP_DECRYPTORSTREAMTYPE_VIDEO, 431 decoder_config.request_id, 432 status == cdm::kSuccess)); 433} 434 435void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type, 436 uint32_t request_id) { 437 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 438 if (cdm_) { 439 cdm_->DeinitializeDecoder( 440 PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 441 } 442 443 CallOnMain(callback_factory_.NewCallback( 444 &CdmAdapter::DecoderDeinitializeDone, 445 decoder_type, 446 request_id)); 447} 448 449void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type, 450 uint32_t request_id) { 451 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 452 if (cdm_) 453 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 454 455 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone, 456 decoder_type, 457 request_id)); 458} 459 460void CdmAdapter::DecryptAndDecode( 461 PP_DecryptorStreamType decoder_type, 462 pp::Buffer_Dev encrypted_buffer, 463 const PP_EncryptedBlockInfo& encrypted_block_info) { 464 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 465 // Release a buffer that the caller indicated it is finished with. 466 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 467 468 cdm::InputBuffer input_buffer; 469 std::vector<cdm::SubsampleEntry> subsamples; 470 if (cdm_ && !encrypted_buffer.is_null()) { 471 ConfigureInputBuffer(encrypted_buffer, 472 encrypted_block_info, 473 &subsamples, 474 &input_buffer); 475 } 476 477 cdm::Status status = cdm::kDecodeError; 478 479 switch (decoder_type) { 480 case PP_DECRYPTORSTREAMTYPE_VIDEO: { 481 LinkedVideoFrame video_frame(new VideoFrameImpl()); 482 if (cdm_) 483 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); 484 CallOnMain(callback_factory_.NewCallback( 485 &CdmAdapter::DeliverFrame, 486 status, 487 video_frame, 488 encrypted_block_info.tracking_info)); 489 return; 490 } 491 492 case PP_DECRYPTORSTREAMTYPE_AUDIO: { 493 LinkedAudioFrames audio_frames(new AudioFramesImpl()); 494 if (cdm_) { 495 status = cdm_->DecryptAndDecodeSamples(input_buffer, 496 audio_frames.get()); 497 } 498 CallOnMain(callback_factory_.NewCallback( 499 &CdmAdapter::DeliverSamples, 500 status, 501 audio_frames, 502 encrypted_block_info.tracking_info)); 503 return; 504 } 505 506 default: 507 PP_NOTREACHED(); 508 return; 509 } 510} 511 512cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) { 513 return allocator_.Allocate(capacity); 514} 515 516void CdmAdapter::SetTimer(int64_t delay_ms, void* context) { 517 // NOTE: doesn't really need to run on the main thread; could just as well run 518 // on a helper thread if |cdm_| were thread-friendly and care was taken. We 519 // only use CallOnMainThread() here to get delayed-execution behavior. 520 pp::Module::Get()->core()->CallOnMainThread( 521 delay_ms, 522 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context), 523 PP_OK); 524} 525 526void CdmAdapter::TimerExpired(int32_t result, void* context) { 527 PP_DCHECK(result == PP_OK); 528 cdm_->TimerExpired(context); 529} 530 531double CdmAdapter::GetCurrentWallTimeInSeconds() { 532 return pp::Module::Get()->core()->GetTime(); 533} 534 535void CdmAdapter::SendKeyMessage( 536 const char* session_id, uint32_t session_id_length, 537 const char* message, uint32_t message_length, 538 const char* default_url, uint32_t default_url_length) { 539 PP_DCHECK(!key_system_.empty()); 540 541 std::string session_id_str(session_id, session_id_length); 542 PP_DCHECK(!session_id_str.empty()); 543 uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str); 544 545 PostOnMain(callback_factory_.NewCallback( 546 &CdmAdapter::SetSessionId, reference_id, session_id_str)); 547 548 PostOnMain(callback_factory_.NewCallback( 549 &CdmAdapter::KeyMessage, 550 reference_id, 551 std::vector<uint8>(message, message + message_length), 552 std::string(default_url, default_url_length))); 553} 554 555void CdmAdapter::SendKeyError(const char* session_id, 556 uint32_t session_id_length, 557 cdm::MediaKeyError error_code, 558 uint32_t system_code) { 559 std::string session_id_str(session_id, session_id_length); 560 uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str); 561 562 SendKeyErrorInternal(reference_id, error_code, system_code); 563} 564 565void CdmAdapter::GetPrivateData(int32_t* instance, 566 GetPrivateInterface* get_interface) { 567 *instance = pp_instance(); 568 *get_interface = pp::Module::Get()->get_browser_interface(); 569} 570 571void CdmAdapter::SendUnknownKeyError(uint32_t reference_id) { 572 SendKeyErrorInternal(reference_id, cdm::kUnknownError, 0); 573} 574 575void CdmAdapter::SendKeyAdded(uint32_t reference_id) { 576 PostOnMain( 577 callback_factory_.NewCallback(&CdmAdapter::KeyAdded, reference_id)); 578} 579 580void CdmAdapter::SendKeyErrorInternal(uint32_t reference_id, 581 cdm::MediaKeyError error_code, 582 uint32_t system_code) { 583 PostOnMain(callback_factory_.NewCallback( 584 &CdmAdapter::KeyError, reference_id, error_code, system_code)); 585} 586 587void CdmAdapter::KeyAdded(int32_t result, uint32_t reference_id) { 588 PP_DCHECK(result == PP_OK); 589 pp::ContentDecryptor_Private::KeyAdded(reference_id); 590} 591 592void CdmAdapter::KeyMessage(int32_t result, 593 uint32_t reference_id, 594 const std::vector<uint8>& message, 595 const std::string& default_url) { 596 PP_DCHECK(result == PP_OK); 597 598 pp::VarArrayBuffer message_array_buffer(message.size()); 599 if (message.size() > 0) { 600 memcpy(message_array_buffer.Map(), message.data(), message.size()); 601 } 602 603 pp::ContentDecryptor_Private::KeyMessage( 604 reference_id, 605 message_array_buffer, 606 default_url); 607} 608 609void CdmAdapter::KeyError(int32_t result, 610 uint32_t reference_id, 611 cdm::MediaKeyError error_code, 612 uint32_t system_code) { 613 PP_DCHECK(result == PP_OK); 614 pp::ContentDecryptor_Private::KeyError(reference_id, error_code, system_code); 615} 616 617void CdmAdapter::SetSessionId(int32_t result, 618 uint32_t reference_id, 619 const std::string& session_id) { 620 PP_DCHECK(result == PP_OK); 621 pp::ContentDecryptor_Private::SetSessionId(reference_id, session_id); 622} 623 624void CdmAdapter::DeliverBlock(int32_t result, 625 const cdm::Status& status, 626 const LinkedDecryptedBlock& decrypted_block, 627 const PP_DecryptTrackingInfo& tracking_info) { 628 PP_DCHECK(result == PP_OK); 629 PP_DecryptedBlockInfo decrypted_block_info; 630 decrypted_block_info.tracking_info = tracking_info; 631 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp(); 632 decrypted_block_info.tracking_info.buffer_id = 0; 633 decrypted_block_info.data_size = 0; 634 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); 635 636 pp::Buffer_Dev buffer; 637 638 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { 639 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer()); 640 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) { 641 PP_NOTREACHED(); 642 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 643 } else { 644 PpbBuffer* ppb_buffer = 645 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer()); 646 buffer = ppb_buffer->buffer_dev(); 647 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 648 decrypted_block_info.data_size = ppb_buffer->Size(); 649 } 650 } 651 652 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); 653} 654 655void CdmAdapter::DecoderInitializeDone(int32_t result, 656 PP_DecryptorStreamType decoder_type, 657 uint32_t request_id, 658 bool success) { 659 PP_DCHECK(result == PP_OK); 660 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, 661 request_id, 662 success); 663} 664 665void CdmAdapter::DecoderDeinitializeDone(int32_t result, 666 PP_DecryptorStreamType decoder_type, 667 uint32_t request_id) { 668 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type, 669 request_id); 670} 671 672void CdmAdapter::DecoderResetDone(int32_t result, 673 PP_DecryptorStreamType decoder_type, 674 uint32_t request_id) { 675 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); 676} 677 678void CdmAdapter::DeliverFrame( 679 int32_t result, 680 const cdm::Status& status, 681 const LinkedVideoFrame& video_frame, 682 const PP_DecryptTrackingInfo& tracking_info) { 683 PP_DCHECK(result == PP_OK); 684 PP_DecryptedFrameInfo decrypted_frame_info; 685 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id; 686 decrypted_frame_info.tracking_info.buffer_id = 0; 687 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status); 688 689 pp::Buffer_Dev buffer; 690 691 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) { 692 if (!IsValidVideoFrame(video_frame)) { 693 PP_NOTREACHED(); 694 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; 695 } else { 696 PpbBuffer* ppb_buffer = 697 static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 698 699 buffer = ppb_buffer->buffer_dev(); 700 701 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp(); 702 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 703 decrypted_frame_info.format = 704 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format()); 705 decrypted_frame_info.width = video_frame->Size().width; 706 decrypted_frame_info.height = video_frame->Size().height; 707 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] = 708 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane); 709 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] = 710 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane); 711 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] = 712 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane); 713 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] = 714 video_frame->Stride(cdm::VideoFrame::kYPlane); 715 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] = 716 video_frame->Stride(cdm::VideoFrame::kUPlane); 717 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] = 718 video_frame->Stride(cdm::VideoFrame::kVPlane); 719 } 720 } 721 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); 722} 723 724void CdmAdapter::DeliverSamples(int32_t result, 725 const cdm::Status& status, 726 const LinkedAudioFrames& audio_frames, 727 const PP_DecryptTrackingInfo& tracking_info) { 728 PP_DCHECK(result == PP_OK); 729 730 PP_DecryptedSampleInfo decrypted_sample_info; 731 decrypted_sample_info.tracking_info = tracking_info; 732 decrypted_sample_info.tracking_info.timestamp = 0; 733 decrypted_sample_info.tracking_info.buffer_id = 0; 734 decrypted_sample_info.data_size = 0; 735 decrypted_sample_info.result = CdmStatusToPpDecryptResult(status); 736 737 pp::Buffer_Dev buffer; 738 739 if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) { 740 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer()); 741 if (!audio_frames.get() || !audio_frames->FrameBuffer()) { 742 PP_NOTREACHED(); 743 decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 744 } else { 745 PpbBuffer* ppb_buffer = 746 static_cast<PpbBuffer*>(audio_frames->FrameBuffer()); 747 buffer = ppb_buffer->buffer_dev(); 748 decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 749 decrypted_sample_info.data_size = ppb_buffer->Size(); 750 decrypted_sample_info.format = 751 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format()); 752 } 753 } 754 755 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info); 756} 757 758bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) { 759 if (!video_frame.get() || 760 !video_frame->FrameBuffer() || 761 (video_frame->Format() != cdm::kI420 && 762 video_frame->Format() != cdm::kYv12)) { 763 return false; 764 } 765 766 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 767 768 for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) { 769 int plane_height = (i == cdm::VideoFrame::kYPlane) ? 770 video_frame->Size().height : (video_frame->Size().height + 1) / 2; 771 cdm::VideoFrame::VideoPlane plane = 772 static_cast<cdm::VideoFrame::VideoPlane>(i); 773 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) + 774 plane_height * video_frame->Stride(plane)) { 775 return false; 776 } 777 } 778 779 return true; 780} 781 782void CdmAdapter::SendPlatformChallenge( 783 const char* service_id, uint32_t service_id_length, 784 const char* challenge, uint32_t challenge_length) { 785#if defined(OS_CHROMEOS) 786 PP_DCHECK(!challenge_in_progress_); 787 788 // Ensure member variables set by the callback are in a clean state. 789 signed_data_output_ = pp::Var(); 790 signed_data_signature_output_ = pp::Var(); 791 platform_key_certificate_output_ = pp::Var(); 792 793 pp::VarArrayBuffer challenge_var(challenge_length); 794 uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map()); 795 memcpy(var_data, challenge, challenge_length); 796 797 std::string service_id_str(service_id, service_id_length); 798 int32_t result = platform_verification_.ChallengePlatform( 799 pp::Var(service_id_str), challenge_var, &signed_data_output_, 800 &signed_data_signature_output_, &platform_key_certificate_output_, 801 callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone)); 802 challenge_var.Unmap(); 803 if (result == PP_OK_COMPLETIONPENDING) { 804 challenge_in_progress_ = true; 805 return; 806 } 807 808 // Fall through on error and issue an empty OnPlatformChallengeResponse(). 809 PP_DCHECK(result != PP_OK); 810#endif 811 812 cdm::PlatformChallengeResponse response = {}; 813 cdm_->OnPlatformChallengeResponse(response); 814} 815 816void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) { 817#if defined(OS_CHROMEOS) 818 output_protection_.EnableProtection( 819 desired_protection_mask, callback_factory_.NewCallback( 820 &CdmAdapter::EnableProtectionDone)); 821 822 // Errors are ignored since clients must call QueryOutputProtectionStatus() to 823 // inspect the protection status on a regular basis. 824 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here... 825#endif 826} 827 828void CdmAdapter::QueryOutputProtectionStatus() { 829#if defined(OS_CHROMEOS) 830 PP_DCHECK(!query_output_protection_in_progress_); 831 832 output_link_mask_ = output_protection_mask_ = 0; 833 const int32_t result = output_protection_.QueryStatus( 834 &output_link_mask_, 835 &output_protection_mask_, 836 callback_factory_.NewCallback( 837 &CdmAdapter::QueryOutputProtectionStatusDone)); 838 if (result == PP_OK_COMPLETIONPENDING) { 839 query_output_protection_in_progress_ = true; 840 return; 841 } 842 843 // Fall through on error and issue an empty OnQueryOutputProtectionStatus(). 844 PP_DCHECK(result != PP_OK); 845#endif 846 847 cdm_->OnQueryOutputProtectionStatus(0, 0); 848} 849 850void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type, 851 cdm::Status decoder_status) { 852 switch (stream_type) { 853 case cdm::kStreamTypeAudio: 854 PP_DCHECK(deferred_initialize_audio_decoder_); 855 CallOnMain( 856 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 857 PP_DECRYPTORSTREAMTYPE_AUDIO, 858 deferred_audio_decoder_config_id_, 859 decoder_status == cdm::kSuccess)); 860 deferred_initialize_audio_decoder_ = false; 861 deferred_audio_decoder_config_id_ = 0; 862 break; 863 case cdm::kStreamTypeVideo: 864 PP_DCHECK(deferred_initialize_video_decoder_); 865 CallOnMain( 866 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 867 PP_DECRYPTORSTREAMTYPE_VIDEO, 868 deferred_video_decoder_config_id_, 869 decoder_status == cdm::kSuccess)); 870 deferred_initialize_video_decoder_ = false; 871 deferred_video_decoder_config_id_ = 0; 872 break; 873 } 874} 875 876#if defined(OS_CHROMEOS) 877void CdmAdapter::SendPlatformChallengeDone(int32_t result) { 878 challenge_in_progress_ = false; 879 880 if (result != PP_OK) { 881 cdm::PlatformChallengeResponse response = {}; 882 cdm_->OnPlatformChallengeResponse(response); 883 return; 884 } 885 886 pp::VarArrayBuffer signed_data_var(signed_data_output_); 887 pp::VarArrayBuffer signed_data_signature_var(signed_data_signature_output_); 888 std::string platform_key_certificate_string = 889 platform_key_certificate_output_.AsString(); 890 891 cdm::PlatformChallengeResponse response = { 892 static_cast<uint8_t*>(signed_data_var.Map()), 893 signed_data_var.ByteLength(), 894 895 static_cast<uint8_t*>(signed_data_signature_var.Map()), 896 signed_data_signature_var.ByteLength(), 897 898 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()), 899 static_cast<uint32_t>(platform_key_certificate_string.length()) 900 }; 901 cdm_->OnPlatformChallengeResponse(response); 902 903 signed_data_var.Unmap(); 904 signed_data_signature_var.Unmap(); 905} 906 907void CdmAdapter::EnableProtectionDone(int32_t result) { 908 // Does nothing since clients must call QueryOutputProtectionStatus() to 909 // inspect the protection status on a regular basis. 910 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here... 911} 912 913void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { 914 PP_DCHECK(query_output_protection_in_progress_); 915 query_output_protection_in_progress_ = false; 916 917 // Return a protection status of none on error. 918 if (result != PP_OK) 919 output_link_mask_ = output_protection_mask_ = 0; 920 921 cdm_->OnQueryOutputProtectionStatus(output_link_mask_, 922 output_protection_mask_); 923} 924#endif 925 926void* GetCdmHost(int host_interface_version, void* user_data) { 927 if (!host_interface_version || !user_data) 928 return NULL; 929 930 COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion == 931 cdm::ContentDecryptionModule_2::Host::kVersion, 932 update_code_below); 933 934 // Ensure IsSupportedCdmHostVersion matches implementation of this function. 935 // Always update this DCHECK when updating this function. 936 // If this check fails, update this function and DCHECK or update 937 // IsSupportedCdmHostVersion. 938 PP_DCHECK( 939 // Future version is not supported. 940 !IsSupportedCdmHostVersion( 941 cdm::ContentDecryptionModule::Host::kVersion + 1) && 942 // Current version is supported. 943 IsSupportedCdmHostVersion(cdm::ContentDecryptionModule::Host::kVersion) && 944 // Include all previous supported versions here. 945 IsSupportedCdmHostVersion(cdm::Host_1::kVersion) && 946 // One older than the oldest supported version is not supported. 947 !IsSupportedCdmHostVersion(cdm::Host_1::kVersion - 1)); 948 PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version)); 949 950 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); 951 switch (host_interface_version) { 952 // The latest CDM host version. 953 case cdm::ContentDecryptionModule::Host::kVersion: 954 return static_cast<cdm::ContentDecryptionModule::Host*>(cdm_adapter); 955 // Older supported version(s) of the CDM host. 956 case cdm::Host_1::kVersion: 957 return static_cast<cdm::Host_1*>(cdm_adapter); 958 default: 959 PP_NOTREACHED(); 960 return NULL; 961 } 962} 963 964// This object is the global object representing this plugin library as long 965// as it is loaded. 966class CdmAdapterModule : public pp::Module { 967 public: 968 CdmAdapterModule() : pp::Module() { 969 // This function blocks the renderer thread (PluginInstance::Initialize()). 970 // Move this call to other places if this may be a concern in the future. 971 INITIALIZE_CDM_MODULE(); 972 } 973 virtual ~CdmAdapterModule() { 974 DeinitializeCdmModule(); 975 } 976 977 virtual pp::Instance* CreateInstance(PP_Instance instance) { 978 return new CdmAdapter(instance, this); 979 } 980}; 981 982} // namespace media 983 984namespace pp { 985 986// Factory function for your specialization of the Module object. 987Module* CreateModule() { 988 return new media::CdmAdapterModule(); 989} 990 991} // namespace pp 992