Index: content/common/gpu/media/v4l2_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc |
index 587da6bbc04ed5449ccadf7bf00f693f9273d3e4..876b38ae0f385c114ccfdd70c1163cf8db295b7e 100644 |
--- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc |
@@ -5,7 +5,6 @@ |
#include <dlfcn.h> |
#include <errno.h> |
#include <fcntl.h> |
-#include <libdrm/drm_fourcc.h> |
#include <linux/videodev2.h> |
#include <poll.h> |
#include <sys/eventfd.h> |
@@ -17,6 +16,7 @@ |
#include "base/memory/shared_memory.h" |
#include "base/message_loop/message_loop.h" |
#include "base/message_loop/message_loop_proxy.h" |
+#include "base/numerics/safe_conversions.h" |
#include "base/posix/eintr_wrapper.h" |
#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" |
#include "media/filters/h264_parser.h" |
@@ -139,8 +139,6 @@ V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() |
egl_sync(EGL_NO_SYNC_KHR), |
picture_id(-1), |
cleared(false) { |
- for (size_t i = 0; i < arraysize(fds); ++i) |
- fds[i] = -1; |
} |
V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} |
@@ -179,6 +177,7 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
output_buffer_queued_count_(0), |
output_buffer_pixelformat_(0), |
output_dpb_size_(0), |
+ output_planes_count_(0), |
picture_clearing_count_(0), |
pictures_assigned_(false, false), |
device_poll_thread_("V4L2DevicePollThread"), |
@@ -267,7 +266,7 @@ bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
struct v4l2_format format; |
memset(&format, 0, sizeof(format)); |
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
- format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; |
+ format.fmt.pix_mp.pixelformat = device_->PreferredOutputFormat(); |
IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
// Subscribe to the resolution change event. |
@@ -330,15 +329,6 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( |
} |
gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
- EGLint attrs[] = { |
- EGL_WIDTH, 0, EGL_HEIGHT, 0, |
- EGL_LINUX_DRM_FOURCC_EXT, 0, EGL_DMA_BUF_PLANE0_FD_EXT, 0, |
- EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, |
- EGL_DMA_BUF_PLANE1_FD_EXT, 0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0, |
- EGL_DMA_BUF_PLANE1_PITCH_EXT, 0, EGL_NONE, }; |
- attrs[1] = frame_buffer_size_.width(); |
- attrs[3] = frame_buffer_size_.height(); |
- attrs[5] = DRM_FORMAT_NV12; |
// It's safe to manipulate all the buffer state here, because the decoder |
// thread is waiting on pictures_assigned_. |
@@ -354,15 +344,11 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( |
DCHECK_EQ(output_record.picture_id, -1); |
DCHECK_EQ(output_record.cleared, false); |
- attrs[7] = output_record.fds[0]; |
- attrs[9] = 0; |
- attrs[11] = frame_buffer_size_.width(); |
- attrs[13] = output_record.fds[1]; |
- attrs[15] = 0; |
- attrs[17] = frame_buffer_size_.width(); |
- |
- EGLImageKHR egl_image = eglCreateImageKHR( |
- egl_display_, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); |
+ EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
+ buffers[i].texture_id(), |
+ frame_buffer_size_, |
+ i, |
+ output_planes_count_); |
if (egl_image == EGL_NO_IMAGE_KHR) { |
DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
// Ownership of EGLImages allocated in previous iterations of this loop |
@@ -372,9 +358,6 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( |
return; |
} |
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, buffers[i].texture_id()); |
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); |
- |
output_record.egl_image = egl_image; |
output_record.picture_id = buffers[i].id(); |
free_output_buffers_.push(i); |
@@ -1005,7 +988,7 @@ void V4L2VideoDecodeAccelerator::DequeueEvents() { |
if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { |
DVLOG(3) << "DequeueEvents(): got resolution change event."; |
DCHECK(!resolution_change_pending_); |
- resolution_change_pending_ = true; |
+ resolution_change_pending_ = IsResolutionChangeNecessary(); |
} else { |
DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type |
<< ") we haven't subscribed to."; |
@@ -1021,10 +1004,10 @@ void V4L2VideoDecodeAccelerator::Dequeue() { |
// Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free |
// list. |
- struct v4l2_buffer dqbuf; |
- struct v4l2_plane planes[2]; |
while (input_buffer_queued_count_ > 0) { |
DCHECK(input_streamon_); |
+ struct v4l2_buffer dqbuf; |
+ struct v4l2_plane planes[1]; |
memset(&dqbuf, 0, sizeof(dqbuf)); |
memset(planes, 0, sizeof(planes)); |
dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
@@ -1053,12 +1036,15 @@ void V4L2VideoDecodeAccelerator::Dequeue() { |
// completed queue. |
while (output_buffer_queued_count_ > 0) { |
DCHECK(output_streamon_); |
+ struct v4l2_buffer dqbuf; |
+ scoped_ptr<struct v4l2_plane[]> planes( |
+ new v4l2_plane[output_planes_count_]); |
memset(&dqbuf, 0, sizeof(dqbuf)); |
- memset(planes, 0, sizeof(planes)); |
+ memset(planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); |
dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
dqbuf.memory = V4L2_MEMORY_MMAP; |
- dqbuf.m.planes = planes; |
- dqbuf.length = 2; |
+ dqbuf.m.planes = planes.get(); |
+ dqbuf.length = output_planes_count_; |
if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
if (errno == EAGAIN) { |
// EAGAIN if we're just out of buffers to dequeue. |
@@ -1154,14 +1140,16 @@ bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { |
output_record.egl_sync = EGL_NO_SYNC_KHR; |
} |
struct v4l2_buffer qbuf; |
- struct v4l2_plane qbuf_planes[arraysize(output_record.fds)]; |
+ scoped_ptr<struct v4l2_plane[]> qbuf_planes( |
+ new v4l2_plane[output_planes_count_]); |
memset(&qbuf, 0, sizeof(qbuf)); |
- memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
+ memset( |
+ qbuf_planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); |
qbuf.index = buffer; |
qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
qbuf.memory = V4L2_MEMORY_MMAP; |
- qbuf.m.planes = qbuf_planes; |
- qbuf.length = arraysize(output_record.fds); |
+ qbuf.m.planes = qbuf_planes.get(); |
+ qbuf.length = output_planes_count_; |
IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
free_output_buffers_.pop(); |
output_record.at_device = true; |
@@ -1632,11 +1620,11 @@ bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format, |
bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( |
const struct v4l2_format& format) { |
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
- CHECK_EQ(format.fmt.pix_mp.num_planes, 2); |
+ output_planes_count_ = format.fmt.pix_mp.num_planes; |
frame_buffer_size_.SetSize( |
format.fmt.pix_mp.width, format.fmt.pix_mp.height); |
output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat; |
- DCHECK_EQ(output_buffer_pixelformat_, V4L2_PIX_FMT_NV12M); |
+ DCHECK_EQ(output_buffer_pixelformat_, device_->PreferredOutputFormat()); |
DVLOG(3) << "CreateBuffersForFormat(): new resolution: " |
<< frame_buffer_size_.ToString(); |
@@ -1733,22 +1721,7 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
reqbufs.memory = V4L2_MEMORY_MMAP; |
IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
- // Create DMABUFs from output buffers. |
output_buffer_map_.resize(reqbufs.count); |
- for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
- OutputRecord& output_record = output_buffer_map_[i]; |
- for (size_t j = 0; j < arraysize(output_record.fds); ++j) { |
- // Export the DMABUF fd so we can export it as a texture. |
- struct v4l2_exportbuffer expbuf; |
- memset(&expbuf, 0, sizeof(expbuf)); |
- expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
- expbuf.index = i; |
- expbuf.plane = j; |
- expbuf.flags = O_CLOEXEC; |
- IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_EXPBUF, &expbuf); |
- output_record.fds[j] = expbuf.fd; |
- } |
- } |
DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " |
<< "buffer_count=" << output_buffer_map_.size() |
@@ -1759,7 +1732,7 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
client_, |
output_buffer_map_.size(), |
frame_buffer_size_, |
- GL_TEXTURE_EXTERNAL_OES)); |
+ device_->GetTextureTarget())); |
// Wait for the client to call AssignPictureBuffers() on the Child thread. |
// We do this, because if we continue decoding without finishing buffer |
@@ -1812,18 +1785,11 @@ bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
OutputRecord& output_record = output_buffer_map_[i]; |
- for (size_t j = 0; j < arraysize(output_record.fds); ++j) { |
- if (output_record.fds[j] != -1) { |
- if (close(output_record.fds[j])) { |
- DVPLOG(1) << __func__ << " close() on a dmabuf fd failed."; |
- success = false; |
- } |
- } |
- } |
+ |
if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
- if (eglDestroyImageKHR(egl_display_, output_record.egl_image) != |
+ if (device_->DestroyEGLImage(egl_display_, output_record.egl_image) != |
EGL_TRUE) { |
- DVLOG(1) << __func__ << " eglDestroyImageKHR failed."; |
+ DVLOG(1) << __func__ << " DestroyEGLImage failed."; |
success = false; |
} |
} |
@@ -1926,4 +1892,32 @@ void V4L2VideoDecodeAccelerator::PictureCleared() { |
SendPictureReady(); |
} |
+bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() { |
+ DVLOG(3) << "IsResolutionChangeNecessary() "; |
+ |
+ struct v4l2_control ctrl; |
+ memset(&ctrl, 0, sizeof(ctrl)); |
+ ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; |
+ IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); |
+ if (ctrl.value != output_dpb_size_) { |
+ DVLOG(3) |
+ << "IsResolutionChangeNecessary(): Returning true since DPB mismatch "; |
+ return true; |
+ } |
+ struct v4l2_format format; |
+ bool again = false; |
+ bool ret = GetFormatInfo(&format, &again); |
+ if (!ret || again) { |
+ DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; |
+ return false; |
+ } |
+ gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), |
+ base::checked_cast<int>(format.fmt.pix_mp.height)); |
+ if (frame_buffer_size_ != new_size) { |
+ DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
} // namespace content |