1 // Copyright (c) 2012 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 "content/renderer/pepper/content_decryptor_delegate.h" 6 7 #include "base/callback_helpers.h" 8 #include "base/debug/trace_event.h" 9 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/metrics/sparse_histogram.h" 11 #include "base/numerics/safe_conversions.h" 12 #include "content/renderer/media/crypto/key_systems.h" 13 #include "content/renderer/pepper/ppb_buffer_impl.h" 14 #include "media/base/audio_buffer.h" 15 #include "media/base/audio_decoder_config.h" 16 #include "media/base/bind_to_current_loop.h" 17 #include "media/base/cdm_promise.h" 18 #include "media/base/channel_layout.h" 19 #include "media/base/data_buffer.h" 20 #include "media/base/decoder_buffer.h" 21 #include "media/base/decrypt_config.h" 22 #include "media/base/limits.h" 23 #include "media/base/video_decoder_config.h" 24 #include "media/base/video_frame.h" 25 #include "media/base/video_util.h" 26 #include "ppapi/shared_impl/array_var.h" 27 #include "ppapi/shared_impl/scoped_pp_resource.h" 28 #include "ppapi/shared_impl/time_conversion.h" 29 #include "ppapi/shared_impl/var.h" 30 #include "ppapi/shared_impl/var_tracker.h" 31 #include "ppapi/thunk/enter.h" 32 #include "ppapi/thunk/ppb_buffer_api.h" 33 #include "ui/gfx/rect.h" 34 35 using media::CdmPromise; 36 using media::Decryptor; 37 using media::KeyIdsPromise; 38 using media::MediaKeys; 39 using media::NewSessionCdmPromise; 40 using media::SimpleCdmPromise; 41 using ppapi::ArrayBufferVar; 42 using ppapi::ArrayVar; 43 using ppapi::PpapiGlobals; 44 using ppapi::ScopedPPResource; 45 using ppapi::StringVar; 46 using ppapi::thunk::EnterResourceNoLock; 47 using ppapi::thunk::PPB_Buffer_API; 48 49 namespace content { 50 51 namespace { 52 53 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer 54 // resource. The |*resource|, if valid, will be in the ResourceTracker with a 55 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns 56 // true upon success and false if any error happened. 57 bool MakeBufferResource(PP_Instance instance, 58 const uint8* data, 59 uint32_t size, 60 scoped_refptr<PPB_Buffer_Impl>* resource) { 61 TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource"); 62 DCHECK(resource); 63 64 if (!data || !size) { 65 DCHECK(!data && !size); 66 resource = NULL; 67 return true; 68 } 69 70 scoped_refptr<PPB_Buffer_Impl> buffer( 71 PPB_Buffer_Impl::CreateResource(instance, size)); 72 if (!buffer.get()) 73 return false; 74 75 BufferAutoMapper mapper(buffer.get()); 76 if (!mapper.data() || mapper.size() < size) 77 return false; 78 memcpy(mapper.data(), data, size); 79 80 *resource = buffer; 81 return true; 82 } 83 84 // Copies the content of |str| into |array|. 85 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the 86 // |array_size| is smaller than the |str| length. 87 template <uint32_t array_size> 88 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) { 89 if (array_size < str.size()) 90 return false; 91 92 memcpy(array, str.data(), str.size()); 93 return true; 94 } 95 96 // Fills the |block_info| with information from |encrypted_buffer|. 97 // 98 // Returns true if |block_info| is successfully filled. Returns false 99 // otherwise. 100 bool MakeEncryptedBlockInfo( 101 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, 102 uint32_t request_id, 103 PP_EncryptedBlockInfo* block_info) { 104 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and 105 // anywhere else. 106 memset(block_info, 0, sizeof(*block_info)); 107 block_info->tracking_info.request_id = request_id; 108 109 // EOS buffers need a request ID and nothing more. 110 if (encrypted_buffer->end_of_stream()) 111 return true; 112 113 DCHECK(encrypted_buffer->data_size()) 114 << "DecryptConfig is set on an empty buffer"; 115 116 block_info->tracking_info.timestamp = 117 encrypted_buffer->timestamp().InMicroseconds(); 118 block_info->data_size = encrypted_buffer->data_size(); 119 120 const media::DecryptConfig* decrypt_config = 121 encrypted_buffer->decrypt_config(); 122 123 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) || 124 !CopyStringToArray(decrypt_config->iv(), block_info->iv)) 125 return false; 126 127 block_info->key_id_size = decrypt_config->key_id().size(); 128 block_info->iv_size = decrypt_config->iv().size(); 129 130 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples)) 131 return false; 132 133 block_info->num_subsamples = decrypt_config->subsamples().size(); 134 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) { 135 block_info->subsamples[i].clear_bytes = 136 decrypt_config->subsamples()[i].clear_bytes; 137 block_info->subsamples[i].cipher_bytes = 138 decrypt_config->subsamples()[i].cypher_bytes; 139 } 140 141 return true; 142 } 143 144 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) { 145 switch (codec) { 146 case media::kCodecVorbis: 147 return PP_AUDIOCODEC_VORBIS; 148 case media::kCodecAAC: 149 return PP_AUDIOCODEC_AAC; 150 default: 151 return PP_AUDIOCODEC_UNKNOWN; 152 } 153 } 154 155 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) { 156 switch (codec) { 157 case media::kCodecVP8: 158 return PP_VIDEOCODEC_VP8; 159 case media::kCodecH264: 160 return PP_VIDEOCODEC_H264; 161 case media::kCodecVP9: 162 return PP_VIDEOCODEC_VP9; 163 default: 164 return PP_VIDEOCODEC_UNKNOWN; 165 } 166 } 167 168 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile( 169 media::VideoCodecProfile profile) { 170 switch (profile) { 171 case media::VP8PROFILE_ANY: 172 case media::VP9PROFILE_ANY: 173 return PP_VIDEOCODECPROFILE_NOT_NEEDED; 174 case media::H264PROFILE_BASELINE: 175 return PP_VIDEOCODECPROFILE_H264_BASELINE; 176 case media::H264PROFILE_MAIN: 177 return PP_VIDEOCODECPROFILE_H264_MAIN; 178 case media::H264PROFILE_EXTENDED: 179 return PP_VIDEOCODECPROFILE_H264_EXTENDED; 180 case media::H264PROFILE_HIGH: 181 return PP_VIDEOCODECPROFILE_H264_HIGH; 182 case media::H264PROFILE_HIGH10PROFILE: 183 return PP_VIDEOCODECPROFILE_H264_HIGH_10; 184 case media::H264PROFILE_HIGH422PROFILE: 185 return PP_VIDEOCODECPROFILE_H264_HIGH_422; 186 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE: 187 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE; 188 default: 189 return PP_VIDEOCODECPROFILE_UNKNOWN; 190 } 191 } 192 193 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat( 194 media::VideoFrame::Format format) { 195 switch (format) { 196 case media::VideoFrame::YV12: 197 return PP_DECRYPTEDFRAMEFORMAT_YV12; 198 case media::VideoFrame::I420: 199 return PP_DECRYPTEDFRAMEFORMAT_I420; 200 default: 201 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; 202 } 203 } 204 205 Decryptor::Status PpDecryptResultToMediaDecryptorStatus( 206 PP_DecryptResult result) { 207 switch (result) { 208 case PP_DECRYPTRESULT_SUCCESS: 209 return Decryptor::kSuccess; 210 case PP_DECRYPTRESULT_DECRYPT_NOKEY: 211 return Decryptor::kNoKey; 212 case PP_DECRYPTRESULT_NEEDMOREDATA: 213 return Decryptor::kNeedMoreData; 214 case PP_DECRYPTRESULT_DECRYPT_ERROR: 215 return Decryptor::kError; 216 case PP_DECRYPTRESULT_DECODE_ERROR: 217 return Decryptor::kError; 218 default: 219 NOTREACHED(); 220 return Decryptor::kError; 221 } 222 } 223 224 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType( 225 Decryptor::StreamType stream_type) { 226 switch (stream_type) { 227 case Decryptor::kAudio: 228 return PP_DECRYPTORSTREAMTYPE_AUDIO; 229 case Decryptor::kVideo: 230 return PP_DECRYPTORSTREAMTYPE_VIDEO; 231 default: 232 NOTREACHED(); 233 return PP_DECRYPTORSTREAMTYPE_VIDEO; 234 } 235 } 236 237 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat( 238 PP_DecryptedSampleFormat result) { 239 switch (result) { 240 case PP_DECRYPTEDSAMPLEFORMAT_U8: 241 return media::kSampleFormatU8; 242 case PP_DECRYPTEDSAMPLEFORMAT_S16: 243 return media::kSampleFormatS16; 244 case PP_DECRYPTEDSAMPLEFORMAT_S32: 245 return media::kSampleFormatS32; 246 case PP_DECRYPTEDSAMPLEFORMAT_F32: 247 return media::kSampleFormatF32; 248 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16: 249 return media::kSampleFormatPlanarS16; 250 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32: 251 return media::kSampleFormatPlanarF32; 252 default: 253 NOTREACHED(); 254 return media::kUnknownSampleFormat; 255 } 256 } 257 258 PP_SessionType MediaSessionTypeToPpSessionType( 259 MediaKeys::SessionType session_type) { 260 switch (session_type) { 261 case MediaKeys::TEMPORARY_SESSION: 262 return PP_SESSIONTYPE_TEMPORARY; 263 case MediaKeys::PERSISTENT_SESSION: 264 return PP_SESSIONTYPE_PERSISTENT; 265 default: 266 NOTREACHED(); 267 return PP_SESSIONTYPE_TEMPORARY; 268 } 269 } 270 271 MediaKeys::Exception PpExceptionTypeToMediaException( 272 PP_CdmExceptionCode exception_code) { 273 switch (exception_code) { 274 case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR: 275 return MediaKeys::NOT_SUPPORTED_ERROR; 276 case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR: 277 return MediaKeys::INVALID_STATE_ERROR; 278 case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR: 279 return MediaKeys::INVALID_ACCESS_ERROR; 280 case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR: 281 return MediaKeys::QUOTA_EXCEEDED_ERROR; 282 case PP_CDMEXCEPTIONCODE_UNKNOWNERROR: 283 return MediaKeys::UNKNOWN_ERROR; 284 case PP_CDMEXCEPTIONCODE_CLIENTERROR: 285 return MediaKeys::CLIENT_ERROR; 286 case PP_CDMEXCEPTIONCODE_OUTPUTERROR: 287 return MediaKeys::OUTPUT_ERROR; 288 default: 289 NOTREACHED(); 290 return MediaKeys::UNKNOWN_ERROR; 291 } 292 } 293 294 // TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated. 295 // See http://crbug.com/412987 for details. 296 void ReportSystemCodeUMA(const std::string& key_system, uint32 system_code) { 297 // Sparse histogram macro does not cache the histogram, so it's safe to use 298 // macro with non-static histogram name here. 299 UMA_HISTOGRAM_SPARSE_SLOWLY( 300 "Media.EME." + KeySystemNameForUMA(key_system) + ".SystemCode", 301 system_code); 302 } 303 304 } // namespace 305 306 ContentDecryptorDelegate::ContentDecryptorDelegate( 307 PP_Instance pp_instance, 308 const PPP_ContentDecryptor_Private* plugin_decryption_interface) 309 : pp_instance_(pp_instance), 310 plugin_decryption_interface_(plugin_decryption_interface), 311 next_decryption_request_id_(1), 312 audio_samples_per_second_(0), 313 audio_channel_count_(0), 314 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE), 315 next_promise_id_(1), 316 weak_ptr_factory_(this) { 317 weak_this_ = weak_ptr_factory_.GetWeakPtr(); 318 } 319 320 ContentDecryptorDelegate::~ContentDecryptorDelegate() { 321 SatisfyAllPendingCallbacksOnError(); 322 } 323 324 void ContentDecryptorDelegate::Initialize( 325 const std::string& key_system, 326 const media::SessionMessageCB& session_message_cb, 327 const media::SessionReadyCB& session_ready_cb, 328 const media::SessionClosedCB& session_closed_cb, 329 const media::SessionErrorCB& session_error_cb, 330 const media::SessionKeysChangeCB& session_keys_change_cb, 331 const media::SessionExpirationUpdateCB& session_expiration_update_cb, 332 const base::Closure& fatal_plugin_error_cb) { 333 DCHECK(!key_system.empty()); 334 DCHECK(key_system_.empty()); 335 key_system_ = key_system; 336 337 session_message_cb_ = session_message_cb; 338 session_ready_cb_ = session_ready_cb; 339 session_closed_cb_ = session_closed_cb; 340 session_error_cb_ = session_error_cb; 341 session_keys_change_cb_ = session_keys_change_cb; 342 session_expiration_update_cb_ = session_expiration_update_cb; 343 fatal_plugin_error_cb_ = fatal_plugin_error_cb; 344 345 plugin_decryption_interface_->Initialize( 346 pp_instance_, StringVar::StringToPPVar(key_system_)); 347 } 348 349 void ContentDecryptorDelegate::InstanceCrashed() { 350 fatal_plugin_error_cb_.Run(); 351 SatisfyAllPendingCallbacksOnError(); 352 } 353 354 void ContentDecryptorDelegate::SetServerCertificate( 355 const uint8_t* certificate, 356 uint32_t certificate_length, 357 scoped_ptr<media::SimpleCdmPromise> promise) { 358 if (!certificate || 359 certificate_length < media::limits::kMinCertificateLength || 360 certificate_length > media::limits::kMaxCertificateLength) { 361 promise->reject( 362 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate."); 363 return; 364 } 365 366 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 367 PP_Var certificate_array = 368 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 369 certificate_length, certificate); 370 plugin_decryption_interface_->SetServerCertificate( 371 pp_instance_, promise_id, certificate_array); 372 } 373 374 void ContentDecryptorDelegate::CreateSession( 375 const std::string& init_data_type, 376 const uint8* init_data, 377 int init_data_length, 378 MediaKeys::SessionType session_type, 379 scoped_ptr<NewSessionCdmPromise> promise) { 380 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 381 PP_Var init_data_array = 382 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 383 init_data_length, init_data); 384 plugin_decryption_interface_->CreateSession( 385 pp_instance_, 386 promise_id, 387 StringVar::StringToPPVar(init_data_type), 388 init_data_array, 389 MediaSessionTypeToPpSessionType(session_type)); 390 } 391 392 void ContentDecryptorDelegate::LoadSession( 393 const std::string& web_session_id, 394 scoped_ptr<NewSessionCdmPromise> promise) { 395 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 396 plugin_decryption_interface_->LoadSession( 397 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); 398 } 399 400 void ContentDecryptorDelegate::UpdateSession( 401 const std::string& web_session_id, 402 const uint8* response, 403 int response_length, 404 scoped_ptr<SimpleCdmPromise> promise) { 405 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 406 PP_Var response_array = 407 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 408 response_length, response); 409 plugin_decryption_interface_->UpdateSession( 410 pp_instance_, 411 promise_id, 412 StringVar::StringToPPVar(web_session_id), 413 response_array); 414 } 415 416 void ContentDecryptorDelegate::CloseSession( 417 const std::string& web_session_id, 418 scoped_ptr<SimpleCdmPromise> promise) { 419 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) { 420 promise->reject( 421 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session."); 422 return; 423 } 424 425 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 426 plugin_decryption_interface_->CloseSession( 427 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); 428 } 429 430 void ContentDecryptorDelegate::RemoveSession( 431 const std::string& web_session_id, 432 scoped_ptr<SimpleCdmPromise> promise) { 433 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) { 434 promise->reject( 435 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session."); 436 return; 437 } 438 439 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 440 plugin_decryption_interface_->RemoveSession( 441 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); 442 } 443 444 void ContentDecryptorDelegate::GetUsableKeyIds( 445 const std::string& web_session_id, 446 scoped_ptr<media::KeyIdsPromise> promise) { 447 if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) { 448 promise->reject( 449 media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session."); 450 return; 451 } 452 453 uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 454 plugin_decryption_interface_->GetUsableKeyIds( 455 pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); 456 } 457 458 // TODO(xhwang): Remove duplication of code in Decrypt(), 459 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). 460 bool ContentDecryptorDelegate::Decrypt( 461 Decryptor::StreamType stream_type, 462 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, 463 const Decryptor::DecryptCB& decrypt_cb) { 464 DVLOG(3) << "Decrypt() - stream_type: " << stream_type; 465 466 // |{audio|video}_input_resource_| is not being used by the plugin 467 // now because there is only one pending audio/video decrypt request at any 468 // time. This is enforced by the media pipeline. 469 scoped_refptr<PPB_Buffer_Impl> encrypted_resource; 470 if (!MakeMediaBufferResource( 471 stream_type, encrypted_buffer, &encrypted_resource) || 472 !encrypted_resource.get()) { 473 return false; 474 } 475 ScopedPPResource pp_resource(encrypted_resource.get()); 476 477 const uint32_t request_id = next_decryption_request_id_++; 478 DVLOG(2) << "Decrypt() - request_id " << request_id; 479 480 PP_EncryptedBlockInfo block_info = {}; 481 DCHECK(encrypted_buffer->decrypt_config()); 482 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) { 483 return false; 484 } 485 486 // There is only one pending decrypt request at any time per stream. This is 487 // enforced by the media pipeline. 488 switch (stream_type) { 489 case Decryptor::kAudio: 490 audio_decrypt_cb_.Set(request_id, decrypt_cb); 491 break; 492 case Decryptor::kVideo: 493 video_decrypt_cb_.Set(request_id, decrypt_cb); 494 break; 495 default: 496 NOTREACHED(); 497 return false; 498 } 499 500 SetBufferToFreeInTrackingInfo(&block_info.tracking_info); 501 502 plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info); 503 return true; 504 } 505 506 bool ContentDecryptorDelegate::CancelDecrypt( 507 Decryptor::StreamType stream_type) { 508 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type; 509 510 Decryptor::DecryptCB decrypt_cb; 511 switch (stream_type) { 512 case Decryptor::kAudio: 513 // Release the shared memory as it can still be in use by the plugin. 514 // The next Decrypt() call will need to allocate a new shared memory 515 // buffer. 516 audio_input_resource_ = NULL; 517 decrypt_cb = audio_decrypt_cb_.ResetAndReturn(); 518 break; 519 case Decryptor::kVideo: 520 // Release the shared memory as it can still be in use by the plugin. 521 // The next Decrypt() call will need to allocate a new shared memory 522 // buffer. 523 video_input_resource_ = NULL; 524 decrypt_cb = video_decrypt_cb_.ResetAndReturn(); 525 break; 526 default: 527 NOTREACHED(); 528 return false; 529 } 530 531 if (!decrypt_cb.is_null()) 532 decrypt_cb.Run(Decryptor::kSuccess, NULL); 533 534 return true; 535 } 536 537 bool ContentDecryptorDelegate::InitializeAudioDecoder( 538 const media::AudioDecoderConfig& decoder_config, 539 const Decryptor::DecoderInitCB& init_cb) { 540 PP_AudioDecoderConfig pp_decoder_config; 541 pp_decoder_config.codec = 542 MediaAudioCodecToPpAudioCodec(decoder_config.codec()); 543 pp_decoder_config.channel_count = 544 media::ChannelLayoutToChannelCount(decoder_config.channel_layout()); 545 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel(); 546 pp_decoder_config.samples_per_second = decoder_config.samples_per_second(); 547 pp_decoder_config.request_id = next_decryption_request_id_++; 548 549 audio_samples_per_second_ = pp_decoder_config.samples_per_second; 550 audio_channel_count_ = pp_decoder_config.channel_count; 551 audio_channel_layout_ = decoder_config.channel_layout(); 552 553 scoped_refptr<PPB_Buffer_Impl> extra_data_resource; 554 if (!MakeBufferResource(pp_instance_, 555 decoder_config.extra_data(), 556 decoder_config.extra_data_size(), 557 &extra_data_resource)) { 558 return false; 559 } 560 ScopedPPResource pp_resource(extra_data_resource.get()); 561 562 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb); 563 plugin_decryption_interface_->InitializeAudioDecoder( 564 pp_instance_, &pp_decoder_config, pp_resource); 565 return true; 566 } 567 568 bool ContentDecryptorDelegate::InitializeVideoDecoder( 569 const media::VideoDecoderConfig& decoder_config, 570 const Decryptor::DecoderInitCB& init_cb) { 571 PP_VideoDecoderConfig pp_decoder_config; 572 pp_decoder_config.codec = 573 MediaVideoCodecToPpVideoCodec(decoder_config.codec()); 574 pp_decoder_config.profile = 575 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile()); 576 pp_decoder_config.format = 577 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format()); 578 pp_decoder_config.width = decoder_config.coded_size().width(); 579 pp_decoder_config.height = decoder_config.coded_size().height(); 580 pp_decoder_config.request_id = next_decryption_request_id_++; 581 582 scoped_refptr<PPB_Buffer_Impl> extra_data_resource; 583 if (!MakeBufferResource(pp_instance_, 584 decoder_config.extra_data(), 585 decoder_config.extra_data_size(), 586 &extra_data_resource)) { 587 return false; 588 } 589 ScopedPPResource pp_resource(extra_data_resource.get()); 590 591 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb); 592 natural_size_ = decoder_config.natural_size(); 593 594 plugin_decryption_interface_->InitializeVideoDecoder( 595 pp_instance_, &pp_decoder_config, pp_resource); 596 return true; 597 } 598 599 bool ContentDecryptorDelegate::DeinitializeDecoder( 600 Decryptor::StreamType stream_type) { 601 CancelDecode(stream_type); 602 603 if (stream_type == Decryptor::kVideo) 604 natural_size_ = gfx::Size(); 605 606 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get 607 // stream type from media stack. 608 plugin_decryption_interface_->DeinitializeDecoder( 609 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); 610 return true; 611 } 612 613 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) { 614 CancelDecode(stream_type); 615 616 // TODO(tomfinegan): Add decoder reset request tracking. 617 plugin_decryption_interface_->ResetDecoder( 618 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); 619 return true; 620 } 621 622 bool ContentDecryptorDelegate::DecryptAndDecodeAudio( 623 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, 624 const Decryptor::AudioDecodeCB& audio_decode_cb) { 625 // |audio_input_resource_| is not being used by the plugin now 626 // because there is only one pending audio decode request at any time. 627 // This is enforced by the media pipeline. 628 scoped_refptr<PPB_Buffer_Impl> encrypted_resource; 629 if (!MakeMediaBufferResource( 630 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) { 631 return false; 632 } 633 634 // The resource should not be NULL for non-EOS buffer. 635 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get()) 636 return false; 637 638 const uint32_t request_id = next_decryption_request_id_++; 639 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id; 640 641 PP_EncryptedBlockInfo block_info = {}; 642 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) { 643 return false; 644 } 645 646 SetBufferToFreeInTrackingInfo(&block_info.tracking_info); 647 648 // There is only one pending audio decode request at any time. This is 649 // enforced by the media pipeline. If this DCHECK is violated, our buffer 650 // reuse policy is not valid, and we may have race problems for the shared 651 // buffer. 652 audio_decode_cb_.Set(request_id, audio_decode_cb); 653 654 ScopedPPResource pp_resource(encrypted_resource.get()); 655 plugin_decryption_interface_->DecryptAndDecode( 656 pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info); 657 return true; 658 } 659 660 bool ContentDecryptorDelegate::DecryptAndDecodeVideo( 661 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, 662 const Decryptor::VideoDecodeCB& video_decode_cb) { 663 // |video_input_resource_| is not being used by the plugin now 664 // because there is only one pending video decode request at any time. 665 // This is enforced by the media pipeline. 666 scoped_refptr<PPB_Buffer_Impl> encrypted_resource; 667 if (!MakeMediaBufferResource( 668 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) { 669 return false; 670 } 671 672 // The resource should not be 0 for non-EOS buffer. 673 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get()) 674 return false; 675 676 const uint32_t request_id = next_decryption_request_id_++; 677 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; 678 TRACE_EVENT_ASYNC_BEGIN0( 679 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id); 680 681 PP_EncryptedBlockInfo block_info = {}; 682 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) { 683 return false; 684 } 685 686 SetBufferToFreeInTrackingInfo(&block_info.tracking_info); 687 688 // Only one pending video decode request at any time. This is enforced by the 689 // media pipeline. If this DCHECK is violated, our buffer 690 // reuse policy is not valid, and we may have race problems for the shared 691 // buffer. 692 video_decode_cb_.Set(request_id, video_decode_cb); 693 694 // TODO(tomfinegan): Need to get stream type from media stack. 695 ScopedPPResource pp_resource(encrypted_resource.get()); 696 plugin_decryption_interface_->DecryptAndDecode( 697 pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info); 698 return true; 699 } 700 701 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) { 702 scoped_ptr<CdmPromise> promise = TakePromise(promise_id); 703 if (!promise || 704 promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) { 705 NOTREACHED(); 706 return; 707 } 708 709 SimpleCdmPromise* simple_promise = 710 static_cast<SimpleCdmPromise*>(promise.get()); 711 simple_promise->resolve(); 712 } 713 714 void ContentDecryptorDelegate::OnPromiseResolvedWithSession( 715 uint32 promise_id, 716 PP_Var web_session_id) { 717 scoped_ptr<CdmPromise> promise = TakePromise(promise_id); 718 if (!promise || 719 promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) { 720 NOTREACHED(); 721 return; 722 } 723 724 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 725 DCHECK(web_session_id_string); 726 727 NewSessionCdmPromise* session_promise = 728 static_cast<NewSessionCdmPromise*>(promise.get()); 729 session_promise->resolve(web_session_id_string->value()); 730 } 731 732 void ContentDecryptorDelegate::OnPromiseResolvedWithKeyIds( 733 uint32 promise_id, 734 PP_Var key_ids_array) { 735 scoped_ptr<CdmPromise> promise = TakePromise(promise_id); 736 737 ArrayVar* key_ids = ArrayVar::FromPPVar(key_ids_array); 738 DCHECK(key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds); 739 media::KeyIdsVector key_ids_vector; 740 if (key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds) { 741 for (size_t i = 0; i < key_ids->GetLength(); ++i) { 742 ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(key_ids->Get(i)); 743 744 if (!array_buffer || 745 array_buffer->ByteLength() < media::limits::kMinKeyIdLength || 746 array_buffer->ByteLength() > media::limits::kMaxKeyIdLength) { 747 NOTREACHED(); 748 continue; 749 } 750 751 std::vector<uint8> key_id; 752 const uint8* data = static_cast<const uint8*>(array_buffer->Map()); 753 key_id.assign(data, data + array_buffer->ByteLength()); 754 key_ids_vector.push_back(key_id); 755 } 756 } 757 758 if (!promise || 759 promise->GetResolveParameterType() != 760 media::CdmPromise::KEY_IDS_VECTOR_TYPE) { 761 NOTREACHED(); 762 return; 763 } 764 765 KeyIdsPromise* key_ids_promise(static_cast<KeyIdsPromise*>(promise.get())); 766 key_ids_promise->resolve(key_ids_vector); 767 } 768 769 void ContentDecryptorDelegate::OnPromiseRejected( 770 uint32 promise_id, 771 PP_CdmExceptionCode exception_code, 772 uint32 system_code, 773 PP_Var error_description) { 774 ReportSystemCodeUMA(key_system_, system_code); 775 776 StringVar* error_description_string = StringVar::FromPPVar(error_description); 777 DCHECK(error_description_string); 778 779 scoped_ptr<CdmPromise> promise = TakePromise(promise_id); 780 DCHECK(promise); 781 if (promise) { 782 promise->reject(PpExceptionTypeToMediaException(exception_code), 783 system_code, 784 error_description_string->value()); 785 } 786 } 787 788 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id, 789 PP_Var message, 790 PP_Var destination_url) { 791 if (session_message_cb_.is_null()) 792 return; 793 794 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 795 DCHECK(web_session_id_string); 796 797 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message); 798 std::vector<uint8> message_vector; 799 if (message_array_buffer) { 800 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map()); 801 message_vector.assign(data, data + message_array_buffer->ByteLength()); 802 } 803 804 StringVar* destination_url_string = StringVar::FromPPVar(destination_url); 805 DCHECK(destination_url_string); 806 807 GURL verified_gurl = GURL(destination_url_string->value()); 808 if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) { 809 DLOG(WARNING) << "SessionMessage default_url is invalid : " 810 << verified_gurl.possibly_invalid_spec(); 811 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url. 812 } 813 814 session_message_cb_.Run( 815 web_session_id_string->value(), message_vector, verified_gurl); 816 } 817 818 void ContentDecryptorDelegate::OnSessionKeysChange( 819 PP_Var web_session_id, 820 PP_Bool has_additional_usable_key) { 821 if (session_keys_change_cb_.is_null()) 822 return; 823 824 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 825 DCHECK(web_session_id_string); 826 827 session_keys_change_cb_.Run(web_session_id_string->value(), 828 PP_ToBool(has_additional_usable_key)); 829 } 830 831 void ContentDecryptorDelegate::OnSessionExpirationChange( 832 PP_Var web_session_id, 833 PP_Time new_expiry_time) { 834 if (session_expiration_update_cb_.is_null()) 835 return; 836 837 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 838 DCHECK(web_session_id_string); 839 840 session_expiration_update_cb_.Run(web_session_id_string->value(), 841 ppapi::PPTimeToTime(new_expiry_time)); 842 } 843 844 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) { 845 if (session_ready_cb_.is_null()) 846 return; 847 848 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 849 DCHECK(web_session_id_string); 850 851 session_ready_cb_.Run(web_session_id_string->value()); 852 } 853 854 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) { 855 if (session_closed_cb_.is_null()) 856 return; 857 858 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 859 DCHECK(web_session_id_string); 860 861 session_closed_cb_.Run(web_session_id_string->value()); 862 } 863 864 void ContentDecryptorDelegate::OnSessionError( 865 PP_Var web_session_id, 866 PP_CdmExceptionCode exception_code, 867 uint32 system_code, 868 PP_Var error_description) { 869 ReportSystemCodeUMA(key_system_, system_code); 870 871 if (session_error_cb_.is_null()) 872 return; 873 874 StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); 875 DCHECK(web_session_id_string); 876 877 StringVar* error_description_string = StringVar::FromPPVar(error_description); 878 DCHECK(error_description_string); 879 880 session_error_cb_.Run(web_session_id_string->value(), 881 PpExceptionTypeToMediaException(exception_code), 882 system_code, 883 error_description_string->value()); 884 } 885 886 void ContentDecryptorDelegate::DecoderInitializeDone( 887 PP_DecryptorStreamType decoder_type, 888 uint32_t request_id, 889 PP_Bool success) { 890 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) { 891 // If the request ID is not valid or does not match what's saved, do 892 // nothing. 893 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id)) 894 return; 895 896 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success)); 897 } else { 898 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id)) 899 return; 900 901 if (!success) 902 natural_size_ = gfx::Size(); 903 904 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success)); 905 } 906 } 907 908 void ContentDecryptorDelegate::DecoderDeinitializeDone( 909 PP_DecryptorStreamType decoder_type, 910 uint32_t request_id) { 911 // TODO(tomfinegan): Add decoder stop completion handling. 912 } 913 914 void ContentDecryptorDelegate::DecoderResetDone( 915 PP_DecryptorStreamType decoder_type, 916 uint32_t request_id) { 917 // TODO(tomfinegan): Add decoder reset completion handling. 918 } 919 920 void ContentDecryptorDelegate::DeliverBlock( 921 PP_Resource decrypted_block, 922 const PP_DecryptedBlockInfo* block_info) { 923 DCHECK(block_info); 924 925 FreeBuffer(block_info->tracking_info.buffer_id); 926 927 const uint32_t request_id = block_info->tracking_info.request_id; 928 DVLOG(2) << "DeliverBlock() - request_id: " << request_id; 929 930 // If the request ID is not valid or does not match what's saved, do nothing. 931 if (request_id == 0) { 932 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id; 933 return; 934 } 935 936 Decryptor::DecryptCB decrypt_cb; 937 if (audio_decrypt_cb_.Matches(request_id)) { 938 decrypt_cb = audio_decrypt_cb_.ResetAndReturn(); 939 } else if (video_decrypt_cb_.Matches(request_id)) { 940 decrypt_cb = video_decrypt_cb_.ResetAndReturn(); 941 } else { 942 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found"; 943 return; 944 } 945 946 Decryptor::Status status = 947 PpDecryptResultToMediaDecryptorStatus(block_info->result); 948 if (status != Decryptor::kSuccess) { 949 decrypt_cb.Run(status, NULL); 950 return; 951 } 952 953 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true); 954 if (!enter.succeeded()) { 955 decrypt_cb.Run(Decryptor::kError, NULL); 956 return; 957 } 958 BufferAutoMapper mapper(enter.object()); 959 if (!mapper.data() || !mapper.size() || 960 mapper.size() < block_info->data_size) { 961 decrypt_cb.Run(Decryptor::kError, NULL); 962 return; 963 } 964 965 // TODO(tomfinegan): Find a way to take ownership of the shared memory 966 // managed by the PPB_Buffer_Dev, and avoid the extra copy. 967 scoped_refptr<media::DecoderBuffer> decrypted_buffer( 968 media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()), 969 block_info->data_size)); 970 decrypted_buffer->set_timestamp( 971 base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp)); 972 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer); 973 } 974 975 // Use a non-class-member function here so that if for some reason 976 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback, 977 // we can still get the shared memory unmapped. 978 static void BufferNoLongerNeeded( 979 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer, 980 base::Closure buffer_no_longer_needed_cb) { 981 ppb_buffer->Unmap(); 982 buffer_no_longer_needed_cb.Run(); 983 } 984 985 // Enters |resource|, maps shared memory and returns pointer of mapped data. 986 // Returns NULL if any error occurs. 987 static uint8* GetMappedBuffer(PP_Resource resource, 988 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) { 989 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); 990 if (!enter.succeeded()) 991 return NULL; 992 993 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map()); 994 if (!enter.object()->IsMapped() || !mapped_data) 995 return NULL; 996 997 uint32_t mapped_size = 0; 998 if (!enter.object()->Describe(&mapped_size) || !mapped_size) { 999 enter.object()->Unmap(); 1000 return NULL; 1001 } 1002 1003 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object()); 1004 1005 return mapped_data; 1006 } 1007 1008 void ContentDecryptorDelegate::DeliverFrame( 1009 PP_Resource decrypted_frame, 1010 const PP_DecryptedFrameInfo* frame_info) { 1011 DCHECK(frame_info); 1012 1013 const uint32_t request_id = frame_info->tracking_info.request_id; 1014 DVLOG(2) << "DeliverFrame() - request_id: " << request_id; 1015 1016 // If the request ID is not valid or does not match what's saved, do nothing. 1017 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) { 1018 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; 1019 FreeBuffer(frame_info->tracking_info.buffer_id); 1020 return; 1021 } 1022 1023 TRACE_EVENT_ASYNC_END0( 1024 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id); 1025 1026 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn(); 1027 1028 Decryptor::Status status = 1029 PpDecryptResultToMediaDecryptorStatus(frame_info->result); 1030 if (status != Decryptor::kSuccess) { 1031 DCHECK(!frame_info->tracking_info.buffer_id); 1032 video_decode_cb.Run(status, NULL); 1033 return; 1034 } 1035 1036 scoped_refptr<PPB_Buffer_Impl> ppb_buffer; 1037 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer); 1038 if (!frame_data) { 1039 FreeBuffer(frame_info->tracking_info.buffer_id); 1040 video_decode_cb.Run(Decryptor::kError, NULL); 1041 return; 1042 } 1043 1044 gfx::Size frame_size(frame_info->width, frame_info->height); 1045 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12); 1046 1047 scoped_refptr<media::VideoFrame> decoded_frame = 1048 media::VideoFrame::WrapExternalYuvData( 1049 media::VideoFrame::YV12, 1050 frame_size, 1051 gfx::Rect(frame_size), 1052 natural_size_, 1053 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y], 1054 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U], 1055 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V], 1056 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y], 1057 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U], 1058 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V], 1059 base::TimeDelta::FromMicroseconds( 1060 frame_info->tracking_info.timestamp), 1061 media::BindToCurrentLoop( 1062 base::Bind(&BufferNoLongerNeeded, 1063 ppb_buffer, 1064 base::Bind(&ContentDecryptorDelegate::FreeBuffer, 1065 weak_this_, 1066 frame_info->tracking_info.buffer_id)))); 1067 1068 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame); 1069 } 1070 1071 void ContentDecryptorDelegate::DeliverSamples( 1072 PP_Resource audio_frames, 1073 const PP_DecryptedSampleInfo* sample_info) { 1074 DCHECK(sample_info); 1075 1076 FreeBuffer(sample_info->tracking_info.buffer_id); 1077 1078 const uint32_t request_id = sample_info->tracking_info.request_id; 1079 DVLOG(2) << "DeliverSamples() - request_id: " << request_id; 1080 1081 // If the request ID is not valid or does not match what's saved, do nothing. 1082 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) { 1083 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found"; 1084 return; 1085 } 1086 1087 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn(); 1088 1089 const Decryptor::AudioBuffers empty_frames; 1090 1091 Decryptor::Status status = 1092 PpDecryptResultToMediaDecryptorStatus(sample_info->result); 1093 if (status != Decryptor::kSuccess) { 1094 audio_decode_cb.Run(status, empty_frames); 1095 return; 1096 } 1097 1098 media::SampleFormat sample_format = 1099 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format); 1100 1101 Decryptor::AudioBuffers audio_frame_list; 1102 if (!DeserializeAudioFrames(audio_frames, 1103 sample_info->data_size, 1104 sample_format, 1105 &audio_frame_list)) { 1106 NOTREACHED() << "CDM did not serialize the buffer correctly."; 1107 audio_decode_cb.Run(Decryptor::kError, empty_frames); 1108 return; 1109 } 1110 1111 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list); 1112 } 1113 1114 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt(). 1115 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) { 1116 switch (stream_type) { 1117 case Decryptor::kAudio: 1118 // Release the shared memory as it can still be in use by the plugin. 1119 // The next DecryptAndDecode() call will need to allocate a new shared 1120 // memory buffer. 1121 audio_input_resource_ = NULL; 1122 if (!audio_decode_cb_.is_null()) 1123 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, 1124 Decryptor::AudioBuffers()); 1125 break; 1126 case Decryptor::kVideo: 1127 // Release the shared memory as it can still be in use by the plugin. 1128 // The next DecryptAndDecode() call will need to allocate a new shared 1129 // memory buffer. 1130 video_input_resource_ = NULL; 1131 if (!video_decode_cb_.is_null()) 1132 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL); 1133 break; 1134 default: 1135 NOTREACHED(); 1136 } 1137 } 1138 1139 bool ContentDecryptorDelegate::MakeMediaBufferResource( 1140 Decryptor::StreamType stream_type, 1141 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, 1142 scoped_refptr<PPB_Buffer_Impl>* resource) { 1143 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource"); 1144 1145 // End of stream buffers are represented as null resources. 1146 if (encrypted_buffer->end_of_stream()) { 1147 *resource = NULL; 1148 return true; 1149 } 1150 1151 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo); 1152 scoped_refptr<PPB_Buffer_Impl>& media_resource = 1153 (stream_type == Decryptor::kAudio) ? audio_input_resource_ 1154 : video_input_resource_; 1155 1156 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size()); 1157 if (!media_resource.get() || media_resource->size() < data_size) { 1158 // Either the buffer hasn't been created yet, or we have one that isn't big 1159 // enough to fit |size| bytes. 1160 1161 // Media resource size starts from |kMinimumMediaBufferSize| and grows 1162 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl, 1163 // which is usually expensive. Since input media buffers are compressed, 1164 // they are usually small (compared to outputs). The over-allocated memory 1165 // should be negligible. 1166 const uint32_t kMinimumMediaBufferSize = 1024; 1167 uint32_t media_resource_size = 1168 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize; 1169 while (media_resource_size < data_size) 1170 media_resource_size *= 2; 1171 1172 DVLOG(2) << "Size of media buffer for " 1173 << ((stream_type == Decryptor::kAudio) ? "audio" : "video") 1174 << " stream bumped to " << media_resource_size 1175 << " bytes to fit input."; 1176 media_resource = 1177 PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size); 1178 if (!media_resource.get()) 1179 return false; 1180 } 1181 1182 BufferAutoMapper mapper(media_resource.get()); 1183 if (!mapper.data() || mapper.size() < data_size) { 1184 media_resource = NULL; 1185 return false; 1186 } 1187 memcpy(mapper.data(), encrypted_buffer->data(), data_size); 1188 1189 *resource = media_resource; 1190 return true; 1191 } 1192 1193 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) { 1194 if (buffer_id) 1195 free_buffers_.push(buffer_id); 1196 } 1197 1198 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo( 1199 PP_DecryptTrackingInfo* tracking_info) { 1200 DCHECK_EQ(tracking_info->buffer_id, 0u); 1201 1202 if (free_buffers_.empty()) 1203 return; 1204 1205 tracking_info->buffer_id = free_buffers_.front(); 1206 free_buffers_.pop(); 1207 } 1208 1209 bool ContentDecryptorDelegate::DeserializeAudioFrames( 1210 PP_Resource audio_frames, 1211 size_t data_size, 1212 media::SampleFormat sample_format, 1213 Decryptor::AudioBuffers* frames) { 1214 DCHECK(frames); 1215 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true); 1216 if (!enter.succeeded()) 1217 return false; 1218 1219 BufferAutoMapper mapper(enter.object()); 1220 if (!mapper.data() || !mapper.size() || 1221 mapper.size() < static_cast<uint32_t>(data_size)) 1222 return false; 1223 1224 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid 1225 // the copy. Since it is possible to get multiple buffers, it would need to be 1226 // sliced and ref counted appropriately. http://crbug.com/255576. 1227 const uint8* cur = static_cast<uint8*>(mapper.data()); 1228 size_t bytes_left = data_size; 1229 1230 const int audio_bytes_per_frame = 1231 media::SampleFormatToBytesPerChannel(sample_format) * 1232 audio_channel_count_; 1233 if (audio_bytes_per_frame <= 0) 1234 return false; 1235 1236 // Allocate space for the channel pointers given to AudioBuffer. 1237 std::vector<const uint8*> channel_ptrs(audio_channel_count_, 1238 static_cast<const uint8*>(NULL)); 1239 do { 1240 int64 timestamp = 0; 1241 int64 frame_size = -1; 1242 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size); 1243 1244 if (bytes_left < kHeaderSize) 1245 return false; 1246 1247 memcpy(×tamp, cur, sizeof(timestamp)); 1248 cur += sizeof(timestamp); 1249 bytes_left -= sizeof(timestamp); 1250 1251 memcpy(&frame_size, cur, sizeof(frame_size)); 1252 cur += sizeof(frame_size); 1253 bytes_left -= sizeof(frame_size); 1254 1255 // We should *not* have empty frames in the list. 1256 if (frame_size <= 0 || 1257 bytes_left < base::checked_cast<size_t>(frame_size)) { 1258 return false; 1259 } 1260 1261 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first 1262 // one in the case of interleaved data. 1263 const int size_per_channel = frame_size / audio_channel_count_; 1264 for (int i = 0; i < audio_channel_count_; ++i) 1265 channel_ptrs[i] = cur + i * size_per_channel; 1266 1267 const int frame_count = frame_size / audio_bytes_per_frame; 1268 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom( 1269 sample_format, 1270 audio_channel_layout_, 1271 audio_channel_count_, 1272 audio_samples_per_second_, 1273 frame_count, 1274 &channel_ptrs[0], 1275 base::TimeDelta::FromMicroseconds(timestamp)); 1276 frames->push_back(frame); 1277 1278 cur += frame_size; 1279 bytes_left -= frame_size; 1280 } while (bytes_left > 0); 1281 1282 return true; 1283 } 1284 1285 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() { 1286 if (!audio_decoder_init_cb_.is_null()) 1287 audio_decoder_init_cb_.ResetAndReturn().Run(false); 1288 1289 if (!video_decoder_init_cb_.is_null()) 1290 video_decoder_init_cb_.ResetAndReturn().Run(false); 1291 1292 audio_input_resource_ = NULL; 1293 video_input_resource_ = NULL; 1294 1295 if (!audio_decrypt_cb_.is_null()) 1296 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); 1297 1298 if (!video_decrypt_cb_.is_null()) 1299 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); 1300 1301 if (!audio_decode_cb_.is_null()) { 1302 const media::Decryptor::AudioBuffers empty_frames; 1303 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, 1304 empty_frames); 1305 } 1306 1307 if (!video_decode_cb_.is_null()) 1308 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); 1309 1310 // Reject all outstanding promises. 1311 for (PromiseMap::iterator it = promises_.begin(); it != promises_.end(); 1312 ++it) { 1313 it->second->reject( 1314 media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin."); 1315 } 1316 promises_.clear(); 1317 } 1318 1319 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) { 1320 uint32_t promise_id = next_promise_id_++; 1321 promises_.add(promise_id, promise.Pass()); 1322 return promise_id; 1323 } 1324 1325 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise( 1326 uint32_t promise_id) { 1327 PromiseMap::iterator it = promises_.find(promise_id); 1328 if (it == promises_.end()) 1329 return scoped_ptr<CdmPromise>(); 1330 return promises_.take_and_erase(it); 1331 } 1332 1333 } // namespace content 1334