Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Unified Diff: media/base/android/media_codec_player.cc

Issue 1254293003: MediaCodecPlayer implementation (stage 4 - preroll) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-browserseek
Patch Set: Rebased Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/android/media_codec_player.h ('k') | media/base/android/media_codec_player_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/media_codec_player.cc
diff --git a/media/base/android/media_codec_player.cc b/media/base/android/media_codec_player.cc
index e1b7562c4e2f29c940fd6cf776485a9e16426bdb..554c9af7aaab9cf79c91de36711ba2cd48b53f0b 100644
--- a/media/base/android/media_codec_player.cc
+++ b/media/base/android/media_codec_player.cc
@@ -482,6 +482,24 @@ void MediaCodecPlayer::OnDemuxerDurationChanged(
duration_ = duration;
}
+void MediaCodecPlayer::SetDecodersTimeCallbackForTests(
+ DecodersTimeCallback cb) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ decoders_time_cb_ = cb;
+}
+
+bool MediaCodecPlayer::IsPrerollingForTests(DemuxerStream::Type type) const {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ DCHECK(audio_decoder_ && video_decoder_);
+
+ if (type == DemuxerStream::AUDIO)
+ return audio_decoder_->IsPrerollingForTests();
+ else if (type == DemuxerStream::VIDEO)
+ return video_decoder_->IsPrerollingForTests();
+ else
+ return false;
+}
+
// Events from Player, called on UI thread
void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration,
@@ -555,12 +573,26 @@ void MediaCodecPlayer::OnPrefetchDone() {
StartPlaybackOrBrowserSeek();
}
+void MediaCodecPlayer::OnPrerollDone() {
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
+ DVLOG(1) << __FUNCTION__;
+
+ DCHECK(interpolator_.interpolating());
+
+ StartStatus status = StartDecoders(interpolator_.GetInterpolatedTime());
+ if (status != kStartOk)
+ GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
+}
+
void MediaCodecPlayer::OnStopDone() {
DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__;
- if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped()))
+ if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped())) {
+ DVLOG(1) << __FUNCTION__ << " both audio and video has to be stopped"
+ << ", ignoring";
return; // Wait until other stream is stopped
+ }
// At this point decoder threads should not be running
if (interpolator_.interpolating())
@@ -636,13 +668,22 @@ void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type,
DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing
<< "," << last_buffered << "]";
+ // For testing only: report time interval as we receive it from decoders
+ // as an indication of what is being rendered.
+ if (!decoders_time_cb_.is_null()) {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(decoders_time_cb_, type, now_playing, last_buffered));
+ }
+
// I assume that audio stream cannot be added after we get configs by
// OnDemuxerConfigsAvailable(), but that audio can finish early.
if (type == DemuxerStream::VIDEO) {
// Ignore video PTS if there is audio stream or if it's behind current
// time as set by audio stream.
- if (!AudioFinished() || now_playing < interpolator_.GetInterpolatedTime())
+ if (!AudioFinished() ||
+ (HasAudio() && now_playing < interpolator_.GetInterpolatedTime()))
return;
}
@@ -792,15 +833,38 @@ MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() {
DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__;
- bool do_audio = !AudioFinished();
- bool do_video = !VideoFinished();
+ // Configure all streams before the start since we may discover that browser
+ // seek is required.
+ MediaCodecPlayer::StartStatus status = ConfigureDecoders();
+ if (status != kStartOk)
+ return status;
+
+ // At this point decoder threads should not be running.
+ if (!interpolator_.interpolating())
+ interpolator_.StartInterpolating();
+
+ base::TimeDelta current_time = GetInterpolatedTime();
+
+ bool preroll_required = false;
+ status = MaybePrerollDecoders(current_time, &preroll_required);
+ if (preroll_required)
+ return status;
+
+ return StartDecoders(current_time);
+}
+
+MediaCodecPlayer::StartStatus MediaCodecPlayer::ConfigureDecoders() {
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
+ DVLOG(1) << __FUNCTION__;
+
+ const bool do_audio = !AudioFinished();
+ const bool do_video = !VideoFinished();
// If there is nothing to play, the state machine should determine this at the
// prefetch state and never call this method.
DCHECK(do_audio || do_video);
- // Configure all streams before the start since we may discover that browser
- // seek is required. Start with video: if browser seek is required it would
+ // Start with video: if browser seek is required it would
// not make sense to configure audio.
if (do_video) {
@@ -823,25 +887,77 @@ MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() {
}
}
- // At this point decoder threads should not be running.
- if (!interpolator_.interpolating())
- interpolator_.StartInterpolating();
+ return kStartOk;
+}
- base::TimeDelta current_time = GetInterpolatedTime();
+MediaCodecPlayer::StartStatus MediaCodecPlayer::MaybePrerollDecoders(
+ base::TimeDelta current_time,
+ bool* preroll_required) {
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
+ DVLOG(1) << __FUNCTION__ << " current_time:" << current_time;
- if (do_audio) {
- if (!audio_decoder_->Start(current_time)) {
+ // If requested, preroll is always done in the beginning of the playback,
+ // after prefetch. The request might not happen at all though, in which case
+ // we won't have prerolling phase. We need the prerolling when we (re)create
+ // the decoder, because its configuration and initialization (getting input,
+ // but not making output) can take time, and after the seek because there
+ // could be some data to be skipped and there is again initialization after
+ // the flush.
+
+ int count = 0;
+ const bool do_audio_preroll = audio_decoder_->NotCompletedAndNeedsPreroll();
+ if (do_audio_preroll)
+ ++count;
+
+ const bool do_video_preroll = video_decoder_->NotCompletedAndNeedsPreroll();
+ if (do_video_preroll)
+ ++count;
+
+ if (count == 0) {
+ DVLOG(1) << __FUNCTION__ << ": preroll is not required, skipping";
+ *preroll_required = false;
+ return kStartOk;
+ }
+
+ *preroll_required = true;
+
+ DCHECK(count > 0);
+ DCHECK(do_audio_preroll || do_video_preroll);
+
+ DVLOG(1) << __FUNCTION__ << ": preroll for " << count << " stream(s)";
+
+ base::Closure preroll_cb = base::BarrierClosure(
+ count, base::Bind(&MediaCodecPlayer::OnPrerollDone, media_weak_this_));
+
+ if (do_audio_preroll) {
+ if (!audio_decoder_->Preroll(current_time, preroll_cb))
+ return kStartFailed;
+ }
+
+ if (do_video_preroll) {
+ if (!video_decoder_->Preroll(current_time, preroll_cb))
+ return kStartFailed;
+ }
+
+ return kStartOk;
+}
+
+MediaCodecPlayer::StartStatus MediaCodecPlayer::StartDecoders(
+ base::TimeDelta current_time) {
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
+ DVLOG(1) << __FUNCTION__ << " current_time:" << current_time;
+
+ if (!AudioFinished()) {
+ if (!audio_decoder_->Start(current_time))
return kStartFailed;
- }
// Attach listener on UI thread
ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
}
- if (do_video) {
- if (!video_decoder_->Start(current_time)) {
+ if (!VideoFinished()) {
+ if (!video_decoder_->Start(current_time))
return kStartFailed;
- }
}
return kStartOk;
« no previous file with comments | « media/base/android/media_codec_player.h ('k') | media/base/android/media_codec_player_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698