1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "EvsInputManager.h"
15
16 #include <chrono>
17 #include <map>
18 #include <shared_mutex>
19 #include <string>
20 #include <thread>
21
22 #include "AnalyzeUseCase.h"
23 #include "BaseAnalyzeCallback.h"
24 #include "InputConfig.pb.h"
25 #include "InputEngineInterface.h"
26 #include "Options.pb.h"
27
28 using ::android::automotive::evs::support::AnalyzeUseCase;
29 using ::android::automotive::evs::support::BaseAnalyzeCallback;
30
31 namespace android {
32 namespace automotive {
33 namespace computepipe {
34 namespace runner {
35 namespace input_manager {
36
analyze(const::android::automotive::evs::support::Frame & frame)37 void AnalyzeCallback::analyze(const ::android::automotive::evs::support::Frame& frame) {
38 std::shared_lock lock(mEngineInterfaceLock);
39 if (mInputEngineInterface != nullptr) {
40 auto time_point = std::chrono::system_clock::now();
41 int64_t timestamp = std::chrono::time_point_cast<std::chrono::microseconds>(time_point)
42 .time_since_epoch()
43 .count();
44 // Stride for hardware buffers is specified in pixels whereas for
45 // InputFrame, it is specified in bytes. We therefore need to multiply
46 // the stride by 4 for an RGBA frame.
47 InputFrame inputFrame(frame.height, frame.width, PixelFormat::RGBA, frame.stride * 4,
48 frame.data);
49 mInputEngineInterface->dispatchInputFrame(mInputStreamId, timestamp, inputFrame);
50 }
51 }
52
setEngineInterface(std::shared_ptr<InputEngineInterface> inputEngineInterface)53 void AnalyzeCallback::setEngineInterface(
54 std::shared_ptr<InputEngineInterface> inputEngineInterface) {
55 std::lock_guard lock(mEngineInterfaceLock);
56 mInputEngineInterface = inputEngineInterface;
57 }
58
EvsInputManager(const proto::InputConfig & inputConfig,std::shared_ptr<InputEngineInterface> inputEngineInterface)59 EvsInputManager::EvsInputManager(const proto::InputConfig& inputConfig,
60 std::shared_ptr<InputEngineInterface> inputEngineInterface) :
61 mInputEngineInterface(inputEngineInterface),
62 mInputConfig(inputConfig) {}
63
createEvsInputManager(const proto::InputConfig & inputConfig,const proto::InputConfig &,std::shared_ptr<InputEngineInterface> inputEngineInterface)64 std::unique_ptr<EvsInputManager> EvsInputManager::createEvsInputManager(
65 const proto::InputConfig& inputConfig, const proto::InputConfig& /*overrideConfig*/,
66 std::shared_ptr<InputEngineInterface> inputEngineInterface) {
67 auto evsManager = std::make_unique<EvsInputManager>(inputConfig, inputEngineInterface);
68 if (evsManager->initializeCameras() == Status::SUCCESS) {
69 return evsManager;
70 }
71
72 return nullptr;
73 }
74
initializeCameras()75 Status EvsInputManager::initializeCameras() {
76 for (int i = 0; i < mInputConfig.input_stream_size(); i++) {
77 // Verify that the stream type specified is a camera stream which is necessary for evs
78 // manager.
79 if (mInputConfig.input_stream(i).type() != proto::InputStreamConfig_InputType_CAMERA) {
80 ALOGE("Evs stream manager expects the input stream type to be camera.");
81 return Status::INVALID_ARGUMENT;
82 }
83 const std::string& cameraId = mInputConfig.input_stream(i).cam_config().cam_id();
84 std::unique_ptr<AnalyzeCallback> analyzeCallback =
85 std::make_unique<AnalyzeCallback>(mInputConfig.input_stream(i).stream_id());
86 AnalyzeUseCase analyzeUseCase =
87 AnalyzeUseCase::createDefaultUseCase(cameraId, analyzeCallback.get());
88 mAnalyzeCallbacks.push_back(std::move(analyzeCallback));
89
90 int streamId = mInputConfig.input_stream(i).stream_id();
91 auto [it, result] = mEvsUseCases.try_emplace(std::move(streamId),
92 std::move(analyzeUseCase));
93 if (!result) {
94 // Multiple camera streams found to have the same camera id.
95 ALOGE("Multiple camera streams have the same stream id.");
96 return Status::INVALID_ARGUMENT;
97 }
98 }
99
100 return Status::SUCCESS;
101 }
102
handleExecutionPhase(const RunnerEvent & e)103 Status EvsInputManager::handleExecutionPhase(const RunnerEvent& e) {
104 // Starting execution cannot be stopped in between. handleStopImmediate needs to be called.
105 if (e.isAborted()) {
106 return Status::INVALID_ARGUMENT;
107 } else if (e.isTransitionComplete()) {
108 return Status::SUCCESS;
109 }
110
111 if (mEvsUseCases.empty()) {
112 ALOGE("No evs use cases configured. Verify that handleConfigPhase has been called");
113 return Status::ILLEGAL_STATE;
114 }
115
116 // Start all the video streams.
117 bool successfullyStartedAllCameras = true;
118 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
119 if (!evsUseCase.startVideoStream()) {
120 successfullyStartedAllCameras = false;
121 ALOGE("Unable to successfully start all cameras");
122 break;
123 }
124 }
125
126 // If not all video streams have started successfully, stop the streams.
127 if (!successfullyStartedAllCameras) {
128 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
129 evsUseCase.stopVideoStream();
130 }
131 return Status::INTERNAL_ERROR;
132 }
133
134 // Set the input to engine interface for callbacks only when all the streams have successfully
135 // started. This prevents any callback from going out unless all of the streams have started.
136 for (auto& analyzeCallback : mAnalyzeCallbacks) {
137 analyzeCallback->setEngineInterface(mInputEngineInterface);
138 }
139
140 return Status::SUCCESS;
141 }
142
handleStopImmediatePhase(const RunnerEvent & e)143 Status EvsInputManager::handleStopImmediatePhase(const RunnerEvent& e) {
144 if (e.isAborted()) {
145 ALOGE(
146 "Unable to abort immediate stopping of EVS cameras. Please start the video streams "
147 "again if "
148 "needed.");
149 } else if (e.isTransitionComplete()) {
150 return Status::SUCCESS;
151 }
152
153 // Reset all input engine interfaces so that callbacks stop going out even if there are evs
154 // frames in flux.
155 for (auto& analyzeCallback : mAnalyzeCallbacks) {
156 analyzeCallback->setEngineInterface(nullptr);
157 }
158
159 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
160 evsUseCase.stopVideoStream();
161 }
162
163 return Status::SUCCESS;
164 }
165
handleStopWithFlushPhase(const RunnerEvent & e)166 Status EvsInputManager::handleStopWithFlushPhase(const RunnerEvent& e) {
167 if (e.isAborted()) {
168 ALOGE(
169 "Unable to abort stopping and flushing of EVS cameras. Please start the video streams "
170 "again if "
171 "needed.");
172 } else if (e.isTransitionComplete()) {
173 return Status::SUCCESS;
174 }
175
176 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
177 evsUseCase.stopVideoStream();
178 }
179 return Status::SUCCESS;
180 }
181
handleResetPhase(const RunnerEvent & e)182 Status EvsInputManager::handleResetPhase(const RunnerEvent& e) {
183 if (e.isAborted()) {
184 ALOGE("Unable to abort reset.");
185 return Status::INVALID_ARGUMENT;
186 }
187 mEvsUseCases.clear();
188 mAnalyzeCallbacks.clear();
189 return Status::SUCCESS;
190 }
191
192 } // namespace input_manager
193 } // namespace runner
194 } // namespace computepipe
195 } // namespace automotive
196 } // namespace android
197