Index: content/common/gpu/media/exynos_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/exynos_video_decode_accelerator.cc b/content/common/gpu/media/exynos_video_decode_accelerator.cc |
index 68d71293b681189c4abd10e25772774dc2d5e0b9..5372fb9ba0816fbb81f32287d527cb25e209291e 100644 |
--- a/content/common/gpu/media/exynos_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/exynos_video_decode_accelerator.cc |
@@ -104,6 +104,13 @@ struct ExynosVideoDecodeAccelerator::EGLSyncKHRRef { |
EGLSyncKHR egl_sync; |
}; |
+struct ExynosVideoDecodeAccelerator::PictureRecord { |
+ PictureRecord(bool cleared, const media::Picture& picture); |
+ ~PictureRecord(); |
+ bool cleared; // whether the texture has been cleared |
+ media::Picture picture; // the decoded picture |
+}; |
+ |
ExynosVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( |
base::WeakPtr<Client>& client, |
scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy, |
@@ -195,12 +202,20 @@ ExynosVideoDecodeAccelerator::GscOutputRecord::GscOutputRecord() |
fd(-1), |
egl_image(EGL_NO_IMAGE_KHR), |
egl_sync(EGL_NO_SYNC_KHR), |
- picture_id(-1) { |
-} |
+ picture_id(-1), |
+ cleared(false) {} |
ExynosVideoDecodeAccelerator::GscOutputRecord::~GscOutputRecord() { |
} |
+ExynosVideoDecodeAccelerator::PictureRecord::PictureRecord( |
+ bool cleared, const media::Picture& picture) |
+ : cleared(cleared), picture(picture) { |
+} |
+ |
+ExynosVideoDecodeAccelerator::PictureRecord::~PictureRecord() { |
+} |
+ |
ExynosVideoDecodeAccelerator::ExynosVideoDecodeAccelerator( |
EGLDisplay egl_display, |
EGLContext egl_context, |
@@ -236,6 +251,7 @@ ExynosVideoDecodeAccelerator::ExynosVideoDecodeAccelerator( |
gsc_input_buffer_queued_count_(0), |
gsc_output_streamon_(false), |
gsc_output_buffer_queued_count_(0), |
+ picture_clearing_count_(0), |
device_poll_thread_("ExynosDevicePollThread"), |
device_poll_interrupt_fd_(-1), |
make_context_current_(make_context_current), |
@@ -1052,6 +1068,7 @@ void ExynosVideoDecodeAccelerator::AssignPictureBuffersTask( |
DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
DCHECK_EQ(output_record.picture_id, -1); |
+ DCHECK_EQ(output_record.cleared, false); |
PictureBufferArrayRef::PictureBufferRef& buffer = |
pic_buffers->picture_buffers[i]; |
output_record.fd = buffer.egl_image_fd; |
@@ -1415,9 +1432,11 @@ void ExynosVideoDecodeAccelerator::DequeueGsc() { |
gsc_output_buffer_queued_count_--; |
DVLOG(3) << "DequeueGsc(): returning input_id=" << dqbuf.timestamp.tv_sec |
<< " as picture_id=" << output_record.picture_id; |
- io_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
- &Client::PictureReady, io_client_, media::Picture( |
- output_record.picture_id, dqbuf.timestamp.tv_sec))); |
+ const media::Picture& picture = |
+ media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec); |
+ pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); |
+ SendPictureReady(); |
+ output_record.cleared = true; |
decoder_frames_at_client_++; |
} |
@@ -2450,4 +2469,40 @@ void ExynosVideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { |
base::Unretained(this))); |
} |
+void ExynosVideoDecodeAccelerator::SendPictureReady() { |
+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
+ while (pending_picture_ready_.size() > 0) { |
+ const media::Picture& picture = pending_picture_ready_.front().picture; |
+ if (!pending_picture_ready_.front().cleared) { |
+ // If the picture is not cleared, post it to the child thread because it |
+ // has to be cleared in the child thread. |
+ child_message_loop_proxy_->PostTaskAndReply( |
+ FROM_HERE, |
+ base::Bind(&Client::PictureReady, client_, picture), |
+ base::Bind(&ExynosVideoDecodeAccelerator::PictureCleared, |
+ weak_this_)); |
+ picture_clearing_count_++; |
+ pending_picture_ready_.pop(); |
+ } else if (picture_clearing_count_ == 0) { |
+ // This picture is cleared. Post it to IO thread to reduce latency. |
+ io_message_loop_proxy_->PostTask( |
+ FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); |
+ pending_picture_ready_.pop(); |
+ } else { |
+ // This picture is cleared. But some pictures are about to be cleared on |
+ // the child thread. To preserve the order, do not send this until those |
+ // pictures are cleared. |
+ break; |
+ } |
+ } |
+} |
+ |
+void ExynosVideoDecodeAccelerator::PictureCleared() { |
+ DVLOG(3) << "PictureCleared()"; |
+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
+ DCHECK_GT(picture_clearing_count_, 0); |
+ picture_clearing_count_--; |
+ SendPictureReady(); |
+} |
+ |
} // namespace content |