Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / media / base / android / media_codec_player.cc
blob27b5bcadb86711426a3a84c18e7f929932578e7a
1 // Copyright 2015 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.
5 #include "media/base/android/media_codec_player.h"
7 #include "base/barrier_closure.h"
8 #include "base/bind.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/threading/thread.h"
13 #include "media/base/android/media_codec_audio_decoder.h"
14 #include "media/base/android/media_codec_video_decoder.h"
15 #include "media/base/android/media_player_manager.h"
16 #include "media/base/buffers.h"
18 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \
19 do { \
20 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
21 DCHECK(ui_task_runner_->BelongsToCurrentThread()); \
22 GetMediaTaskRunner()->PostTask( \
23 FROM_HERE, base::Bind(&MediaCodecPlayer::METHOD, media_weak_this_, \
24 ##__VA_ARGS__)); \
25 return; \
26 } \
27 } while (0)
29 namespace media {
31 class MediaThread : public base::Thread {
32 public:
33 MediaThread() : base::Thread("BrowserMediaThread") {
34 Start();
38 // Create media thread
39 base::LazyInstance<MediaThread>::Leaky
40 g_media_thread = LAZY_INSTANCE_INITIALIZER;
43 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() {
44 return g_media_thread.Pointer()->task_runner();
47 // MediaCodecPlayer implementation.
49 MediaCodecPlayer::MediaCodecPlayer(
50 int player_id,
51 base::WeakPtr<MediaPlayerManager> manager,
52 const RequestMediaResourcesCB& request_media_resources_cb,
53 scoped_ptr<DemuxerAndroid> demuxer,
54 const GURL& frame_url)
55 : MediaPlayerAndroid(player_id,
56 manager.get(),
57 request_media_resources_cb,
58 frame_url),
59 ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
60 demuxer_(demuxer.Pass()),
61 state_(STATE_PAUSED),
62 interpolator_(&default_tick_clock_),
63 pending_start_(false),
64 pending_seek_(kNoTimestamp()),
65 media_weak_factory_(this) {
66 DCHECK(ui_task_runner_->BelongsToCurrentThread());
68 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id;
70 request_resources_cb_ = base::Bind(request_media_resources_cb_, player_id);
72 completion_cb_ =
73 base::Bind(&MediaPlayerManager::OnPlaybackComplete, manager, player_id);
74 seek_done_cb_ =
75 base::Bind(&MediaPlayerManager::OnSeekComplete, manager, player_id);
76 attach_listener_cb_ = base::Bind(&MediaPlayerAndroid::AttachListener,
77 WeakPtrForUIThread(), nullptr);
78 detach_listener_cb_ =
79 base::Bind(&MediaPlayerAndroid::DetachListener, WeakPtrForUIThread());
80 metadata_changed_cb_ = base::Bind(&MediaPlayerAndroid::OnMediaMetadataChanged,
81 WeakPtrForUIThread());
82 time_update_cb_ =
83 base::Bind(&MediaPlayerAndroid::OnTimeUpdate, WeakPtrForUIThread());
85 media_weak_this_ = media_weak_factory_.GetWeakPtr();
87 // Finish initializaton on Media thread
88 GetMediaTaskRunner()->PostTask(
89 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, media_weak_this_));
92 MediaCodecPlayer::~MediaCodecPlayer()
94 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer";
95 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
98 void MediaCodecPlayer::Initialize() {
99 DVLOG(1) << __FUNCTION__;
100 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
102 interpolator_.SetUpperBound(base::TimeDelta());
104 CreateDecoders();
106 // This call might in turn call MediaCodecPlayer::OnDemuxerConfigsAvailable()
107 // which propagates configs into decoders. Therefore CreateDecoders() should
108 // be called first.
109 demuxer_->Initialize(this);
112 // The implementation of MediaPlayerAndroid interface.
114 void MediaCodecPlayer::DeleteOnCorrectThread() {
115 DVLOG(1) << __FUNCTION__;
116 DCHECK(ui_task_runner_->BelongsToCurrentThread());
118 DetachListener();
120 // The base class part that deals with MediaPlayerListener
121 // has to be destroyed on UI thread.
122 DestroyListenerOnUIThread();
124 // Post deletion onto Media thread
125 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
128 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
129 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface));
131 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty");
133 // I assume that if video decoder already has the surface,
134 // there will be two calls:
135 // (1) SetVideoSurface(0)
136 // (2) SetVideoSurface(new_surface)
137 video_decoder_->SetPendingSurface(surface.Pass());
139 if (video_decoder_->HasPendingSurface() &&
140 state_ == STATE_WAITING_FOR_SURFACE) {
141 SetState(STATE_PLAYING);
142 StartPlaybackDecoders();
146 void MediaCodecPlayer::Start() {
147 RUN_ON_MEDIA_THREAD(Start);
149 DVLOG(1) << __FUNCTION__;
151 switch (state_) {
152 case STATE_PAUSED:
153 // Prefetch or wait for initial configuration.
154 if (HasAudio() || HasVideo()) {
155 SetState(STATE_PREFETCHING);
156 StartPrefetchDecoders();
157 } else {
158 SetState(STATE_WAITING_FOR_CONFIG);
160 break;
161 case STATE_STOPPING:
162 case STATE_WAITING_FOR_SEEK:
163 SetPendingStart(true);
164 break;
165 case STATE_WAITING_FOR_CONFIG:
166 case STATE_PREFETCHING:
167 case STATE_PLAYING:
168 case STATE_WAITING_FOR_SURFACE:
169 case STATE_ERROR:
170 break; // Ignore
171 default:
172 NOTREACHED();
173 break;
177 void MediaCodecPlayer::Pause(bool is_media_related_action) {
178 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action);
180 DVLOG(1) << __FUNCTION__;
182 SetPendingStart(false);
184 switch (state_) {
185 case STATE_WAITING_FOR_CONFIG:
186 case STATE_PREFETCHING:
187 case STATE_WAITING_FOR_SURFACE:
188 SetState(STATE_PAUSED);
189 StopDecoders();
190 break;
191 case STATE_PLAYING:
192 SetState(STATE_STOPPING);
193 RequestToStopDecoders();
194 break;
195 case STATE_PAUSED:
196 case STATE_STOPPING:
197 case STATE_WAITING_FOR_SEEK:
198 case STATE_ERROR:
199 break; // Ignore
200 default:
201 NOTREACHED();
202 break;
206 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
207 RUN_ON_MEDIA_THREAD(SeekTo, timestamp);
209 DVLOG(1) << __FUNCTION__ << " " << timestamp;
211 switch (state_) {
212 case STATE_PAUSED:
213 SetState(STATE_WAITING_FOR_SEEK);
214 RequestDemuxerSeek(timestamp);
215 break;
216 case STATE_WAITING_FOR_CONFIG:
217 case STATE_PREFETCHING:
218 case STATE_WAITING_FOR_SURFACE:
219 SetState(STATE_WAITING_FOR_SEEK);
220 StopDecoders();
221 SetPendingStart(true);
222 RequestDemuxerSeek(timestamp);
223 break;
224 case STATE_PLAYING:
225 SetState(STATE_STOPPING);
226 RequestToStopDecoders();
227 SetPendingStart(true);
228 SetPendingSeek(timestamp);
229 break;
230 case STATE_STOPPING:
231 SetPendingSeek(timestamp);
232 break;
233 case STATE_WAITING_FOR_SEEK:
234 SetPendingSeek(timestamp);
235 break;
236 case STATE_ERROR:
237 break; // ignore
238 default:
239 NOTREACHED();
240 break;
244 void MediaCodecPlayer::Release() {
245 RUN_ON_MEDIA_THREAD(Release);
247 DVLOG(1) << __FUNCTION__;
249 SetState(STATE_PAUSED);
250 ReleaseDecoderResources();
253 void MediaCodecPlayer::SetVolume(double volume) {
254 RUN_ON_MEDIA_THREAD(SetVolume, volume);
256 DVLOG(1) << __FUNCTION__ << " " << volume;
257 audio_decoder_->SetVolume(volume);
260 int MediaCodecPlayer::GetVideoWidth() {
261 DCHECK(ui_task_runner_->BelongsToCurrentThread());
262 return metadata_cache_.video_size.width();
265 int MediaCodecPlayer::GetVideoHeight() {
266 DCHECK(ui_task_runner_->BelongsToCurrentThread());
267 return metadata_cache_.video_size.height();
270 base::TimeDelta MediaCodecPlayer::GetCurrentTime() {
271 DCHECK(ui_task_runner_->BelongsToCurrentThread());
272 return current_time_cache_;
275 base::TimeDelta MediaCodecPlayer::GetDuration() {
276 DCHECK(ui_task_runner_->BelongsToCurrentThread());
277 return metadata_cache_.duration;
280 bool MediaCodecPlayer::IsPlaying() {
281 DCHECK(ui_task_runner_->BelongsToCurrentThread());
283 // TODO(timav): Use another variable since |state_| should only be accessed on
284 // Media thread.
285 return state_ == STATE_PLAYING || state_ == STATE_STOPPING;
288 bool MediaCodecPlayer::CanPause() {
289 DCHECK(ui_task_runner_->BelongsToCurrentThread());
290 NOTIMPLEMENTED();
291 return false;
294 bool MediaCodecPlayer::CanSeekForward() {
295 DCHECK(ui_task_runner_->BelongsToCurrentThread());
296 NOTIMPLEMENTED();
297 return false;
300 bool MediaCodecPlayer::CanSeekBackward() {
301 DCHECK(ui_task_runner_->BelongsToCurrentThread());
302 NOTIMPLEMENTED();
303 return false;
306 bool MediaCodecPlayer::IsPlayerReady() {
307 DCHECK(ui_task_runner_->BelongsToCurrentThread());
308 // This method is called to check whether it's safe to release the player when
309 // the OS needs more resources. This class can be released at any time.
310 return true;
313 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
314 DCHECK(ui_task_runner_->BelongsToCurrentThread());
315 NOTIMPLEMENTED();
318 // Callbacks from Demuxer.
320 void MediaCodecPlayer::OnDemuxerConfigsAvailable(
321 const DemuxerConfigs& configs) {
322 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
324 DVLOG(1) << __FUNCTION__;
326 duration_ = configs.duration;
328 SetDemuxerConfigs(configs);
330 // Update cache and notify manager on UI thread
331 gfx::Size video_size = HasVideo() ? configs.video_size : gfx::Size();
332 ui_task_runner_->PostTask(
333 FROM_HERE, base::Bind(metadata_changed_cb_, duration_, video_size));
336 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
337 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
339 DCHECK_LT(0u, data.access_units.size());
340 CHECK_GE(1u, data.demuxer_configs.size());
342 DVLOG(2) << "Player::" << __FUNCTION__;
344 if (data.type == DemuxerStream::AUDIO)
345 audio_decoder_->OnDemuxerDataAvailable(data);
347 if (data.type == DemuxerStream::VIDEO)
348 video_decoder_->OnDemuxerDataAvailable(data);
351 void MediaCodecPlayer::OnDemuxerSeekDone(
352 base::TimeDelta actual_browser_seek_time) {
353 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
355 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time;
357 if (state_ != STATE_WAITING_FOR_SEEK)
358 return; // ignore
360 DCHECK(seek_info_.get());
361 DCHECK(seek_info_->seek_time != kNoTimestamp());
363 // A browser seek must not jump into the past. Ideally, it seeks to the
364 // requested time, but it might jump into the future.
365 DCHECK(!seek_info_->is_browser_seek ||
366 seek_info_->seek_time <= actual_browser_seek_time);
368 // Restrict the current time to be equal to seek_time
369 // for the next StartPlaybackDecoders() call.
371 base::TimeDelta seek_time = seek_info_->is_browser_seek
372 ? actual_browser_seek_time
373 : seek_info_->seek_time;
375 interpolator_.SetBounds(seek_time, seek_time);
376 audio_decoder_->SetBaseTimestamp(seek_time);
378 base::TimeDelta pending_seek_time = GetPendingSeek();
379 if (pending_seek_time != kNoTimestamp()) {
380 // Keep STATE_WAITING_FOR_SEEK
381 SetPendingSeek(kNoTimestamp());
382 RequestDemuxerSeek(pending_seek_time);
383 return;
386 if (HasPendingStart()) {
387 SetPendingStart(false);
388 // Prefetch or wait for initial configuration.
389 if (HasAudio() || HasVideo()) {
390 SetState(STATE_PREFETCHING);
391 StartPrefetchDecoders();
392 } else {
393 SetState(STATE_WAITING_FOR_CONFIG);
395 } else {
396 SetState(STATE_PAUSED);
399 // Notify the Renderer.
400 if (!seek_info_->is_browser_seek)
401 ui_task_runner_->PostTask(FROM_HERE, base::Bind(seek_done_cb_, seek_time));
403 seek_info_.reset();
406 void MediaCodecPlayer::OnDemuxerDurationChanged(
407 base::TimeDelta duration) {
408 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
409 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
411 duration_ = duration;
414 // Events from Player, called on UI thread
416 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration,
417 const gfx::Size& video_size) {
418 DCHECK(ui_task_runner_->BelongsToCurrentThread());
420 if (duration != kNoTimestamp())
421 metadata_cache_.duration = duration;
423 if (!video_size.IsEmpty())
424 metadata_cache_.video_size = video_size;
426 manager()->OnMediaMetadataChanged(player_id(), metadata_cache_.duration,
427 metadata_cache_.video_size.width(),
428 metadata_cache_.video_size.height(), true);
431 void MediaCodecPlayer::OnTimeUpdate(base::TimeDelta current_timestamp,
432 base::TimeTicks current_time_ticks) {
433 DCHECK(ui_task_runner_->BelongsToCurrentThread());
435 current_time_cache_ = current_timestamp;
436 manager()->OnTimeUpdate(player_id(), current_timestamp, current_time_ticks);
439 // Events from Decoders, called on Media thread
441 void MediaCodecPlayer::RequestDemuxerData(DemuxerStream::Type stream_type) {
442 DVLOG(2) << __FUNCTION__ << " streamType:" << stream_type;
444 // Use this method instead of directly binding with
445 // DemuxerAndroid::RequestDemuxerData() to avoid the race condition on
446 // deletion:
447 // 1. DeleteSoon is posted from UI to Media thread.
448 // 2. RequestDemuxerData callback is posted from Decoder to Media thread.
449 // 3. DeleteSoon arrives, we delete the player and detach from
450 // BrowserDemuxerAndroid.
451 // 4. RequestDemuxerData is processed by the media thread queue. Since the
452 // weak_ptr was invalidated in (3), this is a no-op. If we used
453 // DemuxerAndroid::RequestDemuxerData() it would arrive and will try to
454 // call the client, but the client (i.e. this player) would not exist.
455 demuxer_->RequestDemuxerData(stream_type);
458 void MediaCodecPlayer::OnPrefetchDone() {
459 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
461 if (state_ != STATE_PREFETCHING) {
462 DVLOG(1) << __FUNCTION__ << " wrong state " << AsString(state_)
463 << " ignoring";
464 return; // Ignore
467 DVLOG(1) << __FUNCTION__;
469 if (!HasAudio() && !HasVideo()) {
470 // No configuration at all after prefetching.
471 // This is an error, initial configuration is expected
472 // before the first data chunk.
473 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
474 return;
477 if (HasVideo() && !HasPendingSurface()) {
478 SetState(STATE_WAITING_FOR_SURFACE);
479 return;
482 SetState(STATE_PLAYING);
483 StartPlaybackDecoders();
486 void MediaCodecPlayer::OnStopDone() {
487 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
488 DVLOG(1) << __FUNCTION__;
490 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped()))
491 return; // Wait until other stream is stopped
493 // At this point decoder threads should not be running
494 if (interpolator_.interpolating())
495 interpolator_.StopInterpolating();
497 base::TimeDelta seek_time;
498 switch (state_) {
499 case STATE_STOPPING: {
500 base::TimeDelta seek_time = GetPendingSeek();
501 if (seek_time != kNoTimestamp()) {
502 SetState(STATE_WAITING_FOR_SEEK);
503 SetPendingSeek(kNoTimestamp());
504 RequestDemuxerSeek(seek_time);
505 } else if (HasPendingStart()) {
506 SetPendingStart(false);
507 SetState(STATE_PREFETCHING);
508 StartPrefetchDecoders();
509 } else {
510 SetState(STATE_PAUSED);
512 } break;
513 case STATE_PLAYING:
514 // Unexpected stop means completion
515 SetState(STATE_PAUSED);
516 break;
517 default:
518 // DVLOG(0) << __FUNCTION__ << " illegal state: " << AsString(state_);
519 // NOTREACHED();
520 // Ignore! There can be a race condition: audio posts OnStopDone,
521 // then video posts, then first OnStopDone arrives at which point
522 // both streams are already stopped, then second OnStopDone arrives. When
523 // the second one arrives, the state us not STATE_STOPPING any more.
524 break;
527 // DetachListener to UI thread
528 ui_task_runner_->PostTask(FROM_HERE, detach_listener_cb_);
530 if (AudioFinished() && VideoFinished())
531 ui_task_runner_->PostTask(FROM_HERE, completion_cb_);
534 void MediaCodecPlayer::OnError() {
535 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
536 DVLOG(1) << __FUNCTION__;
538 // STATE_ERROR blocks all events
539 SetState(STATE_ERROR);
541 ReleaseDecoderResources();
544 void MediaCodecPlayer::OnStarvation(DemuxerStream::Type type) {
545 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
546 DVLOG(1) << __FUNCTION__ << " stream type:" << type;
548 if (state_ != STATE_PLAYING)
549 return; // Ignore
551 SetState(STATE_STOPPING);
552 RequestToStopDecoders();
553 SetPendingStart(true);
556 void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type,
557 base::TimeDelta now_playing,
558 base::TimeDelta last_buffered) {
559 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
561 DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing
562 << "," << last_buffered << "]";
564 // I assume that audio stream cannot be added after we get configs by
565 // OnDemuxerConfigsAvailable(), but that audio can finish early.
567 if (type == DemuxerStream::VIDEO) {
568 // Ignore video PTS if there is audio stream or if it's behind current
569 // time as set by audio stream.
570 if (!AudioFinished() || now_playing < interpolator_.GetInterpolatedTime())
571 return;
574 interpolator_.SetBounds(now_playing, last_buffered);
576 // Post to UI thread
577 ui_task_runner_->PostTask(FROM_HERE,
578 base::Bind(time_update_cb_, GetInterpolatedTime(),
579 base::TimeTicks::Now()));
582 void MediaCodecPlayer::OnVideoCodecCreated() {
583 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
585 // This callback requests resources by releasing other players.
586 ui_task_runner_->PostTask(FROM_HERE, request_resources_cb_);
589 void MediaCodecPlayer::OnVideoResolutionChanged(const gfx::Size& size) {
590 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
592 DVLOG(1) << __FUNCTION__ << " " << size.width() << "x" << size.height();
594 // Update cache and notify manager on UI thread
595 ui_task_runner_->PostTask(
596 FROM_HERE, base::Bind(metadata_changed_cb_, kNoTimestamp(), size));
599 // State machine operations, called on Media thread
601 void MediaCodecPlayer::SetState(PlayerState new_state) {
602 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
604 DVLOG(1) << "SetState:" << AsString(state_) << " -> " << AsString(new_state);
605 state_ = new_state;
608 void MediaCodecPlayer::SetPendingSurface(gfx::ScopedJavaSurface surface) {
609 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
610 DVLOG(1) << __FUNCTION__;
612 video_decoder_->SetPendingSurface(surface.Pass());
615 bool MediaCodecPlayer::HasPendingSurface() const {
616 return video_decoder_->HasPendingSurface();
619 void MediaCodecPlayer::SetPendingStart(bool need_to_start) {
620 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
621 DVLOG(1) << __FUNCTION__ << ": " << need_to_start;
622 pending_start_ = need_to_start;
625 bool MediaCodecPlayer::HasPendingStart() const {
626 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
627 return pending_start_;
630 void MediaCodecPlayer::SetPendingSeek(base::TimeDelta timestamp) {
631 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
632 DVLOG(1) << __FUNCTION__ << ": " << timestamp;
633 pending_seek_ = timestamp;
636 base::TimeDelta MediaCodecPlayer::GetPendingSeek() const {
637 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
638 return pending_seek_;
641 bool MediaCodecPlayer::HasAudio() const {
642 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
643 return audio_decoder_->HasStream();
646 bool MediaCodecPlayer::HasVideo() const {
647 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
648 return video_decoder_->HasStream();
651 void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) {
652 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
653 DVLOG(1) << __FUNCTION__ << " " << configs;
655 DCHECK(audio_decoder_);
656 DCHECK(video_decoder_);
658 // At least one valid codec must be present.
659 DCHECK(configs.audio_codec != kUnknownAudioCodec ||
660 configs.video_codec != kUnknownVideoCodec);
662 if (configs.audio_codec != kUnknownAudioCodec)
663 audio_decoder_->SetDemuxerConfigs(configs);
665 if (configs.video_codec != kUnknownVideoCodec)
666 video_decoder_->SetDemuxerConfigs(configs);
668 if (state_ == STATE_WAITING_FOR_CONFIG) {
669 SetState(STATE_PREFETCHING);
670 StartPrefetchDecoders();
674 void MediaCodecPlayer::StartPrefetchDecoders() {
675 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
676 DVLOG(1) << __FUNCTION__;
678 bool do_audio = false;
679 bool do_video = false;
680 int count = 0;
681 if (!AudioFinished()) {
682 do_audio = true;
683 ++count;
685 if (!VideoFinished()) {
686 do_video = true;
687 ++count;
690 DCHECK_LT(0, count); // at least one decoder should be active
692 base::Closure prefetch_cb = base::BarrierClosure(
693 count, base::Bind(&MediaCodecPlayer::OnPrefetchDone, media_weak_this_));
695 if (do_audio)
696 audio_decoder_->Prefetch(prefetch_cb);
698 if (do_video)
699 video_decoder_->Prefetch(prefetch_cb);
702 void MediaCodecPlayer::StartPlaybackDecoders() {
703 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
704 DVLOG(1) << __FUNCTION__;
706 // Configure all streams before the start since
707 // we may discover that browser seek is required.
709 bool do_audio = !AudioFinished();
710 bool do_video = !VideoFinished();
712 // If there is nothing to play, the state machine should determine
713 // this at the prefetch state and never call this method.
714 DCHECK(do_audio || do_video);
716 if (do_audio) {
717 MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure();
718 if (status != MediaCodecDecoder::CONFIG_OK) {
719 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
720 return;
724 if (do_video) {
725 MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure();
726 if (status != MediaCodecDecoder::CONFIG_OK) {
727 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
728 return;
732 // At this point decoder threads should not be running.
733 if (!interpolator_.interpolating())
734 interpolator_.StartInterpolating();
736 base::TimeDelta current_time = GetInterpolatedTime();
738 if (do_audio) {
739 if (!audio_decoder_->Start(current_time)) {
740 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
741 return;
744 // Attach listener on UI thread
745 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
748 if (do_video) {
749 if (!video_decoder_->Start(current_time)) {
750 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
751 return;
756 void MediaCodecPlayer::StopDecoders() {
757 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
758 DVLOG(1) << __FUNCTION__;
760 audio_decoder_->SyncStop();
761 video_decoder_->SyncStop();
764 void MediaCodecPlayer::RequestToStopDecoders() {
765 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
766 DVLOG(1) << __FUNCTION__;
768 bool do_audio = false;
769 bool do_video = false;
771 if (audio_decoder_->IsPrefetchingOrPlaying())
772 do_audio = true;
773 if (video_decoder_->IsPrefetchingOrPlaying())
774 do_video = true;
776 if (!do_audio && !do_video) {
777 GetMediaTaskRunner()->PostTask(
778 FROM_HERE, base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_));
779 return;
782 if (do_audio)
783 audio_decoder_->RequestToStop();
784 if (do_video)
785 video_decoder_->RequestToStop();
788 void MediaCodecPlayer::RequestDemuxerSeek(base::TimeDelta seek_time,
789 bool is_browser_seek) {
790 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
791 DVLOG(1) << __FUNCTION__ << " " << seek_time
792 << (is_browser_seek ? " browser_seek" : "");
794 // Flush decoders before requesting demuxer.
795 audio_decoder_->Flush();
796 video_decoder_->Flush();
798 // Save active seek data. Logically it is attached to STATE_WAITING_FOR_SEEK.
799 DCHECK(state_ == STATE_WAITING_FOR_SEEK);
800 seek_info_.reset(new SeekInfo(seek_time, is_browser_seek));
802 demuxer_->RequestDemuxerSeek(seek_time, is_browser_seek);
805 void MediaCodecPlayer::ReleaseDecoderResources() {
806 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
807 DVLOG(1) << __FUNCTION__;
809 if (audio_decoder_)
810 audio_decoder_->ReleaseDecoderResources();
812 if (video_decoder_)
813 video_decoder_->ReleaseDecoderResources();
815 // At this point decoder threads should not be running
816 if (interpolator_.interpolating())
817 interpolator_.StopInterpolating();
820 void MediaCodecPlayer::CreateDecoders() {
821 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
822 DVLOG(1) << __FUNCTION__;
824 error_cb_ = base::Bind(&MediaCodecPlayer::OnError, media_weak_this_);
826 audio_decoder_.reset(new MediaCodecAudioDecoder(
827 GetMediaTaskRunner(), base::Bind(&MediaCodecPlayer::RequestDemuxerData,
828 media_weak_this_, DemuxerStream::AUDIO),
829 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_,
830 DemuxerStream::AUDIO),
831 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_), error_cb_,
832 base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, media_weak_this_,
833 DemuxerStream::AUDIO)));
835 video_decoder_.reset(new MediaCodecVideoDecoder(
836 GetMediaTaskRunner(), base::Bind(&MediaCodecPlayer::RequestDemuxerData,
837 media_weak_this_, DemuxerStream::VIDEO),
838 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_,
839 DemuxerStream::VIDEO),
840 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_), error_cb_,
841 base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, media_weak_this_,
842 DemuxerStream::VIDEO),
843 base::Bind(&MediaCodecPlayer::OnVideoResolutionChanged, media_weak_this_),
844 base::Bind(&MediaCodecPlayer::OnVideoCodecCreated, media_weak_this_)));
847 bool MediaCodecPlayer::AudioFinished() const {
848 return audio_decoder_->IsCompleted() || !audio_decoder_->HasStream();
851 bool MediaCodecPlayer::VideoFinished() const {
852 return video_decoder_->IsCompleted() || !video_decoder_->HasStream();
855 base::TimeDelta MediaCodecPlayer::GetInterpolatedTime() {
856 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
858 base::TimeDelta interpolated_time = interpolator_.GetInterpolatedTime();
859 return std::min(interpolated_time, duration_);
862 #undef RETURN_STRING
863 #define RETURN_STRING(x) \
864 case x: \
865 return #x;
867 const char* MediaCodecPlayer::AsString(PlayerState state) {
868 switch (state) {
869 RETURN_STRING(STATE_PAUSED);
870 RETURN_STRING(STATE_WAITING_FOR_CONFIG);
871 RETURN_STRING(STATE_PREFETCHING);
872 RETURN_STRING(STATE_PLAYING);
873 RETURN_STRING(STATE_STOPPING);
874 RETURN_STRING(STATE_WAITING_FOR_SURFACE);
875 RETURN_STRING(STATE_WAITING_FOR_SEEK);
876 RETURN_STRING(STATE_ERROR);
878 return nullptr; // crash early
881 #undef RETURN_STRING
883 } // namespace media