Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_source_player.h" | 5 #include "media/base/android/media_source_player.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
| 10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 is_audio_encrypted_(false), | 47 is_audio_encrypted_(false), |
| 48 is_video_encrypted_(false), | 48 is_video_encrypted_(false), |
| 49 volume_(-1.0), | 49 volume_(-1.0), |
| 50 clock_(&default_tick_clock_), | 50 clock_(&default_tick_clock_), |
| 51 next_video_data_is_iframe_(true), | 51 next_video_data_is_iframe_(true), |
| 52 doing_browser_seek_(false), | 52 doing_browser_seek_(false), |
| 53 pending_seek_(false), | 53 pending_seek_(false), |
| 54 reconfig_audio_decoder_(false), | 54 reconfig_audio_decoder_(false), |
| 55 reconfig_video_decoder_(false), | 55 reconfig_video_decoder_(false), |
| 56 drm_bridge_(NULL), | 56 drm_bridge_(NULL), |
| 57 cdm_registration_id_(0), | |
| 57 is_waiting_for_key_(false), | 58 is_waiting_for_key_(false), |
| 58 has_pending_audio_data_request_(false), | 59 has_pending_audio_data_request_(false), |
| 59 has_pending_video_data_request_(false), | 60 has_pending_video_data_request_(false), |
| 60 weak_factory_(this) { | 61 weak_factory_(this) { |
| 61 demuxer_->Initialize(this); | 62 demuxer_->Initialize(this); |
| 62 clock_.SetMaxTime(base::TimeDelta()); | 63 clock_.SetMaxTime(base::TimeDelta()); |
| 64 weak_this_ = weak_factory_.GetWeakPtr(); | |
| 63 } | 65 } |
| 64 | 66 |
| 65 MediaSourcePlayer::~MediaSourcePlayer() { | 67 MediaSourcePlayer::~MediaSourcePlayer() { |
| 66 Release(); | 68 Release(); |
| 69 if (drm_bridge_) { | |
| 70 DCHECK_NE(cdm_registration_id_, 0); | |
|
ddorwin
2014/06/02 20:20:29
If you want a DCHECK, it's probably something like
xhwang
2014/06/02 21:41:22
Done.
| |
| 71 drm_bridge_->UnregisterPlayer(cdm_registration_id_); | |
| 72 cdm_registration_id_ = 0; | |
| 73 } | |
| 67 } | 74 } |
| 68 | 75 |
| 69 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { | 76 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { |
| 70 // For an empty surface, always pass it to the decoder job so that it | 77 // For an empty surface, always pass it to the decoder job so that it |
| 71 // can detach from the current one. Otherwise, don't pass an unprotected | 78 // can detach from the current one. Otherwise, don't pass an unprotected |
| 72 // surface if the video content requires a protected one. | 79 // surface if the video content requires a protected one. |
| 73 if (!surface.IsEmpty() && | 80 if (!surface.IsEmpty() && |
| 74 IsProtectedSurfaceRequired() && !surface.is_protected()) { | 81 IsProtectedSurfaceRequired() && !surface.is_protected()) { |
| 75 return; | 82 return; |
| 76 } | 83 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; | 239 DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; |
| 233 ProcessPendingEvents(); | 240 ProcessPendingEvents(); |
| 234 } | 241 } |
| 235 } | 242 } |
| 236 | 243 |
| 237 void MediaSourcePlayer::SetVolume(double volume) { | 244 void MediaSourcePlayer::SetVolume(double volume) { |
| 238 volume_ = volume; | 245 volume_ = volume; |
| 239 SetVolumeInternal(); | 246 SetVolumeInternal(); |
| 240 } | 247 } |
| 241 | 248 |
| 242 void MediaSourcePlayer::OnKeyAdded() { | |
| 243 DVLOG(1) << __FUNCTION__; | |
| 244 if (!is_waiting_for_key_) | |
| 245 return; | |
| 246 | |
| 247 is_waiting_for_key_ = false; | |
| 248 if (playing_) | |
| 249 StartInternal(); | |
| 250 } | |
| 251 | |
| 252 bool MediaSourcePlayer::IsSurfaceInUse() const { | 249 bool MediaSourcePlayer::IsSurfaceInUse() const { |
| 253 return is_surface_in_use_; | 250 return is_surface_in_use_; |
| 254 } | 251 } |
| 255 | 252 |
| 256 bool MediaSourcePlayer::CanPause() { | 253 bool MediaSourcePlayer::CanPause() { |
| 257 return Seekable(); | 254 return Seekable(); |
| 258 } | 255 } |
| 259 | 256 |
| 260 bool MediaSourcePlayer::CanSeekForward() { | 257 bool MediaSourcePlayer::CanSeekForward() { |
| 261 return Seekable(); | 258 return Seekable(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 } | 345 } |
| 349 | 346 |
| 350 void MediaSourcePlayer::OnMediaCryptoReady() { | 347 void MediaSourcePlayer::OnMediaCryptoReady() { |
| 351 DCHECK(!drm_bridge_->GetMediaCrypto().is_null()); | 348 DCHECK(!drm_bridge_->GetMediaCrypto().is_null()); |
| 352 drm_bridge_->SetMediaCryptoReadyCB(base::Closure()); | 349 drm_bridge_->SetMediaCryptoReadyCB(base::Closure()); |
| 353 | 350 |
| 354 if (playing_) | 351 if (playing_) |
| 355 StartInternal(); | 352 StartInternal(); |
| 356 } | 353 } |
| 357 | 354 |
| 358 void MediaSourcePlayer::SetCdm(MediaKeys* cdm) { | 355 void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) { |
| 359 // Currently we don't support DRM change during the middle of playback, even | 356 // Currently we don't support DRM change during the middle of playback, even |
| 360 // if the player is paused. | 357 // if the player is paused. |
| 361 // TODO(qinmin): support DRM change after playback has started. | 358 // TODO(qinmin): support DRM change after playback has started. |
| 362 // http://crbug.com/253792. | 359 // http://crbug.com/253792. |
| 363 if (GetCurrentTime() > base::TimeDelta()) { | 360 if (GetCurrentTime() > base::TimeDelta()) { |
| 364 VLOG(0) << "Setting DRM bridge after playback has started. " | 361 VLOG(0) << "Setting DRM bridge after playback has started. " |
| 365 << "This is not well supported!"; | 362 << "This is not well supported!"; |
| 366 } | 363 } |
| 367 | 364 |
| 365 if (drm_bridge_) { | |
| 366 NOTREACHED() << "Currently we do not support resetting CDM."; | |
| 367 return; | |
| 368 } | |
| 369 | |
| 368 // Only MediaDrmBridge will be set on MediaSourcePlayer. | 370 // Only MediaDrmBridge will be set on MediaSourcePlayer. |
| 369 drm_bridge_ = static_cast<MediaDrmBridge*>(cdm); | 371 drm_bridge_ = static_cast<MediaDrmBridge*>(cdm); |
| 370 | 372 |
| 373 cdm_registration_id_ = drm_bridge_->RegisterPlayer( | |
| 374 base::Bind(&MediaSourcePlayer::OnKeyAdded, weak_this_), | |
| 375 base::Bind(&MediaSourcePlayer::OnCdmUnset, weak_this_)); | |
| 376 | |
| 371 if (drm_bridge_->GetMediaCrypto().is_null()) { | 377 if (drm_bridge_->GetMediaCrypto().is_null()) { |
| 372 drm_bridge_->SetMediaCryptoReadyCB(base::Bind( | 378 drm_bridge_->SetMediaCryptoReadyCB( |
| 373 &MediaSourcePlayer::OnMediaCryptoReady, weak_factory_.GetWeakPtr())); | 379 base::Bind(&MediaSourcePlayer::OnMediaCryptoReady, weak_this_)); |
| 374 return; | 380 return; |
| 375 } | 381 } |
| 376 | 382 |
| 377 if (playing_) | 383 if (playing_) |
| 378 StartInternal(); | 384 StartInternal(); |
| 379 } | 385 } |
| 380 | 386 |
| 381 void MediaSourcePlayer::OnDemuxerSeekDone( | 387 void MediaSourcePlayer::OnDemuxerSeekDone( |
| 382 base::TimeDelta actual_browser_seek_time) { | 388 base::TimeDelta actual_browser_seek_time) { |
| 383 DVLOG(1) << __FUNCTION__; | 389 DVLOG(1) << __FUNCTION__; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); | 523 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); |
| 518 | 524 |
| 519 // It is possible that all streams have finished decode, yet starvation | 525 // It is possible that all streams have finished decode, yet starvation |
| 520 // occurred during the last stream's EOS decode. In this case, prefetch is a | 526 // occurred during the last stream's EOS decode. In this case, prefetch is a |
| 521 // no-op. | 527 // no-op. |
| 522 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 528 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
| 523 if (count == 0) | 529 if (count == 0) |
| 524 return; | 530 return; |
| 525 | 531 |
| 526 SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); | 532 SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
| 527 base::Closure barrier = | 533 base::Closure barrier = BarrierClosure( |
| 528 BarrierClosure(count, | 534 count, base::Bind(&MediaSourcePlayer::OnPrefetchDone, weak_this_)); |
| 529 base::Bind(&MediaSourcePlayer::OnPrefetchDone, | |
| 530 weak_factory_.GetWeakPtr())); | |
| 531 | 535 |
| 532 if (!AudioFinished()) | 536 if (!AudioFinished()) |
| 533 audio_decoder_job_->Prefetch(barrier); | 537 audio_decoder_job_->Prefetch(barrier); |
| 534 | 538 |
| 535 if (!VideoFinished()) | 539 if (!VideoFinished()) |
| 536 video_decoder_job_->Prefetch(barrier); | 540 video_decoder_job_->Prefetch(barrier); |
| 537 | 541 |
| 538 return; | 542 return; |
| 539 } | 543 } |
| 540 | 544 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 } | 652 } |
| 649 | 653 |
| 650 void MediaSourcePlayer::DecodeMoreAudio() { | 654 void MediaSourcePlayer::DecodeMoreAudio() { |
| 651 DVLOG(1) << __FUNCTION__; | 655 DVLOG(1) << __FUNCTION__; |
| 652 DCHECK(!audio_decoder_job_->is_decoding()); | 656 DCHECK(!audio_decoder_job_->is_decoding()); |
| 653 DCHECK(!AudioFinished()); | 657 DCHECK(!AudioFinished()); |
| 654 | 658 |
| 655 scoped_ptr<DemuxerConfigs> configs(audio_decoder_job_->Decode( | 659 scoped_ptr<DemuxerConfigs> configs(audio_decoder_job_->Decode( |
| 656 start_time_ticks_, | 660 start_time_ticks_, |
| 657 start_presentation_timestamp_, | 661 start_presentation_timestamp_, |
| 658 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 662 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true))); |
| 659 weak_factory_.GetWeakPtr(), | |
| 660 true))); | |
| 661 if (!configs) { | 663 if (!configs) { |
| 662 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", | 664 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", |
| 663 audio_decoder_job_.get()); | 665 audio_decoder_job_.get()); |
| 664 return; | 666 return; |
| 665 } | 667 } |
| 666 | 668 |
| 667 // Failed to start the next decode. | 669 // Failed to start the next decode. |
| 668 DCHECK(!reconfig_audio_decoder_); | 670 DCHECK(!reconfig_audio_decoder_); |
| 669 reconfig_audio_decoder_ = true; | 671 reconfig_audio_decoder_ = true; |
| 670 SetDemuxerConfigs(*configs, true); | 672 SetDemuxerConfigs(*configs, true); |
| 671 | 673 |
| 672 // Config change may have just been detected on the other stream. If so, | 674 // Config change may have just been detected on the other stream. If so, |
| 673 // don't send a duplicate demuxer config request. | 675 // don't send a duplicate demuxer config request. |
| 674 if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { | 676 if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
| 675 DCHECK(reconfig_video_decoder_); | 677 DCHECK(reconfig_video_decoder_); |
| 676 return; | 678 return; |
| 677 } | 679 } |
| 678 | 680 |
| 679 SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); | 681 SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); |
| 680 } | 682 } |
| 681 | 683 |
| 682 void MediaSourcePlayer::DecodeMoreVideo() { | 684 void MediaSourcePlayer::DecodeMoreVideo() { |
| 683 DVLOG(1) << __FUNCTION__; | 685 DVLOG(1) << __FUNCTION__; |
| 684 DCHECK(!video_decoder_job_->is_decoding()); | 686 DCHECK(!video_decoder_job_->is_decoding()); |
| 685 DCHECK(!VideoFinished()); | 687 DCHECK(!VideoFinished()); |
| 686 | 688 |
| 687 scoped_ptr<DemuxerConfigs> configs(video_decoder_job_->Decode( | 689 scoped_ptr<DemuxerConfigs> configs(video_decoder_job_->Decode( |
| 688 start_time_ticks_, | 690 start_time_ticks_, |
| 689 start_presentation_timestamp_, | 691 start_presentation_timestamp_, |
| 690 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 692 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, false))); |
| 691 weak_factory_.GetWeakPtr(), | |
| 692 false))); | |
| 693 if (!configs) { | 693 if (!configs) { |
| 694 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", | 694 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", |
| 695 video_decoder_job_.get()); | 695 video_decoder_job_.get()); |
| 696 return; | 696 return; |
| 697 } | 697 } |
| 698 | 698 |
| 699 // Failed to start the next decode. | 699 // Failed to start the next decode. |
| 700 // After this detection of video config change, next video data received | 700 // After this detection of video config change, next video data received |
| 701 // will begin with I-frame. | 701 // will begin with I-frame. |
| 702 next_video_data_is_iframe_ = true; | 702 next_video_data_is_iframe_ = true; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 // For video only streams, fps can be estimated from the difference | 907 // For video only streams, fps can be estimated from the difference |
| 908 // between the previous and current presentation timestamps. The | 908 // between the previous and current presentation timestamps. The |
| 909 // previous presentation timestamp is equal to current_timestamp. | 909 // previous presentation timestamp is equal to current_timestamp. |
| 910 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | 910 // TODO(qinmin): determine whether 2 is a good coefficient for estimating |
| 911 // video frame timeout. | 911 // video frame timeout. |
| 912 timeout = 2 * (current_presentation_timestamp - current_timestamp); | 912 timeout = 2 * (current_presentation_timestamp - current_timestamp); |
| 913 } | 913 } |
| 914 | 914 |
| 915 timeout = std::max(timeout, kMinStarvationTimeout); | 915 timeout = std::max(timeout, kMinStarvationTimeout); |
| 916 | 916 |
| 917 decoder_starvation_callback_.Reset(base::Bind( | 917 decoder_starvation_callback_.Reset( |
| 918 &MediaSourcePlayer::OnDecoderStarved, weak_factory_.GetWeakPtr())); | 918 base::Bind(&MediaSourcePlayer::OnDecoderStarved, weak_this_)); |
| 919 base::MessageLoop::current()->PostDelayedTask( | 919 base::MessageLoop::current()->PostDelayedTask( |
| 920 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | 920 FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
| 921 } | 921 } |
| 922 | 922 |
| 923 void MediaSourcePlayer::SetVolumeInternal() { | 923 void MediaSourcePlayer::SetVolumeInternal() { |
| 924 if (audio_decoder_job_ && volume_ >= 0) | 924 if (audio_decoder_job_ && volume_ >= 0) |
| 925 audio_decoder_job_->SetVolume(volume_); | 925 audio_decoder_job_->SetVolume(volume_); |
| 926 } | 926 } |
| 927 | 927 |
| 928 bool MediaSourcePlayer::IsProtectedSurfaceRequired() { | 928 bool MediaSourcePlayer::IsProtectedSurfaceRequired() { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 is_audio_encrypted_ = configs.is_audio_encrypted; | 1015 is_audio_encrypted_ = configs.is_audio_encrypted; |
| 1016 audio_extra_data_ = configs.audio_extra_data; | 1016 audio_extra_data_ = configs.audio_extra_data; |
| 1017 } else { | 1017 } else { |
| 1018 video_codec_ = configs.video_codec; | 1018 video_codec_ = configs.video_codec; |
| 1019 width_ = configs.video_size.width(); | 1019 width_ = configs.video_size.width(); |
| 1020 height_ = configs.video_size.height(); | 1020 height_ = configs.video_size.height(); |
| 1021 is_video_encrypted_ = configs.is_video_encrypted; | 1021 is_video_encrypted_ = configs.is_video_encrypted; |
| 1022 } | 1022 } |
| 1023 } | 1023 } |
| 1024 | 1024 |
| 1025 void MediaSourcePlayer::OnKeyAdded() { | |
| 1026 DVLOG(1) << __FUNCTION__; | |
| 1027 if (!is_waiting_for_key_) | |
| 1028 return; | |
| 1029 | |
| 1030 is_waiting_for_key_ = false; | |
| 1031 if (playing_) | |
| 1032 StartInternal(); | |
| 1033 } | |
| 1034 | |
| 1035 void MediaSourcePlayer::OnCdmUnset() { | |
| 1036 DVLOG(1) << __FUNCTION__; | |
| 1037 DCHECK(drm_bridge_); | |
| 1038 // TODO(xhwang): Support detachment of CDM. | |
| 1039 DVLOG(1) << "CDM detachment not supported."; | |
| 1040 } | |
| 1041 | |
| 1025 } // namespace media | 1042 } // namespace media |
| OLD | NEW |