cdm_adapter.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 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) 13 14namespace { 15 16bool IsMainThread() { 17 return pp::Module::Get()->core()->IsMainThread(); 18} 19 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. 22void PostOnMain(pp::CompletionCallback cb) { 23 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); 24} 25 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. 28void 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); 35} 36 37// Configures a cdm::InputBuffer. |subsamples| must exist as long as 38// |input_buffer| is in use. 39void 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()); 46 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; 51 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; 57 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; 62 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); 66 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)); 71 } 72 73 input_buffer->subsamples = &(*subsamples)[0]; 74 } 75 76 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp; 77} 78 79PP_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; 94 } 95} 96 97PP_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; 106 } 107} 108 109PP_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; 126 } 127} 128 129cdm::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; 138 } 139} 140 141cdm::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; 150 } 151} 152 153cdm::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; 174 } 175} 176 177cdm::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; 186 } 187} 188 189cdm::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; 196 } 197 198 PP_NOTREACHED(); 199 return cdm::kStreamTypeVideo; 200} 201 202} // namespace 203 204namespace media { 205 206CdmAdapter::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); 224} 225 226CdmAdapter::~CdmAdapter() {} 227 228bool 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); 233} 234 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). 238void 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_)); 242 243 if (!cdm_ && !CreateCdmInstance(key_system)) 244 return; 245 246 PP_DCHECK(cdm_); 247 key_system_ = key_system; 248} 249 250void 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; 257 } 258 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) 268 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()); 276} 277 278void 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; 286 } 287 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); 293 294 if (!key_ptr || !key_size) { 295 SendUnknownKeyError(key_system_, session_id); 296 return; 297 } 298 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; 306 } 307 308 SendKeyAdded(key_system_, session_id); 309} 310 311void 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; 317 } 318 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); 324} 325 326// Note: In the following decryption/decoding related functions, errors are NOT 327// reported via KeyError, but are reported via corresponding PPB calls. 328 329void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer, 330 const PP_EncryptedBlockInfo& encrypted_block_info) { 331 PP_DCHECK(!encrypted_buffer.is_null()); 332 333 // Release a buffer that the caller indicated it is finished with. 334 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 335 336 cdm::Status status = cdm::kDecryptError; 337 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); 338 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())); 348 } 349 350 CallOnMain(callback_factory_.NewCallback( 351 &CdmAdapter::DeliverBlock, 352 status, 353 decrypted_block, 354 encrypted_block_info.tracking_info)); 355} 356 357void 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); 374 } 375 376 if (status == cdm::kDeferredInitialization) { 377 deferred_initialize_audio_decoder_ = true; 378 deferred_audio_decoder_config_id_ = decoder_config.request_id; 379 return; 380 } 381 382 CallOnMain(callback_factory_.NewCallback( 383 &CdmAdapter::DecoderInitializeDone, 384 PP_DECRYPTORSTREAMTYPE_AUDIO, 385 decoder_config.request_id, 386 status == cdm::kSuccess)); 387} 388 389void 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); 409 } 410 411 if (status == cdm::kDeferredInitialization) { 412 deferred_initialize_video_decoder_ = true; 413 deferred_video_decoder_config_id_ = decoder_config.request_id; 414 return; 415 } 416 417 CallOnMain(callback_factory_.NewCallback( 418 &CdmAdapter::DecoderInitializeDone, 419 PP_DECRYPTORSTREAMTYPE_VIDEO, 420 decoder_config.request_id, 421 status == cdm::kSuccess)); 422} 423 424void 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)); 430 } 431 432 CallOnMain(callback_factory_.NewCallback( 433 &CdmAdapter::DecoderDeinitializeDone, 434 decoder_type, 435 request_id)); 436} 437 438void 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)); 443 444 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone, 445 decoder_type, 446 request_id)); 447} 448 449void 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); 456 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); 464 } 465 466 cdm::Status status = cdm::kDecodeError; 467 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; 479 } 480 481 case PP_DECRYPTORSTREAMTYPE_AUDIO: { 482 LinkedAudioFrames audio_frames(new AudioFramesImpl()); 483 if (cdm_) { 484 status = cdm_->DecryptAndDecodeSamples(input_buffer, 485 audio_frames.get()); 486 } 487 CallOnMain(callback_factory_.NewCallback( 488 &CdmAdapter::DeliverSamples, 489 status, 490 audio_frames, 491 encrypted_block_info.tracking_info)); 492 return; 493 } 494 495 default: 496 PP_NOTREACHED(); 497 return; 498 } 499} 500 501cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) { 502 return allocator_.Allocate(capacity); 503} 504 505void 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); 513} 514 515void CdmAdapter::TimerExpired(int32_t result, void* context) { 516 PP_DCHECK(result == PP_OK); 517 cdm_->TimerExpired(context); 518} 519 520double CdmAdapter::GetCurrentWallTimeInSeconds() { 521 return pp::Module::Get()->core()->GetTime(); 522} 523 524void 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))); 535} 536 537void 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); 545} 546 547void CdmAdapter::GetPrivateData(int32_t* instance, 548 GetPrivateInterface* get_interface) { 549 *instance = pp_instance(); 550 *get_interface = pp::Module::Get()->get_browser_interface(); 551} 552 553void CdmAdapter::SendUnknownKeyError(const std::string& key_system, 554 const std::string& session_id) { 555 SendKeyErrorInternal(key_system, session_id, cdm::kUnknownError, 0); 556} 557 558void 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))); 563} 564 565void 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)); 573} 574 575void 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); 580} 581 582void 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()); 588 589 pp::VarArrayBuffer message_array_buffer(message.size()); 590 if (message.size() > 0) { 591 memcpy(message_array_buffer.Map(), message.data(), message.size()); 592 } 593 594 pp::ContentDecryptor_Private::KeyMessage( 595 session_info.key_system, session_info.session_id, 596 message_array_buffer, default_url); 597} 598 599void 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); 607} 608 609void 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); 620 621 pp::Buffer_Dev buffer; 622 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(); 634 } 635 } 636 637 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); 638} 639 640void 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); 648} 649 650void 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); 655} 656 657void CdmAdapter::DecoderResetDone(int32_t result, 658 PP_DecryptorStreamType decoder_type, 659 uint32_t request_id) { 660 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); 661} 662 663void 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); 673 674 pp::Buffer_Dev buffer; 675 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()); 683 684 buffer = ppb_buffer->buffer_dev(); 685 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); 704 } 705 } 706 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); 707} 708 709void 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); 714 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); 721 722 pp::Buffer_Dev buffer; 723 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()); 737 } 738 } 739 740 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info); 741} 742 743bool 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; 749 } 750 751 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 752 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; 761 } 762 } 763 764 return true; 765} 766 767void 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_); 772 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(); 777 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); 781 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; 791 } 792 793 // Fall through on error and issue an empty OnPlatformChallengeResponse(). 794 PP_DCHECK(result != PP_OK); 795#endif 796 797 cdm::PlatformChallengeResponse response = {}; 798 cdm_->OnPlatformChallengeResponse(response); 799} 800 801void 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)); 806 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 811} 812 813void CdmAdapter::QueryOutputProtectionStatus() { 814#if defined(OS_CHROMEOS) 815 PP_DCHECK(!query_output_protection_in_progress_); 816 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; 826 } 827 828 // Fall through on error and issue an empty OnQueryOutputProtectionStatus(). 829 PP_DCHECK(result != PP_OK); 830#endif 831 832 cdm_->OnQueryOutputProtectionStatus(0, 0); 833} 834 835void 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; 858 } 859} 860 861#if defined(OS_CHROMEOS) 862void CdmAdapter::SendPlatformChallengeDone(int32_t result) { 863 challenge_in_progress_ = false; 864 865 if (result != PP_OK) { 866 cdm::PlatformChallengeResponse response = {}; 867 cdm_->OnPlatformChallengeResponse(response); 868 return; 869 } 870 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(); 875 876 cdm::PlatformChallengeResponse response = { 877 static_cast<uint8_t*>(signed_data_var.Map()), 878 signed_data_var.ByteLength(), 879 880 static_cast<uint8_t*>(signed_data_signature_var.Map()), 881 signed_data_signature_var.ByteLength(), 882 883 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()), 884 static_cast<uint32_t>(platform_key_certificate_string.length()) 885 }; 886 cdm_->OnPlatformChallengeResponse(response); 887 888 signed_data_var.Unmap(); 889 signed_data_signature_var.Unmap(); 890} 891 892void 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... 896} 897 898void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { 899 PP_DCHECK(query_output_protection_in_progress_); 900 query_output_protection_in_progress_ = false; 901 902 // Return a protection status of none on error. 903 if (result != PP_OK) 904 output_link_mask_ = output_protection_mask_ = 0; 905 906 cdm_->OnQueryOutputProtectionStatus(output_link_mask_, 907 output_protection_mask_); 908} 909#endif 910 911void* GetCdmHost(int host_interface_version, void* user_data) { 912 if (!host_interface_version || !user_data) 913 return NULL; 914 915 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); 916 switch (host_interface_version) { 917 case cdm::ContentDecryptionModule_1::Host::kVersion: 918 return static_cast<cdm::ContentDecryptionModule_1::Host*>(cdm_adapter); 919 case cdm::ContentDecryptionModule_2::Host::kVersion: 920 return static_cast<cdm::ContentDecryptionModule_2::Host*>(cdm_adapter); 921 default: 922 PP_NOTREACHED(); 923 return NULL; 924 } 925} 926 927// This object is the global object representing this plugin library as long 928// as it is loaded. 929class 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(); 935 } 936 virtual ~CdmAdapterModule() { 937 DeinitializeCdmModule(); 938 } 939 940 virtual pp::Instance* CreateInstance(PP_Instance instance) { 941 return new CdmAdapter(instance, this); 942 } 943}; 944 945} // namespace media 946 947namespace pp { 948 949// Factory function for your specialization of the Module object. 950Module* CreateModule() { 951 return new media::CdmAdapterModule(); 952} 953 954} // namespace pp 955