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 // #define LOG_NDEBUG 0
18 #define LOG_TAG "RequestTracker"
19 
20 #include "request_tracker.h"
21 
22 #include <cutils/log.h>
23 
24 namespace default_camera_hal {
25 
RequestTracker()26 RequestTracker::RequestTracker() {}
27 
~RequestTracker()28 RequestTracker::~RequestTracker() {}
29 
SetStreamConfiguration(const camera3_stream_configuration_t & config)30 void RequestTracker::SetStreamConfiguration(
31     const camera3_stream_configuration_t& config) {
32   // Clear the old configuration.
33   ClearStreamConfiguration();
34   // Add an entry to the buffer tracking map for each configured stream.
35   for (size_t i = 0; i < config.num_streams; ++i) {
36     buffers_in_flight_.emplace(config.streams[i], 0);
37   }
38 }
39 
ClearStreamConfiguration()40 void RequestTracker::ClearStreamConfiguration() {
41   // The keys of the in flight buffer map are the configured streams.
42   buffers_in_flight_.clear();
43 }
44 
45 // Helper: get the streams used by a request.
RequestStreams(const CaptureRequest & request)46 std::set<camera3_stream_t*> RequestStreams(const CaptureRequest& request) {
47   std::set<camera3_stream_t*> result;
48   if (request.input_buffer) {
49     result.insert(request.input_buffer->stream);
50   }
51   for (const auto& output_buffer : request.output_buffers) {
52     result.insert(output_buffer.stream);
53   }
54   return result;
55 }
56 
Add(std::shared_ptr<CaptureRequest> request)57 bool RequestTracker::Add(std::shared_ptr<CaptureRequest> request) {
58   if (!CanAddRequest(*request)) {
59     return false;
60   }
61 
62   // Add to the count for each stream used.
63   for (const auto stream : RequestStreams(*request)) {
64     ++buffers_in_flight_[stream];
65   }
66 
67   // Store the request.
68   frames_in_flight_[request->frame_number] = request;
69 
70   return true;
71 }
72 
Remove(std::shared_ptr<CaptureRequest> request)73 bool RequestTracker::Remove(std::shared_ptr<CaptureRequest> request) {
74   if (!request) {
75     return false;
76   }
77 
78   // Get the request.
79   const auto frame_number_request =
80       frames_in_flight_.find(request->frame_number);
81   if (frame_number_request == frames_in_flight_.end()) {
82     ALOGE("%s: Frame %u is not in flight.", __func__, request->frame_number);
83     return false;
84   } else if (request != frame_number_request->second) {
85     ALOGE(
86         "%s: Request for frame %u cannot be removed: "
87         "does not matched the stored request.",
88         __func__,
89         request->frame_number);
90     return false;
91   }
92 
93   frames_in_flight_.erase(frame_number_request);
94 
95   // Decrement the counts of used streams.
96   for (const auto stream : RequestStreams(*request)) {
97     --buffers_in_flight_[stream];
98   }
99 
100   return true;
101 }
102 
Clear(std::set<std::shared_ptr<CaptureRequest>> * requests)103 void RequestTracker::Clear(
104     std::set<std::shared_ptr<CaptureRequest>>* requests) {
105   // If desired, extract all the currently in-flight requests.
106   if (requests) {
107     for (auto& frame_number_request : frames_in_flight_) {
108       requests->insert(frame_number_request.second);
109     }
110   }
111 
112   // Clear out all tracking.
113   frames_in_flight_.clear();
114   // Maintain the configuration, but reset counts.
115   for (auto& stream_count : buffers_in_flight_) {
116     stream_count.second = 0;
117   }
118 }
119 
CanAddRequest(const CaptureRequest & request) const120 bool RequestTracker::CanAddRequest(const CaptureRequest& request) const {
121   // Check that it's not a duplicate.
122   if (frames_in_flight_.count(request.frame_number) > 0) {
123     ALOGE("%s: Already tracking a request with frame number %d.",
124           __func__,
125           request.frame_number);
126     return false;
127   }
128 
129   // Check that each stream has space
130   // (which implicitly checks if it is configured).
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