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 "content/renderer/media/android/media_source_delegate.h" 6 7 #include "base/message_loop/message_loop_proxy.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "content/renderer/media/android/webmediaplayer_proxy_android.h" 10 #include "content/renderer/media/webmediaplayer_util.h" 11 #include "content/renderer/media/webmediasourceclient_impl.h" 12 #include "media/base/android/demuxer_stream_player_params.h" 13 #include "media/base/bind_to_loop.h" 14 #include "media/base/demuxer_stream.h" 15 #include "media/base/media_log.h" 16 #include "media/filters/chunk_demuxer.h" 17 #include "media/filters/decrypting_demuxer_stream.h" 18 #include "third_party/WebKit/public/platform/WebString.h" 19 #include "third_party/WebKit/public/web/WebMediaSource.h" 20 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 21 22 using media::DemuxerStream; 23 using media::MediaPlayerHostMsg_DemuxerReady_Params; 24 using media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params; 25 using WebKit::WebMediaPlayer; 26 using WebKit::WebString; 27 28 namespace { 29 30 // The size of the access unit to transfer in an IPC in case of MediaSource. 31 // 16: approximately 250ms of content in 60 fps movies. 32 const size_t kAccessUnitSizeForMediaSource = 16; 33 34 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; 35 36 } // namespace 37 38 namespace content { 39 40 #define BIND_TO_RENDER_LOOP(function) \ 41 media::BindToLoop(main_loop_, \ 42 base::Bind(function, main_weak_this_.GetWeakPtr())) 43 44 #define BIND_TO_RENDER_LOOP_1(function, arg1) \ 45 media::BindToLoop(main_loop_, \ 46 base::Bind(function, main_weak_this_.GetWeakPtr(), arg1)) 47 48 #if defined(GOOGLE_TV) 49 #define DCHECK_BELONG_TO_MEDIA_LOOP() \ 50 DCHECK(media_loop_->BelongsToCurrentThread()) 51 #else 52 #define DCHECK_BELONG_TO_MEDIA_LOOP() \ 53 DCHECK(main_loop_->BelongsToCurrentThread()) 54 #endif 55 56 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, 57 const std::string& error) { 58 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); 59 } 60 61 MediaSourceDelegate::MediaSourceDelegate( 62 WebMediaPlayerProxyAndroid* proxy, 63 int player_id, 64 const scoped_refptr<base::MessageLoopProxy>& media_loop, 65 media::MediaLog* media_log) 66 : main_weak_this_(this), 67 media_weak_this_(this), 68 main_loop_(base::MessageLoopProxy::current()), 69 #if defined(GOOGLE_TV) 70 media_loop_(media_loop), 71 send_read_from_demuxer_ack_cb_( 72 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendReadFromDemuxerAck)), 73 send_seek_request_ack_cb_( 74 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendSeekRequestAck)), 75 send_demuxer_ready_cb_( 76 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendDemuxerReady)), 77 #endif 78 proxy_(proxy), 79 player_id_(player_id), 80 media_log_(media_log), 81 demuxer_(NULL), 82 is_demuxer_ready_(false), 83 audio_stream_(NULL), 84 video_stream_(NULL), 85 seeking_(false), 86 last_seek_request_id_(0), 87 key_added_(false), 88 access_unit_size_(0) { 89 } 90 91 MediaSourceDelegate::~MediaSourceDelegate() { 92 DCHECK(main_loop_->BelongsToCurrentThread()); 93 DVLOG(1) << "~MediaSourceDelegate() : " << player_id_; 94 DCHECK(!chunk_demuxer_); 95 DCHECK(!demuxer_); 96 DCHECK(!audio_decrypting_demuxer_stream_); 97 DCHECK(!video_decrypting_demuxer_stream_); 98 DCHECK(!audio_stream_); 99 DCHECK(!video_stream_); 100 } 101 102 void MediaSourceDelegate::Destroy() { 103 DCHECK(main_loop_->BelongsToCurrentThread()); 104 DVLOG(1) << "Destroy() : " << player_id_; 105 if (!demuxer_) { 106 delete this; 107 return; 108 } 109 110 duration_change_cb_.Reset(); 111 update_network_state_cb_.Reset(); 112 media_source_.reset(); 113 proxy_ = NULL; 114 115 main_weak_this_.InvalidateWeakPtrs(); 116 DCHECK(!main_weak_this_.HasWeakPtrs()); 117 118 if (chunk_demuxer_) 119 chunk_demuxer_->Shutdown(); 120 #if defined(GOOGLE_TV) 121 // |this| will be transfered to the callback StopDemuxer() and 122 // OnDemuxerStopDone(). they own |this| and OnDemuxerStopDone() will delete 123 // it when called. Hence using base::Unretained(this) is safe here. 124 media_loop_->PostTask(FROM_HERE, 125 base::Bind(&MediaSourceDelegate::StopDemuxer, 126 base::Unretained(this))); 127 #else 128 StopDemuxer(); 129 #endif 130 } 131 132 void MediaSourceDelegate::StopDemuxer() { 133 DCHECK_BELONG_TO_MEDIA_LOOP(); 134 DCHECK(demuxer_); 135 136 audio_stream_ = NULL; 137 video_stream_ = NULL; 138 // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or 139 // before destroying them. 140 audio_decrypting_demuxer_stream_.reset(); 141 video_decrypting_demuxer_stream_.reset(); 142 143 media_weak_this_.InvalidateWeakPtrs(); 144 DCHECK(!media_weak_this_.HasWeakPtrs()); 145 146 // The callback OnDemuxerStopDone() owns |this| and will delete it when 147 // called. Hence using base::Unretained(this) is safe here. 148 demuxer_->Stop(media::BindToLoop(main_loop_, 149 base::Bind(&MediaSourceDelegate::OnDemuxerStopDone, 150 base::Unretained(this)))); 151 } 152 153 void MediaSourceDelegate::InitializeMediaSource( 154 WebKit::WebMediaSource* media_source, 155 const media::NeedKeyCB& need_key_cb, 156 const media::SetDecryptorReadyCB& set_decryptor_ready_cb, 157 const UpdateNetworkStateCB& update_network_state_cb, 158 const DurationChangeCB& duration_change_cb) { 159 DCHECK(main_loop_->BelongsToCurrentThread()); 160 DCHECK(media_source); 161 media_source_.reset(media_source); 162 need_key_cb_ = need_key_cb; 163 set_decryptor_ready_cb_ = set_decryptor_ready_cb; 164 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); 165 duration_change_cb_ = media::BindToCurrentLoop(duration_change_cb); 166 access_unit_size_ = kAccessUnitSizeForMediaSource; 167 168 chunk_demuxer_.reset(new media::ChunkDemuxer( 169 BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened), 170 BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnNeedKey, ""), 171 // WeakPtrs can only bind to methods without return values. 172 base::Bind(&MediaSourceDelegate::OnAddTextTrack, base::Unretained(this)), 173 base::Bind(&LogMediaSourceError, media_log_))); 174 demuxer_ = chunk_demuxer_.get(); 175 176 #if defined(GOOGLE_TV) 177 // |this| will be retained until StopDemuxer() is posted, so Unretained() is 178 // safe here. 179 media_loop_->PostTask(FROM_HERE, 180 base::Bind(&MediaSourceDelegate::InitializeDemuxer, 181 base::Unretained(this))); 182 #else 183 InitializeDemuxer(); 184 #endif 185 } 186 187 void MediaSourceDelegate::InitializeDemuxer() { 188 DCHECK_BELONG_TO_MEDIA_LOOP(); 189 demuxer_->Initialize(this, base::Bind(&MediaSourceDelegate::OnDemuxerInitDone, 190 media_weak_this_.GetWeakPtr())); 191 } 192 193 #if defined(GOOGLE_TV) 194 void MediaSourceDelegate::InitializeMediaStream( 195 media::Demuxer* demuxer, 196 const UpdateNetworkStateCB& update_network_state_cb) { 197 DCHECK(main_loop_->BelongsToCurrentThread()); 198 DCHECK(demuxer); 199 demuxer_ = demuxer; 200 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); 201 // When playing Media Stream, don't wait to accumulate multiple packets per 202 // IPC communication. 203 access_unit_size_ = 1; 204 205 // |this| will be retained until StopDemuxer() is posted, so Unretained() is 206 // safe here. 207 media_loop_->PostTask(FROM_HERE, 208 base::Bind(&MediaSourceDelegate::InitializeDemuxer, 209 base::Unretained(this))); 210 } 211 #endif 212 213 const WebKit::WebTimeRanges& MediaSourceDelegate::Buffered() { 214 buffered_web_time_ranges_ = 215 ConvertToWebTimeRanges(buffered_time_ranges_); 216 return buffered_web_time_ranges_; 217 } 218 219 size_t MediaSourceDelegate::DecodedFrameCount() const { 220 return statistics_.video_frames_decoded; 221 } 222 223 size_t MediaSourceDelegate::DroppedFrameCount() const { 224 return statistics_.video_frames_dropped; 225 } 226 227 size_t MediaSourceDelegate::AudioDecodedByteCount() const { 228 return statistics_.audio_bytes_decoded; 229 } 230 231 size_t MediaSourceDelegate::VideoDecodedByteCount() const { 232 return statistics_.video_bytes_decoded; 233 } 234 235 void MediaSourceDelegate::Seek(base::TimeDelta time, unsigned seek_request_id) { 236 DCHECK(main_loop_->BelongsToCurrentThread()); 237 DVLOG(1) << "Seek(" << time.InSecondsF() << ") : " << player_id_; 238 239 last_seek_time_ = time; 240 last_seek_request_id_ = seek_request_id; 241 242 if (chunk_demuxer_) { 243 if (IsSeeking()) { 244 chunk_demuxer_->CancelPendingSeek(time); 245 return; 246 } 247 248 chunk_demuxer_->StartWaitingForSeek(time); 249 } 250 251 SetSeeking(true); 252 #if defined(GOOGLE_TV) 253 media_loop_->PostTask(FROM_HERE, 254 base::Bind(&MediaSourceDelegate::SeekInternal, 255 base::Unretained(this), 256 time, seek_request_id)); 257 #else 258 SeekInternal(time, seek_request_id); 259 #endif 260 } 261 262 void MediaSourceDelegate::SeekInternal(base::TimeDelta time, 263 unsigned request_id) { 264 DCHECK_BELONG_TO_MEDIA_LOOP(); 265 demuxer_->Seek(time, base::Bind(&MediaSourceDelegate::OnDemuxerSeekDone, 266 media_weak_this_.GetWeakPtr(), request_id)); 267 } 268 269 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) { 270 NOTIMPLEMENTED(); 271 } 272 273 void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) { 274 NOTIMPLEMENTED(); 275 } 276 277 void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start, 278 base::TimeDelta end) { 279 buffered_time_ranges_.Add(start, end); 280 } 281 282 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { 283 DVLOG(1) << "SetDuration(" << duration.InSecondsF() << ") : " << player_id_; 284 // Notify our owner (e.g. WebMediaPlayerAndroid) that duration has changed. 285 // |duration_change_cb_| is bound to the main thread. 286 if (!duration_change_cb_.is_null()) 287 duration_change_cb_.Run(duration); 288 } 289 290 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) { 291 DCHECK(main_loop_->BelongsToCurrentThread()); 292 #if defined(GOOGLE_TV) 293 media_loop_->PostTask( 294 FROM_HERE, 295 base::Bind(&MediaSourceDelegate::OnReadFromDemuxerInternal, 296 base::Unretained(this), type)); 297 #else 298 OnReadFromDemuxerInternal(type); 299 #endif 300 } 301 302 void MediaSourceDelegate::OnReadFromDemuxerInternal( 303 media::DemuxerStream::Type type) { 304 DCHECK_BELONG_TO_MEDIA_LOOP(); 305 DVLOG(1) << "OnReadFromDemuxer(" << type << ") : " << player_id_; 306 if (IsSeeking()) 307 return; // Drop the request during seeking. 308 309 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); 310 // The access unit size should have been initialized properly at this stage. 311 DCHECK_GT(access_unit_size_, 0u); 312 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params( 313 new MediaPlayerHostMsg_ReadFromDemuxerAck_Params()); 314 params->type = type; 315 params->access_units.resize(access_unit_size_); 316 ReadFromDemuxerStream(type, params.Pass(), 0); 317 } 318 319 void MediaSourceDelegate::ReadFromDemuxerStream( 320 media::DemuxerStream::Type type, 321 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, 322 size_t index) { 323 DCHECK_BELONG_TO_MEDIA_LOOP(); 324 // DemuxerStream::Read() always returns the read callback asynchronously. 325 DemuxerStream* stream = 326 (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; 327 stream->Read(base::Bind( 328 &MediaSourceDelegate::OnBufferReady, 329 media_weak_this_.GetWeakPtr(), type, base::Passed(¶ms), index)); 330 } 331 332 void MediaSourceDelegate::OnBufferReady( 333 media::DemuxerStream::Type type, 334 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, 335 size_t index, 336 DemuxerStream::Status status, 337 const scoped_refptr<media::DecoderBuffer>& buffer) { 338 DCHECK_BELONG_TO_MEDIA_LOOP(); 339 DVLOG(1) << "OnBufferReady(" << index << ", " << status << ", " 340 << ((!buffer || buffer->end_of_stream()) ? 341 -1 : buffer->timestamp().InMilliseconds()) 342 << ") : " << player_id_; 343 DCHECK(demuxer_); 344 345 // No new OnReadFromDemuxer() will be called during seeking. So this callback 346 // must be from previous OnReadFromDemuxer() call and should be ignored. 347 if (IsSeeking()) { 348 DVLOG(1) << "OnBufferReady(): Ignore previous read during seeking."; 349 return; 350 } 351 352 bool is_audio = (type == DemuxerStream::AUDIO); 353 if (status != DemuxerStream::kAborted && 354 index >= params->access_units.size()) { 355 LOG(ERROR) << "The internal state inconsistency onBufferReady: " 356 << (is_audio ? "Audio" : "Video") << ", index " << index 357 <<", size " << params->access_units.size() 358 << ", status " << static_cast<int>(status); 359 NOTREACHED(); 360 return; 361 } 362 363 switch (status) { 364 case DemuxerStream::kAborted: 365 // Because the abort was caused by the seek, don't respond ack. 366 DVLOG(1) << "OnBufferReady() : Aborted"; 367 return; 368 369 case DemuxerStream::kConfigChanged: 370 // In case of kConfigChanged, need to read decoder_config once 371 // for the next reads. 372 // TODO(kjyoun): Investigate if we need to use this new config. See 373 // http://crbug.com/255783 374 if (is_audio) { 375 audio_stream_->audio_decoder_config(); 376 } else { 377 gfx::Size size = video_stream_->video_decoder_config().coded_size(); 378 DVLOG(1) << "Video config is changed: " << size.width() << "x" 379 << size.height(); 380 } 381 params->access_units[index].status = status; 382 params->access_units.resize(index + 1); 383 break; 384 385 case DemuxerStream::kOk: 386 params->access_units[index].status = status; 387 if (buffer->end_of_stream()) { 388 params->access_units[index].end_of_stream = true; 389 params->access_units.resize(index + 1); 390 break; 391 } 392 // TODO(ycheo): We assume that the inputed stream will be decoded 393 // right away. 394 // Need to implement this properly using MediaPlayer.OnInfoListener. 395 if (is_audio) { 396 statistics_.audio_bytes_decoded += buffer->data_size(); 397 } else { 398 statistics_.video_bytes_decoded += buffer->data_size(); 399 statistics_.video_frames_decoded++; 400 } 401 params->access_units[index].timestamp = buffer->timestamp(); 402 params->access_units[index].data = std::vector<uint8>( 403 buffer->data(), 404 buffer->data() + buffer->data_size()); 405 #if !defined(GOOGLE_TV) 406 // Vorbis needs 4 extra bytes padding on Android. Check 407 // NuMediaExtractor.cpp in Android source code. 408 if (is_audio && media::kCodecVorbis == 409 audio_stream_->audio_decoder_config().codec()) { 410 params->access_units[index].data.insert( 411 params->access_units[index].data.end(), kVorbisPadding, 412 kVorbisPadding + 4); 413 } 414 #endif 415 if (buffer->decrypt_config()) { 416 params->access_units[index].key_id = std::vector<char>( 417 buffer->decrypt_config()->key_id().begin(), 418 buffer->decrypt_config()->key_id().end()); 419 params->access_units[index].iv = std::vector<char>( 420 buffer->decrypt_config()->iv().begin(), 421 buffer->decrypt_config()->iv().end()); 422 params->access_units[index].subsamples = 423 buffer->decrypt_config()->subsamples(); 424 } 425 if (++index < params->access_units.size()) { 426 ReadFromDemuxerStream(type, params.Pass(), index); 427 return; 428 } 429 break; 430 431 default: 432 NOTREACHED(); 433 } 434 435 #if defined(GOOGLE_TV) 436 send_read_from_demuxer_ack_cb_.Run(params.Pass()); 437 #else 438 SendReadFromDemuxerAck(params.Pass()); 439 #endif 440 } 441 442 void MediaSourceDelegate::SendReadFromDemuxerAck( 443 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params) { 444 DCHECK(main_loop_->BelongsToCurrentThread()); 445 if (!IsSeeking() && proxy_) 446 proxy_->ReadFromDemuxerAck(player_id_, *params); 447 } 448 449 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { 450 DVLOG(1) << "OnDemuxerError(" << status << ") : " << player_id_; 451 // |update_network_state_cb_| is bound to the main thread. 452 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) 453 update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); 454 } 455 456 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { 457 DCHECK_BELONG_TO_MEDIA_LOOP(); 458 DVLOG(1) << "OnDemuxerInitDone(" << status << ") : " << player_id_; 459 DCHECK(demuxer_); 460 461 if (status != media::PIPELINE_OK) { 462 OnDemuxerError(status); 463 return; 464 } 465 466 audio_stream_ = demuxer_->GetStream(DemuxerStream::AUDIO); 467 video_stream_ = demuxer_->GetStream(DemuxerStream::VIDEO); 468 469 if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && 470 !set_decryptor_ready_cb_.is_null()) { 471 InitAudioDecryptingDemuxerStream(); 472 // InitVideoDecryptingDemuxerStream() will be called in 473 // OnAudioDecryptingDemuxerStreamInitDone(). 474 return; 475 } 476 477 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && 478 !set_decryptor_ready_cb_.is_null()) { 479 InitVideoDecryptingDemuxerStream(); 480 return; 481 } 482 483 // Notify demuxer ready when both streams are not encrypted. 484 is_demuxer_ready_ = true; 485 if (CanNotifyDemuxerReady()) 486 NotifyDemuxerReady(); 487 } 488 489 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { 490 DCHECK_BELONG_TO_MEDIA_LOOP(); 491 DVLOG(1) << "InitAudioDecryptingDemuxerStream() : " << player_id_; 492 DCHECK(!set_decryptor_ready_cb_.is_null()); 493 494 audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 495 base::MessageLoopProxy::current(), set_decryptor_ready_cb_)); 496 audio_decrypting_demuxer_stream_->Initialize( 497 audio_stream_, 498 base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, 499 media_weak_this_.GetWeakPtr())); 500 } 501 502 void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { 503 DCHECK_BELONG_TO_MEDIA_LOOP(); 504 DVLOG(1) << "InitVideoDecryptingDemuxerStream() : " << player_id_; 505 DCHECK(!set_decryptor_ready_cb_.is_null()); 506 507 video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 508 base::MessageLoopProxy::current(), set_decryptor_ready_cb_)); 509 video_decrypting_demuxer_stream_->Initialize( 510 video_stream_, 511 base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone, 512 media_weak_this_.GetWeakPtr())); 513 } 514 515 void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( 516 media::PipelineStatus status) { 517 DCHECK_BELONG_TO_MEDIA_LOOP(); 518 DVLOG(1) << "OnAudioDecryptingDemuxerStreamInitDone(" << status 519 << ") : " << player_id_; 520 DCHECK(demuxer_); 521 522 if (status != media::PIPELINE_OK) 523 audio_decrypting_demuxer_stream_.reset(); 524 else 525 audio_stream_ = audio_decrypting_demuxer_stream_.get(); 526 527 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { 528 InitVideoDecryptingDemuxerStream(); 529 return; 530 } 531 532 // Try to notify demuxer ready when audio DDS initialization finished and 533 // video is not encrypted. 534 is_demuxer_ready_ = true; 535 if (CanNotifyDemuxerReady()) 536 NotifyDemuxerReady(); 537 } 538 539 void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( 540 media::PipelineStatus status) { 541 DCHECK_BELONG_TO_MEDIA_LOOP(); 542 DVLOG(1) << "OnVideoDecryptingDemuxerStreamInitDone(" << status 543 << ") : " << player_id_; 544 DCHECK(demuxer_); 545 546 if (status != media::PIPELINE_OK) 547 video_decrypting_demuxer_stream_.reset(); 548 else 549 video_stream_ = video_decrypting_demuxer_stream_.get(); 550 551 // Try to notify demuxer ready when video DDS initialization finished. 552 is_demuxer_ready_ = true; 553 if (CanNotifyDemuxerReady()) 554 NotifyDemuxerReady(); 555 } 556 557 void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id, 558 media::PipelineStatus status) { 559 DCHECK_BELONG_TO_MEDIA_LOOP(); 560 DVLOG(1) << "OnDemuxerSeekDone(" << status << ") : " << player_id_; 561 DCHECK(IsSeeking()); 562 563 if (status != media::PIPELINE_OK) { 564 OnDemuxerError(status); 565 return; 566 } 567 568 // Newer seek has been issued. Resume the last seek request. 569 if (seek_request_id != last_seek_request_id_) { 570 if (chunk_demuxer_) 571 chunk_demuxer_->StartWaitingForSeek(last_seek_time_); 572 SeekInternal(last_seek_time_, last_seek_request_id_); 573 return; 574 } 575 576 ResetAudioDecryptingDemuxerStream(); 577 } 578 579 void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() { 580 DCHECK_BELONG_TO_MEDIA_LOOP(); 581 DVLOG(1) << "ResetAudioDecryptingDemuxerStream() : " << player_id_; 582 if (audio_decrypting_demuxer_stream_) { 583 audio_decrypting_demuxer_stream_->Reset( 584 base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream, 585 media_weak_this_.GetWeakPtr())); 586 } else { 587 ResetVideoDecryptingDemuxerStream(); 588 } 589 } 590 591 void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() { 592 DCHECK_BELONG_TO_MEDIA_LOOP(); 593 DVLOG(1) << "ResetVideoDecryptingDemuxerStream()"; 594 #if defined(GOOGLE_TV) 595 if (video_decrypting_demuxer_stream_) 596 video_decrypting_demuxer_stream_->Reset(send_seek_request_ack_cb_); 597 else 598 send_seek_request_ack_cb_.Run(); 599 #else 600 if (video_decrypting_demuxer_stream_) { 601 video_decrypting_demuxer_stream_->Reset( 602 base::Bind(&MediaSourceDelegate::SendSeekRequestAck, 603 main_weak_this_.GetWeakPtr())); 604 } else { 605 SendSeekRequestAck(); 606 } 607 #endif 608 } 609 610 void MediaSourceDelegate::SendSeekRequestAck() { 611 DVLOG(1) << "SendSeekRequestAck() : " << player_id_; 612 SetSeeking(false); 613 proxy_->SeekRequestAck(player_id_, last_seek_request_id_); 614 last_seek_request_id_ = 0; 615 } 616 617 void MediaSourceDelegate::OnDemuxerStopDone() { 618 DCHECK(main_loop_->BelongsToCurrentThread()); 619 DVLOG(1) << "OnDemuxerStopDone() : " << player_id_; 620 chunk_demuxer_.reset(); 621 demuxer_ = NULL; 622 delete this; 623 } 624 625 void MediaSourceDelegate::OnMediaConfigRequest() { 626 #if defined(GOOGLE_TV) 627 if (!media_loop_->BelongsToCurrentThread()) { 628 media_loop_->PostTask(FROM_HERE, 629 base::Bind(&MediaSourceDelegate::OnMediaConfigRequest, 630 base::Unretained(this))); 631 return; 632 } 633 #endif 634 if (CanNotifyDemuxerReady()) 635 NotifyDemuxerReady(); 636 } 637 638 void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) { 639 #if defined(GOOGLE_TV) 640 if (!media_loop_->BelongsToCurrentThread()) { 641 media_loop_->PostTask(FROM_HERE, 642 base::Bind(&MediaSourceDelegate::NotifyKeyAdded, 643 base::Unretained(this), key_system)); 644 return; 645 } 646 #endif 647 DVLOG(1) << "NotifyKeyAdded() : " << player_id_; 648 // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady() 649 // For now, we calls it when the first key is added. See 650 // http://crbug.com/255781 651 if (key_added_) 652 return; 653 key_added_ = true; 654 key_system_ = key_system; 655 if (!CanNotifyDemuxerReady()) 656 return; 657 if (HasEncryptedStream()) 658 NotifyDemuxerReady(); 659 } 660 661 bool MediaSourceDelegate::CanNotifyDemuxerReady() { 662 DCHECK_BELONG_TO_MEDIA_LOOP(); 663 // This can happen when a key is added before the demuxer is initialized. 664 // See NotifyKeyAdded(). 665 // TODO(kjyoun): Remove NotifyDemxuerReady() call from NotifyKeyAdded() so 666 // that we can remove all is_demuxer_ready_/key_added_/key_system_ madness. 667 // See http://crbug.com/255781 668 if (!is_demuxer_ready_) 669 return false; 670 if (HasEncryptedStream() && !key_added_) 671 return false; 672 return true; 673 } 674 675 void MediaSourceDelegate::NotifyDemuxerReady() { 676 DCHECK_BELONG_TO_MEDIA_LOOP(); 677 DVLOG(1) << "NotifyDemuxerReady() : " << player_id_; 678 DCHECK(CanNotifyDemuxerReady()); 679 680 scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params( 681 new MediaPlayerHostMsg_DemuxerReady_Params()); 682 if (audio_stream_) { 683 media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); 684 params->audio_codec = config.codec(); 685 params->audio_channels = 686 media::ChannelLayoutToChannelCount(config.channel_layout()); 687 params->audio_sampling_rate = config.samples_per_second(); 688 params->is_audio_encrypted = config.is_encrypted(); 689 params->audio_extra_data = std::vector<uint8>( 690 config.extra_data(), config.extra_data() + config.extra_data_size()); 691 } 692 if (video_stream_) { 693 media::VideoDecoderConfig config = video_stream_->video_decoder_config(); 694 params->video_codec = config.codec(); 695 params->video_size = config.natural_size(); 696 params->is_video_encrypted = config.is_encrypted(); 697 params->video_extra_data = std::vector<uint8>( 698 config.extra_data(), config.extra_data() + config.extra_data_size()); 699 } 700 params->duration_ms = GetDurationMs(); 701 params->key_system = HasEncryptedStream() ? key_system_ : ""; 702 703 #if defined(GOOGLE_TV) 704 send_demuxer_ready_cb_.Run(params.Pass()); 705 #else 706 SendDemuxerReady(params.Pass()); 707 #endif 708 } 709 710 void MediaSourceDelegate::SendDemuxerReady( 711 scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params) { 712 DCHECK(main_loop_->BelongsToCurrentThread()); 713 if (proxy_) 714 proxy_->DemuxerReady(player_id_, *params); 715 } 716 717 int MediaSourceDelegate::GetDurationMs() { 718 DCHECK_BELONG_TO_MEDIA_LOOP(); 719 if (!chunk_demuxer_) 720 return -1; 721 722 double duration_ms = chunk_demuxer_->GetDuration() * 1000; 723 if (duration_ms > std::numeric_limits<int32>::max()) { 724 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably " 725 "something has gone wrong."; 726 return std::numeric_limits<int32>::max(); 727 } 728 return duration_ms; 729 } 730 731 void MediaSourceDelegate::OnDemuxerOpened() { 732 DCHECK(main_loop_->BelongsToCurrentThread()); 733 if (!media_source_) 734 return; 735 736 media_source_->open(new WebMediaSourceClientImpl( 737 chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); 738 } 739 740 void MediaSourceDelegate::OnNeedKey(const std::string& session_id, 741 const std::string& type, 742 scoped_ptr<uint8[]> init_data, 743 int init_data_size) { 744 DCHECK(main_loop_->BelongsToCurrentThread()); 745 if (need_key_cb_.is_null()) 746 return; 747 748 need_key_cb_.Run(session_id, type, init_data.Pass(), init_data_size); 749 } 750 751 scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack( 752 media::TextKind kind, 753 const std::string& label, 754 const std::string& language) { 755 return scoped_ptr<media::TextTrack>(); 756 } 757 758 bool MediaSourceDelegate::HasEncryptedStream() { 759 DCHECK_BELONG_TO_MEDIA_LOOP(); 760 return (audio_stream_ && 761 audio_stream_->audio_decoder_config().is_encrypted()) || 762 (video_stream_ && 763 video_stream_->video_decoder_config().is_encrypted()); 764 } 765 766 void MediaSourceDelegate::SetSeeking(bool seeking) { 767 base::AutoLock auto_lock(seeking_lock_); 768 seeking_ = seeking; 769 } 770 771 bool MediaSourceDelegate::IsSeeking() const { 772 base::AutoLock auto_lock(seeking_lock_); 773 return seeking_; 774 } 775 776 } // namespace content 777