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"
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, ...) \
20 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
21 DCHECK(ui_task_runner_->BelongsToCurrentThread()); \
22 GetMediaTaskRunner()->PostTask( \
23 FROM_HERE, base::Bind(&MediaCodecPlayer::METHOD, media_weak_this_, \
31 class MediaThread
: public base::Thread
{
33 MediaThread() : base::Thread("BrowserMediaThread") {
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(
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
,
57 request_media_resources_cb
,
59 ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
60 demuxer_(demuxer
.Pass()),
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
);
73 base::Bind(&MediaPlayerManager::OnPlaybackComplete
, manager
, player_id
);
75 base::Bind(&MediaPlayerManager::OnSeekComplete
, manager
, player_id
);
76 attach_listener_cb_
= base::Bind(&MediaPlayerAndroid::AttachListener
,
77 WeakPtrForUIThread(), nullptr);
79 base::Bind(&MediaPlayerAndroid::DetachListener
, WeakPtrForUIThread());
80 metadata_changed_cb_
= base::Bind(&MediaPlayerAndroid::OnMediaMetadataChanged
,
81 WeakPtrForUIThread());
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());
106 // This call might in turn call MediaCodecPlayer::OnDemuxerConfigsAvailable()
107 // which propagates configs into decoders. Therefore CreateDecoders() should
109 demuxer_
->Initialize(this);
112 // The implementation of MediaPlayerAndroid interface.
114 void MediaCodecPlayer::DeleteOnCorrectThread() {
115 DVLOG(1) << __FUNCTION__
;
116 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
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__
;
153 // Prefetch or wait for initial configuration.
154 if (HasAudio() || HasVideo()) {
155 SetState(STATE_PREFETCHING
);
156 StartPrefetchDecoders();
158 SetState(STATE_WAITING_FOR_CONFIG
);
162 case STATE_WAITING_FOR_SEEK
:
163 SetPendingStart(true);
165 case STATE_WAITING_FOR_CONFIG
:
166 case STATE_PREFETCHING
:
168 case STATE_WAITING_FOR_SURFACE
:
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);
185 case STATE_WAITING_FOR_CONFIG
:
186 case STATE_PREFETCHING
:
187 case STATE_WAITING_FOR_SURFACE
:
188 SetState(STATE_PAUSED
);
192 SetState(STATE_STOPPING
);
193 RequestToStopDecoders();
197 case STATE_WAITING_FOR_SEEK
:
206 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp
) {
207 RUN_ON_MEDIA_THREAD(SeekTo
, timestamp
);
209 DVLOG(1) << __FUNCTION__
<< " " << timestamp
;
213 SetState(STATE_WAITING_FOR_SEEK
);
214 RequestDemuxerSeek(timestamp
);
216 case STATE_WAITING_FOR_CONFIG
:
217 case STATE_PREFETCHING
:
218 case STATE_WAITING_FOR_SURFACE
:
219 SetState(STATE_WAITING_FOR_SEEK
);
221 SetPendingStart(true);
222 RequestDemuxerSeek(timestamp
);
225 SetState(STATE_STOPPING
);
226 RequestToStopDecoders();
227 SetPendingStart(true);
228 SetPendingSeek(timestamp
);
231 SetPendingSeek(timestamp
);
233 case STATE_WAITING_FOR_SEEK
:
234 SetPendingSeek(timestamp
);
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
285 return state_
== STATE_PLAYING
|| state_
== STATE_STOPPING
;
288 bool MediaCodecPlayer::CanPause() {
289 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
294 bool MediaCodecPlayer::CanSeekForward() {
295 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
300 bool MediaCodecPlayer::CanSeekBackward() {
301 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
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.
313 void MediaCodecPlayer::SetCdm(BrowserCdm
* cdm
) {
314 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
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
)
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
);
386 if (HasPendingStart()) {
387 SetPendingStart(false);
388 // Prefetch or wait for initial configuration.
389 if (HasAudio() || HasVideo()) {
390 SetState(STATE_PREFETCHING
);
391 StartPrefetchDecoders();
393 SetState(STATE_WAITING_FOR_CONFIG
);
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
));
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
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_
)
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_
);
477 if (HasVideo() && !HasPendingSurface()) {
478 SetState(STATE_WAITING_FOR_SURFACE
);
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
;
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();
510 SetState(STATE_PAUSED
);
514 // Unexpected stop means completion
515 SetState(STATE_PAUSED
);
518 // DVLOG(0) << __FUNCTION__ << " illegal state: " << AsString(state_);
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.
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
)
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())
574 interpolator_
.SetBounds(now_playing
, last_buffered
);
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
);
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;
681 if (!AudioFinished()) {
685 if (!VideoFinished()) {
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_
));
696 audio_decoder_
->Prefetch(prefetch_cb
);
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
);
717 MediaCodecDecoder::ConfigStatus status
= audio_decoder_
->Configure();
718 if (status
!= MediaCodecDecoder::CONFIG_OK
) {
719 GetMediaTaskRunner()->PostTask(FROM_HERE
, error_cb_
);
725 MediaCodecDecoder::ConfigStatus status
= video_decoder_
->Configure();
726 if (status
!= MediaCodecDecoder::CONFIG_OK
) {
727 GetMediaTaskRunner()->PostTask(FROM_HERE
, error_cb_
);
732 // At this point decoder threads should not be running.
733 if (!interpolator_
.interpolating())
734 interpolator_
.StartInterpolating();
736 base::TimeDelta current_time
= GetInterpolatedTime();
739 if (!audio_decoder_
->Start(current_time
)) {
740 GetMediaTaskRunner()->PostTask(FROM_HERE
, error_cb_
);
744 // Attach listener on UI thread
745 ui_task_runner_
->PostTask(FROM_HERE
, attach_listener_cb_
);
749 if (!video_decoder_
->Start(current_time
)) {
750 GetMediaTaskRunner()->PostTask(FROM_HERE
, error_cb_
);
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())
773 if (video_decoder_
->IsPrefetchingOrPlaying())
776 if (!do_audio
&& !do_video
) {
777 GetMediaTaskRunner()->PostTask(
778 FROM_HERE
, base::Bind(&MediaCodecPlayer::OnStopDone
, media_weak_this_
));
783 audio_decoder_
->RequestToStop();
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__
;
810 audio_decoder_
->ReleaseDecoderResources();
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_
);
863 #define RETURN_STRING(x) \
867 const char* MediaCodecPlayer::AsString(PlayerState 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