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