Refactor capture processing to be async friendly

Set up a series of methods that can be producers/consumers/callbacks.
For now, they call each other synchronously.

TEST: manually tested with app
BUG: 29334616

Change-Id: Icb6cf9d9970521d5291c54f02dc5032f43b26616
diff --git a/modules/camera/3_4/v4l2_camera.cpp b/modules/camera/3_4/v4l2_camera.cpp
index 521f835..f7c75d2 100644
--- a/modules/camera/3_4/v4l2_camera.cpp
+++ b/modules/camera/3_4/v4l2_camera.cpp
@@ -164,70 +164,130 @@
   return 0;
 }
 
-int V4L2Camera::enqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
+int V4L2Camera::enqueueRequest(
+    std::shared_ptr<default_camera_hal::CaptureRequest> request) {
   HAL_LOG_ENTER();
 
-  int res = device_->EnqueueBuffer(camera_buffer);
-  if (res) {
-    HAL_LOGE("Device failed to enqueue buffer.");
-    return res;
+  // Assume request validated before calling this function.
+  // (For now, always exactly 1 output buffer, no inputs).
+
+  {
+    std::lock_guard<std::mutex> guard(request_queue_lock_);
+    request_queue_.push(request);
   }
 
-  // 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 = device_->StreamOn();
-  if (res) {
-    HAL_LOGE("Device failed to turn on stream.");
-    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 = device_->DequeueBuffer(&result_buffer);
-  if (res) {
-    HAL_LOGE("Device failed to dequeue buffer.");
-    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 = device_->StreamOff();
-  if (res) {
-    HAL_LOGE("Device failed to turn off stream.");
-    return res;
-  }
+  // TODO(b/29334616): Enqueueing of request buffers should be
+  // done by a consumer thread loop instead of here
+  enqueueRequestBuffers();
 
   return 0;
 }
 
-int V4L2Camera::getResultSettings(android::CameraMetadata* metadata,
-                                  uint64_t* timestamp) {
-  HAL_LOG_ENTER();
+std::shared_ptr<default_camera_hal::CaptureRequest>
+V4L2Camera::dequeueRequest() {
+  std::lock_guard<std::mutex> guard(request_queue_lock_);
+  if (request_queue_.empty()) {
+    return nullptr;
+  }
+  std::shared_ptr<default_camera_hal::CaptureRequest> request =
+      request_queue_.front();
+  request_queue_.pop();
+  return request;
+}
 
-  // Get the results.
-  int res = metadata_->FillResultMetadata(metadata);
-  if (res) {
-    HAL_LOGE("Failed to fill result metadata.");
-    return res;
+void V4L2Camera::enqueueRequestBuffers() {
+  // Get a request from the queue.
+  std::shared_ptr<default_camera_hal::CaptureRequest> request =
+      dequeueRequest();
+  if (!request) {
+    return;
   }
 
-  // Extract the timestamp.
-  int64_t frame_time = 0;
-  res = SingleTagValue(*metadata, ANDROID_SENSOR_TIMESTAMP, &frame_time);
-  if (res) {
-    HAL_LOGE("Failed to extract timestamp from result metadata");
-    return res;
-  }
-  *timestamp = static_cast<uint64_t>(frame_time);
+  // Assume request validated before being added to the queue
+  // (For now, always exactly 1 output buffer, no inputs).
+  {
+    std::lock_guard<std::mutex> guard(in_flight_lock_);
 
-  return 0;
+    // Set the requested settings
+    int res = metadata_->SetRequestSettings(request->settings);
+    if (res) {
+      HAL_LOGE("Failed to set settings.");
+      completeRequest(request, res);
+      return;
+    }
+
+    // Replace the requested settings with a snapshot of
+    // the used settings/state.
+    res = metadata_->FillResultMetadata(&request->settings);
+    if (res) {
+      HAL_LOGE("Failed to fill result metadata.");
+      completeRequest(request, res);
+      return;
+    }
+
+    // Actually enqueue the buffer for capture.
+    res = device_->EnqueueBuffer(&request->output_buffers[0]);
+    if (res) {
+      HAL_LOGE("Device failed to enqueue buffer.");
+      completeRequest(request, res);
+      return;
+    }
+
+    if (in_flight_.empty()) {
+      // Nothing in flight, stream should be off, so it needs to be turned on.
+      res = device_->StreamOn();
+      if (res) {
+        HAL_LOGE("Device failed to turn on stream.");
+        completeRequest(request, res);
+        return;
+      }
+    }
+    in_flight_.push(request);
+  }
+
+  // TODO(b/29334616): Dequeueing of request buffers should be
+  // done by a consumer thread loop instead of here
+  dequeueRequestBuffers();
+}
+
+void V4L2Camera::dequeueRequestBuffers() {
+  std::shared_ptr<default_camera_hal::CaptureRequest> request;
+  {
+    std::lock_guard<std::mutex> guard(in_flight_lock_);
+    if (in_flight_.empty()) {
+      return;
+    }
+
+    request = in_flight_.front();
+    in_flight_.pop();
+
+    // Dequeue the buffer. For now, since each request has only 1 buffer,
+    // and the in_flight_lock_ is held while enqueueing and dequeuing
+    // from the device, just assume that the dequeued buffer corresponds
+    // to the dequeued request.
+    // TODO(b/31657008): in_flight_ should map buffer handles to requests;
+    // this consumer should just dequeue whatever it gets, then match
+    // that to a handle.
+    v4l2_buffer result_buffer;
+    int res = device_->DequeueBuffer(&result_buffer);
+    if (res) {
+      HAL_LOGE("Device failed to dequeue buffer.");
+      completeRequest(request, res);
+      return;
+    }
+
+    // All done, turn off the stream if it's empty.
+    if (in_flight_.empty()) {
+      res = device_->StreamOff();
+      if (res) {
+        HAL_LOGE("Device failed to turn off stream.");
+        completeRequest(request, res);
+        return;
+      }
+    }
+  }
+
+  completeRequest(request, 0);
 }
 
 bool V4L2Camera::isSupportedStreamSet(default_camera_hal::Stream** streams,
@@ -356,17 +416,22 @@
   return 0;
 }
 
-bool V4L2Camera::isValidCaptureSettings(
-    const android::CameraMetadata& settings) {
+bool V4L2Camera::isValidRequest(
+    const default_camera_hal::CaptureRequest& request) {
   HAL_LOG_ENTER();
 
-  return metadata_->IsValidRequest(settings);
-}
+  if (request.input_buffer != nullptr) {
+    HAL_LOGE("Input buffer reprocessing not implemented.");
+    return false;
+  } else if (request.output_buffers.size() > 1) {
+    HAL_LOGE("Only 1 output buffer allowed per request.");
+    return false;
+  } else if (!metadata_->IsValidRequest(request.settings)) {
+    HAL_LOGE("Invalid request settings.");
+    return false;
+  }
 
-int V4L2Camera::setSettings(const android::CameraMetadata& new_settings) {
-  HAL_LOG_ENTER();
-
-  return metadata_->SetRequestSettings(new_settings);
+  return true;
 }
 
 }  // namespace v4l2_camera_hal