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

Unified Diff: media/gpu/vaapi_video_decode_accelerator.cc

Issue 2642623002: Fix Vaapi VDA flush handling during resolution change (Closed)
Patch Set: queue a dummy flush buffer Created 3 years, 11 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
Index: media/gpu/vaapi_video_decode_accelerator.cc
diff --git a/media/gpu/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi_video_decode_accelerator.cc
index a119f0fd16b039ddefc831c5be2fef71e14837de..4640c83cc10de48cbabab07c8242167225ff1da4 100644
--- a/media/gpu/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi_video_decode_accelerator.cc
@@ -268,7 +268,7 @@ class VaapiVideoDecodeAccelerator::VaapiVP9Accelerator
DISALLOW_COPY_AND_ASSIGN(VaapiVP9Accelerator);
};
-VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0) {}
+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() {}
VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {}
@@ -461,7 +461,7 @@ void VaapiVideoDecodeAccelerator::TryOutputSurface() {
FinishFlush();
}
-void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
+bool VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
const BitstreamBuffer& bitstream_buffer) {
DCHECK(task_runner_->BelongsToCurrentThread());
TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id",
@@ -477,14 +477,22 @@ void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
if (bitstream_buffer.size() == 0) {
if (client_)
client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
- return;
+ return true;
}
RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(), "Failed to map input buffer",
- UNREADABLE_INPUT, );
+ UNREADABLE_INPUT, false);
base::AutoLock auto_lock(lock_);
+ if (IsFlushPending_Locked()) {
+ LOG(ERROR) << "Shouldn't enqueue more input before FlushDone";
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
+ NotifyError(PLATFORM_FAILURE);
+ return false;
+ }
+
// Set up a new input buffer and queue it for later.
linked_ptr<InputBuffer> input_buffer(new InputBuffer());
input_buffer->shm = std::move(shm);
@@ -496,6 +504,7 @@ void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
input_buffers_.push(input_buffer);
input_ready_.Signal();
+ return true;
}
bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
@@ -514,12 +523,6 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
// We could have got woken up in a different state or never got to sleep
// due to current state; check for that.
switch (state_) {
- case kFlushing:
- // Here we are only interested in finishing up decoding buffers that are
- // already queued up. Otherwise will stop decoding.
- if (input_buffers_.empty())
- return false;
- // else fallthrough
case kDecoding:
case kIdle:
DCHECK(!input_buffers_.empty());
@@ -527,12 +530,17 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
curr_input_buffer_ = input_buffers_.front();
input_buffers_.pop();
- DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id
- << " size: " << curr_input_buffer_->shm->size();
+ if (curr_input_buffer_->dummy_flush) {
+ DVLOG(4) << "New flush buffer";
+ } else {
+ DVLOG(4) << "New current bitstream buffer, id: "
+ << curr_input_buffer_->id
+ << " size: " << curr_input_buffer_->shm->size();
- decoder_->SetStream(
- static_cast<uint8_t*>(curr_input_buffer_->shm->memory()),
- curr_input_buffer_->shm->size());
+ decoder_->SetStream(
+ static_cast<uint8_t*>(curr_input_buffer_->shm->memory()),
+ curr_input_buffer_->shm->size());
+ }
return true;
default:
@@ -565,16 +573,30 @@ bool VaapiVideoDecodeAccelerator::WaitForSurfaces_Locked() {
DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
while (available_va_surfaces_.empty() &&
- (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
+ (state_ == kDecoding || state_ == kIdle)) {
surfaces_available_.Wait();
}
- if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
+ if (state_ != kDecoding && state_ != kIdle)
return false;
return true;
}
+bool VaapiVideoDecodeAccelerator::IsFlushPending_Locked() {
Owen Lin 2017/01/19 07:39:16 I am thinking maybe we can get rid of this functio
kcwu 2017/01/19 08:26:10 It's intentional to reject them since this is inva
Owen Lin 2017/01/20 02:20:06 Yes, I see your point and it makes totally sense.
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (finish_flush_pending_)
+ return true;
+
+ if (curr_input_buffer_.get() && curr_input_buffer_->dummy_flush)
+ return true;
+
+ // Checking last element of |input_buffers_| is enough because no more
+ // buffers will be queued after flush.
+ return !input_buffers_.empty() && input_buffers_.back()->dummy_flush;
+}
+
void VaapiVideoDecodeAccelerator::DecodeTask() {
DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
@@ -591,6 +613,11 @@ void VaapiVideoDecodeAccelerator::DecodeTask() {
while (GetInputBuffer_Locked()) {
DCHECK(curr_input_buffer_.get());
+ if (curr_input_buffer_->dummy_flush) {
+ FlushTask();
+ break;
+ }
+
AcceleratedVideoDecoder::DecodeResult res;
{
// We are OK releasing the lock here, as decoder never calls our methods
@@ -736,7 +763,8 @@ void VaapiVideoDecodeAccelerator::Decode(
}
// We got a new input buffer from the client, map it and queue for later use.
- MapAndQueueNewInputBuffer(bitstream_buffer);
+ if (!MapAndQueueNewInputBuffer(bitstream_buffer))
+ return;
base::AutoLock auto_lock(lock_);
switch (state_) {
@@ -824,10 +852,8 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
surfaces_available_.Signal();
}
- // The resolution changing may happen while resetting or flushing. In this
- // case we do not change state and post DecodeTask().
- if (state_ != kResetting && state_ != kFlushing) {
- state_ = kDecoding;
+ // Resume DecodeTask if it is still in decoding state.
+ if (state_ == kDecoding) {
decoder_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask,
base::Unretained(this)));
@@ -908,8 +934,15 @@ void VaapiVideoDecodeAccelerator::ReusePictureBuffer(
void VaapiVideoDecodeAccelerator::FlushTask() {
DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK(input_buffers_.empty()) << "Input buffers should be empty because"
Owen Lin 2017/01/19 07:39:16 It looks like a comment instead of what we should
kcwu 2017/01/20 07:49:03 Code removed.
+ << " the client cannot queue buffers before"
+ << " FlushDone";
+ DCHECK(curr_input_buffer_.get() && curr_input_buffer_->dummy_flush);
+
DVLOG(1) << "Flush task";
+ curr_input_buffer_.reset();
+
// First flush all the pictures that haven't been outputted, notifying the
// client to output them.
bool res = decoder_->Flush();
@@ -929,11 +962,40 @@ void VaapiVideoDecodeAccelerator::Flush() {
DVLOG(1) << "Got flush request";
base::AutoLock auto_lock(lock_);
- state_ = kFlushing;
- // Queue a flush task after all existing decoding tasks to clean up.
- decoder_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::FlushTask,
- base::Unretained(this)));
+ if (IsFlushPending_Locked()) {
+ LOG(ERROR) << "Shouldn't Flush again before FlushDone";
+ NotifyError(PLATFORM_FAILURE);
+ return;
+ }
+
+ switch (state_) {
+ case kIdle:
+ state_ = kDecoding;
+ decoder_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask,
Owen Lin 2017/01/19 07:39:16 Can we extract the common part of this function an
kcwu 2017/01/19 08:26:10 Regarding to Flush() to use empty buffer, I don't
Owen Lin 2017/01/20 02:20:06 First, empty buffer is not invalid, we do accept e
kcwu 2017/01/20 07:49:03 Done.
+ base::Unretained(this)));
+ break;
+
+ case kDecoding:
+ // Decoder already running.
+ break;
+
+ case kResetting:
+ // When resetting, allow accumulating bitstream buffers, so that
+ // the client can queue after-seek-buffers while we are finishing with
+ // the before-seek one.
+ break;
+
+ default:
+ RETURN_AND_NOTIFY_ON_FAILURE(
+ false, "Decode request from client in invalid state: " << state_,
+ PLATFORM_FAILURE, );
+ break;
+ }
+
+ linked_ptr<InputBuffer> input_buffer(new InputBuffer());
+ input_buffer->dummy_flush = true;
+ input_buffers_.push(input_buffer);
input_ready_.Signal();
surfaces_available_.Signal();
@@ -945,7 +1007,7 @@ void VaapiVideoDecodeAccelerator::FinishFlush() {
finish_flush_pending_ = false;
base::AutoLock auto_lock(lock_);
- if (state_ != kFlushing) {
+ if (state_ != kDecoding) {
DCHECK_EQ(state_, kDestroying);
return; // We could've gotten destroyed already.
}
@@ -997,9 +1059,11 @@ void VaapiVideoDecodeAccelerator::Reset() {
// Drop all remaining input buffers, if present.
while (!input_buffers_.empty()) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&Client::NotifyEndOfBitstreamBuffer, client_,
- input_buffers_.front()->id));
+ const auto& input_buffer = input_buffers_.front();
+ if (!input_buffer->dummy_flush)
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Client::NotifyEndOfBitstreamBuffer, client_,
+ input_buffer->id));
input_buffers_.pop();
}
« media/gpu/vaapi_video_decode_accelerator.h ('K') | « media/gpu/vaapi_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698