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/StreamFormat.h b/modules/camera/3_4/StreamFormat.h
index 3686564..1b00068 100644
--- a/modules/camera/3_4/StreamFormat.h
+++ b/modules/camera/3_4/StreamFormat.h
@@ -40,7 +40,10 @@
 
   void FillFormatRequest(v4l2_format* format) const;
   FormatCategory Category() const;
-  inline uint32_t get_type() const { return type_; };
+
+  // Accessors.
+  inline uint32_t type() const { return type_; };
+  inline uint32_t bytes_per_line() const { return bytes_per_line_; };
 
   bool operator==(const StreamFormat& other) const;
   bool operator!=(const StreamFormat& other) const;
diff --git a/modules/camera/3_4/V4L2Gralloc.cpp b/modules/camera/3_4/V4L2Gralloc.cpp
index d46d119..111996e 100644
--- a/modules/camera/3_4/V4L2Gralloc.cpp
+++ b/modules/camera/3_4/V4L2Gralloc.cpp
@@ -82,14 +82,7 @@
   HAL_LOG_ENTER();
 
   // Unlock buffers that are still locked.
-  for (auto const& entry : mBufferMap) {
-    mModule->unlock(mModule, *entry.second->camera_buffer->buffer);
-    // Clean up dynamically allocated stuff.
-    if (entry.second->transform_dest) {
-      delete [] reinterpret_cast<uint8_t*>(entry.first);
-    }
-    delete entry.second;
-  }
+  unlockAllBuffers();
 }
 
 int V4L2Gralloc::lock(const camera3_stream_buffer_t* camera_buffer,
@@ -270,4 +263,31 @@
   return 0;
 }
 
+int V4L2Gralloc::unlockAllBuffers() {
+  HAL_LOG_ENTER();
+
+  bool failed = false;
+  for (auto const& entry : mBufferMap) {
+    int res = mModule->unlock(mModule, *entry.second->camera_buffer->buffer);
+    if (res) {
+      failed = true;
+    }
+    // When there is a transform to be made, the buffer returned by lock()
+    // is dynamically allocated (to hold the pre-transform data).
+    if (entry.second->transform_dest) {
+      delete [] reinterpret_cast<uint8_t*>(entry.first);
+    }
+    // The BufferData entry is always dynamically allocated in lock().
+    delete entry.second;
+  }
+
+  // If any unlock failed, return error.
+  if (failed) {
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+
 } // namespace default_camera_hal
diff --git a/modules/camera/3_4/V4L2Gralloc.h b/modules/camera/3_4/V4L2Gralloc.h
index a58a84d..ebec963 100644
--- a/modules/camera/3_4/V4L2Gralloc.h
+++ b/modules/camera/3_4/V4L2Gralloc.h
@@ -46,6 +46,8 @@
   // Unlock a buffer that was locked by this helper (equality determined
   // based on buffer user pointer, not the specific object).
   int unlock(const v4l2_buffer* device_buffer);
+  // Release all held locks.
+  int unlockAllBuffers();
 
 private:
   // Constructor is private to allow failing on bad input.
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
diff --git a/modules/camera/3_4/V4L2Wrapper.h b/modules/camera/3_4/V4L2Wrapper.h
index 4126e90..5fc8af6 100644
--- a/modules/camera/3_4/V4L2Wrapper.h
+++ b/modules/camera/3_4/V4L2Wrapper.h
@@ -26,11 +26,14 @@
 #include "Common.h"
 #include "Stream.h"
 #include "StreamFormat.h"
+#include "V4L2Gralloc.h"
 
 namespace v4l2_camera_hal {
 class V4L2Wrapper {
  public:
-  V4L2Wrapper(const std::string device_path);
+  // Use this method to create V4L2Wrapper objects. Functionally equivalent
+  // to "new V4L2Wrapper", except that it may return nullptr in case of failure.
+  static V4L2Wrapper* NewV4L2Wrapper(const std::string device_path);
   virtual ~V4L2Wrapper();
 
   // Connect or disconnect to the device.
@@ -45,10 +48,18 @@
   int SetControl(uint32_t control_id, int32_t desired, int32_t* result);
   // Manage format.
   int SetFormat(const default_camera_hal::Stream& stream);
+  // Manage buffers.
+  int EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer);
+  int DequeueBuffer(v4l2_buffer* buffer);
 
   inline bool connected() { return device_fd_.get() >= 0; }
 
  private:
+  // Constructor is private to allow failing on bad input.
+  // Use NewV4L2Wrapper instead.
+  V4L2Wrapper(const std::string device_path,
+              std::unique_ptr<V4L2Gralloc> gralloc);
+
   // Perform an ioctl call in a thread-safe fashion.
   template <typename T>
   int IoctlLocked(int request, T data);
@@ -59,6 +70,8 @@
   const std::string device_path_;
   // The opened device fd.
   ScopedFd device_fd_;
+  // The underlying gralloc module.
+  std::unique_ptr<V4L2Gralloc> gralloc_;
   // Whether or not the device supports the extended control query.
   bool extended_query_supported_;
   // The format this device is set up for.