cdm_adapter.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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() >= 50 static_cast<uint32_t>(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 110cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec( 111 PP_AudioCodec codec) { 112 switch (codec) { 113 case PP_AUDIOCODEC_VORBIS: 114 return cdm::AudioDecoderConfig::kCodecVorbis; 115 case PP_AUDIOCODEC_AAC: 116 return cdm::AudioDecoderConfig::kCodecAac; 117 default: 118 return cdm::AudioDecoderConfig::kUnknownAudioCodec; 119 } 120} 121 122cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec( 123 PP_VideoCodec codec) { 124 switch (codec) { 125 case PP_VIDEOCODEC_VP8: 126 return cdm::VideoDecoderConfig::kCodecVp8; 127 case PP_VIDEOCODEC_H264: 128 return cdm::VideoDecoderConfig::kCodecH264; 129 default: 130 return cdm::VideoDecoderConfig::kUnknownVideoCodec; 131 } 132} 133 134cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile( 135 PP_VideoCodecProfile profile) { 136 switch (profile) { 137 case PP_VIDEOCODECPROFILE_VP8_MAIN: 138 return cdm::VideoDecoderConfig::kVp8ProfileMain; 139 case PP_VIDEOCODECPROFILE_H264_BASELINE: 140 return cdm::VideoDecoderConfig::kH264ProfileBaseline; 141 case PP_VIDEOCODECPROFILE_H264_MAIN: 142 return cdm::VideoDecoderConfig::kH264ProfileMain; 143 case PP_VIDEOCODECPROFILE_H264_EXTENDED: 144 return cdm::VideoDecoderConfig::kH264ProfileExtended; 145 case PP_VIDEOCODECPROFILE_H264_HIGH: 146 return cdm::VideoDecoderConfig::kH264ProfileHigh; 147 case PP_VIDEOCODECPROFILE_H264_HIGH_10: 148 return cdm::VideoDecoderConfig::kH264ProfileHigh10; 149 case PP_VIDEOCODECPROFILE_H264_HIGH_422: 150 return cdm::VideoDecoderConfig::kH264ProfileHigh422; 151 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE: 152 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive; 153 default: 154 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile; 155 } 156} 157 158cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat( 159 PP_DecryptedFrameFormat format) { 160 switch (format) { 161 case PP_DECRYPTEDFRAMEFORMAT_YV12: 162 return cdm::kYv12; 163 case PP_DECRYPTEDFRAMEFORMAT_I420: 164 return cdm::kI420; 165 default: 166 return cdm::kUnknownVideoFormat; 167 } 168} 169 170cdm::StreamType PpDecryptorStreamTypeToCdmStreamType( 171 PP_DecryptorStreamType stream_type) { 172 switch (stream_type) { 173 case PP_DECRYPTORSTREAMTYPE_AUDIO: 174 return cdm::kStreamTypeAudio; 175 case PP_DECRYPTORSTREAMTYPE_VIDEO: 176 return cdm::kStreamTypeVideo; 177 } 178 179 PP_NOTREACHED(); 180 return cdm::kStreamTypeVideo; 181} 182 183} // namespace 184 185namespace media { 186 187CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module) 188 : pp::Instance(instance), 189 pp::ContentDecryptor_Private(this), 190#if defined(OS_CHROMEOS) 191 output_protection_(this), 192 platform_verification_(this), 193 challenge_in_progress_(false), 194 output_link_mask_(0), 195 output_protection_mask_(0), 196 query_output_protection_in_progress_(false), 197#endif 198 allocator_(this), 199 cdm_(NULL) { 200 callback_factory_.Initialize(this); 201} 202 203CdmAdapter::~CdmAdapter() {} 204 205bool CdmAdapter::CreateCdmInstance(const std::string& key_system) { 206 PP_DCHECK(!cdm_); 207 cdm_ = make_linked_ptr(CdmWrapper::Create( 208 key_system.data(), key_system.size(), GetCdmHost, this)); 209 return (cdm_ != NULL); 210} 211 212// No KeyErrors should be reported in this function because they cannot be 213// bubbled up in the WD EME API. Those errors will be reported during session 214// creation (aka GenerateKeyRequest). 215void CdmAdapter::Initialize(const std::string& key_system, 216 bool can_challenge_platform) { 217 PP_DCHECK(!key_system.empty()); 218 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); 219 220 if (!cdm_ && !CreateCdmInstance(key_system)) 221 return; 222 223 PP_DCHECK(cdm_); 224 key_system_ = key_system; 225} 226 227void CdmAdapter::GenerateKeyRequest(const std::string& type, 228 pp::VarArrayBuffer init_data) { 229 // Initialize() doesn't report an error, so GenerateKeyRequest() can be called 230 // even if Initialize() failed. 231 if (!cdm_) { 232 SendUnknownKeyError(key_system_, std::string()); 233 return; 234 } 235 236#if defined(CHECK_DOCUMENT_URL) 237 PP_URLComponents_Dev url_components = {}; 238 pp::Var href = pp::URLUtil_Dev::Get()->GetDocumentURL( 239 pp::InstanceHandle(pp_instance()), &url_components); 240 PP_DCHECK(href.is_string()); 241 PP_DCHECK(!href.AsString().empty()); 242 PP_DCHECK(url_components.host.begin); 243 PP_DCHECK(0 < url_components.host.len); 244#endif // defined(CHECK_DOCUMENT_URL) 245 246 cdm::Status status = cdm_->GenerateKeyRequest( 247 type.data(), type.size(), 248 static_cast<const uint8_t*>(init_data.Map()), 249 init_data.ByteLength()); 250 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); 251 if (status != cdm::kSuccess) 252 SendUnknownKeyError(key_system_, std::string()); 253} 254 255void CdmAdapter::AddKey(const std::string& session_id, 256 pp::VarArrayBuffer key, 257 pp::VarArrayBuffer init_data) { 258 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 259 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 260 if (!cdm_) { 261 SendUnknownKeyError(key_system_, session_id); 262 return; 263 } 264 265 const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map()); 266 int key_size = key.ByteLength(); 267 const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map()); 268 int init_data_size = init_data.ByteLength(); 269 PP_DCHECK(!init_data_ptr == !init_data_size); 270 271 if (!key_ptr || key_size <= 0) { 272 SendUnknownKeyError(key_system_, session_id); 273 return; 274 } 275 276 cdm::Status status = cdm_->AddKey(session_id.data(), session_id.size(), 277 key_ptr, key_size, 278 init_data_ptr, init_data_size); 279 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); 280 if (status != cdm::kSuccess) { 281 SendUnknownKeyError(key_system_, session_id); 282 return; 283 } 284 285 SendKeyAdded(key_system_, session_id); 286} 287 288void CdmAdapter::CancelKeyRequest(const std::string& session_id) { 289 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 290 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 291 if (!cdm_) { 292 SendUnknownKeyError(key_system_, session_id); 293 return; 294 } 295 296 cdm::Status status = cdm_->CancelKeyRequest(session_id.data(), 297 session_id.size()); 298 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); 299 if (status != cdm::kSuccess) 300 SendUnknownKeyError(key_system_, session_id); 301} 302 303// Note: In the following decryption/decoding related functions, errors are NOT 304// reported via KeyError, but are reported via corresponding PPB calls. 305 306void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer, 307 const PP_EncryptedBlockInfo& encrypted_block_info) { 308 PP_DCHECK(!encrypted_buffer.is_null()); 309 310 // Release a buffer that the caller indicated it is finished with. 311 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 312 313 cdm::Status status = cdm::kDecryptError; 314 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); 315 316 if (cdm_) { 317 cdm::InputBuffer input_buffer; 318 std::vector<cdm::SubsampleEntry> subsamples; 319 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples, 320 &input_buffer); 321 status = cdm_->Decrypt(input_buffer, decrypted_block.get()); 322 PP_DCHECK(status != cdm::kSuccess || 323 (decrypted_block->DecryptedBuffer() && 324 decrypted_block->DecryptedBuffer()->Size())); 325 } 326 327 CallOnMain(callback_factory_.NewCallback( 328 &CdmAdapter::DeliverBlock, 329 status, 330 decrypted_block, 331 encrypted_block_info.tracking_info)); 332} 333 334void CdmAdapter::InitializeAudioDecoder( 335 const PP_AudioDecoderConfig& decoder_config, 336 pp::Buffer_Dev extra_data_buffer) { 337 cdm::Status status = cdm::kSessionError; 338 if (cdm_) { 339 cdm::AudioDecoderConfig cdm_decoder_config; 340 cdm_decoder_config.codec = 341 PpAudioCodecToCdmAudioCodec(decoder_config.codec); 342 cdm_decoder_config.channel_count = decoder_config.channel_count; 343 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel; 344 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second; 345 cdm_decoder_config.extra_data = 346 static_cast<uint8_t*>(extra_data_buffer.data()); 347 cdm_decoder_config.extra_data_size = 348 static_cast<int32_t>(extra_data_buffer.size()); 349 status = cdm_->InitializeAudioDecoder(cdm_decoder_config); 350 } 351 352 CallOnMain(callback_factory_.NewCallback( 353 &CdmAdapter::DecoderInitializeDone, 354 PP_DECRYPTORSTREAMTYPE_AUDIO, 355 decoder_config.request_id, 356 status == cdm::kSuccess)); 357} 358 359void CdmAdapter::InitializeVideoDecoder( 360 const PP_VideoDecoderConfig& decoder_config, 361 pp::Buffer_Dev extra_data_buffer) { 362 cdm::Status status = cdm::kSessionError; 363 if (cdm_) { 364 cdm::VideoDecoderConfig cdm_decoder_config; 365 cdm_decoder_config.codec = 366 PpVideoCodecToCdmVideoCodec(decoder_config.codec); 367 cdm_decoder_config.profile = 368 PpVCProfileToCdmVCProfile(decoder_config.profile); 369 cdm_decoder_config.format = 370 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format); 371 cdm_decoder_config.coded_size.width = decoder_config.width; 372 cdm_decoder_config.coded_size.height = decoder_config.height; 373 cdm_decoder_config.extra_data = 374 static_cast<uint8_t*>(extra_data_buffer.data()); 375 cdm_decoder_config.extra_data_size = 376 static_cast<int32_t>(extra_data_buffer.size()); 377 status = cdm_->InitializeVideoDecoder(cdm_decoder_config); 378 } 379 380 CallOnMain(callback_factory_.NewCallback( 381 &CdmAdapter::DecoderInitializeDone, 382 PP_DECRYPTORSTREAMTYPE_VIDEO, 383 decoder_config.request_id, 384 status == cdm::kSuccess)); 385} 386 387void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type, 388 uint32_t request_id) { 389 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 390 if (cdm_) { 391 cdm_->DeinitializeDecoder( 392 PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 393 } 394 395 CallOnMain(callback_factory_.NewCallback( 396 &CdmAdapter::DecoderDeinitializeDone, 397 decoder_type, 398 request_id)); 399} 400 401void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type, 402 uint32_t request_id) { 403 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 404 if (cdm_) 405 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 406 407 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone, 408 decoder_type, 409 request_id)); 410} 411 412void CdmAdapter::DecryptAndDecode( 413 PP_DecryptorStreamType decoder_type, 414 pp::Buffer_Dev encrypted_buffer, 415 const PP_EncryptedBlockInfo& encrypted_block_info) { 416 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 417 // Release a buffer that the caller indicated it is finished with. 418 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 419 420 cdm::InputBuffer input_buffer; 421 std::vector<cdm::SubsampleEntry> subsamples; 422 if (cdm_ && !encrypted_buffer.is_null()) { 423 ConfigureInputBuffer(encrypted_buffer, 424 encrypted_block_info, 425 &subsamples, 426 &input_buffer); 427 } 428 429 cdm::Status status = cdm::kDecodeError; 430 431 switch (decoder_type) { 432 case PP_DECRYPTORSTREAMTYPE_VIDEO: { 433 LinkedVideoFrame video_frame(new VideoFrameImpl()); 434 if (cdm_) 435 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); 436 CallOnMain(callback_factory_.NewCallback( 437 &CdmAdapter::DeliverFrame, 438 status, 439 video_frame, 440 encrypted_block_info.tracking_info)); 441 return; 442 } 443 444 case PP_DECRYPTORSTREAMTYPE_AUDIO: { 445 LinkedAudioFrames audio_frames(new AudioFramesImpl()); 446 if (cdm_) { 447 status = cdm_->DecryptAndDecodeSamples(input_buffer, 448 audio_frames.get()); 449 } 450 CallOnMain(callback_factory_.NewCallback( 451 &CdmAdapter::DeliverSamples, 452 status, 453 audio_frames, 454 encrypted_block_info.tracking_info)); 455 return; 456 } 457 458 default: 459 PP_NOTREACHED(); 460 return; 461 } 462} 463 464cdm::Buffer* CdmAdapter::Allocate(int32_t capacity) { 465 return allocator_.Allocate(capacity); 466} 467 468void CdmAdapter::SetTimer(int64_t delay_ms, void* context) { 469 // NOTE: doesn't really need to run on the main thread; could just as well run 470 // on a helper thread if |cdm_| were thread-friendly and care was taken. We 471 // only use CallOnMainThread() here to get delayed-execution behavior. 472 pp::Module::Get()->core()->CallOnMainThread( 473 delay_ms, 474 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context), 475 PP_OK); 476} 477 478void CdmAdapter::TimerExpired(int32_t result, void* context) { 479 PP_DCHECK(result == PP_OK); 480 cdm_->TimerExpired(context); 481} 482 483double CdmAdapter::GetCurrentWallTimeInSeconds() { 484 return pp::Module::Get()->core()->GetTime(); 485} 486 487void CdmAdapter::SendKeyMessage( 488 const char* session_id, int32_t session_id_length, 489 const char* message, int32_t message_length, 490 const char* default_url, int32_t default_url_length) { 491 PP_DCHECK(!key_system_.empty()); 492 PostOnMain(callback_factory_.NewCallback( 493 &CdmAdapter::KeyMessage, 494 SessionInfo(key_system_, 495 std::string(session_id, session_id_length)), 496 std::vector<uint8>(message, message + message_length), 497 std::string(default_url, default_url_length))); 498} 499 500void CdmAdapter::SendKeyError(const char* session_id, 501 int32_t session_id_length, 502 cdm::MediaKeyError error_code, 503 uint32_t system_code) { 504 SendKeyErrorInternal(key_system_, 505 std::string(session_id, session_id_length), 506 error_code, 507 system_code); 508} 509 510void CdmAdapter::GetPrivateData(int32_t* instance, 511 GetPrivateInterface* get_interface) { 512 *instance = pp_instance(); 513 *get_interface = pp::Module::Get()->get_browser_interface(); 514} 515 516void CdmAdapter::SendUnknownKeyError(const std::string& key_system, 517 const std::string& session_id) { 518 SendKeyErrorInternal(key_system, session_id, cdm::kUnknownError, 0); 519} 520 521void CdmAdapter::SendKeyAdded(const std::string& key_system, 522 const std::string& session_id) { 523 PostOnMain(callback_factory_.NewCallback( 524 &CdmAdapter::KeyAdded, 525 SessionInfo(key_system_, session_id))); 526} 527 528void CdmAdapter::SendKeyErrorInternal(const std::string& key_system, 529 const std::string& session_id, 530 cdm::MediaKeyError error_code, 531 uint32_t system_code) { 532 PostOnMain(callback_factory_.NewCallback(&CdmAdapter::KeyError, 533 SessionInfo(key_system_, session_id), 534 error_code, 535 system_code)); 536} 537 538void CdmAdapter::KeyAdded(int32_t result, const SessionInfo& session_info) { 539 PP_DCHECK(result == PP_OK); 540 PP_DCHECK(!session_info.key_system.empty()); 541 pp::ContentDecryptor_Private::KeyAdded(session_info.key_system, 542 session_info.session_id); 543} 544 545void CdmAdapter::KeyMessage(int32_t result, 546 const SessionInfo& session_info, 547 const std::vector<uint8>& message, 548 const std::string& default_url) { 549 PP_DCHECK(result == PP_OK); 550 PP_DCHECK(!session_info.key_system.empty()); 551 552 pp::VarArrayBuffer message_array_buffer(message.size()); 553 if (message.size() > 0) { 554 memcpy(message_array_buffer.Map(), message.data(), message.size()); 555 } 556 557 pp::ContentDecryptor_Private::KeyMessage( 558 session_info.key_system, session_info.session_id, 559 message_array_buffer, default_url); 560} 561 562void CdmAdapter::KeyError(int32_t result, 563 const SessionInfo& session_info, 564 cdm::MediaKeyError error_code, 565 uint32_t system_code) { 566 PP_DCHECK(result == PP_OK); 567 pp::ContentDecryptor_Private::KeyError( 568 session_info.key_system, session_info.session_id, 569 error_code, system_code); 570} 571 572void CdmAdapter::DeliverBlock(int32_t result, 573 const cdm::Status& status, 574 const LinkedDecryptedBlock& decrypted_block, 575 const PP_DecryptTrackingInfo& tracking_info) { 576 PP_DCHECK(result == PP_OK); 577 PP_DecryptedBlockInfo decrypted_block_info; 578 decrypted_block_info.tracking_info = tracking_info; 579 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp(); 580 decrypted_block_info.tracking_info.buffer_id = 0; 581 decrypted_block_info.data_size = 0; 582 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); 583 584 pp::Buffer_Dev buffer; 585 586 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { 587 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer()); 588 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) { 589 PP_NOTREACHED(); 590 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 591 } else { 592 PpbBuffer* ppb_buffer = 593 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer()); 594 buffer = ppb_buffer->buffer_dev(); 595 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 596 decrypted_block_info.data_size = ppb_buffer->Size(); 597 } 598 } 599 600 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); 601} 602 603void CdmAdapter::DecoderInitializeDone(int32_t result, 604 PP_DecryptorStreamType decoder_type, 605 uint32_t request_id, 606 bool success) { 607 PP_DCHECK(result == PP_OK); 608 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, 609 request_id, 610 success); 611} 612 613void CdmAdapter::DecoderDeinitializeDone(int32_t result, 614 PP_DecryptorStreamType decoder_type, 615 uint32_t request_id) { 616 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type, 617 request_id); 618} 619 620void CdmAdapter::DecoderResetDone(int32_t result, 621 PP_DecryptorStreamType decoder_type, 622 uint32_t request_id) { 623 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); 624} 625 626void CdmAdapter::DeliverFrame( 627 int32_t result, 628 const cdm::Status& status, 629 const LinkedVideoFrame& video_frame, 630 const PP_DecryptTrackingInfo& tracking_info) { 631 PP_DCHECK(result == PP_OK); 632 PP_DecryptedFrameInfo decrypted_frame_info; 633 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id; 634 decrypted_frame_info.tracking_info.buffer_id = 0; 635 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status); 636 637 pp::Buffer_Dev buffer; 638 639 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) { 640 if (!IsValidVideoFrame(video_frame)) { 641 PP_NOTREACHED(); 642 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; 643 } else { 644 PpbBuffer* ppb_buffer = 645 static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 646 647 buffer = ppb_buffer->buffer_dev(); 648 649 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp(); 650 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 651 decrypted_frame_info.format = 652 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format()); 653 decrypted_frame_info.width = video_frame->Size().width; 654 decrypted_frame_info.height = video_frame->Size().height; 655 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] = 656 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane); 657 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] = 658 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane); 659 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] = 660 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane); 661 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] = 662 video_frame->Stride(cdm::VideoFrame::kYPlane); 663 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] = 664 video_frame->Stride(cdm::VideoFrame::kUPlane); 665 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] = 666 video_frame->Stride(cdm::VideoFrame::kVPlane); 667 } 668 } 669 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); 670} 671 672void CdmAdapter::DeliverSamples(int32_t result, 673 const cdm::Status& status, 674 const LinkedAudioFrames& audio_frames, 675 const PP_DecryptTrackingInfo& tracking_info) { 676 PP_DCHECK(result == PP_OK); 677 678 PP_DecryptedBlockInfo decrypted_block_info; 679 decrypted_block_info.tracking_info = tracking_info; 680 decrypted_block_info.tracking_info.timestamp = 0; 681 decrypted_block_info.tracking_info.buffer_id = 0; 682 decrypted_block_info.data_size = 0; 683 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); 684 685 pp::Buffer_Dev buffer; 686 687 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { 688 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer()); 689 if (!audio_frames.get() || !audio_frames->FrameBuffer()) { 690 PP_NOTREACHED(); 691 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 692 } else { 693 PpbBuffer* ppb_buffer = 694 static_cast<PpbBuffer*>(audio_frames->FrameBuffer()); 695 buffer = ppb_buffer->buffer_dev(); 696 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 697 decrypted_block_info.data_size = ppb_buffer->Size(); 698 } 699 } 700 701 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info); 702} 703 704bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) { 705 if (!video_frame.get() || 706 !video_frame->FrameBuffer() || 707 (video_frame->Format() != cdm::kI420 && 708 video_frame->Format() != cdm::kYv12)) { 709 return false; 710 } 711 712 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 713 714 for (int i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) { 715 int plane_height = (i == cdm::VideoFrame::kYPlane) ? 716 video_frame->Size().height : (video_frame->Size().height + 1) / 2; 717 cdm::VideoFrame::VideoPlane plane = 718 static_cast<cdm::VideoFrame::VideoPlane>(i); 719 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) + 720 plane_height * video_frame->Stride(plane)) { 721 return false; 722 } 723 } 724 725 return true; 726} 727 728void CdmAdapter::SendPlatformChallenge( 729 const char* service_id, int32_t service_id_length, 730 const char* challenge, int32_t challenge_length) { 731#if defined(OS_CHROMEOS) 732 PP_DCHECK(!challenge_in_progress_); 733 734 // Ensure member variables set by the callback are in a clean state. 735 signed_data_output_ = pp::Var(); 736 signed_data_signature_output_ = pp::Var(); 737 platform_key_certificate_output_ = pp::Var(); 738 739 pp::VarArrayBuffer challenge_var(challenge_length); 740 uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map()); 741 memcpy(var_data, challenge, challenge_length); 742 743 std::string service_id_str(service_id, service_id_length); 744 int32_t result = platform_verification_.ChallengePlatform( 745 pp::Var(service_id_str), challenge_var, &signed_data_output_, 746 &signed_data_signature_output_, &platform_key_certificate_output_, 747 callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone)); 748 challenge_var.Unmap(); 749 if (result == PP_OK_COMPLETIONPENDING) { 750 challenge_in_progress_ = true; 751 return; 752 } 753 754 // Fall through on error and issue an empty OnPlatformChallengeResponse(). 755 PP_DCHECK(result != PP_OK); 756#endif 757 758 cdm::PlatformChallengeResponse response = {}; 759 cdm_->OnPlatformChallengeResponse(response); 760} 761 762void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) { 763#if defined(OS_CHROMEOS) 764 output_protection_.EnableProtection( 765 desired_protection_mask, callback_factory_.NewCallback( 766 &CdmAdapter::EnableProtectionDone)); 767 768 // Errors are ignored since clients must call QueryOutputProtectionStatus() to 769 // inspect the protection status on a regular basis. 770 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here... 771#endif 772} 773 774void CdmAdapter::QueryOutputProtectionStatus() { 775#if defined(OS_CHROMEOS) 776 PP_DCHECK(!query_output_protection_in_progress_); 777 778 output_link_mask_ = output_protection_mask_ = 0; 779 const int32_t result = output_protection_.QueryStatus( 780 &output_link_mask_, 781 &output_protection_mask_, 782 callback_factory_.NewCallback( 783 &CdmAdapter::QueryOutputProtectionStatusDone)); 784 if (result == PP_OK_COMPLETIONPENDING) { 785 query_output_protection_in_progress_ = true; 786 return; 787 } 788 789 // Fall through on error and issue an empty OnQueryOutputProtectionStatus(). 790 PP_DCHECK(result != PP_OK); 791#endif 792 793 cdm_->OnQueryOutputProtectionStatus(0, 0); 794} 795 796#if defined(OS_CHROMEOS) 797void CdmAdapter::SendPlatformChallengeDone(int32_t result) { 798 challenge_in_progress_ = false; 799 800 if (result != PP_OK) { 801 cdm::PlatformChallengeResponse response = {}; 802 cdm_->OnPlatformChallengeResponse(response); 803 return; 804 } 805 806 pp::VarArrayBuffer signed_data_var(signed_data_output_); 807 pp::VarArrayBuffer signed_data_signature_var(signed_data_signature_output_); 808 std::string platform_key_certificate_string = 809 platform_key_certificate_output_.AsString(); 810 811 cdm::PlatformChallengeResponse response = { 812 static_cast<uint8_t*>(signed_data_var.Map()), 813 static_cast<int32_t>(signed_data_var.ByteLength()), 814 815 static_cast<uint8_t*>(signed_data_signature_var.Map()), 816 static_cast<int32_t>(signed_data_signature_var.ByteLength()), 817 818 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()), 819 static_cast<int32_t>(platform_key_certificate_string.length()) 820 }; 821 cdm_->OnPlatformChallengeResponse(response); 822 823 signed_data_var.Unmap(); 824 signed_data_signature_var.Unmap(); 825} 826 827void CdmAdapter::EnableProtectionDone(int32_t result) { 828 // Does nothing since clients must call QueryOutputProtectionStatus() to 829 // inspect the protection status on a regular basis. 830 // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here... 831} 832 833void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { 834 PP_DCHECK(query_output_protection_in_progress_); 835 query_output_protection_in_progress_ = false; 836 837 // Return a protection status of none on error. 838 if (result != PP_OK) 839 output_link_mask_ = output_protection_mask_ = 0; 840 841 cdm_->OnQueryOutputProtectionStatus(output_link_mask_, 842 output_protection_mask_); 843} 844#endif 845 846void* GetCdmHost(int host_interface_version, void* user_data) { 847 if (!host_interface_version || !user_data) 848 return NULL; 849 850 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); 851 switch (host_interface_version) { 852 case cdm::kHostInterfaceVersion_1: 853 return static_cast<cdm::Host_1*>(cdm_adapter); 854 case cdm::kHostInterfaceVersion_2: 855 return static_cast<cdm::Host_2*>(cdm_adapter); 856 default: 857 PP_NOTREACHED(); 858 return NULL; 859 } 860} 861 862// This object is the global object representing this plugin library as long 863// as it is loaded. 864class CdmAdapterModule : public pp::Module { 865 public: 866 CdmAdapterModule() : pp::Module() { 867 // This function blocks the renderer thread (PluginInstance::Initialize()). 868 // Move this call to other places if this may be a concern in the future. 869 INITIALIZE_CDM_MODULE(); 870 } 871 virtual ~CdmAdapterModule() { 872 DeinitializeCdmModule(); 873 } 874 875 virtual pp::Instance* CreateInstance(PP_Instance instance) { 876 return new CdmAdapter(instance, this); 877 } 878}; 879 880} // namespace media 881 882namespace pp { 883 884// Factory function for your specialization of the Module object. 885Module* CreateModule() { 886 return new media::CdmAdapterModule(); 887} 888 889} // namespace pp 890