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..21b5d3ebc6c7bf661bace376176e547619c3ec27 100644 |
--- a/media/gpu/vaapi_video_decode_accelerator.cc |
+++ b/media/gpu/vaapi_video_decode_accelerator.cc |
@@ -268,9 +268,8 @@ class VaapiVideoDecodeAccelerator::VaapiVP9Accelerator |
DISALLOW_COPY_AND_ASSIGN(VaapiVP9Accelerator); |
}; |
-VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0) {} |
- |
-VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {} |
+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() = default; |
+VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() = default; |
void VaapiVideoDecodeAccelerator::NotifyError(Error error) { |
if (!task_runner_->BelongsToCurrentThread()) { |
@@ -461,41 +460,62 @@ void VaapiVideoDecodeAccelerator::TryOutputSurface() { |
FinishFlush(); |
} |
-void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( |
+void VaapiVideoDecodeAccelerator::QueueInputBuffer( |
const BitstreamBuffer& bitstream_buffer) { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
- TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id", |
+ TRACE_EVENT1("Video Decoder", "QueueInputBuffer", "input_id", |
bitstream_buffer.id()); |
- DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() |
+ DVLOG(4) << "Queueing new input buffer id: " << bitstream_buffer.id() |
<< " size: " << (int)bitstream_buffer.size(); |
- std::unique_ptr<SharedMemoryRegion> shm( |
- new SharedMemoryRegion(bitstream_buffer, true)); |
- |
- // Skip empty buffers. |
+ base::AutoLock auto_lock(lock_); |
if (bitstream_buffer.size() == 0) { |
- if (client_) |
- client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id()); |
- return; |
+ // Dummy buffer for flush. |
+ DCHECK(!base::SharedMemory::IsHandleValid(bitstream_buffer.handle())); |
+ input_buffers_.push(make_linked_ptr(new InputBuffer())); |
+ } else { |
+ std::unique_ptr<SharedMemoryRegion> shm( |
+ new SharedMemoryRegion(bitstream_buffer, true)); |
+ |
+ RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(), "Failed to map input buffer", |
+ UNREADABLE_INPUT, ); |
+ |
+ linked_ptr<InputBuffer> input_buffer(new InputBuffer()); |
+ input_buffer->shm = std::move(shm); |
+ input_buffer->id = bitstream_buffer.id(); |
+ input_buffers_.push(input_buffer); |
+ ++num_stream_bufs_at_decoder_; |
+ TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", |
+ num_stream_bufs_at_decoder_); |
} |
- RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(), "Failed to map input buffer", |
- UNREADABLE_INPUT, ); |
+ input_ready_.Signal(); |
- base::AutoLock auto_lock(lock_); |
+ switch (state_) { |
+ case kIdle: |
+ state_ = kDecoding; |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, |
+ base::Unretained(this))); |
+ break; |
- // Set up a new input buffer and queue it for later. |
- linked_ptr<InputBuffer> input_buffer(new InputBuffer()); |
- input_buffer->shm = std::move(shm); |
- input_buffer->id = bitstream_buffer.id(); |
+ case kDecoding: |
+ // Decoder already running. |
+ break; |
- ++num_stream_bufs_at_decoder_; |
- TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", |
- num_stream_bufs_at_decoder_); |
+ 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; |
- input_buffers_.push(input_buffer); |
- input_ready_.Signal(); |
+ default: |
+ LOG(ERROR) << "Decode/Flush request from client in invalid state: " |
+ << state_; |
+ NotifyError(PLATFORM_FAILURE); |
+ break; |
+ } |
} |
bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { |
@@ -514,12 +534,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 +541,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_->is_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,11 +584,11 @@ 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; |
@@ -591,6 +610,11 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { |
while (GetInputBuffer_Locked()) { |
DCHECK(curr_input_buffer_.get()); |
+ if (curr_input_buffer_->is_flush()) { |
+ FlushTask(); |
+ break; |
+ } |
+ |
AcceleratedVideoDecoder::DecodeResult res; |
{ |
// We are OK releasing the lock here, as decoder never calls our methods |
@@ -735,32 +759,17 @@ void VaapiVideoDecodeAccelerator::Decode( |
return; |
} |
- // We got a new input buffer from the client, map it and queue for later use. |
- MapAndQueueNewInputBuffer(bitstream_buffer); |
- |
- base::AutoLock auto_lock(lock_); |
- switch (state_) { |
- case kIdle: |
- state_ = kDecoding; |
- decoder_thread_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, |
- base::Unretained(this))); |
- break; |
- |
- case kDecoding: |
- // Decoder already running, fallthrough. |
- 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; |
+ // Skip empty buffers. VaapiVDA uses empty buffer as dummy buffer for flush |
+ // internally. |
+ if (bitstream_buffer.size() == 0) { |
+ if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) |
+ base::SharedMemory::CloseHandle(bitstream_buffer.handle()); |
+ if (client_) |
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id()); |
+ return; |
} |
+ |
+ QueueInputBuffer(bitstream_buffer); |
} |
void VaapiVideoDecodeAccelerator::RecycleVASurfaceID( |
@@ -824,10 +833,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 +915,12 @@ void VaapiVideoDecodeAccelerator::ReusePictureBuffer( |
void VaapiVideoDecodeAccelerator::FlushTask() { |
DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
+ DCHECK(curr_input_buffer_.get() && curr_input_buffer_->is_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(); |
@@ -928,15 +939,8 @@ void VaapiVideoDecodeAccelerator::Flush() { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
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))); |
- |
- input_ready_.Signal(); |
- surfaces_available_.Signal(); |
+ // Queue a dummy buffer, which means flush. |
+ QueueInputBuffer(media::BitstreamBuffer()); |
} |
void VaapiVideoDecodeAccelerator::FinishFlush() { |
@@ -945,7 +949,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. |
} |
@@ -957,7 +961,14 @@ void VaapiVideoDecodeAccelerator::FinishFlush() { |
return; |
} |
- state_ = kIdle; |
+ // Resume decoding if necessary. |
+ if (input_buffers_.empty()) { |
+ state_ = kIdle; |
+ } else { |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, |
+ base::Unretained(this))); |
+ } |
task_runner_->PostTask(FROM_HERE, |
base::Bind(&Client::NotifyFlushDone, client_)); |
@@ -997,9 +1008,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->is_flush()) |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Client::NotifyEndOfBitstreamBuffer, client_, |
+ input_buffer->id)); |
input_buffers_.pop(); |
} |