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 drm_bridge_->UnregisterPlayer(cdm_registration_id_); | |
|
ddorwin
2014/05/30 20:50:05
Should this be called even if cdm_registration_id_
xhwang
2014/06/02 20:11:43
Done.
| |
| 71 cdm_registration_id_ = 0; | |
| 67 } | 72 } |
| 68 | 73 |
| 69 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { | 74 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { |
| 70 // For an empty surface, always pass it to the decoder job so that it | 75 // 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 | 76 // can detach from the current one. Otherwise, don't pass an unprotected |
| 72 // surface if the video content requires a protected one. | 77 // surface if the video content requires a protected one. |
| 73 if (!surface.IsEmpty() && | 78 if (!surface.IsEmpty() && |
| 74 IsProtectedSurfaceRequired() && !surface.is_protected()) { | 79 IsProtectedSurfaceRequired() && !surface.is_protected()) { |
| 75 return; | 80 return; |
| 76 } | 81 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; | 237 DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; |
| 233 ProcessPendingEvents(); | 238 ProcessPendingEvents(); |
| 234 } | 239 } |
| 235 } | 240 } |
| 236 | 241 |
| 237 void MediaSourcePlayer::SetVolume(double volume) { | 242 void MediaSourcePlayer::SetVolume(double volume) { |
| 238 volume_ = volume; | 243 volume_ = volume; |
| 239 SetVolumeInternal(); | 244 SetVolumeInternal(); |
| 240 } | 245 } |
| 241 | 246 |
| 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 { | 247 bool MediaSourcePlayer::IsSurfaceInUse() const { |
| 253 return is_surface_in_use_; | 248 return is_surface_in_use_; |
| 254 } | 249 } |
| 255 | 250 |
| 256 bool MediaSourcePlayer::CanPause() { | 251 bool MediaSourcePlayer::CanPause() { |
| 257 return Seekable(); | 252 return Seekable(); |
| 258 } | 253 } |
| 259 | 254 |
| 260 bool MediaSourcePlayer::CanSeekForward() { | 255 bool MediaSourcePlayer::CanSeekForward() { |
| 261 return Seekable(); | 256 return Seekable(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 } | 343 } |
| 349 | 344 |
| 350 void MediaSourcePlayer::OnMediaCryptoReady() { | 345 void MediaSourcePlayer::OnMediaCryptoReady() { |
| 351 DCHECK(!drm_bridge_->GetMediaCrypto().is_null()); | 346 DCHECK(!drm_bridge_->GetMediaCrypto().is_null()); |
| 352 drm_bridge_->SetMediaCryptoReadyCB(base::Closure()); | 347 drm_bridge_->SetMediaCryptoReadyCB(base::Closure()); |
| 353 | 348 |
| 354 if (playing_) | 349 if (playing_) |
| 355 StartInternal(); | 350 StartInternal(); |
| 356 } | 351 } |
| 357 | 352 |
| 358 void MediaSourcePlayer::SetCdm(MediaKeys* cdm) { | 353 void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) { |
| 359 // Currently we don't support DRM change during the middle of playback, even | 354 // Currently we don't support DRM change during the middle of playback, even |
| 360 // if the player is paused. | 355 // if the player is paused. |
| 361 // TODO(qinmin): support DRM change after playback has started. | 356 // TODO(qinmin): support DRM change after playback has started. |
| 362 // http://crbug.com/253792. | 357 // http://crbug.com/253792. |
| 363 if (GetCurrentTime() > base::TimeDelta()) { | 358 if (GetCurrentTime() > base::TimeDelta()) { |
| 364 VLOG(0) << "Setting DRM bridge after playback has started. " | 359 VLOG(0) << "Setting DRM bridge after playback has started. " |
| 365 << "This is not well supported!"; | 360 << "This is not well supported!"; |
| 366 } | 361 } |
| 367 | 362 |
| 363 // Currently we don't support resetting |drm_bridge_|. | |
|
ddorwin
2014/05/30 20:50:05
Ditto about DCHECK and error reporting.
xhwang
2014/06/02 20:11:43
Done.
| |
| 364 if (drm_bridge_) | |
| 365 return; | |
| 366 | |
| 368 // Only MediaDrmBridge will be set on MediaSourcePlayer. | 367 // Only MediaDrmBridge will be set on MediaSourcePlayer. |
| 369 drm_bridge_ = static_cast<MediaDrmBridge*>(cdm); | 368 drm_bridge_ = static_cast<MediaDrmBridge*>(cdm); |
| 370 | 369 |
| 370 cdm_registration_id_ = cdm->RegisterPlayer( | |
|
ddorwin
2014/05/30 20:50:05
A bit odd to cast then use the previous pointer (c
xhwang
2014/06/02 20:11:43
Done.
| |
| 371 base::Bind(&MediaSourcePlayer::OnKeyAdded, weak_this_), | |
| 372 base::Bind(&MediaSourcePlayer::OnCdmDestroyed, weak_this_)); | |
| 373 | |
| 371 if (drm_bridge_->GetMediaCrypto().is_null()) { | 374 if (drm_bridge_->GetMediaCrypto().is_null()) { |
|
ddorwin
2014/05/30 20:50:05
Should this logic be made generic as well? Some ty
xhwang
2014/06/02 20:11:43
Not sure whether there's a general need for this.
| |
| 372 drm_bridge_->SetMediaCryptoReadyCB(base::Bind( | 375 drm_bridge_->SetMediaCryptoReadyCB( |
| 373 &MediaSourcePlayer::OnMediaCryptoReady, weak_factory_.GetWeakPtr())); | 376 base::Bind(&MediaSourcePlayer::OnMediaCryptoReady, weak_this_)); |
| 374 return; | 377 return; |
| 375 } | 378 } |
| 376 | 379 |
| 377 if (playing_) | 380 if (playing_) |
| 378 StartInternal(); | 381 StartInternal(); |
| 379 } | 382 } |
| 380 | 383 |
| 381 void MediaSourcePlayer::OnDemuxerSeekDone( | 384 void MediaSourcePlayer::OnDemuxerSeekDone( |
| 382 base::TimeDelta actual_browser_seek_time) { | 385 base::TimeDelta actual_browser_seek_time) { |
| 383 DVLOG(1) << __FUNCTION__; | 386 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); | 520 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); |
| 518 | 521 |
| 519 // It is possible that all streams have finished decode, yet starvation | 522 // 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 | 523 // occurred during the last stream's EOS decode. In this case, prefetch is a |
| 521 // no-op. | 524 // no-op. |
| 522 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 525 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
| 523 if (count == 0) | 526 if (count == 0) |
| 524 return; | 527 return; |
| 525 | 528 |
| 526 SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); | 529 SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
| 527 base::Closure barrier = | 530 base::Closure barrier = BarrierClosure( |
| 528 BarrierClosure(count, | 531 count, base::Bind(&MediaSourcePlayer::OnPrefetchDone, weak_this_)); |
| 529 base::Bind(&MediaSourcePlayer::OnPrefetchDone, | |
| 530 weak_factory_.GetWeakPtr())); | |
| 531 | 532 |
| 532 if (!AudioFinished()) | 533 if (!AudioFinished()) |
| 533 audio_decoder_job_->Prefetch(barrier); | 534 audio_decoder_job_->Prefetch(barrier); |
| 534 | 535 |
| 535 if (!VideoFinished()) | 536 if (!VideoFinished()) |
| 536 video_decoder_job_->Prefetch(barrier); | 537 video_decoder_job_->Prefetch(barrier); |
| 537 | 538 |
| 538 return; | 539 return; |
| 539 } | 540 } |
| 540 | 541 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 } | 649 } |
| 649 | 650 |
| 650 void MediaSourcePlayer::DecodeMoreAudio() { | 651 void MediaSourcePlayer::DecodeMoreAudio() { |
| 651 DVLOG(1) << __FUNCTION__; | 652 DVLOG(1) << __FUNCTION__; |
| 652 DCHECK(!audio_decoder_job_->is_decoding()); | 653 DCHECK(!audio_decoder_job_->is_decoding()); |
| 653 DCHECK(!AudioFinished()); | 654 DCHECK(!AudioFinished()); |
| 654 | 655 |
| 655 scoped_ptr<DemuxerConfigs> configs(audio_decoder_job_->Decode( | 656 scoped_ptr<DemuxerConfigs> configs(audio_decoder_job_->Decode( |
| 656 start_time_ticks_, | 657 start_time_ticks_, |
| 657 start_presentation_timestamp_, | 658 start_presentation_timestamp_, |
| 658 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 659 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true))); |
| 659 weak_factory_.GetWeakPtr(), | |
| 660 true))); | |
| 661 if (!configs) { | 660 if (!configs) { |
| 662 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", | 661 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", |
| 663 audio_decoder_job_.get()); | 662 audio_decoder_job_.get()); |
| 664 return; | 663 return; |
| 665 } | 664 } |
| 666 | 665 |
| 667 // Failed to start the next decode. | 666 // Failed to start the next decode. |
| 668 DCHECK(!reconfig_audio_decoder_); | 667 DCHECK(!reconfig_audio_decoder_); |
| 669 reconfig_audio_decoder_ = true; | 668 reconfig_audio_decoder_ = true; |
| 670 SetDemuxerConfigs(*configs, true); | 669 SetDemuxerConfigs(*configs, true); |
| 671 | 670 |
| 672 // Config change may have just been detected on the other stream. If so, | 671 // Config change may have just been detected on the other stream. If so, |
| 673 // don't send a duplicate demuxer config request. | 672 // don't send a duplicate demuxer config request. |
| 674 if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { | 673 if (IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
| 675 DCHECK(reconfig_video_decoder_); | 674 DCHECK(reconfig_video_decoder_); |
| 676 return; | 675 return; |
| 677 } | 676 } |
| 678 | 677 |
| 679 SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); | 678 SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING); |
| 680 } | 679 } |
| 681 | 680 |
| 682 void MediaSourcePlayer::DecodeMoreVideo() { | 681 void MediaSourcePlayer::DecodeMoreVideo() { |
| 683 DVLOG(1) << __FUNCTION__; | 682 DVLOG(1) << __FUNCTION__; |
| 684 DCHECK(!video_decoder_job_->is_decoding()); | 683 DCHECK(!video_decoder_job_->is_decoding()); |
| 685 DCHECK(!VideoFinished()); | 684 DCHECK(!VideoFinished()); |
| 686 | 685 |
| 687 scoped_ptr<DemuxerConfigs> configs(video_decoder_job_->Decode( | 686 scoped_ptr<DemuxerConfigs> configs(video_decoder_job_->Decode( |
| 688 start_time_ticks_, | 687 start_time_ticks_, |
| 689 start_presentation_timestamp_, | 688 start_presentation_timestamp_, |
| 690 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, | 689 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, false))); |
| 691 weak_factory_.GetWeakPtr(), | |
| 692 false))); | |
| 693 if (!configs) { | 690 if (!configs) { |
| 694 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", | 691 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", |
| 695 video_decoder_job_.get()); | 692 video_decoder_job_.get()); |
| 696 return; | 693 return; |
| 697 } | 694 } |
| 698 | 695 |
| 699 // Failed to start the next decode. | 696 // Failed to start the next decode. |
| 700 // After this detection of video config change, next video data received | 697 // After this detection of video config change, next video data received |
| 701 // will begin with I-frame. | 698 // will begin with I-frame. |
| 702 next_video_data_is_iframe_ = true; | 699 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 | 904 // For video only streams, fps can be estimated from the difference |
| 908 // between the previous and current presentation timestamps. The | 905 // between the previous and current presentation timestamps. The |
| 909 // previous presentation timestamp is equal to current_timestamp. | 906 // previous presentation timestamp is equal to current_timestamp. |
| 910 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | 907 // TODO(qinmin): determine whether 2 is a good coefficient for estimating |
| 911 // video frame timeout. | 908 // video frame timeout. |
| 912 timeout = 2 * (current_presentation_timestamp - current_timestamp); | 909 timeout = 2 * (current_presentation_timestamp - current_timestamp); |
| 913 } | 910 } |
| 914 | 911 |
| 915 timeout = std::max(timeout, kMinStarvationTimeout); | 912 timeout = std::max(timeout, kMinStarvationTimeout); |
| 916 | 913 |
| 917 decoder_starvation_callback_.Reset(base::Bind( | 914 decoder_starvation_callback_.Reset( |
| 918 &MediaSourcePlayer::OnDecoderStarved, weak_factory_.GetWeakPtr())); | 915 base::Bind(&MediaSourcePlayer::OnDecoderStarved, weak_this_)); |
| 919 base::MessageLoop::current()->PostDelayedTask( | 916 base::MessageLoop::current()->PostDelayedTask( |
| 920 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | 917 FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
| 921 } | 918 } |
| 922 | 919 |
| 923 void MediaSourcePlayer::SetVolumeInternal() { | 920 void MediaSourcePlayer::SetVolumeInternal() { |
| 924 if (audio_decoder_job_ && volume_ >= 0) | 921 if (audio_decoder_job_ && volume_ >= 0) |
| 925 audio_decoder_job_->SetVolume(volume_); | 922 audio_decoder_job_->SetVolume(volume_); |
| 926 } | 923 } |
| 927 | 924 |
| 928 bool MediaSourcePlayer::IsProtectedSurfaceRequired() { | 925 bool MediaSourcePlayer::IsProtectedSurfaceRequired() { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 is_audio_encrypted_ = configs.is_audio_encrypted; | 1012 is_audio_encrypted_ = configs.is_audio_encrypted; |
| 1016 audio_extra_data_ = configs.audio_extra_data; | 1013 audio_extra_data_ = configs.audio_extra_data; |
| 1017 } else { | 1014 } else { |
| 1018 video_codec_ = configs.video_codec; | 1015 video_codec_ = configs.video_codec; |
| 1019 width_ = configs.video_size.width(); | 1016 width_ = configs.video_size.width(); |
| 1020 height_ = configs.video_size.height(); | 1017 height_ = configs.video_size.height(); |
| 1021 is_video_encrypted_ = configs.is_video_encrypted; | 1018 is_video_encrypted_ = configs.is_video_encrypted; |
| 1022 } | 1019 } |
| 1023 } | 1020 } |
| 1024 | 1021 |
| 1022 void MediaSourcePlayer::OnKeyAdded() { | |
| 1023 DVLOG(1) << __FUNCTION__; | |
| 1024 if (!is_waiting_for_key_) | |
| 1025 return; | |
| 1026 | |
| 1027 is_waiting_for_key_ = false; | |
| 1028 if (playing_) | |
| 1029 StartInternal(); | |
| 1030 } | |
| 1031 | |
| 1032 void MediaSourcePlayer::OnCdmDestroyed() { | |
| 1033 DVLOG(1) << __FUNCTION__; | |
| 1034 DCHECK(drm_bridge_); | |
| 1035 // TODO(xhwang): Support detachment of CDM. | |
|
ddorwin
2014/05/30 20:50:05
Don't you need to handle the platform-driven case
xhwang
2014/06/02 20:11:43
That'll be a non-trivial change. I'll probably do
ddorwin
2014/06/02 20:20:29
But does this break existing prefixed API behavior
xhwang
2014/06/02 21:41:22
Currently we are not releasing MediaDrm when the d
| |
| 1036 DVLOG(1) << "CDM detachment not supported."; | |
| 1037 } | |
| 1038 | |
| 1025 } // namespace media | 1039 } // namespace media |
| OLD | NEW |