| 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..d6646d14219ceb2d538a0b9e19fed7fc7b22bc74 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 is cleared and safe to render from.
|
| + media::Picture picture; // The decoded picture.
|
| +};
|
| +
|
| ExynosVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
|
| base::WeakPtr<Client>& client,
|
| scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy,
|
| @@ -195,12 +202,19 @@ 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 +250,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 +1067,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 +1431,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_++;
|
| }
|
|
|
| @@ -1629,6 +1647,7 @@ void ExynosVideoDecodeAccelerator::FlushTask() {
|
| new BitstreamBufferRef(io_client_, io_message_loop_proxy_, NULL, 0,
|
| kFlushBufferId)));
|
| decoder_flushing_ = true;
|
| + SendPictureReady(); // Send all pending PictureReady.
|
|
|
| ScheduleDecodeBufferTaskIfNeeded();
|
| }
|
| @@ -1722,6 +1741,7 @@ void ExynosVideoDecodeAccelerator::ResetTask() {
|
| // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening
|
| // jobs will early-out in the kResetting state.
|
| decoder_state_ = kResetting;
|
| + SendPictureReady(); // Send all pending PictureReady.
|
| decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
|
| &ExynosVideoDecodeAccelerator::ResetDoneTask, base::Unretained(this)));
|
| }
|
| @@ -2450,4 +2470,53 @@ void ExynosVideoDecodeAccelerator::ResolutionChangeDestroyBuffers() {
|
| base::Unretained(this)));
|
| }
|
|
|
| +void ExynosVideoDecodeAccelerator::SendPictureReady() {
|
| + DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
|
| + bool resetting_or_flushing =
|
| + (decoder_state_ == kResetting || decoder_flushing_);
|
| + while (pending_picture_ready_.size() > 0) {
|
| + bool cleared = pending_picture_ready_.front().cleared;
|
| + const media::Picture& picture = pending_picture_ready_.front().picture;
|
| + if (cleared && picture_clearing_count_ == 0) {
|
| + // This picture is cleared. Post it to IO thread to reduce latency. This
|
| + // should be the case after all pictures are cleared at the beginning.
|
| + io_message_loop_proxy_->PostTask(
|
| + FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture));
|
| + pending_picture_ready_.pop();
|
| + } else if (!cleared || resetting_or_flushing) {
|
| + DVLOG(3) << "SendPictureReady()"
|
| + << ". cleared=" << pending_picture_ready_.front().cleared
|
| + << ", decoder_state_=" << decoder_state_
|
| + << ", decoder_flushing_=" << decoder_flushing_
|
| + << ", picture_clearing_count_=" << picture_clearing_count_;
|
| + // If the picture is not cleared, post it to the child thread because it
|
| + // has to be cleared in the child thread. A picture only needs to be
|
| + // cleared once. If the decoder is resetting or flushing, send all
|
| + // pictures to ensure PictureReady arrive before reset or flush done.
|
| + child_message_loop_proxy_->PostTaskAndReply(
|
| + FROM_HERE,
|
| + base::Bind(&Client::PictureReady, client_, picture),
|
| + // Unretained is safe. If Client::PictureReady gets to run, |this| is
|
| + // alive. Destroy() will wait the decode thread to finish.
|
| + base::Bind(&ExynosVideoDecodeAccelerator::PictureCleared,
|
| + base::Unretained(this)));
|
| + picture_clearing_count_++;
|
| + 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(). clearing count=" << picture_clearing_count_;
|
| + DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
|
| + DCHECK_GT(picture_clearing_count_, 0);
|
| + picture_clearing_count_--;
|
| + SendPictureReady();
|
| +}
|
| +
|
| } // namespace content
|
|
|