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" |
| 11 #include "base/barrier_closure.h" | 11 #include "base/barrier_closure.h" |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
| 15 #include "base/debug/trace_event.h" | 15 #include "base/debug/trace_event.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "media/base/android/audio_decoder_job.h" | 18 #include "media/base/android/audio_decoder_job.h" |
| 19 #include "media/base/android/media_drm_bridge.h" | 19 #include "media/base/android/media_drm_bridge.h" |
| 20 #include "media/base/android/media_player_manager.h" | 20 #include "media/base/android/media_player_manager.h" |
| 21 #include "media/base/android/video_decoder_job.h" | 21 #include "media/base/android/video_decoder_job.h" |
| 22 | 22 |
| 23 | |
| 24 namespace media { | 23 namespace media { |
| 25 | 24 |
| 26 MediaSourcePlayer::MediaSourcePlayer( | 25 MediaSourcePlayer::MediaSourcePlayer( |
| 27 int player_id, | 26 int player_id, |
| 28 MediaPlayerManager* manager, | 27 MediaPlayerManager* manager, |
| 29 const RequestMediaResourcesCB& request_media_resources_cb, | 28 const RequestMediaResourcesCB& request_media_resources_cb, |
| 30 scoped_ptr<DemuxerAndroid> demuxer, | 29 scoped_ptr<DemuxerAndroid> demuxer, |
| 31 const GURL& frame_url) | 30 const GURL& frame_url) |
| 32 : MediaPlayerAndroid(player_id, | 31 : MediaPlayerAndroid(player_id, |
| 33 manager, | 32 manager, |
| 34 request_media_resources_cb, | 33 request_media_resources_cb, |
| 35 frame_url), | 34 frame_url), |
| 36 demuxer_(demuxer.Pass()), | 35 demuxer_(demuxer.Pass()), |
| 37 pending_event_(NO_EVENT_PENDING), | 36 pending_event_(NO_EVENT_PENDING), |
| 38 playing_(false), | 37 playing_(false), |
| 39 interpolator_(&default_tick_clock_), | 38 interpolator_(&default_tick_clock_), |
| 40 doing_browser_seek_(false), | 39 doing_browser_seek_(false), |
| 41 pending_seek_(false), | 40 pending_seek_(false), |
| 42 drm_bridge_(NULL), | 41 drm_bridge_(NULL), |
| 43 cdm_registration_id_(0), | 42 cdm_registration_id_(0), |
| 44 is_waiting_for_key_(false), | 43 is_waiting_for_key_(false), |
| 44 key_added_while_decode_pending_(false), | |
| 45 is_waiting_for_audio_decoder_(false), | 45 is_waiting_for_audio_decoder_(false), |
| 46 is_waiting_for_video_decoder_(false), | 46 is_waiting_for_video_decoder_(false), |
| 47 prerolling_(true), | 47 prerolling_(true), |
| 48 weak_factory_(this) { | 48 weak_factory_(this) { |
| 49 audio_decoder_job_.reset(new AudioDecoderJob( | 49 audio_decoder_job_.reset(new AudioDecoderJob( |
| 50 base::Bind(&DemuxerAndroid::RequestDemuxerData, | 50 base::Bind(&DemuxerAndroid::RequestDemuxerData, |
| 51 base::Unretained(demuxer_.get()), | 51 base::Unretained(demuxer_.get()), |
| 52 DemuxerStream::AUDIO), | 52 DemuxerStream::AUDIO), |
| 53 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, | 53 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, |
| 54 weak_factory_.GetWeakPtr()))); | 54 weak_factory_.GetWeakPtr()))); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 bool MediaSourcePlayer::IsPlayerReady() { | 216 bool MediaSourcePlayer::IsPlayerReady() { |
| 217 return audio_decoder_job_ || video_decoder_job_; | 217 return audio_decoder_job_ || video_decoder_job_; |
| 218 } | 218 } |
| 219 | 219 |
| 220 void MediaSourcePlayer::StartInternal() { | 220 void MediaSourcePlayer::StartInternal() { |
| 221 DVLOG(1) << __FUNCTION__; | 221 DVLOG(1) << __FUNCTION__; |
| 222 // If there are pending events, wait for them finish. | 222 // If there are pending events, wait for them finish. |
| 223 if (pending_event_ != NO_EVENT_PENDING) | 223 if (pending_event_ != NO_EVENT_PENDING) |
| 224 return; | 224 return; |
| 225 | 225 |
| 226 // When we start, we'll have new demuxed data coming in. This new data could | 226 // When we start, we could have new demuxed data coming in. This new data |
| 227 // be clear (not encrypted) or encrypted with different keys. So | 227 // could be clear (not encrypted) or encrypted with different keys. So key |
| 228 // |is_waiting_for_key_| condition may not be true anymore. | 228 // related info should all be cleared. |
| 229 is_waiting_for_key_ = false; | 229 is_waiting_for_key_ = false; |
| 230 key_added_while_decode_pending_ = false; | |
| 230 AttachListener(NULL); | 231 AttachListener(NULL); |
| 231 | 232 |
| 232 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 233 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
| 233 ProcessPendingEvents(); | 234 ProcessPendingEvents(); |
| 234 } | 235 } |
| 235 | 236 |
| 236 void MediaSourcePlayer::OnDemuxerConfigsAvailable( | 237 void MediaSourcePlayer::OnDemuxerConfigsAvailable( |
| 237 const DemuxerConfigs& configs) { | 238 const DemuxerConfigs& configs) { |
| 238 DVLOG(1) << __FUNCTION__; | 239 DVLOG(1) << __FUNCTION__; |
| 239 DCHECK(!HasAudio() && !HasVideo()); | 240 DCHECK(!HasAudio() && !HasVideo()); |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) | 496 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) |
| 496 return; | 497 return; |
| 497 | 498 |
| 498 if (!playing_) { | 499 if (!playing_) { |
| 499 if (is_clock_manager) | 500 if (is_clock_manager) |
| 500 interpolator_.StopInterpolating(); | 501 interpolator_.StopInterpolating(); |
| 501 return; | 502 return; |
| 502 } | 503 } |
| 503 | 504 |
| 504 if (status == MEDIA_CODEC_NO_KEY) { | 505 if (status == MEDIA_CODEC_NO_KEY) { |
| 505 is_waiting_for_key_ = true; | 506 if (key_added_while_decode_pending_) { |
| 507 DVLOG(2) << __FUNCTION__ << ": Key was added during decoding."; | |
| 508 ResumePlaybackAfterKeyAdded(); | |
| 509 } else { | |
| 510 is_waiting_for_key_ = true; | |
| 511 } | |
| 506 return; | 512 return; |
| 507 } | 513 } |
| 508 | 514 |
| 515 // If |key_added_while_decode_pending_| is true and both audio and video | |
| 516 // decoding succeeded, we should clear |key_added_while_decode_pending_| here. | |
| 517 // But that would add more complexity into this function. If we don't clear it | |
| 518 // here, the worst case would be we call ResumePlaybackAfterKeyAdded() when | |
| 519 // we don't really have a new key. This should rarely happen and the | |
| 520 // performance impact should be pretty small. | |
|
xhwang
2014/10/24 23:24:11
qinmin: let me know what you think of this.
qinmin
2014/10/24 23:45:56
I saw an issue that audio can clear out video's ke
xhwang
2014/10/25 00:11:36
Thanks for the review. Here's what I thought that
| |
| 521 // TODO(qinmin/xhwang): This class is complicated because we handle both audio | |
| 522 // and video in one file. If we separate them, we should be able to remove a | |
| 523 // lot of duplication. | |
| 524 | |
| 509 // If the status is MEDIA_CODEC_STOPPED, stop decoding new data. The player is | 525 // If the status is MEDIA_CODEC_STOPPED, stop decoding new data. The player is |
| 510 // in the middle of a seek or stop event and needs to wait for the IPCs to | 526 // in the middle of a seek or stop event and needs to wait for the IPCs to |
| 511 // come. | 527 // come. |
| 512 if (status == MEDIA_CODEC_STOPPED) | 528 if (status == MEDIA_CODEC_STOPPED) |
| 513 return; | 529 return; |
| 514 | 530 |
| 515 if (prerolling_ && IsPrerollFinished(is_audio)) { | 531 if (prerolling_ && IsPrerollFinished(is_audio)) { |
| 516 if (IsPrerollFinished(!is_audio)) { | 532 if (IsPrerollFinished(!is_audio)) { |
| 517 prerolling_ = false; | 533 prerolling_ = false; |
| 518 StartInternal(); | 534 StartInternal(); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 748 if (audio) | 764 if (audio) |
| 749 is_waiting_for_audio_decoder_ = false; | 765 is_waiting_for_audio_decoder_ = false; |
| 750 if (video) | 766 if (video) |
| 751 is_waiting_for_video_decoder_ = false; | 767 is_waiting_for_video_decoder_ = false; |
| 752 if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) | 768 if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) |
| 753 ProcessPendingEvents(); | 769 ProcessPendingEvents(); |
| 754 } | 770 } |
| 755 | 771 |
| 756 void MediaSourcePlayer::OnKeyAdded() { | 772 void MediaSourcePlayer::OnKeyAdded() { |
| 757 DVLOG(1) << __FUNCTION__; | 773 DVLOG(1) << __FUNCTION__; |
| 758 if (!is_waiting_for_key_) | 774 |
| 775 if (is_waiting_for_key_) { | |
| 776 ResumePlaybackAfterKeyAdded(); | |
| 759 return; | 777 return; |
| 778 } | |
| 760 | 779 |
| 780 if ((audio_decoder_job_->is_content_encrypted() && | |
| 781 audio_decoder_job_->is_decoding()) || | |
| 782 (video_decoder_job_->is_content_encrypted() && | |
| 783 video_decoder_job_->is_decoding())) { | |
| 784 DVLOG(2) << __FUNCTION__ << ": " << "Key added during pending decode."; | |
| 785 key_added_while_decode_pending_ = true; | |
| 786 } | |
| 787 } | |
| 788 | |
| 789 void MediaSourcePlayer::ResumePlaybackAfterKeyAdded() { | |
| 790 DVLOG(2) << __FUNCTION__; | |
|
gunsch
2014/10/24 23:51:03
nit: rest of file is DVLOG(1)
xhwang
2014/10/25 00:11:36
Done.
| |
| 761 is_waiting_for_key_ = false; | 791 is_waiting_for_key_ = false; |
| 792 key_added_while_decode_pending_ = false; | |
| 793 // StartInternal() will trigger a prefetch. But since we already HasData(), | |
|
gunsch
2014/10/24 23:51:03
is it worth asserting HasData() on both jobs here?
xhwang
2014/10/25 00:11:36
I don't have confidence in a DCHECK here given all
| |
| 794 // we'll just use previously received data. | |
| 762 if (playing_) | 795 if (playing_) |
| 763 StartInternal(); | 796 StartInternal(); |
| 764 } | 797 } |
| 765 | 798 |
| 766 void MediaSourcePlayer::OnCdmUnset() { | 799 void MediaSourcePlayer::OnCdmUnset() { |
| 767 DVLOG(1) << __FUNCTION__; | 800 DVLOG(1) << __FUNCTION__; |
| 768 DCHECK(drm_bridge_); | 801 DCHECK(drm_bridge_); |
| 769 // TODO(xhwang): Currently this is only called during teardown. Support full | 802 // TODO(xhwang): Currently this is only called during teardown. Support full |
| 770 // detachment of CDM during playback. This will be needed when we start to | 803 // detachment of CDM during playback. This will be needed when we start to |
| 771 // support setMediaKeys(0) (see http://crbug.com/330324), or when we release | 804 // support setMediaKeys(0) (see http://crbug.com/330324), or when we release |
| 772 // MediaDrm when the video is paused, or when the device goes to sleep (see | 805 // MediaDrm when the video is paused, or when the device goes to sleep (see |
| 773 // http://crbug.com/272421). | 806 // http://crbug.com/272421). |
| 774 audio_decoder_job_->SetDrmBridge(NULL); | 807 audio_decoder_job_->SetDrmBridge(NULL); |
| 775 video_decoder_job_->SetDrmBridge(NULL); | 808 video_decoder_job_->SetDrmBridge(NULL); |
| 776 cdm_registration_id_ = 0; | 809 cdm_registration_id_ = 0; |
| 777 drm_bridge_ = NULL; | 810 drm_bridge_ = NULL; |
| 778 } | 811 } |
| 779 | 812 |
| 780 } // namespace media | 813 } // namespace media |
| OLD | NEW |