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 |