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

Unified Diff: media/base/android/media_codec_decoder.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_decoder.h ('k') | media/base/android/media_codec_decoder_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_decoder.cc
diff --git a/media/base/android/media_codec_decoder.cc b/media/base/android/media_codec_decoder.cc
index bf0147faba27d097db7df975acf3b1652b7d2c43..ee8f2291b056620626de11212a643c9e8ce3f169 100644
--- a/media/base/android/media_codec_decoder.cc
+++ b/media/base/android/media_codec_decoder.cc
@@ -46,6 +46,7 @@ MediaCodecDecoder::MediaCodecDecoder(
stop_done_cb_(stop_done_cb),
error_cb_(error_cb),
state_(kStopped),
+ needs_preroll_(true),
eos_enqueued_(false),
completed_(false),
last_frame_posted_(false),
@@ -61,37 +62,18 @@ MediaCodecDecoder::MediaCodecDecoder(
internal_error_cb_ =
base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr());
+ internal_preroll_done_cb_ =
+ base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr());
request_data_cb_ =
base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr());
}
-MediaCodecDecoder::~MediaCodecDecoder() {
- DCHECK(media_task_runner_->BelongsToCurrentThread());
-
- DVLOG(1) << "Decoder::~Decoder()";
-
- // NB: ReleaseDecoderResources() is virtual
- ReleaseDecoderResources();
-}
+MediaCodecDecoder::~MediaCodecDecoder() {}
const char* MediaCodecDecoder::class_name() const {
return "Decoder";
}
-void MediaCodecDecoder::ReleaseDecoderResources() {
- DCHECK(media_task_runner_->BelongsToCurrentThread());
-
- DVLOG(1) << class_name() << "::" << __FUNCTION__;
-
- // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
- SetState(kInEmergencyStop);
-
- decoder_thread_.Stop(); // synchronous
-
- SetState(kStopped);
- media_codec_bridge_.reset();
-}
-
void MediaCodecDecoder::Flush() {
DCHECK(media_task_runner_->BelongsToCurrentThread());
@@ -117,6 +99,8 @@ void MediaCodecDecoder::Flush() {
verify_next_frame_is_key_ = true;
#endif
+ needs_preroll_ = true;
+
if (media_codec_bridge_) {
// MediaCodecBridge::Reset() performs MediaCodecBridge.flush()
MediaCodecStatus flush_status = media_codec_bridge_->Reset();
@@ -134,13 +118,29 @@ void MediaCodecDecoder::ReleaseMediaCodec() {
DVLOG(1) << class_name() << "::" << __FUNCTION__;
media_codec_bridge_.reset();
+ needs_preroll_ = true;
}
bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
DCHECK(media_task_runner_->BelongsToCurrentThread());
+ // Whether decoder needs to be stopped.
base::AutoLock lock(state_lock_);
- return state_ == kPrefetching || state_ == kRunning;
+ switch (state_) {
+ case kPrefetching:
+ case kPrefetched:
+ case kPrerolling:
+ case kPrerolled:
+ case kRunning:
+ return true;
+ case kStopped:
+ case kStopping:
+ case kInEmergencyStop:
+ case kError:
+ return false;
+ }
+ NOTREACHED();
+ return false;
}
bool MediaCodecDecoder::IsStopped() const {
@@ -155,6 +155,12 @@ bool MediaCodecDecoder::IsCompleted() const {
return completed_;
}
+bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+ return HasStream() && needs_preroll_ && !completed_;
+}
+
base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
base::android::ScopedJavaLocalRef<jobject> media_crypto;
@@ -192,12 +198,7 @@ MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
DVLOG(1) << class_name() << "::" << __FUNCTION__
<< ": needs reconfigure, deleting MediaCodec";
needs_reconfigure_ = false;
- media_codec_bridge_.reset();
-
- // No need to release these buffers since the MediaCodec is deleted, just
- // remove their indexes from |delayed_buffers_|.
-
- ClearDelayedBuffers(false);
+ ReleaseMediaCodec();
}
MediaCodecDecoder::ConfigStatus result;
@@ -222,18 +223,14 @@ MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
return result;
}
-bool MediaCodecDecoder::Start(base::TimeDelta current_time) {
+bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp,
+ const base::Closure& preroll_done_cb) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << class_name() << "::" << __FUNCTION__
- << " current_time:" << current_time;
+ << " preroll_timestamp:" << preroll_timestamp;
DecoderState state = GetState();
- if (state == kRunning) {
- DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started";
- return true; // already started
- }
-
if (state != kPrefetched) {
DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
<< AsString(state) << ", ignoring";
@@ -247,10 +244,13 @@ bool MediaCodecDecoder::Start(base::TimeDelta current_time) {
}
DCHECK(!decoder_thread_.IsRunning());
+ DCHECK(needs_preroll_);
+
+ preroll_done_cb_ = preroll_done_cb;
// We only synchronize video stream.
- // When audio is present, the |current_time| is audio time.
- SynchronizePTSWithTime(current_time);
+ DissociatePTSFromTime(); // associaton will happen after preroll is done.
+ preroll_timestamp_ = preroll_timestamp;
last_frame_posted_ = false;
@@ -261,7 +261,48 @@ bool MediaCodecDecoder::Start(base::TimeDelta current_time) {
return false;
}
- DVLOG(0) << class_name() << "::" << __FUNCTION__ << " decoder thread started";
+ SetState(kPrerolling);
+
+ decoder_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)));
+
+ return true;
+}
+
+bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+ DVLOG(1) << class_name() << "::" << __FUNCTION__
+ << " start_timestamp:" << start_timestamp;
+
+ DecoderState state = GetState();
+
+ if (state != kPrefetched && state != kPrerolled) {
+ DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
+ << AsString(state) << ", ignoring";
+ return false;
+ }
+
+ if (!media_codec_bridge_) {
+ DVLOG(0) << class_name() << "::" << __FUNCTION__
+ << ": not configured, ignoring";
+ return false;
+ }
+
+ // We only synchronize video stream.
+ AssociateCurrentTimeWithPTS(start_timestamp);
+ preroll_timestamp_ = base::TimeDelta();
+
+ // Start the decoder thread
+ if (!decoder_thread_.IsRunning()) {
+ last_frame_posted_ = false;
+ if (!decoder_thread_.Start()) {
+ DVLOG(1) << class_name() << "::" << __FUNCTION__
+ << ": cannot start decoder thread";
+ return false;
+ }
+ }
SetState(kRunning);
@@ -283,16 +324,9 @@ void MediaCodecDecoder::SyncStop() {
return;
}
- // After this method returns, decoder thread will not be running.
+ DoEmergencyStop();
- // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
- SetState(kInEmergencyStop);
-
- decoder_thread_.Stop(); // synchronous
-
- SetState(kStopped);
-
- ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|.
+ ReleaseDelayedBuffers();
}
void MediaCodecDecoder::RequestToStop() {
@@ -309,6 +343,14 @@ void MediaCodecDecoder::RequestToStop() {
case kRunning:
SetState(kStopping);
break;
+ case kPrerolling:
+ case kPrerolled:
+ DCHECK(decoder_thread_.IsRunning());
+ // Synchronous stop.
+ decoder_thread_.Stop();
+ SetState(kStopped);
+ media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
+ break;
case kStopping:
break; // ignore
case kStopped:
@@ -336,9 +378,26 @@ void MediaCodecDecoder::OnLastFrameRendered(bool completed) {
SetState(kStopped);
completed_ = completed;
+ if (completed_ && !preroll_done_cb_.is_null())
+ media_task_runner_->PostTask(FROM_HERE,
+ base::ResetAndReturn(&preroll_done_cb_));
+
media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
}
+void MediaCodecDecoder::OnPrerollDone() {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+ DVLOG(1) << class_name() << "::" << __FUNCTION__;
+
+ if (GetState() == kPrerolling) {
+ SetState(kPrerolled);
+ needs_preroll_ = false;
+ media_task_runner_->PostTask(FROM_HERE,
+ base::ResetAndReturn(&preroll_done_cb_));
+ }
+}
+
void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
@@ -371,10 +430,29 @@ void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
PrefetchNextChunk();
}
+bool MediaCodecDecoder::IsPrerollingForTests() const {
+ // UI task runner.
+ return GetState() == kPrerolling;
+}
+
int MediaCodecDecoder::NumDelayedRenderTasks() const {
return 0;
}
+void MediaCodecDecoder::DoEmergencyStop() {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+ DVLOG(1) << class_name() << "::" << __FUNCTION__;
+
+ // After this method returns, decoder thread will not be running.
+
+ // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
+ SetState(kInEmergencyStop);
+
+ decoder_thread_.Stop(); // synchronous
+
+ SetState(kStopped);
+}
+
void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
bool has_delayed_tasks) {
DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
@@ -440,7 +518,7 @@ void MediaCodecDecoder::ProcessNextFrame() {
DecoderState state = GetState();
- if (state != kRunning && state != kStopping) {
+ if (state != kPrerolling && state != kRunning && state != kStopping) {
DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running";
return;
}
@@ -460,7 +538,7 @@ void MediaCodecDecoder::ProcessNextFrame() {
return;
}
- DCHECK(state == kRunning);
+ DCHECK(state == kPrerolling || state == kRunning);
if (!EnqueueInputBuffer())
return;
@@ -605,6 +683,8 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue() {
MediaCodecStatus status;
bool eos_encountered = false;
+ RenderMode render_mode;
+
base::TimeDelta timeout =
base::TimeDelta::FromMilliseconds(kOutputBufferTimeout);
@@ -632,8 +712,23 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue() {
break;
case MEDIA_CODEC_OK:
- // We got the decoded frame
- Render(buffer_index, offset, size, true, pts, eos_encountered);
+ // We got the decoded frame.
+
+ if (pts < preroll_timestamp_)
+ render_mode = kRenderSkip;
+ else if (GetState() == kPrerolling)
+ render_mode = kRenderAfterPreroll;
+ else
+ render_mode = kRenderNow;
+
+ Render(buffer_index, offset, size, render_mode, pts, eos_encountered);
+
+ if (render_mode == kRenderAfterPreroll) {
+ DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
+ << " preroll done, stopping frame processing";
+ media_task_runner_->PostTask(FROM_HERE, internal_preroll_done_cb_);
+ return false;
+ }
break;
case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
@@ -686,18 +781,28 @@ void MediaCodecDecoder::SetState(DecoderState state) {
case x: \
return #x;
+const char* MediaCodecDecoder::AsString(RenderMode render_mode) {
+ switch (render_mode) {
+ RETURN_STRING(kRenderSkip);
+ RETURN_STRING(kRenderAfterPreroll);
+ RETURN_STRING(kRenderNow);
+ }
+ return nullptr; // crash early
+}
+
const char* MediaCodecDecoder::AsString(DecoderState state) {
switch (state) {
RETURN_STRING(kStopped);
RETURN_STRING(kPrefetching);
RETURN_STRING(kPrefetched);
+ RETURN_STRING(kPrerolling);
+ RETURN_STRING(kPrerolled);
RETURN_STRING(kRunning);
RETURN_STRING(kStopping);
RETURN_STRING(kInEmergencyStop);
RETURN_STRING(kError);
- default:
- return "Unknown DecoderState";
}
+ return nullptr; // crash early
}
#undef RETURN_STRING
« no previous file with comments | « media/base/android/media_codec_decoder.h ('k') | media/base/android/media_codec_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698