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/clear_key_cdm.h" 6 7 #include <algorithm> 8 #include <sstream> 9 #include <string> 10 #include <vector> 11 12 #include "base/bind.h" 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/time/time.h" 16 #include "media/base/decoder_buffer.h" 17 #include "media/base/decrypt_config.h" 18 #include "media/cdm/ppapi/cdm_video_decoder.h" 19 20 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 21 #include "base/basictypes.h" 22 static const int64 kNoTimestamp = kint64min; 23 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 24 25 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 26 #include "base/at_exit.h" 27 #include "base/files/file_path.h" 28 #include "base/path_service.h" 29 #include "media/base/media.h" 30 #include "media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h" 31 #include "media/cdm/ppapi/ffmpeg_cdm_video_decoder.h" 32 33 // Include FFmpeg avformat.h for av_register_all(). 34 extern "C" { 35 // Temporarily disable possible loss of data warning. 36 MSVC_PUSH_DISABLE_WARNING(4244); 37 #include <libavformat/avformat.h> 38 MSVC_POP_WARNING(); 39 } // extern "C" 40 41 // TODO(tomfinegan): When COMPONENT_BUILD is not defined an AtExitManager must 42 // exist before the call to InitializeFFmpegLibraries(). This should no longer 43 // be required after http://crbug.com/91970 because we'll be able to get rid of 44 // InitializeFFmpegLibraries(). 45 #if !defined COMPONENT_BUILD 46 static base::AtExitManager g_at_exit_manager; 47 #endif 48 49 // TODO(tomfinegan): InitializeFFmpegLibraries() and |g_cdm_module_initialized| 50 // are required for running in the sandbox, and should no longer be required 51 // after http://crbug.com/91970 is fixed. 52 static bool InitializeFFmpegLibraries() { 53 base::FilePath file_path; 54 CHECK(PathService::Get(base::DIR_MODULE, &file_path)); 55 CHECK(media::InitializeMediaLibrary(file_path)); 56 return true; 57 } 58 59 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries(); 60 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 61 62 static const char kClearKeyCdmVersion[] = "0.1.0.1"; 63 static const char kExternalClearKey[] = "org.chromium.externalclearkey"; 64 static const int64 kSecondsPerMinute = 60; 65 static const int64 kMsPerSecond = 1000; 66 static const int64 kInitialTimerDelayMs = 200; 67 static const int64 kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond; 68 // Heart beat message header. If a key message starts with |kHeartBeatHeader|, 69 // it's a heart beat message. Otherwise, it's a key request. 70 static const char kHeartBeatHeader[] = "HEARTBEAT"; 71 72 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is 73 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. 74 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( 75 const cdm::InputBuffer& input_buffer) { 76 if (!input_buffer.data) { 77 DCHECK_EQ(input_buffer.data_size, 0); 78 return media::DecoderBuffer::CreateEOSBuffer(); 79 } 80 81 // TODO(tomfinegan): Get rid of this copy. 82 scoped_refptr<media::DecoderBuffer> output_buffer = 83 media::DecoderBuffer::CopyFrom(input_buffer.data, input_buffer.data_size); 84 85 std::vector<media::SubsampleEntry> subsamples; 86 for (int32_t i = 0; i < input_buffer.num_subsamples; ++i) { 87 media::SubsampleEntry subsample; 88 subsample.clear_bytes = input_buffer.subsamples[i].clear_bytes; 89 subsample.cypher_bytes = input_buffer.subsamples[i].cipher_bytes; 90 subsamples.push_back(subsample); 91 } 92 93 scoped_ptr<media::DecryptConfig> decrypt_config(new media::DecryptConfig( 94 std::string(reinterpret_cast<const char*>(input_buffer.key_id), 95 input_buffer.key_id_size), 96 std::string(reinterpret_cast<const char*>(input_buffer.iv), 97 input_buffer.iv_size), 98 input_buffer.data_offset, 99 subsamples)); 100 101 output_buffer->set_decrypt_config(decrypt_config.Pass()); 102 output_buffer->set_timestamp( 103 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); 104 105 return output_buffer; 106 } 107 108 template<typename Type> 109 class ScopedResetter { 110 public: 111 explicit ScopedResetter(Type* object) : object_(object) {} 112 ~ScopedResetter() { object_->Reset(); } 113 114 private: 115 Type* const object_; 116 }; 117 118 void INITIALIZE_CDM_MODULE() { 119 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 120 DVLOG(2) << "FFmpeg libraries initialized: " << g_ffmpeg_lib_initialized; 121 av_register_all(); 122 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 123 } 124 125 void DeinitializeCdmModule() { 126 } 127 128 void* CreateCdmInstance( 129 int cdm_interface_version, 130 const char* key_system, int key_system_size, 131 GetCdmHostFunc get_cdm_host_func, void* user_data) { 132 DVLOG(1) << "CreateCdmInstance()"; 133 134 if (cdm_interface_version != cdm::kCdmInterfaceVersion) 135 return NULL; 136 137 cdm::Host* host = static_cast<cdm::Host*>( 138 get_cdm_host_func(cdm::kHostInterfaceVersion, user_data)); 139 if (!host) 140 return NULL; 141 142 return static_cast<cdm::ContentDecryptionModule*>( 143 new media::ClearKeyCdm(host)); 144 } 145 146 const char* GetCdmVersion() { 147 return kClearKeyCdmVersion; 148 } 149 150 namespace media { 151 152 ClearKeyCdm::Client::Client() : status_(kKeyError) {} 153 154 ClearKeyCdm::Client::~Client() {} 155 156 void ClearKeyCdm::Client::Reset() { 157 status_ = kKeyError; 158 session_id_.clear(); 159 key_message_.clear(); 160 default_url_.clear(); 161 } 162 163 void ClearKeyCdm::Client::KeyAdded(const std::string& session_id) { 164 status_ = kKeyAdded; 165 session_id_ = session_id; 166 } 167 168 void ClearKeyCdm::Client::KeyError(const std::string& session_id, 169 media::MediaKeys::KeyError error_code, 170 int system_code) { 171 status_ = kKeyError; 172 session_id_ = session_id; 173 } 174 175 void ClearKeyCdm::Client::KeyMessage(const std::string& session_id, 176 const std::vector<uint8>& message, 177 const std::string& default_url) { 178 status_ = kKeyMessage; 179 session_id_ = session_id; 180 key_message_ = message; 181 default_url_ = default_url; 182 } 183 184 ClearKeyCdm::ClearKeyCdm(cdm::Host* host) 185 : decryptor_(base::Bind(&Client::KeyAdded, base::Unretained(&client_)), 186 base::Bind(&Client::KeyError, base::Unretained(&client_)), 187 base::Bind(&Client::KeyMessage, base::Unretained(&client_))), 188 host_(host), 189 timer_delay_ms_(kInitialTimerDelayMs), 190 timer_set_(false) { 191 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 192 channel_count_ = 0; 193 bits_per_channel_ = 0; 194 samples_per_second_ = 0; 195 output_timestamp_base_in_microseconds_ = kNoTimestamp; 196 total_samples_generated_ = 0; 197 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 198 } 199 200 ClearKeyCdm::~ClearKeyCdm() {} 201 202 cdm::Status ClearKeyCdm::GenerateKeyRequest(const char* type, int type_size, 203 const uint8_t* init_data, 204 int init_data_size) { 205 DVLOG(1) << "GenerateKeyRequest()"; 206 base::AutoLock auto_lock(client_lock_); 207 ScopedResetter<Client> auto_resetter(&client_); 208 decryptor_.GenerateKeyRequest(std::string(type, type_size), 209 init_data, init_data_size); 210 211 if (client_.status() != Client::kKeyMessage) { 212 host_->SendKeyError(NULL, 0, cdm::kUnknownError, 0); 213 return cdm::kSessionError; 214 } 215 216 host_->SendKeyMessage( 217 client_.session_id().data(), client_.session_id().size(), 218 reinterpret_cast<const char*>(&client_.key_message()[0]), 219 client_.key_message().size(), 220 client_.default_url().data(), client_.default_url().size()); 221 222 // Only save the latest session ID for heartbeat messages. 223 heartbeat_session_id_ = client_.session_id(); 224 225 return cdm::kSuccess; 226 } 227 228 cdm::Status ClearKeyCdm::AddKey(const char* session_id, 229 int session_id_size, 230 const uint8_t* key, 231 int key_size, 232 const uint8_t* key_id, 233 int key_id_size) { 234 DVLOG(1) << "AddKey()"; 235 base::AutoLock auto_lock(client_lock_); 236 ScopedResetter<Client> auto_resetter(&client_); 237 decryptor_.AddKey(key, key_size, key_id, key_id_size, 238 std::string(session_id, session_id_size)); 239 240 if (client_.status() != Client::kKeyAdded) 241 return cdm::kSessionError; 242 243 if (!timer_set_) { 244 ScheduleNextHeartBeat(); 245 timer_set_ = true; 246 } 247 248 return cdm::kSuccess; 249 } 250 251 cdm::Status ClearKeyCdm::CancelKeyRequest(const char* session_id, 252 int session_id_size) { 253 DVLOG(1) << "CancelKeyRequest()"; 254 base::AutoLock auto_lock(client_lock_); 255 ScopedResetter<Client> auto_resetter(&client_); 256 decryptor_.CancelKeyRequest(std::string(session_id, session_id_size)); 257 return cdm::kSuccess; 258 } 259 260 void ClearKeyCdm::TimerExpired(void* context) { 261 std::string heartbeat_message; 262 if (!next_heartbeat_message_.empty() && 263 context == &next_heartbeat_message_[0]) { 264 heartbeat_message = next_heartbeat_message_; 265 } else { 266 heartbeat_message = "ERROR: Invalid timer context found!"; 267 } 268 269 // This URL is only used for testing the code path for defaultURL. 270 // There is no service at this URL, so applications should ignore it. 271 const char url[] = "http://test.externalclearkey.chromium.org"; 272 273 host_->SendKeyMessage( 274 heartbeat_session_id_.data(), heartbeat_session_id_.size(), 275 heartbeat_message.data(), heartbeat_message.size(), 276 url, arraysize(url) - 1); 277 278 ScheduleNextHeartBeat(); 279 } 280 281 static void CopyDecryptResults( 282 media::Decryptor::Status* status_copy, 283 scoped_refptr<media::DecoderBuffer>* buffer_copy, 284 media::Decryptor::Status status, 285 const scoped_refptr<media::DecoderBuffer>& buffer) { 286 *status_copy = status; 287 *buffer_copy = buffer; 288 } 289 290 cdm::Status ClearKeyCdm::Decrypt( 291 const cdm::InputBuffer& encrypted_buffer, 292 cdm::DecryptedBlock* decrypted_block) { 293 DVLOG(1) << "Decrypt()"; 294 DCHECK(encrypted_buffer.data); 295 296 scoped_refptr<media::DecoderBuffer> buffer; 297 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer); 298 299 if (status != cdm::kSuccess) 300 return status; 301 302 DCHECK(buffer->data()); 303 decrypted_block->SetDecryptedBuffer( 304 host_->Allocate(buffer->data_size())); 305 memcpy(reinterpret_cast<void*>(decrypted_block->DecryptedBuffer()->Data()), 306 buffer->data(), 307 buffer->data_size()); 308 decrypted_block->DecryptedBuffer()->SetSize(buffer->data_size()); 309 decrypted_block->SetTimestamp(buffer->timestamp().InMicroseconds()); 310 311 return cdm::kSuccess; 312 } 313 314 cdm::Status ClearKeyCdm::InitializeAudioDecoder( 315 const cdm::AudioDecoderConfig& audio_decoder_config) { 316 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 317 if (!audio_decoder_) 318 audio_decoder_.reset(new media::FFmpegCdmAudioDecoder(host_)); 319 320 if (!audio_decoder_->Initialize(audio_decoder_config)) 321 return cdm::kSessionError; 322 323 return cdm::kSuccess; 324 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 325 channel_count_ = audio_decoder_config.channel_count; 326 bits_per_channel_ = audio_decoder_config.bits_per_channel; 327 samples_per_second_ = audio_decoder_config.samples_per_second; 328 return cdm::kSuccess; 329 #else 330 NOTIMPLEMENTED(); 331 return cdm::kSessionError; 332 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 333 } 334 335 cdm::Status ClearKeyCdm::InitializeVideoDecoder( 336 const cdm::VideoDecoderConfig& video_decoder_config) { 337 if (video_decoder_ && video_decoder_->is_initialized()) { 338 DCHECK(!video_decoder_->is_initialized()); 339 return cdm::kSessionError; 340 } 341 342 // Any uninitialized decoder will be replaced. 343 video_decoder_ = CreateVideoDecoder(host_, video_decoder_config); 344 if (!video_decoder_) 345 return cdm::kSessionError; 346 347 return cdm::kSuccess; 348 } 349 350 void ClearKeyCdm::ResetDecoder(cdm::StreamType decoder_type) { 351 DVLOG(1) << "ResetDecoder()"; 352 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 353 switch (decoder_type) { 354 case cdm::kStreamTypeVideo: 355 video_decoder_->Reset(); 356 break; 357 case cdm::kStreamTypeAudio: 358 audio_decoder_->Reset(); 359 break; 360 default: 361 NOTREACHED() << "ResetDecoder(): invalid cdm::StreamType"; 362 } 363 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 364 if (decoder_type == cdm::kStreamTypeAudio) { 365 output_timestamp_base_in_microseconds_ = kNoTimestamp; 366 total_samples_generated_ = 0; 367 } 368 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 369 } 370 371 void ClearKeyCdm::DeinitializeDecoder(cdm::StreamType decoder_type) { 372 DVLOG(1) << "DeinitializeDecoder()"; 373 switch (decoder_type) { 374 case cdm::kStreamTypeVideo: 375 video_decoder_->Deinitialize(); 376 break; 377 case cdm::kStreamTypeAudio: 378 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 379 audio_decoder_->Deinitialize(); 380 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 381 output_timestamp_base_in_microseconds_ = kNoTimestamp; 382 total_samples_generated_ = 0; 383 #endif 384 break; 385 default: 386 NOTREACHED() << "DeinitializeDecoder(): invalid cdm::StreamType"; 387 } 388 } 389 390 cdm::Status ClearKeyCdm::DecryptAndDecodeFrame( 391 const cdm::InputBuffer& encrypted_buffer, 392 cdm::VideoFrame* decoded_frame) { 393 DVLOG(1) << "DecryptAndDecodeFrame()"; 394 TRACE_EVENT0("eme", "ClearKeyCdm::DecryptAndDecodeFrame"); 395 396 scoped_refptr<media::DecoderBuffer> buffer; 397 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer); 398 399 if (status != cdm::kSuccess) 400 return status; 401 402 const uint8_t* data = NULL; 403 int32_t size = 0; 404 int64_t timestamp = 0; 405 if (!buffer->end_of_stream()) { 406 data = buffer->data(); 407 size = buffer->data_size(); 408 timestamp = encrypted_buffer.timestamp; 409 } 410 411 return video_decoder_->DecodeFrame(data, size, timestamp, decoded_frame); 412 } 413 414 cdm::Status ClearKeyCdm::DecryptAndDecodeSamples( 415 const cdm::InputBuffer& encrypted_buffer, 416 cdm::AudioFrames* audio_frames) { 417 DVLOG(1) << "DecryptAndDecodeSamples()"; 418 419 scoped_refptr<media::DecoderBuffer> buffer; 420 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer); 421 422 if (status != cdm::kSuccess) 423 return status; 424 425 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 426 const uint8_t* data = NULL; 427 int32_t size = 0; 428 int64_t timestamp = 0; 429 if (!buffer->end_of_stream()) { 430 data = buffer->data(); 431 size = buffer->data_size(); 432 timestamp = encrypted_buffer.timestamp; 433 } 434 435 return audio_decoder_->DecodeBuffer(data, size, timestamp, audio_frames); 436 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 437 int64 timestamp_in_microseconds = kNoTimestamp; 438 if (!buffer->end_of_stream()) { 439 timestamp_in_microseconds = buffer->GetTimestamp().InMicroseconds(); 440 DCHECK(timestamp_in_microseconds != kNoTimestamp); 441 } 442 return GenerateFakeAudioFrames(timestamp_in_microseconds, audio_frames); 443 #else 444 return cdm::kSuccess; 445 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 446 } 447 448 void ClearKeyCdm::Destroy() { 449 DVLOG(1) << "Destroy()"; 450 delete this; 451 } 452 453 void ClearKeyCdm::ScheduleNextHeartBeat() { 454 // Prepare the next heartbeat message and set timer. 455 std::ostringstream msg_stream; 456 msg_stream << kHeartBeatHeader << " from ClearKey CDM set at time " 457 << host_->GetCurrentWallTimeInSeconds() << "."; 458 next_heartbeat_message_ = msg_stream.str(); 459 460 host_->SetTimer(timer_delay_ms_, &next_heartbeat_message_[0]); 461 462 // Use a smaller timer delay at start-up to facilitate testing. Increase the 463 // timer delay up to a limit to avoid message spam. 464 if (timer_delay_ms_ < kMaxTimerDelayMs) 465 timer_delay_ms_ = std::min(2 * timer_delay_ms_, kMaxTimerDelayMs); 466 } 467 468 cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer( 469 const cdm::InputBuffer& encrypted_buffer, 470 scoped_refptr<media::DecoderBuffer>* decrypted_buffer) { 471 DCHECK(decrypted_buffer); 472 scoped_refptr<media::DecoderBuffer> buffer = 473 CopyDecoderBufferFrom(encrypted_buffer); 474 475 if (buffer->end_of_stream()) { 476 *decrypted_buffer = buffer; 477 return cdm::kSuccess; 478 } 479 480 // Callback is called synchronously, so we can use variables on the stack. 481 media::Decryptor::Status status = media::Decryptor::kError; 482 // The AesDecryptor does not care what the stream type is. Pass kVideo 483 // for both audio and video decryption. 484 decryptor_.Decrypt( 485 media::Decryptor::kVideo, 486 buffer, 487 base::Bind(&CopyDecryptResults, &status, decrypted_buffer)); 488 489 if (status == media::Decryptor::kError) 490 return cdm::kDecryptError; 491 492 if (status == media::Decryptor::kNoKey) 493 return cdm::kNoKey; 494 495 DCHECK_EQ(status, media::Decryptor::kSuccess); 496 return cdm::kSuccess; 497 } 498 499 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 500 int64 ClearKeyCdm::CurrentTimeStampInMicroseconds() const { 501 return output_timestamp_base_in_microseconds_ + 502 base::Time::kMicrosecondsPerSecond * 503 total_samples_generated_ / samples_per_second_; 504 } 505 506 int ClearKeyCdm::GenerateFakeAudioFramesFromDuration( 507 int64 duration_in_microseconds, 508 cdm::AudioFrames* audio_frames) const { 509 int64 samples_to_generate = static_cast<double>(samples_per_second_) * 510 duration_in_microseconds / base::Time::kMicrosecondsPerSecond + 0.5; 511 if (samples_to_generate <= 0) 512 return 0; 513 514 int64 bytes_per_sample = channel_count_ * bits_per_channel_ / 8; 515 // |frame_size| must be a multiple of |bytes_per_sample|. 516 int64 frame_size = bytes_per_sample * samples_to_generate; 517 518 int64 timestamp = CurrentTimeStampInMicroseconds(); 519 520 const int kHeaderSize = sizeof(timestamp) + sizeof(frame_size); 521 audio_frames->SetFrameBuffer(host_->Allocate(kHeaderSize + frame_size)); 522 uint8_t* data = audio_frames->FrameBuffer()->Data(); 523 524 memcpy(data, ×tamp, sizeof(timestamp)); 525 data += sizeof(timestamp); 526 memcpy(data, &frame_size, sizeof(frame_size)); 527 data += sizeof(frame_size); 528 // You won't hear anything because we have all zeros here. But the video 529 // should play just fine! 530 memset(data, 0, frame_size); 531 532 audio_frames->FrameBuffer()->SetSize(kHeaderSize + frame_size); 533 534 return samples_to_generate; 535 } 536 537 cdm::Status ClearKeyCdm::GenerateFakeAudioFrames( 538 int64 timestamp_in_microseconds, 539 cdm::AudioFrames* audio_frames) { 540 if (timestamp_in_microseconds == kNoTimestamp) 541 return cdm::kNeedMoreData; 542 543 // Return kNeedMoreData for the first frame because duration is unknown. 544 if (output_timestamp_base_in_microseconds_ == kNoTimestamp) { 545 output_timestamp_base_in_microseconds_ = timestamp_in_microseconds; 546 return cdm::kNeedMoreData; 547 } 548 549 int samples_generated = GenerateFakeAudioFramesFromDuration( 550 timestamp_in_microseconds - CurrentTimeStampInMicroseconds(), 551 audio_frames); 552 total_samples_generated_ += samples_generated; 553 554 return samples_generated == 0 ? cdm::kNeedMoreData : cdm::kSuccess; 555 } 556 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 557 558 } // namespace media 559