1 /*
2  * Copyright 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "request_tracker.h"
18 
19 // #define LOG_NDEBUG 0
20 #define LOG_TAG "RequestTracker"
21 #include <cutils/log.h>
22 
23 namespace default_camera_hal {
24 
RequestTracker()25 RequestTracker::RequestTracker() {}
26 
~RequestTracker()27 RequestTracker::~RequestTracker() {}
28 
SetStreamConfiguration(const camera3_stream_configuration_t & config)29 void RequestTracker::SetStreamConfiguration(
30     const camera3_stream_configuration_t& config) {
31   // Clear the old configuration.
32   ClearStreamConfiguration();
33   // Add an entry to the buffer tracking map for each configured stream.
34   for (size_t i = 0; i < config.num_streams; ++i) {
35     buffers_in_flight_.emplace(config.streams[i], 0);
36   }
37 }
38 
ClearStreamConfiguration()39 void RequestTracker::ClearStreamConfiguration() {
40   // The keys of the in flight buffer map are the configured streams.
41   buffers_in_flight_.clear();
42 }
43 
44 // Helper: get the streams used by a request.
RequestStreams(const CaptureRequest & request)45 std::set<camera3_stream_t*> RequestStreams(const CaptureRequest& request) {
46   std::set<camera3_stream_t*> result;
47   if (request.input_buffer) {
48     result.insert(request.input_buffer->stream);
49   }
50   for (const auto& output_buffer : request.output_buffers) {
51     result.insert(output_buffer.stream);
52   }
53   return std::move(result);
54 }
55 
Add(std::shared_ptr<CaptureRequest> request)56 bool RequestTracker::Add(std::shared_ptr<CaptureRequest> request) {
57   if (!CanAddRequest(*request)) {
58     return false;
59   }
60 
61   // Add to the count for each stream used.
62   for (const auto stream : RequestStreams(*request)) {
63     ++buffers_in_flight_[stream];
64   }
65 
66   // Store the request.
67   frames_in_flight_[request->frame_number] = request;
68 
69   return true;
70 }
71 
Remove(std::shared_ptr<CaptureRequest> request)72 bool RequestTracker::Remove(std::shared_ptr<CaptureRequest> request) {
73   if (!request) {
74     return false;
75   }
76 
77   // Get the request.
78   const auto frame_number_request =
79       frames_in_flight_.find(request->frame_number);
80   if (frame_number_request == frames_in_flight_.end()) {
81     ALOGE("%s: Frame %u is not in flight.", __func__, request->frame_number);
82     return false;
83   } else if (request != frame_number_request->second) {
84     ALOGE(
85         "%s: Request for frame %u cannot be removed: "
86         "does not matched the stored request.",
87         __func__,
88         request->frame_number);
89     return false;
90   }
91 
92   frames_in_flight_.erase(frame_number_request);
93 
94   // Decrement the counts of used streams.
95   for (const auto stream : RequestStreams(*request)) {
96     --buffers_in_flight_[stream];
97   }
98 
99   return true;
100 }
101 
Clear(std::set<std::shared_ptr<CaptureRequest>> * requests)102 void RequestTracker::Clear(
103     std::set<std::shared_ptr<CaptureRequest>>* requests) {
104   // If desired, extract all the currently in-flight requests.
105   if (requests) {
106     for (auto& frame_number_request : frames_in_flight_) {
107       requests->insert(frame_number_request.second);
108     }
109   }
110 
111   // Clear out all tracking.
112   frames_in_flight_.clear();
113   // Maintain the configuration, but reset counts.
114   for (auto& stream_count : buffers_in_flight_) {
115     stream_count.second = 0;
116   }
117 }
118 
CanAddRequest(const CaptureRequest & request) const119 bool RequestTracker::CanAddRequest(const CaptureRequest& request) const {
120   // Check that it's not a duplicate.
121   if (frames_in_flight_.count(request.frame_number) > 0) {
122     ALOGE("%s: Already tracking a request with frame number %d.",
123           __func__,
124           request.frame_number);
125     return false;
126   }
127 
128   // Check that each stream has space
129   // (which implicitly checks if it is configured).
130   bool result = true;
131   for (const auto stream : RequestStreams(request)) {
132     if (StreamFull(stream)) {
133       ALOGE("%s: Stream %p is full.", __func__, stream);
134       return false;
135     }
136   }
137   return true;
138 }
139 
StreamFull(const camera3_stream_t * handle) const140 bool RequestTracker::StreamFull(const camera3_stream_t* handle) const {
141   const auto it = buffers_in_flight_.find(handle);
142   if (it == buffers_in_flight_.end()) {
143     // Unconfigured streams are implicitly full.
144     ALOGV("%s: Stream %p is not a configured stream.", __func__, handle);
145     return true;
146   } else {
147     return it->second >= it->first->max_buffers;
148   }
149 }
150 
InFlight(uint32_t frame_number) const151 bool RequestTracker::InFlight(uint32_t frame_number) const {
152   return frames_in_flight_.count(frame_number) > 0;
153 }
154 
Empty() const155 bool RequestTracker::Empty() const {
156   return frames_in_flight_.empty();
157 }
158 
159 }  // namespace default_camera_hal
160