Index: media/gpu/v4l2_video_decode_accelerator.cc |
diff --git a/media/gpu/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2_video_decode_accelerator.cc |
index b4ac8a19f993babcca1d4833d9a59ce3e83dc9e4..2fa10b10a7eda1f4ab2e48e7dc2b2203ca3c842c 100644 |
--- a/media/gpu/v4l2_video_decode_accelerator.cc |
+++ b/media/gpu/v4l2_video_decode_accelerator.cc |
@@ -164,6 +164,8 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
decoder_decode_buffer_tasks_scheduled_(0), |
decoder_frames_at_client_(0), |
decoder_flushing_(false), |
+ decoder_cmd_supported_(false), |
+ flush_waiting_last_output_buffer_(false), |
reset_pending_(false), |
decoder_partial_frame_pending_(false), |
input_streamon_(false), |
@@ -287,6 +289,8 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, |
return false; |
} |
+ decoder_cmd_supported_ = IsDecoderCmdSupported(); |
Pawel Osciak
2016/10/19 09:23:04
Ideally, we should try to run this on decoder_thre
wuchengli
2016/10/20 10:14:06
I've moved it before decoder_thread start. Many ot
|
+ |
decoder_state_ = kInitialized; |
output_mode_ = config.output_mode; |
@@ -824,7 +828,16 @@ void V4L2VideoDecodeAccelerator::DecodeBufferTask() { |
kFlushBufferId) |
schedule_task = FlushInputFrame(); |
- if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { |
+ if (decoder_cmd_supported_) { |
wuchengli
2016/10/19 08:02:08
Pawel. It looks like I need to check schedule_task
Pawel Osciak
2016/10/19 09:23:04
Yes, but probably best to separate that logic in a
wuchengli
2016/10/20 10:14:06
Done.
|
+ DVLOGF(2) << "sending decoder cmd to flush"; |
+ DCHECK(!flush_waiting_last_output_buffer_); |
+ struct v4l2_decoder_cmd cmd; |
+ memset(&cmd, 0, sizeof(cmd)); |
+ cmd.cmd = V4L2_DEC_CMD_STOP; |
+ IOCTL_OR_ERROR_RETURN(VIDIOC_DECODER_CMD, &cmd); |
+ flush_waiting_last_output_buffer_ = true; |
kcwu
2016/10/18 05:07:13
Do you need to set decoder_partial_frame_pending_=
wuchengli
2016/10/19 08:26:58
We should set decoder_partial_frame_pending_=false
|
+ } else if (schedule_task && AppendToInputFrame(NULL, 0) && |
+ FlushInputFrame()) { |
DVLOGF(2) << "enqueued flush buffer"; |
decoder_partial_frame_pending_ = false; |
schedule_task = true; |
@@ -1359,6 +1372,10 @@ bool V4L2VideoDecodeAccelerator::DequeueOutputBuffer() { |
// EAGAIN if we're just out of buffers to dequeue. |
return false; |
} |
+ if (errno == EPIPE) { |
Pawel Osciak
2016/10/19 09:23:04
else if?
Or even if (errno == EAGAIN || errno ==
wuchengli
2016/10/20 10:14:06
Changed to else if
|
+ DVLOGF(3) << "Got EPIPE. Last output buffer was already dequeued."; |
+ return false; |
+ } |
PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
NOTIFY_ERROR(PLATFORM_FAILURE); |
return false; |
@@ -1394,6 +1411,17 @@ bool V4L2VideoDecodeAccelerator::DequeueOutputBuffer() { |
output_record.cleared = true; |
} |
} |
+ if ((dqbuf.flags & V4L2_BUF_FLAG_LAST)) { |
Pawel Osciak
2016/10/19 09:23:04
s/((/(/
s/))/)/
wuchengli
2016/10/20 10:14:06
Done.
|
+ DVLOGF(3) << "Got last output buffer. Waiting last buffer=" |
+ << flush_waiting_last_output_buffer_; |
+ if (flush_waiting_last_output_buffer_) { |
Pawel Osciak
2016/10/19 09:23:04
Would we perhaps always want to restart, even afte
wuchengli
2016/10/20 10:14:06
Your V4L2 spec doesn't way we need to do CMD_START
|
+ struct v4l2_decoder_cmd cmd; |
+ memset(&cmd, 0, sizeof(cmd)); |
+ cmd.cmd = V4L2_DEC_CMD_START; |
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_DECODER_CMD, &cmd); |
+ flush_waiting_last_output_buffer_ = false; |
Pawel Osciak
2016/10/19 09:23:04
We could possibly set this at the beginning, since
wuchengli
2016/10/20 10:14:06
Done. It doesn't matter much because VDA will be d
|
+ } |
+ } |
return true; |
} |
@@ -1531,8 +1559,10 @@ void V4L2VideoDecodeAccelerator::FlushTask() { |
TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); |
// Flush outstanding buffers. |
- if (decoder_state_ == kInitialized) { |
- // There's nothing in the pipe, so return done immediately. |
+ if (!output_streamon_) { |
kcwu
2016/10/18 05:07:13
This change sounds not good because you do somethi
wuchengli
2016/10/19 08:26:58
Done.
|
+ // If output stream is off, output buffers are not allocated. Or the decoder |
+ // is initialized, resetting or changing resolution. There's nothing in the |
+ // pipe, so return done immediately. |
DVLOGF(3) << "returning flush"; |
child_task_runner_->PostTask(FROM_HERE, |
base::Bind(&Client::NotifyFlushDone, client_)); |
@@ -1568,15 +1598,27 @@ void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
// * All image processor buffers are returned. |
if (!decoder_input_queue_.empty()) { |
if (decoder_input_queue_.front()->input_id != |
- decoder_delay_bitstream_buffer_id_) |
+ decoder_delay_bitstream_buffer_id_) { |
+ DVLOGF(3) << "Some input bitstream buffers are not queued."; |
return; |
+ } |
} |
- if (decoder_current_input_buffer_ != -1) |
+ if (decoder_current_input_buffer_ != -1) { |
+ DVLOGF(3) << "Current input buffer != -1"; |
return; |
- if ((input_ready_queue_.size() + input_buffer_queued_count_) != 0) |
+ } |
+ if ((input_ready_queue_.size() + input_buffer_queued_count_) != 0) { |
+ DVLOGF(3) << "Some input buffers are not dequeued."; |
return; |
- if (image_processor_bitstream_buffer_ids_.size() != 0) |
+ } |
+ if (image_processor_bitstream_buffer_ids_.size() != 0) { |
+ DVLOGF(3) << "Waiting for image processor to complete."; |
return; |
+ } |
+ if (flush_waiting_last_output_buffer_) { |
+ DVLOGF(3) << "Waiting for last output buffer."; |
+ return; |
+ } |
// TODO(posciak): crbug.com/270039. Exynos requires a streamoff-streamon |
// sequence after flush to continue, even if we are not resetting. This would |
@@ -1603,6 +1645,18 @@ void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
ScheduleDecodeBufferTaskIfNeeded(); |
} |
+bool V4L2VideoDecodeAccelerator::IsDecoderCmdSupported() { |
Pawel Osciak
2016/10/19 09:23:04
Could we DCHECK we are on decoder thread here?
wuchengli
2016/10/20 10:14:06
Explained in the above comment. This still runs in
|
+ struct v4l2_decoder_cmd cmd; |
+ memset(&cmd, 0, sizeof(cmd)); |
+ cmd.cmd = V4L2_DEC_CMD_STOP; |
kcwu
2016/10/17 16:24:52
Do you need to add CMD_START back?
wuchengli
2016/10/18 02:04:51
No. I found VIDIOC_TRY_DECODER_CMD didn't mean if
kcwu
2016/10/18 05:07:13
I don't fully understand. Do you mean we can try C
wuchengli
2016/10/19 08:26:58
That's right.
|
+ if (device_->Ioctl(VIDIOC_TRY_DECODER_CMD, &cmd) != 0) { |
+ DVLOGF(3) "V4L2_DEC_CMD_STOP is not supported."; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
void V4L2VideoDecodeAccelerator::ResetTask() { |
DVLOGF(3); |
DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
@@ -1722,6 +1776,7 @@ void V4L2VideoDecodeAccelerator::DestroyTask() { |
while (!decoder_input_queue_.empty()) |
decoder_input_queue_.pop(); |
decoder_flushing_ = false; |
+ flush_waiting_last_output_buffer_ = false; |
if (image_processor_) |
image_processor_.release()->Destroy(); |
@@ -1785,6 +1840,9 @@ bool V4L2VideoDecodeAccelerator::StopOutputStream() { |
IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); |
output_streamon_ = false; |
+ // Output stream is stopped. No need to wait the buffer anymore. |
+ flush_waiting_last_output_buffer_ = false; |
+ |
for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
// After streamoff, the device drops ownership of all buffers, even if we |
// don't dequeue them explicitly. Some of them may still be owned by the |