Revert "Revert "Paint buffers, basic result metadata.""

This reverts commit a147f83c8c58f078fad95f99a19ac4441bcb5914.
Was reverted originally due to an issue in a parent CL. Now
that has been fixed, and this CL can be reinstated.

Change-Id: Ie281b6cc80705d8843572f21edde2398c892e35b
diff --git a/modules/camera/3_4/Camera.cpp b/modules/camera/3_4/Camera.cpp
index d1d1a9e..eb8ad18 100644
--- a/modules/camera/3_4/Camera.cpp
+++ b/modules/camera/3_4/Camera.cpp
@@ -17,6 +17,8 @@
 // Modified from hardware/libhardware/modules/camera/Camera.cpp
 
 #include <cstdlib>
+#include <memory>
+#include <vector>
 #include <stdio.h>
 #include <hardware/camera3.h>
 #include <sync/sync.h>
@@ -337,7 +339,7 @@
 
 int Camera::processCaptureRequest(camera3_capture_request_t *request)
 {
-    camera3_capture_result result;
+    int res;
 
     ALOGV("%s:%d: request=%p", __func__, mId, request);
     ATRACE_CALL();
@@ -385,28 +387,61 @@
                 request->num_output_buffers);
         return -EINVAL;
     }
-    result.num_output_buffers = request->num_output_buffers;
-    result.output_buffers = new camera3_stream_buffer_t[result.num_output_buffers];
-    for (unsigned int i = 0; i < request->num_output_buffers; i++) {
-        int res = processCaptureBuffer(&request->output_buffers[i],
-                const_cast<camera3_stream_buffer_t*>(&result.output_buffers[i]));
-        if (res)
-            goto err_out;
-    }
 
+    camera3_capture_result result;
+    result.num_output_buffers = request->num_output_buffers;
+    std::vector<camera3_stream_buffer_t> output_buffers(
+        result.num_output_buffers);
+    for (unsigned int i = 0; i < request->num_output_buffers; i++) {
+        res = processCaptureBuffer(&request->output_buffers[i],
+                                   &output_buffers[i]);
+        if (res)
+            return -ENODEV;
+    }
+    result.output_buffers = &output_buffers[0];
+
+    // Get metadata for this frame. Since the framework guarantees only
+    // one call to process_capture_request at a time, this call is guaranteed
+    // to correspond with the most recently enqueued buffer.
+
+    // Not wrapped in a unique_ptr since control is immediately
+    // handed off to the device via getResultSettings.
+    // TODO(b/30035628): This shouldn't even be an issue actually -
+    // the result settings returned should be a completely new
+    // object allocated by the function, not passed in and back
+    // out (the cloning of the request metadata is just a shim
+    // to fill in all the control fields until the device actually
+    // checks their real values).
+    camera_metadata_t* result_metadata = clone_camera_metadata(
+        request->settings);
+    if (!result_metadata) {
+        return -ENODEV;
+    }
+    uint64_t timestamp = 0;
+    // TODO(b/29334616): this may also want to use a callback, since
+    // the shutter may not happen immediately.
+    res = getResultSettings(&result_metadata, &timestamp);
+    // Upon getting result settings (for now from this function,
+    // eventually by callback, the Camera regains responsibility for
+    // the metadata, so immediately wrap it in a unique_ptr, before
+    // potentially returning due to failure.
+    std::unique_ptr<camera_metadata_t, void(*)(camera_metadata_t *)>
+        returned_metadata(result_metadata, free_camera_metadata);
+    if (res) {
+        return res;
+    }
+    result.result = returned_metadata.get();
+
+    // Notify the framework with the shutter time.
     result.frame_number = request->frame_number;
-    // TODO: return actual captured/reprocessed settings
-    result.result = request->settings;
-    // TODO: asynchronously return results
-    notifyShutter(request->frame_number, 0);
+    notifyShutter(result.frame_number, timestamp);
+
+    // TODO(b/29334616): asynchronously return results (the following should
+    // be done once all enqueued buffers for the request complete and callback).
+    result.partial_result = 1;
     mCallbackOps->process_capture_result(mCallbackOps, &result);
 
     return 0;
-
-err_out:
-    delete [] result.output_buffers;
-    // TODO: this should probably be a total device failure; transient for now
-    return -EINVAL;
 }
 
 void Camera::setSettings(const camera_metadata_t *new_settings)
@@ -431,8 +466,13 @@
 int Camera::processCaptureBuffer(const camera3_stream_buffer_t *in,
         camera3_stream_buffer_t *out)
 {
+    int res;
+    // TODO(b/29334616): This probably should be non-blocking (currently blocks
+    // here and on gralloc lock). Perhaps caller should put "in" in a queue
+    // initially, then have a thread that dequeues from there and calls this
+    // function.
     if (in->acquire_fence != -1) {
-        int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
+        res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
         if (res == -ETIME) {
             ALOGE("%s:%d: Timeout waiting on buffer acquire fence",
                     __func__, mId);
@@ -447,11 +487,18 @@
     out->stream = in->stream;
     out->buffer = in->buffer;
     out->status = CAMERA3_BUFFER_STATUS_OK;
+
+    // Enqueue buffer for software-painting
+    res = enqueueBuffer(out);
+    if (res) {
+      return res;
+    }
+
+    // TODO(b/29334616): This should be part of a callback made when the
+    // enqueued buffer finishes painting.
     // TODO: use driver-backed release fences
     out->acquire_fence = -1;
     out->release_fence = -1;
-
-    // TODO: lock and software-paint buffer
     return 0;
 }
 
diff --git a/modules/camera/3_4/Camera.h b/modules/camera/3_4/Camera.h
index c596350..d4b7272 100644
--- a/modules/camera/3_4/Camera.h
+++ b/modules/camera/3_4/Camera.h
@@ -69,9 +69,18 @@
         // buffers that stream can handle (max_buffers is an output parameter)
         virtual int setupStream(Stream* stream, uint32_t* max_buffers) = 0;
         // Verify settings are valid for a capture
-        virtual bool isValidCaptureSettings(const camera_metadata_t *) = 0;
+        virtual bool isValidCaptureSettings(
+            const camera_metadata_t *settings) = 0;
         // Separate initialization method for individual devices when opened
         virtual int initDevice() = 0;
+        // Enqueue a buffer to receive data from the camera
+        virtual int enqueueBuffer(
+            const camera3_stream_buffer_t *camera_buffer) = 0;
+        // Get the shutter time and updated settings for the most recent frame.
+        // The metadata parameter is both an input and output; frame-specific
+        // result fields should be appended to what is passed in.
+        virtual int getResultSettings(camera_metadata_t **metadata,
+                                      uint64_t *timestamp) = 0;
         // Accessor used by initDevice() to set the templates' metadata
         int setTemplate(int type, const camera_metadata_t *static_info);
         // Prettyprint template names
diff --git a/modules/camera/3_4/V4L2Camera.cpp b/modules/camera/3_4/V4L2Camera.cpp
index f27dc1f..25a5955 100644
--- a/modules/camera/3_4/V4L2Camera.cpp
+++ b/modules/camera/3_4/V4L2Camera.cpp
@@ -68,6 +68,8 @@
 // Helper function. Should be used instead of ioctl throughout this class.
 template<typename T>
 int V4L2Camera::ioctlLocked(int request, T data) {
+  HAL_LOG_ENTER();
+
   android::Mutex::Autolock al(mDeviceLock);
   if (mDeviceFd.get() < 0) {
     return -ENODEV;
@@ -118,6 +120,35 @@
   mOutStreamMaxBuffers = 0;
 }
 
+int V4L2Camera::streamOn() {
+  HAL_LOG_ENTER();
+
+  if (!mOutStreamType) {
+    HAL_LOGE("Stream format must be set before turning on stream.");
+    return -EINVAL;
+  }
+
+  if (ioctlLocked(VIDIOC_STREAMON, &mOutStreamType) < 0) {
+    HAL_LOGE("STREAMON fails: %s", strerror(errno));
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+int V4L2Camera::streamOff() {
+  HAL_LOG_ENTER();
+
+  // TODO(b/30000211): support mplane as well.
+  if (ioctlLocked(VIDIOC_STREAMOFF, &mOutStreamType) < 0) {
+    HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+
 int V4L2Camera::initStaticInfo(camera_metadata_t** out) {
   HAL_LOG_ENTER();
 
@@ -678,7 +709,7 @@
   }
 
   // Result keys will be duplicated from the request, plus a few extras.
-  // TODO(b/29335262): additonal available result keys.
+  // TODO(b/30035628): additonal available result keys.
   std::vector<int32_t> avail_result_keys(avail_request_keys);
   res = info.update(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
                     avail_result_keys.data(), avail_result_keys.size());
@@ -748,6 +779,117 @@
   return 0;
 }
 
+int V4L2Camera::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 = mOutStreamType;
+
+  // Use QUERYBUF to ensure our buffer/device is in good shape.
+  if (ioctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
+    HAL_LOGE("QUERYBUF (%d) fails: %s", 0, 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 = mGralloc.lock(camera_buffer, mOutStreamBytesPerLine,
+                          &device_buffer);
+  if (res) {
+    return res;
+  }
+  if (ioctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
+    HAL_LOGE("QBUF (%d) fails: %s", 0, strerror(errno));
+    mGralloc.unlock(&device_buffer);
+    return -ENODEV;
+  }
+
+  // Turn on the stream.
+  // TODO(b/29334616): Lock around stream on/off access, only start stream
+  // if not already on. (For now, since it's synchronous, it will always be
+  // turned off before another call to this function).
+  res = streamOn();
+  if (res) {
+    mGralloc.unlock(&device_buffer);
+    return res;
+  }
+
+  // TODO(b/29334616): Enqueueing and dequeueing should be separate worker
+  // threads, not in the same function.
+
+  // Dequeue the buffer.
+  v4l2_buffer result_buffer;
+  res = dequeueBuffer(&result_buffer);
+  if (res) {
+    mGralloc.unlock(&result_buffer);
+    return res;
+  }
+  // Now that we're done painting the buffer, we can unlock it.
+  res = mGralloc.unlock(&result_buffer);
+  if (res) {
+    return res;
+  }
+
+  // All done, cleanup.
+  // TODO(b/29334616): Lock around stream on/off access, only stop stream if
+  // buffer queue is empty (synchronously, there's only ever 1 buffer in the
+  // queue at a time, so this is safe).
+  res = streamOff();
+  if (res) {
+    return res;
+  }
+
+  // Sanity check.
+  if (result_buffer.m.userptr != device_buffer.m.userptr) {
+    HAL_LOGE("Got the wrong buffer 0x%x back (expected 0x%x)",
+             result_buffer.m.userptr, device_buffer.m.userptr);
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+int V4L2Camera::dequeueBuffer(v4l2_buffer* buffer) {
+  HAL_LOG_ENTER();
+
+  memset(buffer, 0, sizeof(*buffer));
+  buffer->type = mOutStreamType;
+  buffer->memory = V4L2_MEMORY_USERPTR;
+  if (ioctlLocked(VIDIOC_DQBUF, buffer) < 0) {
+    HAL_LOGE("DQBUF fails: %s", strerror(errno));
+    return -ENODEV;
+  }
+  return 0;
+}
+
+int V4L2Camera::getResultSettings(camera_metadata** metadata,
+                                  uint64_t* timestamp) {
+  HAL_LOG_ENTER();
+
+  int res;
+  android::CameraMetadata frame_metadata(*metadata);
+
+  // TODO(b/30035628): fill in.
+  // For now just spoof the timestamp to a non-0 value and send it back.
+  int64_t frame_time = 1;
+  res = frame_metadata.update(ANDROID_SENSOR_TIMESTAMP, &frame_time, 1);
+  if (res != android::OK) {
+    return res;
+  }
+
+  *metadata = frame_metadata.release();
+  *timestamp = frame_time;
+
+  return 0;
+}
+
 int V4L2Camera::initTemplates() {
   HAL_LOG_ENTER();
   int res;
@@ -1378,9 +1520,14 @@
   mOutStreamWidth = format.fmt.pix.width;
   mOutStreamHeight = format.fmt.pix.height;
   mOutStreamBytesPerLine = format.fmt.pix.bytesperline;
+  HAL_LOGV("New format: type %u, pixel format %u, width %u, height %u, "
+           "bytes/line %u", mOutStreamType, mOutStreamFormat, mOutStreamWidth,
+           mOutStreamHeight, mOutStreamBytesPerLine);
+
   // Since our format changed, our maxBuffers may be incorrect.
   mOutStreamMaxBuffers = 0;
 
+
   return 0;
 }
 
@@ -1391,7 +1538,7 @@
   // tells V4L2 to switch into userspace buffer mode).
   v4l2_requestbuffers req_buffers;
   memset(&req_buffers, 0, sizeof(req_buffers));
-  req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req_buffers.type = mOutStreamType;
   req_buffers.memory = V4L2_MEMORY_USERPTR;
   req_buffers.count = 1;
   if (ioctlLocked(VIDIOC_REQBUFS, &req_buffers) < 0) {
diff --git a/modules/camera/3_4/V4L2Camera.h b/modules/camera/3_4/V4L2Camera.h
index bb6aac8..1fabde9 100644
--- a/modules/camera/3_4/V4L2Camera.h
+++ b/modules/camera/3_4/V4L2Camera.h
@@ -63,10 +63,19 @@
                   uint32_t* max_buffers) override;
   // Verify settings are valid for a capture with this device.
   bool isValidCaptureSettings(const camera_metadata_t* settings) override;
+  // Enqueue a buffer to receive data from the camera.
+  int enqueueBuffer(const camera3_stream_buffer_t* camera_buffer) override;
+  // Get the shutter time and updated settings for the most recent frame.
+  // The metadata parameter is both an input and output; frame-specific
+  // result fields should be appended to what is passed in.
+  int getResultSettings(camera_metadata_t** metadata, uint64_t* timestamp);
 
   // Helper functions for V4L2 functionality.
+  int streamOn();
+  int streamOff();
   int setFormat(const default_camera_hal::Stream* stream);
   int setupBuffers();
+  int dequeueBuffer(v4l2_buffer* buffer);
 
   // HAL <-> V4L2 conversions.
   uint32_t halToV4L2PixelFormat(int hal_format);  // 0 for unrecognized.