Add buffer management to V4L2 wrapper.
Functions to enqueue and dequeue buffers.
Extended gralloc helper with a mass-unlock function.
Change-Id: I72c83138fd37463d314bf02b5df5befc68bc05af
diff --git a/modules/camera/3_4/V4L2Wrapper.cpp b/modules/camera/3_4/V4L2Wrapper.cpp
index fdcd179..495467a 100644
--- a/modules/camera/3_4/V4L2Wrapper.cpp
+++ b/modules/camera/3_4/V4L2Wrapper.cpp
@@ -28,11 +28,25 @@
#include "Common.h"
#include "Stream.h"
#include "StreamFormat.h"
+#include "V4L2Gralloc.h"
namespace v4l2_camera_hal {
-V4L2Wrapper::V4L2Wrapper(const std::string device_path)
- : device_path_(device_path), max_buffers_(0) {
+V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
+ HAL_LOG_ENTER();
+
+ std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
+ if (!gralloc) {
+ HAL_LOGE("Failed to initialize gralloc helper.");
+ return nullptr;
+ }
+
+ return new V4L2Wrapper(device_path, std::move(gralloc));
+}
+
+V4L2Wrapper::V4L2Wrapper(const std::string device_path,
+ std::unique_ptr<V4L2Gralloc> gralloc)
+ : device_path_(device_path), gralloc_(std::move(gralloc)), max_buffers_(0) {
HAL_LOG_ENTER();
}
@@ -58,7 +72,7 @@
// Check if this connection has the extended control query capability.
v4l2_query_ext_ctrl query;
query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
- // Already holding the lock, so don't call ioctlLocked.
+ // Already holding the lock, so don't call IoctlLocked.
int res = TEMP_FAILURE_RETRY(
ioctl(device_fd_.get(), VIDIOC_QUERY_EXT_CTRL, &query));
extended_query_supported_ = (res == 0);
@@ -79,6 +93,8 @@
device_fd_.reset(); // Includes close().
format_.reset();
max_buffers_ = 0;
+ // Closing the device releases all queued buffers back to the user.
+ gralloc_->unlockAllBuffers();
}
// Helper function. Should be used instead of ioctl throughout this class.
@@ -102,7 +118,7 @@
return -EINVAL;
}
- int32_t type = format_->get_type();
+ int32_t type = format_->type();
if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
HAL_LOGE("STREAMON fails: %s", strerror(errno));
return -ENODEV;
@@ -114,11 +130,18 @@
int V4L2Wrapper::StreamOff() {
HAL_LOG_ENTER();
- int32_t type = format_->get_type();
- if (IoctlLocked(VIDIOC_STREAMOFF, &type) < 0) {
+ int32_t type = format_->type();
+ int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
+ // Calling STREAMOFF releases all queued buffers back to the user.
+ int gralloc_res = gralloc_->unlockAllBuffers();
+ if (res < 0) {
HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
return -ENODEV;
}
+ if (gralloc_res < 0) {
+ HAL_LOGE("Failed to unlock all buffers after turning stream off.");
+ return gralloc_res;
+ }
return 0;
}
@@ -256,17 +279,81 @@
// tells V4L2 to switch into userspace buffer mode).
v4l2_requestbuffers req_buffers;
memset(&req_buffers, 0, sizeof(req_buffers));
- req_buffers.type = format_->get_type();
+ req_buffers.type = format_->type();
req_buffers.memory = V4L2_MEMORY_USERPTR;
req_buffers.count = 1;
- if (IoctlLocked(VIDIOC_REQBUFS, &req_buffers) < 0) {
+
+ int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
+ // Calling REQBUFS releases all queued buffers back to the user.
+ int gralloc_res = gralloc_->unlockAllBuffers();
+ if (res < 0) {
HAL_LOGE("REQBUFS failed: %s", strerror(errno));
return -ENODEV;
}
+ if (gralloc_res < 0) {
+ HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
+ return gralloc_res;
+ }
// V4L2 will set req_buffers.count to a number of buffers it can handle.
max_buffers_ = req_buffers.count;
return 0;
}
+int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
+ HAL_LOG_ENTER();
+
+ // Set up a v4l2 buffer struct.
+ v4l2_buffer device_buffer;
+ memset(&device_buffer, 0, sizeof(device_buffer));
+ device_buffer.type = format_->type();
+
+ // Use QUERYBUF to ensure our buffer/device is in good shape.
+ if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
+ HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Configure the device buffer based on the stream buffer.
+ device_buffer.memory = V4L2_MEMORY_USERPTR;
+ // TODO(b/29334616): when this is async, actually limit the number
+ // of buffers used to the known max, and set this according to the
+ // queue length.
+ device_buffer.index = 0;
+ // Lock the buffer for writing.
+ int res =
+ gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
+ if (res) {
+ HAL_LOGE("Gralloc failed to lock buffer.");
+ return res;
+ }
+ if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
+ HAL_LOGE("QBUF (%d) fails: %s", 0, strerror(errno));
+ gralloc_->unlock(&device_buffer);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int V4L2Wrapper::DequeueBuffer(v4l2_buffer* buffer) {
+ HAL_LOG_ENTER();
+
+ memset(buffer, 0, sizeof(*buffer));
+ buffer->type = format_->type();
+ buffer->memory = V4L2_MEMORY_USERPTR;
+ if (IoctlLocked(VIDIOC_DQBUF, buffer) < 0) {
+ HAL_LOGE("DQBUF fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Now that we're done painting the buffer, we can unlock it.
+ int res = gralloc_->unlock(buffer);
+ if (res) {
+ return res;
+ }
+
+ return 0;
+}
+
} // namespace v4l2_camera_hal