Add request tracking.

RequestTracker keeps track of how many buffers are in flight for
each stream, and what frame numbers correspond to what requests/buffers.

BUG: 31044638
TEST: unit tests pass

Change-Id: I8ef3fcacdf8171514ea7f7eaf77301a641bff61e
diff --git a/modules/camera/3_4/request_tracker.cpp b/modules/camera/3_4/request_tracker.cpp
new file mode 100644
index 0000000..60715b5
--- /dev/null
+++ b/modules/camera/3_4/request_tracker.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "request_tracker.h"
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "RequestTracker"
+#include <cutils/log.h>
+
+namespace default_camera_hal {
+
+RequestTracker::RequestTracker() {}
+
+RequestTracker::~RequestTracker() {}
+
+void RequestTracker::SetStreamConfiguration(
+    const camera3_stream_configuration_t& config) {
+  // Clear the old configuration.
+  ClearStreamConfiguration();
+  // Add an entry to the buffer tracking map for each configured stream.
+  for (size_t i = 0; i < config.num_streams; ++i) {
+    buffers_in_flight_.emplace(config.streams[i], 0);
+  }
+}
+
+void RequestTracker::ClearStreamConfiguration() {
+  // The keys of the in flight buffer map are the configured streams.
+  buffers_in_flight_.clear();
+}
+
+// Helper: get the streams used by a request.
+std::set<camera3_stream_t*> RequestStreams(const CaptureRequest& request) {
+  std::set<camera3_stream_t*> result;
+  if (request.input_buffer) {
+    result.insert(request.input_buffer->stream);
+  }
+  for (const auto& output_buffer : request.output_buffers) {
+    result.insert(output_buffer.stream);
+  }
+  return std::move(result);
+}
+
+bool RequestTracker::Add(std::unique_ptr<CaptureRequest> request) {
+  if (!CanAddRequest(*request)) {
+    return false;
+  }
+
+  // Add to the count for each stream used.
+  for (const auto stream : RequestStreams(*request)) {
+    ++buffers_in_flight_[stream];
+  }
+
+  // Store the request.
+  frames_in_flight_[request->frame_number] = std::move(request);
+
+  return true;
+}
+
+bool RequestTracker::Remove(uint32_t frame_number,
+                            std::unique_ptr<CaptureRequest>* request) {
+  // Get the request.
+  std::unique_ptr<CaptureRequest> stored_request =
+      std::move(frames_in_flight_[frame_number]);
+  if (!stored_request) {
+    ALOGE("%s: Frame %u is not in flight.", __func__, frame_number);
+    return false;
+  }
+  frames_in_flight_.erase(frame_number);
+
+  // Decrement the counts of used streams.
+  for (const auto stream : RequestStreams(*stored_request)) {
+    --buffers_in_flight_[stream];
+  }
+
+  // Return the request if requested.
+  if (request) {
+    *request = std::move(stored_request);
+  }
+  return true;
+}
+
+void RequestTracker::Clear(
+    std::set<std::unique_ptr<CaptureRequest>>* requests) {
+  // If desired, extract all the currently in-flight requests.
+  if (requests) {
+    for (auto& frame_number_request : frames_in_flight_) {
+      requests->insert(std::move(frame_number_request.second));
+    }
+  }
+
+  // Clear out all tracking.
+  frames_in_flight_.clear();
+  buffers_in_flight_.clear();
+}
+
+bool RequestTracker::CanAddRequest(const CaptureRequest& request) const {
+  // Check that it's not a duplicate.
+  if (frames_in_flight_.count(request.frame_number) > 0) {
+    ALOGE("%s: Already tracking a request with frame number %d.",
+          __func__,
+          request.frame_number);
+    return false;
+  }
+
+  // Check that each stream has space
+  // (which implicitly checks if it is configured).
+  bool result = true;
+  for (const auto stream : RequestStreams(request)) {
+    if (StreamFull(stream)) {
+      ALOGE("%s: Stream %p is full.", __func__, stream);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool RequestTracker::StreamFull(const camera3_stream_t* handle) const {
+  const auto it = buffers_in_flight_.find(handle);
+  if (it == buffers_in_flight_.end()) {
+    // Unconfigured streams are implicitly full.
+    ALOGV("%s: Stream %p is not a configured stream.", __func__, handle);
+    return true;
+  } else {
+    return it->second >= it->first->max_buffers;
+  }
+}
+
+bool RequestTracker::InFlight(uint32_t frame_number) const {
+  return frames_in_flight_.count(frame_number) > 0;
+}
+
+bool RequestTracker::Empty() const {
+  return frames_in_flight_.empty();
+}
+
+}  // namespace default_camera_hal