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

Unified Diff: content/common/gpu/media/android_video_decode_accelerator.cc

Issue 1862303002: Delay actual flush and reset in AVDA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Kept OUTPUT_FORMAT_CHANGED processing while draining, rebased Created 4 years, 8 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 | « content/common/gpu/media/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/gpu/media/android_video_decode_accelerator.cc
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index 0f23cefc87289e7e34c7f238a9af54433d37ca9f..69ed8f8223397df9b20c587d6dc0ad30b003ac75 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -12,6 +12,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -311,6 +312,7 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
is_encrypted_(false),
state_(NO_ERROR),
picturebuffers_requested_(false),
+ drain_type_(DRAIN_TYPE_NONE),
media_drm_bridge_cdm_context_(nullptr),
cdm_registration_id_(0),
pending_input_buf_index_(-1),
@@ -555,8 +557,6 @@ bool AndroidVideoDecodeAccelerator::QueueInput() {
TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount",
pending_bitstream_buffers_.size());
- DCHECK_NE(state_, ERROR);
- state_ = WAITING_FOR_EOS;
media_codec_->QueueEOS(input_buf_index);
return true;
}
@@ -675,17 +675,32 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
switch (status) {
case media::MEDIA_CODEC_ERROR:
- POST_ERROR(PLATFORM_FAILURE, "DequeueOutputBuffer failed.");
+ // Do not post an error if we are draining for reset and destroy.
+ // Instead, run the drain completion task.
+ if (IsDrainingForResetOrDestroy()) {
+ DVLOG(1) << __FUNCTION__ << ": error while codec draining";
+ state_ = ERROR;
+ OnDrainCompleted();
+ } else {
+ POST_ERROR(PLATFORM_FAILURE, "DequeueOutputBuffer failed.");
+ }
return false;
case media::MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
return false;
case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: {
+ // An OUTPUT_FORMAT_CHANGED is not reported after flush() if the frame
+ // size does not change. Therefore we have to keep track on the format
+ // even if draining, unless we are draining for destroy.
+ if (drain_type_ == DRAIN_FOR_DESTROY)
+ return true; // ignore
+
if (media_codec_->GetOutputSize(&size_) != media::MEDIA_CODEC_OK) {
POST_ERROR(PLATFORM_FAILURE, "GetOutputSize failed.");
return false;
}
+
DVLOG(3) << __FUNCTION__
<< " OUTPUT_FORMAT_CHANGED, new size: " << size_.ToString();
@@ -725,28 +740,15 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
} while (buf_index < 0);
if (eos) {
- DVLOG(3) << __FUNCTION__ << ": Resetting codec state after EOS";
-
- // If we were waiting for an EOS, clear the state and reset the MediaCodec
- // as normal. Otherwise, enter the ERROR state which will force destruction
- // of MediaCodec during ResetCodecState().
- //
- // Some Android platforms seem to send an EOS buffer even when we're not
- // expecting it. In this case, destroy and reset the codec but don't notify
- // flush done since it violates the state machine. http://crbug.com/585959.
- const bool was_waiting_for_eos = state_ == WAITING_FOR_EOS;
- state_ = was_waiting_for_eos ? NO_ERROR : ERROR;
-
- ResetCodecState();
- // |media_codec_| might still be null.
- if (was_waiting_for_eos) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone,
- weak_this_factory_.GetWeakPtr()));
- }
+ OnDrainCompleted();
return false;
}
+ if (IsDrainingForResetOrDestroy()) {
+ media_codec_->ReleaseOutputBuffer(buf_index, false);
+ return true;
+ }
+
if (!picturebuffers_requested_) {
// If, somehow, we get a decoded frame back before a FORMAT_CHANGED
// message, then we might not have any picture buffers to use. This
@@ -875,9 +877,11 @@ void AndroidVideoDecodeAccelerator::DecodeBuffer(
}
void AndroidVideoDecodeAccelerator::RequestPictureBuffers() {
- client_->ProvidePictureBuffers(kNumPictureBuffers, 1,
- strategy_->GetPictureBufferSize(),
- strategy_->GetTextureTarget());
+ if (client_) {
+ client_->ProvidePictureBuffers(kNumPictureBuffers, 1,
+ strategy_->GetPictureBufferSize(),
+ strategy_->GetTextureTarget());
+ }
}
void AndroidVideoDecodeAccelerator::AssignPictureBuffers(
@@ -933,9 +937,10 @@ void AndroidVideoDecodeAccelerator::ReusePictureBuffer(
}
void AndroidVideoDecodeAccelerator::Flush() {
+ DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
- DecodeBuffer(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0));
+ StartCodecDrain(DRAIN_FOR_FLUSH);
}
void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
@@ -1027,13 +1032,76 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured(
ManageTimer(true);
}
-void AndroidVideoDecodeAccelerator::ResetCodecState() {
+void AndroidVideoDecodeAccelerator::StartCodecDrain(DrainType drain_type) {
+ DVLOG(2) << __FUNCTION__ << " drain_type:" << drain_type;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // We assume that DRAIN_FOR_FLUSH and DRAIN_FOR_RESET cannot come while
+ // another drain request is present, but DRAIN_FOR_DESTROY can.
+ DCHECK_NE(drain_type, DRAIN_TYPE_NONE);
+ DCHECK(drain_type_ == DRAIN_TYPE_NONE || drain_type == DRAIN_FOR_DESTROY)
+ << "Unexpected StartCodecDrain() with drain type " << drain_type
+ << " while already draining with drain type " << drain_type_;
+
+ const bool enqueue_eos = drain_type_ == DRAIN_TYPE_NONE;
+ drain_type_ = drain_type;
+
+ if (enqueue_eos)
+ DecodeBuffer(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0));
+}
+
+bool AndroidVideoDecodeAccelerator::IsDrainingForResetOrDestroy() const {
+ return drain_type_ == DRAIN_FOR_RESET || drain_type_ == DRAIN_FOR_DESTROY;
+}
+
+void AndroidVideoDecodeAccelerator::OnDrainCompleted() {
+ DVLOG(2) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If we were waiting for an EOS, clear the state and reset the MediaCodec
+ // as normal. Otherwise, enter the ERROR state which will force destruction
+ // of MediaCodec during ResetCodecState().
+ //
+ // Some Android platforms seem to send an EOS buffer even when we're not
+ // expecting it. In this case, destroy and reset the codec but don't notify
+ // flush done since it violates the state machine. http://crbug.com/585959.
+
+ switch (drain_type_) {
+ case DRAIN_TYPE_NONE:
+ // Unexpected EOS.
+ state_ = ERROR;
+ ResetCodecState(base::Closure());
+ break;
+ case DRAIN_FOR_FLUSH:
+ ResetCodecState(media::BindToCurrentLoop(
+ base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone,
+ weak_this_factory_.GetWeakPtr())));
+ break;
+ case DRAIN_FOR_RESET:
+ ResetCodecState(media::BindToCurrentLoop(
+ base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
+ weak_this_factory_.GetWeakPtr())));
+ break;
+ case DRAIN_FOR_DESTROY:
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::ActualDestroy,
+ weak_this_factory_.GetWeakPtr()));
+ break;
+ }
+ drain_type_ = DRAIN_TYPE_NONE;
+}
+
+void AndroidVideoDecodeAccelerator::ResetCodecState(
+ const base::Closure& done_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
// If there is already a reset in flight, then that counts. This can really
// only happen if somebody calls Reset.
- if (state_ == WAITING_FOR_CODEC)
+ if (state_ == WAITING_FOR_CODEC) {
+ if (!done_cb.is_null())
+ done_cb.Run();
return;
+ }
bitstream_buffers_in_decoder_.clear();
@@ -1046,8 +1114,8 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
pending_input_buf_index_ = -1;
}
- if (state_ == WAITING_FOR_KEY)
- state_ = NO_ERROR;
+ const bool did_codec_error_happen = state_ == ERROR;
+ state_ = NO_ERROR;
// We might increment error_sequence_token here to cancel any delayed errors,
// but right now it's unclear that it's safe to do so. If we are in an error
@@ -1062,7 +1130,7 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
// (b/8125974, b/8347958) so we must delete the MediaCodec and create a new
// one. The full reconfigure is much slower and may cause visible freezing if
// done mid-stream.
- if (state_ == NO_ERROR &&
+ if (!did_codec_error_happen &&
base::android::BuildInfo::GetInstance()->sdk_int() >= 18) {
DVLOG(3) << __FUNCTION__ << " Doing fast MediaCodec reset (flush).";
media_codec_->Reset();
@@ -1075,12 +1143,15 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
g_avda_timer.Pointer()->StopTimer(this);
// Changing the codec will also notify the strategy to forget about any
// output buffers it has currently.
- state_ = NO_ERROR;
ConfigureMediaCodecAsynchronously();
}
+
+ if (!done_cb.is_null())
+ done_cb.Run();
}
void AndroidVideoDecodeAccelerator::Reset() {
+ DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
TRACE_EVENT0("media", "AVDA::Reset");
@@ -1101,16 +1172,23 @@ void AndroidVideoDecodeAccelerator::Reset() {
// Any error that is waiting to post can be ignored.
error_sequence_token_++;
- ResetCodecState();
+ DCHECK(strategy_);
+ strategy_->ReleaseCodecBuffers(output_picture_buffers_);
- // Note that |media_codec_| might not yet be ready, but we can still post
- // this anyway.
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
- weak_this_factory_.GetWeakPtr()));
+ // Some VP8 files require complete MediaCodec drain before we can call
+ // MediaCodec.flush() or MediaCodec.reset(). http://crbug.com/598963.
+ if (media_codec_ && codec_config_->codec_ == media::kCodecVP8) {
+ // Postpone ResetCodecState() after the drain.
+ StartCodecDrain(DRAIN_FOR_RESET);
+ } else {
+ ResetCodecState(media::BindToCurrentLoop(
+ base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
+ weak_this_factory_.GetWeakPtr())));
+ }
}
void AndroidVideoDecodeAccelerator::Destroy() {
+ DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
bool have_context = make_context_current_cb_.Run();
@@ -1126,6 +1204,26 @@ void AndroidVideoDecodeAccelerator::Destroy() {
on_frame_available_handler_ = nullptr;
}
+ client_ = nullptr;
+
+ // Some VP8 files require complete MediaCodec drain before we can call
+ // MediaCodec.flush() or MediaCodec.reset(). http://crbug.com/598963.
+ if (media_codec_ && codec_config_->codec_ == media::kCodecVP8) {
+ // Clear pending_bitstream_buffers_.
+ while (!pending_bitstream_buffers_.empty())
+ pending_bitstream_buffers_.pop();
+
+ // Postpone ActualDestroy after the drain.
+ StartCodecDrain(DRAIN_FOR_DESTROY);
+ } else {
+ ActualDestroy();
+ }
+}
+
+void AndroidVideoDecodeAccelerator::ActualDestroy() {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
// Note that async codec construction might still be in progress. In that
// case, the codec will be deleted when it completes once we invalidate all
// our weak refs.
@@ -1232,25 +1330,30 @@ void AndroidVideoDecodeAccelerator::OnKeyAdded() {
}
void AndroidVideoDecodeAccelerator::NotifyInitializationComplete(bool success) {
- client_->NotifyInitializationComplete(success);
+ if (client_)
+ client_->NotifyInitializationComplete(success);
}
void AndroidVideoDecodeAccelerator::NotifyPictureReady(
const media::Picture& picture) {
- client_->PictureReady(picture);
+ if (client_)
+ client_->PictureReady(picture);
}
void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
int input_buffer_id) {
- client_->NotifyEndOfBitstreamBuffer(input_buffer_id);
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(input_buffer_id);
}
void AndroidVideoDecodeAccelerator::NotifyFlushDone() {
- client_->NotifyFlushDone();
+ if (client_)
+ client_->NotifyFlushDone();
}
void AndroidVideoDecodeAccelerator::NotifyResetDone() {
- client_->NotifyResetDone();
+ if (client_)
+ client_->NotifyResetDone();
}
void AndroidVideoDecodeAccelerator::NotifyError(
@@ -1261,7 +1364,8 @@ void AndroidVideoDecodeAccelerator::NotifyError(
if (token != error_sequence_token_)
return;
- client_->NotifyError(error);
+ if (client_)
+ client_->NotifyError(error);
}
void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) {
« no previous file with comments | « content/common/gpu/media/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698